๐ง Hooks testing?
๋ฆฌ์กํธ ํ๋ก์ ํธ์์ react-hooks
๋ฅผ ์ฌ์ฉํ๋ค๋ฉด, ๊ณตํต๋ ๋ก์ง์ด๋ ์ํ๊ด๋ จ ๋ก์ง์ด๋ ๋ค์ํ custom hook์ ๋ง๋ค์ด ์ฌ์ฉํ๊ฒ๋๋ค.
๋ฐ๋ผ์ reducer๋ component ํ
์คํ
๋ฟ๋ง ์๋๋ผ ์ด๋ฌํ custom hook๋ค์ด ์๋๋๋ก ์๋ํ๋์ง๋ ํ
์คํ
ํด์ฃผ๋ ๊ฒ์ด ์ข๋ค.
ํ๋์ component์์ ์ฌ์ฉ๋๋ hook์ด๊ฑฐ๋ ๊ฐ๋จํ ๋ก์ง์ hook์ด๋ผ๋ฉด ์ง์ ํ
์คํ
ํ๋ ๊ฒ์ด ์ฝ๊ฒ ์ง๋ง,
๋ณต์กํ ๋ก์ง์ hook์ด๋ API์์ฒญ์ด ์๋ hook๋ฑ์ ์ง์ ํ
์คํ
ํ๋ ๊ฒ์ด ์กฐ๊ธ์ ๋ณต์กํ ์ ์๋ค.testing-library/react-hook
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ฌํ hook๋ค์ ์ฝ๊ฒ ํ
์คํ
ํ ์ ์๋ค.
๐ testing-library/react-hooks
testing-library/react-hooks
์ API ์ค ๊ฐ์ฅ ํํ๊ฒ ์ฐ์ด๋ ๊ฒ๋ค์ renderHook
, act
์ด๋ค.renderHook
์ ์ปค์คํ
ํ
์ ๋ฐ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ง๋คํ์์์ด ์ฝ๊ฒ ํ
์คํธํ ์ ์๊ฒํด์ฃผ๊ณ act
๋ ์ปค์คํ
ํ
์ ์
๋ฐ์ดํธํ ๋ ์ฐ์ด๋ API์ด๋ค.
๊ทธ์ธ ๋ค์ํ API๋ค์ ์ด๊ณณ์ ์ฐธ๊ณ ํ๋ฉด ๋๋ค.
์์ฑํ ํ ์คํธ์ฝ๋
// useFilter.ts
export function useFilter() {
const filter = useRootState((state) => state.filter);
const dispatch = useDispatch();
const actions = useMemo(() => bindActionCreators(filterActions, dispatch), [dispatch]);
return [filter, actions.applyFilter] as const;
}
// useFilter.test.ts
import { act, renderHook } from '@testing-library/react-hooks';
import prepareMockReduxWrapper from '@/lib/prepareMockReduxWrapper';
import { filterActions } from '@/_reducer/filter';
import { useFilter } from '@/hooks/useFilter';
import configureMockStore from 'redux-mock-store';
describe('useFilter', () => {
const setup = () => {
const [wrapper, store] = prepareMockReduxWrapper({
filter: 'ALL',
todos: [],
});
const { result } = renderHook(() => useFilter(), { wrapper });
return { store, result };
};
...
it('confirm dispatch', () => {
const { store, result } = setup();
// applyFilter ํจ์๋ฅผ ํธ์ถํ๊ณ
act(() => {
result.current[1]('DONE');
});
// ํด๋น ์ก์
์ด ๋์คํจ์น ๋๋์ง ํ์ธ
expect(store.getActions()).toEqual([filterActions.applyFilter('DONE')]);
});
...
});
์์ prepareMockReduxWrapper
์ redux-mock-store
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ initial state
๋ฅผ ๋ฐ๊ณ , wrapper
์ store
์ ๋ฆฌํดํ๋ ํจ์๋ค.renderHook
์ ์ฌ์ฉํ๋ฉด ์์ฒ๋ผ ํน์ wrapper๋ก ๊ฐ์ธ์ค ์๋ ์๊ณ , ์ด๊ฒ์ธ์๋ ๋ค์ํ option์ ์ถ๊ฐํ์ฌ ์ปค์คํ
ํ
์ ํ
์คํ
ํ ์ ์๋ค.renderHook
์ result
๊ฐ์ฒด์ current
์๋ ์ปค์คํ
ํ
์ ๋ฆฌํด๊ฐ์ด ํฌํจ๋์ด์๋ค.
๋ฐ๋ผ์ useFilter.ts
์ ๋ฆฌํด๊ฐ ์ค filter
์ ์ ๊ทผํ๊ธฐ ์ํด์๋ result.current[0]
์ผ๋ก ์ ๊ทผํ ์ ์๊ฒ๋๋ค.
์ด๋ฌํ hook
์ ์
๋ฐ์ดํธํ๊ธฐ์ํด์ act
ํจ์๋ฅผ ์ฌ์ฉํ์๊ณ , ์ ๋๋ก ์ก์
์ด ๋์คํจ์น๋๋์ง ํ์ธํ๋ ์ฝ๋๋ฅผ ์์ฑํ์๋ค.
๋น๋๊ธฐ hooks ํ ์คํ
testing-library/react-hooks
๋ ๋น๋๊ธฐ์ ์ผ๋ก ์
๋ฐ์ดํธ๋๋ hooks ํ
์คํ
๋ ๋์์ค๋ค.๐
import { renderHook } from '@testing-library/react-hooks'
import { useCounter } from './counter'
test('should increment counter after delay', async () => {
const { result, waitForNextUpdate } = renderHook(() => useCounter())
result.current.incrementAsync()
await waitForNextUpdate()
expect(result.current.count).toBe(1)
})
๋ฐ๋ก renderHook์ ๋ฆฌํด๊ฐ ์ค waitForNextUpdate
ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.await waitForNextUpdate()
๋ฅผ ์คํํ๋ฉด ์ปค์คํ
ํ
์ ๋น๋๊ธฐํจ์์ธ incrementAsync
ํจ์๊ฐ ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ ๋ค ํ
์คํ
ํ ์ ์๋ค.
๐ ์ฐธ๊ณ
'๊ฐ์ธ๊ณต๋ถ > TDD' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
React Testing: Components testing (0) | 2021.11.25 |
---|---|
React Testing: Reducer testing (with Redux) (0) | 2021.11.17 |
Typescript, Jestํ๊ฒฝ์์ alias์ ์ฉํ๊ธฐ (์ ๋๊ฒฝ๋ก import) (0) | 2021.10.31 |
jest ํ๊ฒฝ์์ import ์ฌ์ฉ ์ค์ ํ๊ธฐ(typescript) (0) | 2021.10.19 |
Jest ์ด๊ธฐํ๊ฒฝ ์ค์ ์์ ์๋ฌํธ๋ค๋ง (0) | 2021.09.13 |