가수면

경로 이동 테스트 오류 본문

일지

경로 이동 테스트 오류

니비앙 2023. 7. 2. 06:35

카카오 로그인의 테스트 코드를 작성하던 중 테스트 코드 상의 경로가 제대로 이동되지 않는 문제가 발생했다.

 

하나씩 클리어해 간 과정과 잊어버리지 않도록 주의해야 할 점들을 기록한다.

 

1. axios 오류

평범하게 msw를 설치해 axios를 사용할 경우 모듈 외부에서 import 문을 사용할 수 없다며 axios import하는 부분에 오류가 발생하게 된다.

 

Jest는 Node.js 환경에서 사용되는 테스트 프레임워크다.

그러나 애플리케이션이 웹 클라이언트용으로 빌드되고, axios가 버전업이 되면서 CommonJS 대신 ES 모듈로 빌드되도록 변경되었기 때문에 CommonJS 형식으로 작성된 Node.js에서 실행되지 않는 문제가 발생한 것이다.

 

여러 해결 방법이 있었는데, 나는 axios를 CJS 모듈로 가져오기를 강제하는 방법으로 해결했다.

  "scripts": {
  
    "test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!axios)/\"",

  },

 

 

2. 요청 핸들러에 따른 경로 이동이 안되던 문제

이 경우 두 가지 문제를 동시에 해결해야 했어서 조건을 찾느라 한참을 헤맸다...

 

우선 오류 상황은 다음과 같다.

  useEffect(() => {
    const loginFetch = async () => {
      const { data } = await instance.post("/auth/login", {
        code,
      });
      if (data.code === 200) return navigate("/");
      if (data.code === 201) return navigate("/signup");
      alert("로그인 에러");
      navigate("/");
    };
    
    if (code) {
      loginFetch();
    }
  }, [navigate, code]);
// src\mocks\handlers.ts

import { rest } from "msw";

export const handlers = [
  rest.post(`${process.env.REACT_APP_MY_API}/auth/login`, (req, res, ctx) => {
    return res(ctx.json({ code: 201 }));
  }),
];
describe("로그인 기능 테스트", () => {
  const user = userEvent.setup();
  const url = `${process.env.REACT_APP_MY_API}/auth/login`;

  render(<LoginSection />);

  const loginButton = screen.getByRole("button", { name: "카카오 로그인" });

  test("로그인 성공 시 200이면 /으로 이동", async () => {
    await user.click(loginButton);

    render(
      <BrowserRouter>
        <KakaoRedirect />
      </BrowserRouter>
    );

    const loadingText = screen.getByText("로딩중");
    await waitFor(() => expect(loadingText).toBeInTheDocument());

    expect(window.location.pathname).toEqual("/");
  });
  .
  .
  .
});

handlers처럼 code가 201이면 "/signup"으로 이동해야 하건만 "/"으로 이동하며 실패하는 문제가 발생했다.

 

2-1) 문제1.

useEffect 안에 if문이 문제였다.

실제로는 잘 동작하는 코드였지만, 테스트 코드에서는 실패하는 결과를 가져오는 코드였다.

해당 if문을 삭제하고 함수를 호출하는 것으로 변경해 해결.

  useEffect(() => {
    const loginFetch = async () => {
      const { data } = await instance.post("/auth/login", {
        code,
      });
      if (data.code === 200) return navigate("/");
      if (data.code === 201) return navigate("/signup");
      alert("로그인 에러");
      navigate("/");
    };

    loginFetch();
  }, [navigate, code]);

 

2-2) 문제2.

기본으로 설치되는 @testing-library/react 버전이 13.4.0인데 14.0.0으로 버전업하니 해결되었다.

 

3. 쿠키를 설정하면 오류나던 문제

// api

export const authAPI = {
  login: async (code: string | null) => {
    const { data } = await instance.post("/auth/login", { code });
    setCookie(data.data.kakao_access_token);
    return data;
  },
};
  const loginFetch = useCallback(async () => {
    const data = await authAPI.login(code);
    if (data.code === 200) return navigate("/");
    if (data.code === 201) return navigate("/signup");
    alert("로그인 에러");
    navigate("/");
  }, [code, navigate]);

  useEffect(() => {
    loginFetch();
  }, [loginFetch]);

서비스 로직을 분리한 뒤 쿠키를 저장하는 작업을 추가하니 아래와 같은 오류가 발생했다.

해당 문제는 모킹에 대한 개념이 부족해 발생한 문제였다.

 

export const handlers = [
  rest.post(`${process.env.REACT_APP_MY_API}/auth/login`, (req, res, ctx) => {
  	return res(ctx.json({ code: 200 }));
  }),

인스턴스 서버를 살펴보면 data : { code:200 }을 반환하고 있는 걸 볼 수 있다.

 

그러나 쿠키에 대한 리턴 값이 없기 때문에 요청 이후 setCookie에 들어가는 data,data,kakao_access_token이 곧 undefined이므로 에러가 발생하게 된 것이다.

 

이 경우 모킹 서버가 쿠키를 반환할 수 있도록 설정해 클라이언트딴의 로직이 정상 작동할 수 있도록 해줘야 한다.

export const handlers = [
  rest.post(`${process.env.REACT_APP_MY_API}/auth/login`, (req, res, ctx) => {
    return res(ctx.json({ data: { kakao_access_token: "1" }, code: 200 }));
  }),

그리고 이것은 인스턴스 외에 서버를 개별적으로 설정해줄 때 역시 해당되는 말이다.

 

  test("로그인 성공 시 201이면 /signup으로 이동", async () => {
    server.use(rest.post(url, (req, res, ctx) => res.once(ctx.json({ data: { kakao_access_token: "1" }, code: 201 }))));
    await user.click(loginButton);

    renderWithRouter(<KakaoRedirect />);

    const loading = screen.getByText("로딩중");
    await waitFor(() => expect(loading).toBeInTheDocument());

    expect(window.location.pathname).toEqual("/signup");
  });

  test("로그인 실패 테스트", async () => {
    server.use(rest.post(url, (req, res, ctx) => res.once(ctx.json({ data: { kakao_access_token: "1" }, code: 400 }))));
    await user.click(loginButton);

    renderWithRouter(<KakaoRedirect />);

    const loading = screen.getByText("로딩중");
    await waitFor(() => expect(loading).toBeInTheDocument());

    expect(window.location.pathname).toEqual("/");
  });

 

즉, test 파일에서 호출되는 모든 api요청 함수는(실제 api 함수를 import해오더라도) setupTests의 설정에 의해서 모킹 서버가 실제 요청을 가로채 완전히 대체하게 되므로 클라이언트 로직이 제대로 동작할 수 있는 모양으로 모킹 서버를 설정해줘야 한다.

Comments