NextJs 통합 테스트 - React Context

import { createContext } from "react";
// ToastContext.tsx
// React Context Types

export type ToastStyle = "succeed" | "failed" | "busy";

export type ToastState = {
  isShown: boolean;
  message: string;
  style: ToastStyle;
};

// React Context
export const initialState: ToastState = {
  isShown: false,
  message: "",
  style: "succeed",
};

export const ToastStateContext = createContext(initialState);

export type ToastAction = {
  showToast: (state?: Partial<Omit<ToastState, "isShown">>) => void;
  hideToast: () => void;
};

export const initialAction: ToastAction = {
  showToast: () => {},
  hideToast: () => {},
};

export const ToastActionContext = createContext(initialAction);
// useToastProvider.tsx

import { useCallback, useState } from "react";
import { initialState, ToastState } from "./ToastContext";

export function useToastProvider(defaultState?: Partial<ToastState>) {
  const [{ isShown, message, style }, setState] = useState({
    ...initialState,
    ...defaultState,
  });
  const showToast = useCallback(
    (props?: Partial<Omit<ToastState, "isShown">>) => {
      setState((prev) => ({ ...prev, ...props, isShown: true }));
    },
    []
  );
  const hideToast = useCallback(() => {
    setState((prev) => ({ ...prev, isShown: false }));
  }, []);
  return { isShown, message, style, showToast, hideToast };
}
// index.tsx
export const ToastProvider = ({
  children,
  defaultState,
}: {
  children: ReactNode;
  defaultState?: Partial<ToastState>;
}) => {
  const { isShown, message, style, showToast, hideToast } =
    useToastProvider(defaultState);
  return (
    <ToastStateContext.Provider value={{ isShown, message, style }}>
      <ToastActionContext.Provider value={{ showToast, hideToast }}>
        {children}
        {isShown && <Toast message={message} style={style} />}
      </ToastActionContext.Provider>
    </ToastStateContext.Provider>
  );
};

테스트 코드

  • 1번째 방법

    • 테스트용 컴포넌트를 만들어 인터랙션 실행

// TestComponent를 먼저 선언
const TestComponent = ({ message }: { message: string }) => {
  const { showToast } = useToastAction();

  return <button onClick={() => showToast({ message })} show></button>;
};

test("showToast 호출", () => {
  const message = 'bom'
  render(
    // Provider 안에 TestComponent를 넣어준다.
    <ToastProvider>
      <TestComponent message={message}>
    </ToastProvider>
  )

  expect(screen.queryByRole('alert')).not.toBeInTheDocument()
  await user.click(screen.getByRole('button'))
  expect(screen.getByRole('alert')).toHaveTextContent(messgae)
});
  • 2번째 방법

    • 초기값 주입하여 렌더링된 내용 확인

test('Succed', () => {
  const state: ToastState = {
    isShown : true,
    messagea : '성공',
    style : 'succed'
  }

  render(
    <ToastProvider defaultState={state}>
      {null}
    </ToastPropvider>
  )
  expect(screen.getByRole('alert')).toHaveTextContent(state.message)
})

2번째 방법보다, 1번째 방법이 useToastAction을 포함하므로 더 넓은 범위의 통합 테스트라고 할 수 있다.

Last updated