问题
I have an event listener that runs an asynchronous function, and removes some elements from the DOM after completion:
async function fetchAndRemove() {
try {
const response = await fetch('/endpoint-that-returns-json')
const result = await response.json()
if (result.status === 'Success') {
document.querySelector('.my-element').remove()
}
} catch (error) {
console.log(error)
}
}
function setupListeners () {
const button = document.querySelector('.my-button')
button.addEventListener('click', () => {
fetchAndRemove()
})
}
setupListeners()
In my test, I have:
import fetch from 'jest-fetch-mock';
test('it removes the element after clicking', () => {
fetch.mockResponse(JSON.stringify({ status: 'Success' }))
setupListeners()
document.querySelector('.my-button').click() // .click comes from JSDOM
expect(document.querySelector('.my-element')).toBeNull()
}
However that doesn't work because I believe in the test, setting up the event listener and clicking the button runs synchronously and doesn't wait for the async work to finish.
I tried this idea but no good results:
test('it removes the element after clicking', async () => {
fetch.mockResponse(JSON.stringify({ status: 'Success' }))
setupListeners()
await Promise.resolve(document.querySelector('.my-button').click())
expect(document.querySelector('.my-element')).toBeNull()
}
回答1:
This is wrong because DOM events don't involve promises and await Promise.resolve is redundant:
await Promise.resolve(document.querySelector('.my-button').click())
It creates one-tick delay and that's all.
Since fetchAndRemove is referred in the same module it's defined, it cannot be spied, so fetch promise should be chained in order to maintain correct execution order.
Considering that fetch is a spy, it can be:
fetch.mockResponse(JSON.stringify({ status: 'Success' }))
setupListeners()
document.querySelector('.my-button').click()
await fetch.mock.results[0].value; // delay for fetch()
await null; // another delay for res.json()
expect(fetch).toBeCalledWith('/endpoint-that-returns-json')
expect(document.querySelector('.my-element')).toBeNull()
来源:https://stackoverflow.com/questions/62088063/how-to-test-an-async-function-in-an-event-listener-with-jest