본문으로 건너뛰기

원티드 프리온보딩 과제 - 6일차

· 약 6분
arch-spatula

Jest 통신 테스트 환경 설정

문제: syntaxerror: Cannot use import statement outside a module 에러 발생

Axios를 설치하고 통신 테스트를 시작하면서 문제가 발생했습니다. 이런 에러메시지를 받았습니다.

시도: syntaxerror: Cannot use import statement outside a module 에러 발생

"Cannot use import statement outside a module" with Axios

해결하기 전 여기까지 검색했습니다. 생각보다 많은 사람들이 문제로 생각하고 있었습니다.

해결

axios 1.1.2 버전 issue ( SyntaxError: Cannot use import statement outside a module) - 인프런

{
"name": "wanted-pre-onboarding-frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
// 생략
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!axios)/\"",
"eject": "react-scripts eject"
},
"devDependencies": {
"msw": "^1.2.1",
"prettier": "^2.8.7",
"prettier-plugin-tailwindcss": "^0.2.7",
"tailwindcss": "^3.3.1"
}
}

"test": "react-scripts test"test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!axios)/\""으로 변경하면 됩니다.

학습

Jest 개발환경은 생각보다 좋지 않습니다. 또 테스트 설정자체를 깊게 공부할 필요도 있을 것 같습니다.

유저의 행동을 테스트하는 방법

describe('CustomButton', () => {
it('활성화되어 있는 동안에 클릭하면 기능을 수행할 수 있습니다.', () => {
const mockOnClick = jest.fn();
render(
<CustomButton text="회원가입" hierarchy="primary" onClick={mockOnClick} />
);
const button = screen.getByRole('button');
userEvent.click(button);
expect(mockOnClick).toHaveBeenCalledTimes(1);
});

it('비활성화되어 있는 동안에 클릭하면 기능을 수행할 수 없습니다.', () => {
const mockOnClick = jest.fn();
render(
<CustomButton
text="회원가입"
hierarchy="primary"
onClick={mockOnClick}
disabled={true}
/>
);
const button = screen.getByRole('button');
userEvent.click(button);
expect(mockOnClick).toHaveBeenCalledTimes(0);
});
});

disabled props가 정상동작하는지 검증해야 하는 상황입니다. 비활성화에서는 함수가 호출되지 않고 활성화에는 함수가 호출되어야 합니다.

이렇게 유저의 행동을 코드 재현할 수 있습니다. 물론 아주 단순한 클릭만 재현하고 있습니다.

Axios try-catch error 타입지정

문제

async function signin(email: string, password: string) {
try {
const res = await client.post(
AUTH_PATH + SIGNIN_PATH,
{ email, password },
{ headers: { 'Content-Type': 'application/json' } }
);
if (res.status === 200) return res.data;
} catch (error) {
if (error.response?.status === 401) return '비밀번호가 일치하지 않습니다.';
if (error.response?.status === 404) return '가입되지 않은 이메일입니다';
}
}
  • 여기서 errorTypesafe하지 않았습니다.

시도

async function signin(email: string, password: string) {
try {
const res = await client.post(
AUTH_PATH + SIGNIN_PATH,
{ email, password },
{ headers: { 'Content-Type': 'application/json' } }
);
if (res.status === 200) return res.data;
} catch (error: AxiosError) {
// Catch clause variable type annotation must be 'any' or 'unknown' if specified.
if (error.response?.status === 401) return '비밀번호가 일치하지 않습니다.';
if (error.response?.status === 404) return '가입되지 않은 이메일입니다';
}
}

Catch clause variable type annotation must be 'any' or 'unknown' if specified.

이런 에러메시지를 줍니다.

해결

axios Error typescript, annotation must be 'any' or 'unknown' if?

async function signin(email: string, password: string) {
try {
const res = await client.post(
AUTH_PATH + SIGNIN_PATH,
{ email, password },
{ headers: { 'Content-Type': 'application/json' } }
);
if (res.status === 200) return res.data;
} catch (error) {
const err = error as AxiosError;
if (err.response?.status === 401) return '비밀번호가 일치하지 않습니다.';
if (err.response?.status === 404) return '가입되지 않은 이메일입니다';
}
}
  • error as AxiosError으로 타입지정하고 err식별자를 따로 만들고 활용했습니다. 이렇게 되면 Typesafe해집니다.

학습

try-catcherrorany 혹은 unknown입니다. 이 타입으로 고정되어 있습니다.

Jest: mocking console.error - tests fails

문제: 너무 많은 에러 메시지

  • 통신과 관련해서 테스트를 시작할 때 에러메시지가 많았습니다.

시도

  • 한번에 검색하고 한번에 해결했습니다.

해결

setupTests.ts를 수정하는 것으로 해결했습니다.

Jest: mocking console.error - tests fails

// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

import { server } from './mocks/server';
// Establish API mocking before all tests.
beforeAll(() => server.listen());

const original = console.error;

// Reset any request handlers that we may add during the tests,
// so they don't affect other tests.
afterEach(() => {
// console.error("you cant see me");
console.error = original;
// console.error("now you can");

return server.resetHandlers();
});

// Clean up after the tests are finished.
afterAll(() => server.close());

beforeEach(() => {
console.error = jest.fn();
console.error('you cant see me');
});

최종적으로는 이렇게 되었습니다.

학습: console 객체를 공부합시다.

자주 하는 결심들이 있습니다. 자바스크립트 정규표현식과 에러객체좀 학습하자고 늘 결심만 하고 실천하지 않습니다. 또 결심하고 실천을 언제해야 할지 모르겠습니다. 나중에 자바스크립트 정리하는 프로젝트에 정리할 것 같습니다. 잘 쓰면 상당히 효율적인 객체인데 잘 활용하고 있지 않고 있었습니다.