1. ProductFilter ์ปดํฌ๋ํธ
์ด ์ปดํฌ๋ํธ๋ ์ํ๋ช , ์นดํ ๊ณ ๋ฆฌ, ๊ฐ๊ฒฉ ๋ฒ์ ๋ฑ์ ๊ฒ์ ์กฐ๊ฑด์ ์ ํํด ํ๋ฉด์ ๋ณด์ผ ์ํ๋ค์ ๋ชฉ๋ก์ ๋ณ๊ฒฝํ๋ ์ปดํฌ๋ํธ๋ค.
๋ ๋๋ง ๋๋ ์์๋ก๋ ๋ค์์ ๊ฒ๋ค์ด ์๋ค :
- ์ํ๋ช ํ ์คํธ ์ธํ
- ์นดํ ๊ณ ๋ฆฌ ์ ํ ๋ผ๋์ค ๋ฒํผ
- ๊ฐ๊ฒฉ ๋ฒ์ ํ ์คํธ ์ธํ (์ต์, ์ต๋)
์ด ์ปดํฌ๋ํธ์ ๋๋ฉ์ธ์ ๋ฌด์์ด ์์๊น? ์ฆ ๋ฌด์์ ๊ฒ์ฆํด์ผ ํ ๊น? (๋ ๋๋ง ์ฌ๋ถ๋ ๋ค๋ฅธ ์ปดํฌ๋ํธ์์ ๋ค๋ฃจ๊ธฐ ๋๋ฌธ์ ํจ์์ ํธ์ถ ์ฌ๋ถ๋ง ๊ฒ์ฆํ๋ค.)
- ์ํ๋ช ์ ์ ๋ ฅํ๋ฉด ๊ทธ๊ฒ์ด ์ ์ฉ ๋๋๊ฐ?
- ์นดํ
๊ณ ๋ฆฌ๋ฅผ ํด๋ฆญํ๋ฉด ์นดํ
๊ณ ๋ฆฌ ์ ํ์ด ์ ์ฉ๋๋๊ฐ?
- ์นดํ ๊ณ ๋ฆฌ ์ ํ ์ด์ ์ ๋ชจ๋ ์นดํ ๊ณ ๋ฆฌ๊ฐ ์ ๋๋ก ๋ ๋๋ง ๋๋์ง๋ถํฐ ๊ฒ์ฆํด์ผ ํ๋ค.
- ๊ฐ๊ฒฉ ๋ฒ์ ์ค์ ์ด ์ ์ฉ ๋๋๊ฐ?
์ด ์ปดํฌ๋ํธ๋ ์์ ๊ธฐ๋ฅ๋ค์ ๋ค์๊ณผ ๊ฐ์ ํจ์๋ค๋ก ๊ตฌํํ๊ณ ์๋ค.
- setTitle
- setCategoryId
- setMinPrice ์ setMaxPrice
์์ ํจ์๋ค์ ๋ชจ๋ useFilterStore ์ฃผ์คํ ๋ ์คํ ์ด ์ก์
๋ค์ด๋ค. ๊ทธ๋ฌ๋ฉด ์ฐ๋ฆฌ๋ useFilterStore๋ฅผ ๋ชจํนํด์ผ ํจ์ ์ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ ๊ทธ ์ ์ ํ์ธํด์ผ ํ๋๊ฒ์ด ์๋๋ฐ ๋ฐ๋ก ์นดํ
๊ณ ๋ฆฌ ๋ชฉ๋ก์ ๊ฐ์ ธ์ค๋ api useCategories์ ๋ํ ๋ชจํน์ด๋ค.
api ๋ชจํน - MSW
์ฌ๊ธฐ์ ์ ํ๋ ์นดํ
๊ณ ๋ฆฌ๋ค์ ๋ชฉ๋ก์ useCategories ํ
์ ์ฌ์ฉํด ์๋ฒ์์ ๊ฐ์ ธ์จ๋ค.
(ProductFilter ๋ด๋ถ์ CategoryRadioGroup ์ปดํฌ๋ํธ์์ ์ฌ์ฉ์ค)
const useCategories = options =>
useFetch({ url: pathToUrl(apiRoutes.categories), options });
์๋๋ผ๋ฉด ์ด ์ฝ๋๋ ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ฒ ์ง๋ง, msw๋ฅผ ์ฌ์ฉํ๋ฉด ๋์ src/__mocks__/handler.js ์ ์ ํ๋๋ก ์๋ํ๋ค.
์์ ์ฝ๋์์๋ src/__mocks__/response ์ ์์ฑํ json ํ์ผ์ ๋ถ๋ฌ์ ์ ๋ฌํ๋๊ฒ์ผ๋ก ๋์ด์๋ค.
// handler.js
import response from '@/__mocks__/response';
...
rest.get(`${API_DOMAIN}${path}`, (_, res, ctx) =>
res(ctx.status(200), ctx.json(response[path])),
),
...
// response/categories.json
[
{
"creationAt": "2023-03-25T12:00:00.000Z",
"id": 1,
"image": "https://api.lorem.space/image/fashion",
"name": "category1",
"updatedAt": "2023-03-25T12:00:00.000Z"
},
...
it('์นดํ
๊ณ ๋ฆฌ ๋ชฉ๋ก์ ๊ฐ์ ธ์จ ํ ์นดํ
๊ณ ๋ฆฌ ํ๋์ ์ ๋ณด๋ค์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋ ๋๋ง๋๋ค.', async () => {
await render(<ProductFilter />);
expect(await screen.findByLabelText('category1')).toBeInTheDocument();
expect(await screen.findByLabelText('category2')).toBeInTheDocument();
expect(await screen.findByLabelText('category3')).toBeInTheDocument();
});
์์ ํ ์คํธ๋ฅผ ์คํํ๋ฉด api๊ฐ json์ ์์ฑ๋์ด ์๋๋๋ก ์ ๊ฐ์ ธ์จ๋ค๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์คํ ์ด ๋ชจํน
๋ฐ์ดํฐ ํจ์นญ api๊ฐ ์๋ํ๋ ๊ฒ์ ๊ฒ์ฆํ์ผ๋ ์ด์ ๋๋ฉ์ธ๋ค์ ๊ฒ์ฆํด์ผ ํ๋ค.
ํ
์คํธ ๋ฐฉ์์ ๋ชจํน ํจ์๋ฅผ toHaveBeenCalledWith() ๋งค์ฒ๋ก ํ์ธํ๋ ๋ฐฉ์์ ์ฌ์ฉํ๋ค. (์์์๋ ์ค๋ช
ํ๋ฏ, ์ค์ ํ๋ฉด์ ๋ ๋๋ง ํ๋ ์ปดํฌ๋ํธ๋ ๋ค๋ฅธ ์ปดํฌ๋ํธ๊ณ ์ง๊ธ ์งํํ๋ ํ
์คํธ์ ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ค.)
beforeEach(() => {
mockUseFilterStore({
setMinPrice: setMinPriceFn,
setMaxPrice: setMaxPriceFn,
setTitle: setTitleFn,
});
});
it('์ํ๋ช
์ ์์ ํ๋ ๊ฒฝ์ฐ setTitle ์ก์
์ด ํธ์ถ๋๋ค.', async () => {
...
expect(setTitleFn).toHaveBeenCalledWith('test');
});
it('์นดํ
๊ณ ๋ฆฌ๋ฅผ ํด๋ฆญ ํ ๊ฒฝ์ฐ์ ํด๋ฆญํ ์นดํ
๊ณ ๋ฆฌ๊ฐ ์ฒดํฌ๋๋ค.', async () => {
...
expect(category3).toBeChecked();
});
it('์ต์ ๊ฐ๊ฒฉ ๋๋ ์ต๋ ๊ฐ๊ฒฉ์ ์์ ํ๋ฉด setMinPrice๊ณผ setMaxPrice ์ก์
์ด ํธ์ถ๋๋ค.', async () => {
...
expect(setMinPriceFn).toHaveBeenCalledWith('1');
...
expect(setMaxPriceFn).toHaveBeenCalledWith('2');
});