react-use/tests/useAsync.test.tsx
2020-01-17 09:24:06 +01:00

178 lines
4.4 KiB
TypeScript

import { renderHook } from '@testing-library/react-hooks';
import { useCallback } from 'react';
import useAsync from '../src/useAsync';
describe('useAsync', () => {
it('should be defined', () => {
expect(useAsync).toBeDefined();
});
describe('a success', () => {
let hook;
let callCount = 0;
const resolver = async () => {
return new Promise(resolve => {
callCount++;
const wait = setTimeout(() => {
clearTimeout(wait);
resolve('yay');
}, 0);
});
};
beforeEach(() => {
callCount = 0;
hook = renderHook(({ fn }) => useAsync(fn, [fn]), {
initialProps: {
fn: resolver,
},
});
});
it('initially starts loading', async () => {
expect(hook.result.current.loading).toEqual(true);
await hook.waitForNextUpdate();
});
it('resolves', async () => {
expect.assertions(4);
hook.rerender({ fn: resolver });
await hook.waitForNextUpdate();
expect(callCount).toEqual(1);
expect(hook.result.current.loading).toBeFalsy();
expect(hook.result.current.value).toEqual('yay');
expect(hook.result.current.error).toEqual(undefined);
});
});
describe('an error', () => {
let hook;
let callCount = 0;
const rejection = async () => {
return new Promise((_, reject) => {
callCount++;
const wait = setTimeout(() => {
clearTimeout(wait);
reject('yay');
}, 0);
});
};
beforeEach(() => {
callCount = 0;
hook = renderHook(({ fn }) => useAsync(fn, [fn]), {
initialProps: {
fn: rejection,
},
});
});
it('initially starts loading', async () => {
expect(hook.result.current.loading).toBeTruthy();
await hook.waitForNextUpdate();
});
it('resolves', async () => {
expect.assertions(4);
hook.rerender({ fn: rejection });
await hook.waitForNextUpdate();
expect(callCount).toEqual(1);
expect(hook.result.current.loading).toBeFalsy();
expect(hook.result.current.error).toEqual('yay');
expect(hook.result.current.value).toEqual(undefined);
});
});
describe('re-evaluates when dependencies change', () => {
describe('the fn is a dependency', () => {
let hook;
let callCount = 0;
const initialFn = async () => {
callCount++;
return 'value';
};
const differentFn = async () => {
callCount++;
return 'new value';
};
beforeEach(done => {
callCount = 0;
hook = renderHook(({ fn }) => useAsync(fn, [fn]), {
initialProps: { fn: initialFn },
});
hook.waitForNextUpdate().then(done);
});
it('renders the first value', () => {
expect(hook.result.current.value).toEqual('value');
});
it('renders a different value when deps change', async () => {
expect.assertions(3);
expect(callCount).toEqual(1);
hook.rerender({ fn: differentFn }); // change the fn to initiate new request
await hook.waitForNextUpdate();
expect(callCount).toEqual(2);
expect(hook.result.current.value).toEqual('new value');
});
});
describe('the additional dependencies list changes', () => {
let callCount = 0;
let hook;
const staticFunction = async counter => {
callCount++;
return `counter is ${counter} and callCount is ${callCount}`;
};
beforeEach(done => {
callCount = 0;
hook = renderHook(
({ fn, counter }) => {
const callback = useCallback(() => fn(counter), [counter]);
return useAsync<any>(callback, [callback]);
},
{
initialProps: {
counter: 0,
fn: staticFunction,
},
}
);
hook.waitForNextUpdate().then(done);
});
it('initial renders the first passed pargs', () => {
expect(hook.result.current.value).toEqual('counter is 0 and callCount is 1');
});
it('renders a different value when deps change', async () => {
expect.assertions(1);
hook.rerender({ fn: staticFunction, counter: 1 });
await hook.waitForNextUpdate();
expect(hook.result.current.value).toEqual('counter is 1 and callCount is 2');
});
});
});
});