use-abort-controller.test.tsx 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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. loading: boolean
  10. success: boolean | null
  11. error: any | null
  12. }
  13. beforeEach(function () {
  14. fetchMock.restore()
  15. status = {
  16. loading: false,
  17. success: null,
  18. error: null,
  19. }
  20. })
  21. after(function () {
  22. fetchMock.restore()
  23. })
  24. function AbortableRequest({ url }: { url: string }) {
  25. const { signal } = useAbortController()
  26. React.useEffect(() => {
  27. status.loading = true
  28. getJSON(url, { signal })
  29. .then(() => {
  30. status.success = true
  31. })
  32. .catch(error => {
  33. status.error = error
  34. })
  35. .finally(() => {
  36. status.loading = false
  37. })
  38. }, [signal, url])
  39. return null
  40. }
  41. it('calls then when the request succeeds', async function () {
  42. fetchMock.get('/test', { status: 204 }, { delay: 100 })
  43. render(<AbortableRequest url="/test" />)
  44. expect(status.loading).to.be.true
  45. await waitFor(() => expect(status.loading).to.be.false)
  46. expect(status.success).to.be.true
  47. expect(status.error).to.be.null
  48. })
  49. it('calls catch when the request fails', async function () {
  50. fetchMock.get('/test', { status: 500 }, { delay: 100 })
  51. render(<AbortableRequest url="/test" />)
  52. expect(status.loading).to.be.true
  53. await waitFor(() => expect(status.loading).to.be.false)
  54. expect(status.success).to.be.null
  55. expect(status.error).not.to.be.null
  56. })
  57. it('cancels a request when unmounted', async function () {
  58. fetchMock.get('/test', { status: 204 }, { delay: 100 })
  59. const { unmount } = render(<AbortableRequest url="/test" />)
  60. expect(status.loading).to.be.true
  61. unmount()
  62. await fetchMock.flush(true)
  63. expect(fetchMock.done()).to.be.true
  64. // wait for Promises to be resolved
  65. await new Promise(resolve => setTimeout(resolve, 0))
  66. expect(status.success).to.be.null
  67. expect(status.error).to.be.null
  68. expect(status.loading).to.be.true
  69. })
  70. })