How to test an async function in an event listener with Jest?

ぃ、小莉子 提交于 2021-01-28 04:26:29

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!