[react-native] 테스팅 툴 변경 (enzyme -> testing-library/react-native)
2021. 11. 11. 22:56ㆍ공부내용 공유하기
enzyme 환경에서 비동기 처리 후 state변경에 대응하는 과정에서 너무 고통을 받다 보니, waitFor expectation을 지원하는 testing-library를 써야겠다는 생각이 들었다.
전환하고 나니 테스트도 원할해지고, 직관적으로 사용할 수 있는 것 같아 만족스럽다.
enzyme 다 썰어버리고 심플하게 간다
testHelper/utils.tsx
import React from "react";
import {
fireEvent as fe,
FireEventFunction,
render as rtlRender,
} from "@testing-library/react-native";
import { Provider } from "react-redux";
import reduxStore from "@src/redux/store";
import { ReactTestInstance } from "react-test-renderer";
function render(
ui,
// @ts-ignore
{ preloadedState, store = reduxStore, ...renderOptions } = {}
) {
function Wrapper({ children }) {
return <Provider store={store}>{children}</Provider>;
}
return rtlRender(ui, { wrapper: Wrapper, ...renderOptions });
}
// FireEvent Type override -> ReactTestInstance는 null도 리턴함.
type NullableFireEventAPI = FireEventFunction & {
press: (element: ReactTestInstance | null) => any;
changeText: (element: ReactTestInstance | null, ...data: Array<any>) => any;
scroll: (element: ReactTestInstance | null, ...data: Array<any>) => any;
};
const fireEvent: NullableFireEventAPI = fe as any;
// re-export everything
export * from "@testing-library/react-native";
// override render method
export { render, fireEvent };
authFlow/index.test.tsx
import { fireEvent, render } from "@src/testHelper/utils";
import makeFlow from "@src/testHelper/makeFlow";
import { AuthFlow } from "@src/navigation";
import React from "react";
import { act, waitFor } from "@testing-library/react-native";
import { ScreenName } from "@src/types/screen";
const DUMMY_SIGNUP_INFO = {
id: "testID",
pw: "123123123q",
};
describe("회원가입 플로우 테스트", () => {
it("메인 스크린 컴포넌트 정상 마운트 확인", async () => {
const { queryByText, toJSON, unmount } = render(
makeFlow(<AuthFlow />)
);
expect(toJSON()).toMatchSnapshot();
expect(queryByText("회원가입")).toBeDefined();
expect(queryByText("로그인")).toBeDefined();
unmount();
});
it("회원가입 프로세스", async () => {
const {
queryByText,
queryByTestId,
queryByPlaceholderText,
toJSON,
} = render(
makeFlow(<AuthFlow initialScreen={ScreenName.SIGN_UP} />)
);
expect(toJSON()).toMatchSnapshot();
fireEvent.changeText(
queryByPlaceholderText("아이디 입력"),
DUMMY_SIGNUP_INFO.id
);
fireEvent.changeText(
queryByPlaceholderText("비밀번호 확인"),
DUMMY_SIGNUP_INFO.pw
);
fireEvent.changeText(
queryByPlaceholderText("영문/숫자/특수문자 혼합하여 8자 이상"),
DUMMY_SIGNUP_INFO.pw
);
expect(queryByText("중복확인")?.props.size).toEqual("small");
await act(async () => {
fireEvent.press(queryByText("중복확인"));
});
await waitFor(
() => {
expect(queryByText("중복확인")?.props.active).toEqual(false);
},
{ timeout: 1500 }
);
await waitFor(
() => {
expect(queryByText("다음")?.props.active).toEqual(true);
},
{ timeout: 1500 }
);
fireEvent.press(queryByText("다음"));
expect(toJSON()).toMatchSnapshot();
// 다음화면 이동 확인
expect(queryByTestId("next_screen")).toBeDefined();
});
});
테스트 코드 작성이 너무 쉬워졌다...
놀랐던 게 testing library에서는 내가 저번에 만들었던 selector들이 이미 내장되어 있어서 queryByText, queryByTestId 등으로 굉장히 쉽게 각 요소들을 테스트할 수 있었다....
참 이런 순간마다 미묘하다.
나 혼자 좋은 아이디어라고 생각하고 구현한 것들이 나중에 알고보니 이미 잘 구현되어 있으면 두 가지 생각이 든다.
하나는 내가 허튼 방식으로 생각하지는 않는구나 하는 안도감, 하나는 내가 생각할 정도면 누군가 이미 생각했구나... 계속 더 창의적인 생각을 해서 남들이 안 하는 걸 찾아봐야겠다는 호승심...
뭐 그런 생각은 나중에 하고, 지금은 테스트가 잘 되어서 만족스럽다.
사용자 인터랙션에 가장 밀접한 방식으로 테스트 할 수 있어서 바꾸길 잘했다는 생각이 든다.