Javascript 如何修复使用Jest测试时未正确检查的ajv模式

Javascript 如何修复使用Jest测试时未正确检查的ajv模式,javascript,jestjs,ajv,Javascript,Jestjs,Ajv,基本上,我目前正在为一个函数编写一个单元测试,它使用AJV模式检查json-文件是否有效。问题是,对模式的检查在浏览器中有效,但在测试中无效 无效文件错误 export class InvalidFileError extends Error { constructor(message) { super(message) this.name = "InvalidFileError" } } 我要测试的功能 export function impo

基本上,我目前正在为一个函数编写一个单元测试,它使用AJV模式检查
json
-文件是否有效。问题是,对模式的检查在浏览器中有效,但在测试中无效

无效文件错误

export class InvalidFileError extends Error {
    constructor(message) {
        super(message)
        this.name = "InvalidFileError"
    }
}
我要测试的功能

export function importFile(e, importScenarios, importDevices) {
    const file = e.target.files[0]
    const fileReader = new FileReader()
    fileReader.readAsText(file)

    fileReader.onload = () => { // File loaded
        const fileContent = JSON.parse(fileReader.result)

        const ajv = new Ajv({allErrors: true})
        const validate = ajv.compile(schema)
        const contentIsValid = validate(fileContent)

        console.log("Content is valid: ", contentIsValid)
        if (contentIsValid) {
            importScenarios(fileContent.scenarios)
            importDevices(fileContent.devices)
        } else {
            throw new InvalidFileError("This file doesn't match the schema")
        }
    }
}
我写的当前测试

describe("Does Importing a file work properly?", () => {
    let file
    let e = {
        target: {
            files: []
        }
    }

    let importScenarios = () => {}
    let importDevices = () => {}

    test("Does it work with a file matching the schema?", () => {
        file = new Blob(correctTestContent, { type: "application/json" })

        e.target.files.push(file)
        expect(() => {
            FileManager.importFile(e, importScenarios, importDevices)
        }).not.toThrow(InvalidFileError)
    })

    test("Does it work with a file not matching the schema??", () => {
        file = new Blob(incorrectTestContent, { type: "application/json" })
        e.target.files.push(file)

        expect(() => {
            FileManager.importFile(e, importScenarios, importDevices)
        }).toThrow(InvalidFileError)
    })

    afterEach(() => {
        e.target.files = []
    })
})
当我在浏览器中使用此功能时,通过上载无效文件,它会抛出错误,如果我上载有效文件,则不会。
这在测试中应该是完全相同的,但不幸的是事实并非如此。

问题在于,您尝试测试的代码是异步的,而您编写的测试不是异步的

运行测试时,在执行相应测试期间,
FileReader
onload
回调不会被执行。相反,它是在测试执行后调用的。事实上,因为你有这样的陈述:

console.log("Content is valid: ", contentIsValid)
importFile
方法中,您应该在控制台中看到如下消息:

测试完成后无法登录。您是否忘记在测试中等待异步的内容

您需要进行测试,以便它们等待
onload
回调执行。不幸的是,您的代码很难进行测试,因为您无法知道何时执行了
onload
回调,因此在测试中也很难等到那一刻

解决这个问题的一种方法是将异步代码包装在一个包中并返回它,这样我们就可以等待承诺完成。使用这种方法,您的
导入文件将类似于:

export function importFile(e, importScenarios, importDevices) {
    const file = e.target.files[0]
    const fileReader = new FileReader()
    fileReader.readAsText(file)

    return new Promise((resolve, reject) => {
        fileReader.onload = () => { // File loaded
            const fileContent = JSON.parse(fileReader.result)

            const ajv = new Ajv({allErrors: true})
            const validate = ajv.compile(schema)
            const contentIsValid = validate(fileContent)

            if (contentIsValid) {
                importScenarios(fileContent.scenarios)
                importDevices(fileContent.devices)
                resolve()
            } else {
                reject(new InvalidFileError("This file doesn't match the schema"))
            }
        }
    });
}
然后,您可以通过在测试中返回承诺来测试此方法(以便jest知道它必须等待承诺得到解决或拒绝):

请注意,我已经重新定义了变量
importScenarios
importDevices
,这样我们就可以检查它们是否被调用了。另外,请注意使用
expect.assertions
来验证是否调用了一定数量的断言

最后,要考虑到,如果您重新定义了
importFile
,使其返回承诺,那么您可能需要更改调用它的位置来处理拒绝案例。如果您有:

try {
    FileManager.importFile(e, importScenarios, importDevices)
} catch(e) {
    // Some treatment of your exception
}
您将需要:

FileManager.importFile(e, importScenarios, importDevices).catch(e => {
    // Some treatment of your exception
})

嘿,姆加西亚,谢谢你的回答!不幸的是,当我在测试控制台中进行这些更改时,它现在打印以下行:
Timeout-异步回调没有在jest.setTimeout指定的5000ms超时内调用。错误:
另外,现在在用户界面中,当我尝试导入与架构不匹配的文件时,它会以任何方式导入它,没有在consoleCorrection中记录捕获到的错误消息:关于接口的最后一部分是我犯的错误,导入了错误的文件,事实上记录了错误我确实尝试将jest超时增加到30秒,以查看这是否会改变任何内容,但它给出了相同的错误,但是现在使用
30000ms
而不是最初的
5000ms
,代码中似乎没有调用某些内容,可能是因为键入错误。您是否在
导入文件
函数和测试中都返回了承诺?验证正确时,是否在
importFile
中调用
resolve
方法?
FileManager.importFile(e, importScenarios, importDevices).catch(e => {
    // Some treatment of your exception
})