use-abort-controller.test.js 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import fetchMock from 'fetch-mock'
  2. import { expect } from 'chai'
  3. import React from 'react'
  4. import { render, waitFor } from '@testing-library/react'
  5. import useAbortController from '../../../../frontend/js/shared/hooks/use-abort-controller'
  6. import { getJSON } from '../../../../frontend/js/infrastructure/fetch-json'
  7. describe('useAbortController', function () {
  8. let status
  9. beforeEach(function () {
  10. fetchMock.restore()
  11. status = {
  12. loading: false,
  13. success: null,
  14. error: null,
  15. }
  16. })
  17. after(function () {
  18. fetchMock.restore()
  19. })
  20. function AbortableRequest({ url }) {
  21. const { signal } = useAbortController()
  22. React.useEffect(() => {
  23. status.loading = true
  24. getJSON(url, { signal })
  25. .then(() => {
  26. status.success = true
  27. })
  28. .catch(error => {
  29. status.error = error
  30. })
  31. .finally(() => {
  32. status.loading = false
  33. })
  34. }, [signal, url])
  35. return null
  36. }
  37. it('calls then when the request succeeds', async function () {
  38. fetchMock.get('/test', { status: 204 }, { delay: 100 })
  39. render(<AbortableRequest url="/test" />)
  40. expect(status.loading).to.be.true
  41. await waitFor(() => expect(status.loading).to.be.false)
  42. expect(status.success).to.be.true
  43. expect(status.error).to.be.null
  44. })
  45. it('calls catch when the request fails', async function () {
  46. fetchMock.get('/test', { status: 500 }, { delay: 100 })
  47. render(<AbortableRequest url="/test" />)
  48. expect(status.loading).to.be.true
  49. await waitFor(() => expect(status.loading).to.be.false)
  50. expect(status.success).to.be.null
  51. expect(status.error).not.to.be.null
  52. })
  53. it('cancels a request when unmounted', async function () {
  54. fetchMock.get('/test', { status: 204 }, { delay: 100 })
  55. const { unmount } = render(<AbortableRequest url="/test" />)
  56. expect(status.loading).to.be.true
  57. unmount()
  58. await fetchMock.flush(true)
  59. expect(fetchMock.done()).to.be.true
  60. // wait for Promises to be resolved
  61. await new Promise(resolve => setTimeout(resolve, 0))
  62. expect(status.success).to.be.null
  63. expect(status.error).to.be.null
  64. expect(status.loading).to.be.true
  65. })
  66. })