์ด์
authoriztion token์ ๋ณด๋ก api์ ์์ฒญ์ ๋ฐ์์ ํ๋ฉด์ ์ ์ ์ ๋ณด๋ฅผ ๋์ฐ๋ ๋ง์ด ํ์ด์ง๊ฐ ์๋ค.
ํ ์คํธ๋ฅผ ๋๋ฆฌ๋๋ฐ ํ ์คํธ ํ๊ฒฝ์์ ์๊พธ ์ ์ ์ ๋ณด๊ฐ ๋น๊ฐ์ผ๋ก ๋์ค๋ ์ด์๊ฐ ์์๋ค.
์ปดํฌ๋ํธ ๊ตฌํ
์ ์ ์ ๋ณด๋ฅผ get ํด์ค๋ ค๋ฉด ์ ์ฅ๋ ํ ํฐ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๋ฒ์ ์์ฒญํด์ response๋ก ๋ฐ์์์ผํ๋ค.
์ด๋, ์ธ์ฆ ํ ํฐ์ ๋ก์ปฌ์คํ ๋ฆฌ์ง์์ ํ ํฐ ์ ๋ณด๋ฅผ ๋ฐ์์ค๋๋ฐ, ๋ก์ปฌ ์คํ ๋ฆฌ์ง์์ ํ ํฐ์ ๋ณด๋ฅผ ๋ฐ์์ฌ๋ localStorage Web API๋ฅผ ์ฌ์ฉํด์ localStorage.getItem("token")๋ก ๋ฐ๋ก ๋ฐ์์ค๋ ๊ฒ์ด ์๋๊ณ , store๋ผ๋ 3rd party ํจํค์ง๋ฅผ ํตํด ์คํ ๋ฆฌ์ง์ ์ ๊ทผํ๋ค.
//package.json
"dependencies": {
"store": "2.0.12"
},
๋ฐ๋ผ์, ์ปดํฌ๋ํธ์์ ์๋ฒ์์ ๋ฐ์์จ ๋ฐ์ดํฐ๋ฅผ ํ์ถํ๋ ค๋ฉด, ํด๋ผ์ด์ธํธ์์ ๊ฐ์ง๊ณ ์๋ ํ ํฐ ์ ๋ณด๋ก (์คํ ๋ฆฌ์ง์์ ๊ฐ์ ธ์จ ํ ํฐ์ผ๋ก) ์๋ฒ์ get ์์ฒญ์ ํค๋์ authorization ํ๋กํผํฐ์ Bearer ํ ํฐ์ ๋ณด๋ฅผ ์ฃ์ด์ ๋ณด๋ด์ผํ๋ค.
์ธ๋ถ store ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ ์ฝ๋
์๋ฒ์ ์์ฒญ๋ณด๋ผ๋๋ query์ ์์์ ๋งํ๊ฒ์ฒ๋ผ ํ ํฐ์ ๋ณด๋ฅผ ์ฃ์ด์๋ณด๋ด๋๋ฐ, ์คํ ๋ฆฌ์ง์์ token ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด store ํจํค์ง์ ๋ด๋ถ ๋งค์๋๋ฅผ ์ฌ์ฉํด์ ๊ฐ์ง๊ณ ์ค๊ณ , ๊ทธ ์ฝ๋๋ ์๋์ ๊ฐ๋ค.
// AuthStorage.ts
import store from 'store';
export function getTokenFromStorage(): string | null {
return store.get('ACCESS_TOKEN')
? (store.get('ACCESS_TOKEN') as string)
: null;
}
ํ ์คํธ์ฝ๋
๊ทธ๋ฆฌ๊ณ ์๋์ ๊ฐ์ด ํ ์คํธ์ฝ๋๋ฅผ ์คํ์ํค๋ฉด ์๋์ ๊ฐ์ ์๋ฌ๊ฐ ๋๋ค.
import { Route, Routes } from 'react-router-dom';
import { renderWithMemoryRouter, screen, waitFor } from '@/utils/testUtils';
function renderMyInfo() {
return renderWithMemoryRouter(
<Routes>
<Route path={ROUTES.MY_INFO} element={<MyInfo />} />
</Routes>,
{
initialEntries: [ROUTES.MY_INFO],
},
);
}
it('๋ด์ ๋ณด view ์ปดํฌ๋ํธ๊ฐ ํ์ถ๋๋ค', async () => {
const { user } = renderMyInfo();
expect(screen.getByText('๋ด ์ ๋ณด')).toBeInTheDocument();
expect(screen.getByText('ํ๊ธธ๋')).toBeInTheDocument();
expect(screen.getByText('010 1212 1212')).toBeInTheDocument();
});
});
TypeError: Cannt read properties of undefined (reading 'get')
3rd party ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ store์ get ๋ฉ์๋๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค๋๊ฑฐ๋ค.
์์ธ
์ด๋ ๊ฒ ํ ์คํธ๊ฐ ์ธ๋ถ ํ๊ฒฝ์ ์์กด์ฑ์ ๊ฐ์ง๊ฒ๋๋ฉด, ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๋ฆฌํดํ๋ ๊ฒฐ๊ณผ๋ฅผ ํญ์ ์์ ์ ์ผ๋ก ๋ฐํํ ์ ์๋๋ก mocking์ ํด์ฃผ์ด์ผ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค. ํ ์คํธ ์ฝ๋ ์ ์ฅ์์๋ ์ฑ์ ๋ก์ง์ ๊ฒ์ฆํ๋๊ฒ ์ค์ํ ๊ฒ์ด์ง, ์ธ๋ถ์์ธ (์ ๊ฒฝ์ฐ์๋ ์ค์ ์คํ ๋ฆฌ์ง์ ์ ์ฅ์ด ๋์ด์๋์ง, ์คํ ๋ฆฌ์ง์ ์ ์ฅ๋ ๊ฐ์ ์ค์ ๋ก ๊ฐ์ ธ์ค๋ ๊ฒ์ธ์ง ๋ฑ) ์ํ๋ฅผ ํ์ธํ ํ์๋ ์๊ธฐ ๋๋ฌธ์ ๋ชจํน์ ํตํด 3rd party ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ก์ง์ ๊ฐ์ง๋ก ๋ชจํนํ๊ณ ์ฑ์ด ํ๊ณ ์ํ๋ ๋ก์ง์ ํ ์คํธ ํ ์ ์๋ค.
ํด๊ฒฐ
jest์ spyOn ํจ์๋ฅผ ํ์ฉํ์ฌ 3rd party ๋ชจ๋์ ์ฌ์ฉํ๊ณ ์๋ AuthStorageํ์ผ ๋ด๋ถ ์ ์ฒด๋ฅผ ์คํ์ดํด์จ๋ค.
`jest.spyOn(object, methodName)` AuthStorage์์ exportํ๋ ํจ์๋ค์ ๋ชจ๋ ๊ฐ์ฒด๋ก ๊ฐ์ ธ์ ์คํ์ด(๋ชฐ๋ ์ ๋ณด๋ฅผ ์บ์ค๊ธฐ)ํด์ค๊ณ ๊ทธ ๋ด๋ถ์์ ๊ตฌํ๋ ํจ์์ธ `getTokenFromStorage` ์ฝ๋๋ฅผ ๊ฐ์ ธ์, ๋ฆฌํดํด์ฃผ๋ ๋ฐธ๋ฅ๋ฅผ ์คํธ๋ง๊ฐ์ผ๋ก ์๋ฌด๊ฑฐ๋ ๋ชจํนํด์ฃผ์ด ๋ฆฌํดํด์ค๋ค.
//test.tsx
import * as AuthStorage from '@/components/auth/AuthStorage';
beforeEach(() => {
jest
.spyOn(AuthStorage, 'getTokenFromStorage')
.mockReturnValue('MockAccessToken');
});
์ด๋ ๊ฒ spyOn์ผ๋ก ๊ฐ์ง ํ ํฐ๊ฐ์ ๋ชจํนํด์ฃผ๊ณ token ๊ฐ์ ๊ฐ์ง๊ณ ์ค๋ ๊ตฌํ๋ถ์ธ baseQuery์์ ์ฝ์์ ์ฐ์ด๋ณด๋ฉด, ํ ์คํธํ๊ฒฝ์์๋ `getTokenFromStorage` ํจ์๊ฐ ๋ฆฌํดํด์ฃผ๋ ๋ชจํน๊ฐ์ด ๊ทธ๋๋ก ์ ์ฐํ๋๊ฑธ ํ์ธํ ์ ์๋ค.