request.spec.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import { act, fireEvent, render, RenderResult, waitFor } from '@testing-library/react';
  2. import { AxiosInstance, AxiosResponse } from 'axios';
  3. import nock from 'nock';
  4. import React from 'react';
  5. import { useRequestCallback } from './request';
  6. describe(useRequestCallback.name, () => {
  7. type MyQuery = { something: string };
  8. type MyResponse = { result: number };
  9. const onError = jest.fn();
  10. const sendRequest = (axios: AxiosInstance, query: MyQuery): Promise<AxiosResponse<MyResponse>> =>
  11. axios.get(`http://my-api.url:1234/my/request?something=${query.something}`);
  12. const TestComponent: React.FC = () => {
  13. const [onRequest, response, loading, cancel] = useRequestCallback<MyQuery, MyResponse>({
  14. onError,
  15. sendRequest,
  16. });
  17. return (
  18. <>
  19. <button onClick={(): void => onRequest({ something: 'yes' })}>Send request!</button>
  20. <button onClick={(): void => cancel.current?.()}>Cancel!</button>
  21. <div data-testid="response">{JSON.stringify(response)}</div>
  22. <div data-testid="loading">{loading ? 'Loading' : 'Not loading'}</div>
  23. </>
  24. );
  25. };
  26. afterEach(() => {
  27. nock.cleanAll();
  28. });
  29. const setupRequest = (): RenderResult => {
  30. const renderResult = render(<TestComponent />);
  31. act(() => {
  32. fireEvent.click(renderResult.getByText('Send request!'));
  33. });
  34. return renderResult;
  35. };
  36. it('should return null as the initial response', () => {
  37. expect.assertions(1);
  38. const { getByTestId } = render(<TestComponent />);
  39. expect(JSON.parse(getByTestId('response').innerHTML)).toBeNull();
  40. });
  41. it('should initially set the loading state to false', () => {
  42. expect.assertions(1);
  43. const { getByTestId } = render(<TestComponent />);
  44. expect(getByTestId('loading')).toHaveTextContent('Not loading');
  45. });
  46. describe('when sending a request', () => {
  47. beforeEach(() => {
  48. nock('http://my-api.url:1234')
  49. .get('/my/request?something=yes')
  50. .reply(200, { result: 125 }, { 'Access-Control-Allow-Origin': '*' });
  51. });
  52. it('should set the loading state to true', async () => {
  53. expect.assertions(1);
  54. const { getByTestId, unmount } = setupRequest();
  55. expect(getByTestId('loading')).toHaveTextContent('Loading');
  56. unmount();
  57. });
  58. it('should set the response and loading state back to false', async () => {
  59. expect.hasAssertions();
  60. const { getByTestId, unmount } = setupRequest();
  61. await waitFor(() => {
  62. expect(getByTestId('loading')).toHaveTextContent('Not loading');
  63. });
  64. expect(JSON.parse(getByTestId('response').innerHTML)).toStrictEqual({ result: 125 });
  65. unmount();
  66. });
  67. describe('when the request is cancelled', () => {
  68. it('should set the loading state back to false and not set the response', async () => {
  69. expect.hasAssertions();
  70. const { getByText, getByTestId, unmount } = setupRequest();
  71. act(() => {
  72. fireEvent.click(getByText('Cancel!'));
  73. });
  74. expect(getByTestId('loading')).toHaveTextContent('Loading');
  75. await waitFor(() => {
  76. expect(getByTestId('loading')).toHaveTextContent('Not loading');
  77. });
  78. expect(JSON.parse(getByTestId('response').innerHTML)).toBeNull();
  79. unmount();
  80. });
  81. });
  82. });
  83. describe('when an error occurs', () => {
  84. beforeEach(() => {
  85. nock('http://my-api.url:1234')
  86. .get('/my/request?something=yes')
  87. .reply(500, 'Some error occurred', { 'Access-Control-Allow-Origin': '*' });
  88. onError.mockClear();
  89. });
  90. it('should call onError', async () => {
  91. expect.hasAssertions();
  92. const { unmount } = setupRequest();
  93. await waitFor(() => {
  94. expect(onError).toHaveBeenCalledTimes(1);
  95. expect(onError).toHaveBeenCalledWith(new Error('Request failed with status code 500'));
  96. });
  97. unmount();
  98. });
  99. });
  100. });