问题
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