|
1 | 1 | import { useAsync } from '../src';
|
2 | 2 | import { renderHook } from '@testing-library/react-hooks';
|
3 | 3 |
|
| 4 | +const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); |
| 5 | + |
4 | 6 | interface StarwarsHero {
|
5 | 7 | name: string;
|
6 | 8 | }
|
7 | 9 |
|
8 |
| -export const generateMockResponseData = (amount: number = 5): StarwarsHero[] => |
| 10 | +export const generateFakeResults = (pageSize: number = 5): StarwarsHero[] => |
9 | 11 | // @ts-ignore
|
10 |
| - [...Array(amount).keys()].map(n => ({ |
| 12 | + [...Array(pageSize).keys()].map(n => ({ |
11 | 13 | id: n + 1,
|
12 | 14 | name: `Starwars Hero ${n + 1}`,
|
13 | 15 | }));
|
14 | 16 |
|
| 17 | +export const generateFakeResultsAsync = async ( |
| 18 | + pageSize: number = 5, |
| 19 | + delay = 100 |
| 20 | +): Promise<StarwarsHero[]> => { |
| 21 | + await sleep(delay); |
| 22 | + return generateFakeResults(pageSize); |
| 23 | +}; |
| 24 | + |
15 | 25 | describe('useAync', () => {
|
16 |
| - const fakeResults = generateMockResponseData(); |
| 26 | + const fakeResults = generateFakeResults(); |
17 | 27 |
|
18 | 28 | it('should have a useAsync hook', () => {
|
19 | 29 | expect(useAsync).toBeDefined();
|
20 | 30 | });
|
21 | 31 |
|
22 |
| - it('should resolve a successful request', async () => { |
| 32 | + it('should resolve a successful resolved promise', async () => { |
23 | 33 | const onSuccess = jest.fn();
|
24 | 34 | const onError = jest.fn();
|
25 | 35 |
|
@@ -47,6 +57,90 @@ describe('useAync', () => {
|
47 | 57 | expect(onError).not.toHaveBeenCalled();
|
48 | 58 | });
|
49 | 59 |
|
| 60 | + it('should resolve a successful real-world request + handle params update', async () => { |
| 61 | + const onSuccess = jest.fn(); |
| 62 | + const onError = jest.fn(); |
| 63 | + |
| 64 | + const { result, waitForNextUpdate, rerender } = renderHook( |
| 65 | + ({ pageSize }: { pageSize: number }) => |
| 66 | + useAsync(() => generateFakeResultsAsync(pageSize), [pageSize], { |
| 67 | + onSuccess: () => onSuccess(), |
| 68 | + onError: () => onError(), |
| 69 | + }), |
| 70 | + { |
| 71 | + initialProps: { pageSize: 5 }, |
| 72 | + } |
| 73 | + ); |
| 74 | + |
| 75 | + expect(result.current.loading).toBe(true); |
| 76 | + await waitForNextUpdate(); |
| 77 | + expect(result.current.result).toEqual(generateFakeResults(5)); |
| 78 | + expect(result.current.loading).toBe(false); |
| 79 | + expect(result.current.error).toBeUndefined(); |
| 80 | + expect(onSuccess).toHaveBeenCalledTimes(1); |
| 81 | + expect(onError).not.toHaveBeenCalled(); |
| 82 | + |
| 83 | + rerender({ |
| 84 | + pageSize: 6, |
| 85 | + }); |
| 86 | + |
| 87 | + expect(result.current.loading).toBe(true); |
| 88 | + await waitForNextUpdate(); |
| 89 | + expect(result.current.result).toEqual(generateFakeResults(6)); |
| 90 | + expect(result.current.loading).toBe(false); |
| 91 | + expect(result.current.error).toBeUndefined(); |
| 92 | + expect(onSuccess).toHaveBeenCalledTimes(2); |
| 93 | + expect(onError).not.toHaveBeenCalled(); |
| 94 | + }); |
| 95 | + |
| 96 | + it('should resolve a successful real-world requests with potential race conditions', async () => { |
| 97 | + const onSuccess = jest.fn(); |
| 98 | + const onError = jest.fn(); |
| 99 | + |
| 100 | + const { result, waitForNextUpdate, rerender } = renderHook( |
| 101 | + ({ pageSize, delay }: { pageSize: number; delay: number }) => |
| 102 | + useAsync( |
| 103 | + () => generateFakeResultsAsync(pageSize, delay), |
| 104 | + [pageSize, delay], |
| 105 | + { |
| 106 | + onSuccess: () => onSuccess(), |
| 107 | + onError: () => onError(), |
| 108 | + } |
| 109 | + ), |
| 110 | + { |
| 111 | + initialProps: { pageSize: 5, delay: 200 }, |
| 112 | + } |
| 113 | + ); |
| 114 | + |
| 115 | + rerender({ |
| 116 | + pageSize: 6, |
| 117 | + delay: 100, |
| 118 | + }); |
| 119 | + |
| 120 | + rerender({ |
| 121 | + pageSize: 7, |
| 122 | + delay: 0, |
| 123 | + }); |
| 124 | + |
| 125 | + expect(result.current.loading).toBe(true); |
| 126 | + await waitForNextUpdate(); |
| 127 | + expect(result.current.result).toEqual(generateFakeResults(7)); |
| 128 | + expect(result.current.loading).toBe(false); |
| 129 | + expect(result.current.error).toBeUndefined(); |
| 130 | + expect(onSuccess).toHaveBeenCalledTimes(1); |
| 131 | + expect(onError).not.toHaveBeenCalled(); |
| 132 | + |
| 133 | + await sleep(100); |
| 134 | + expect(onSuccess).toHaveBeenCalledTimes(2); |
| 135 | + |
| 136 | + await sleep(100); |
| 137 | + expect(onSuccess).toHaveBeenCalledTimes(3); |
| 138 | + |
| 139 | + expect(result.current.result).toEqual(generateFakeResults(7)); |
| 140 | + expect(result.current.loading).toBe(false); |
| 141 | + expect(result.current.error).toBeUndefined(); |
| 142 | + }); |
| 143 | + |
50 | 144 | // Test added because Jest mocks can return promises that arre not instances of Promises
|
51 | 145 | // This test ensures better testability of user code
|
52 | 146 | // See https://github.com/slorber/react-async-hook/issues/24
|
|
0 commit comments