변경되었거나 테스트가 없는 Pinpoint 프론트엔드 코드에 대한 Jest 테스트를 작성합니다. 훅, 아톰, 유틸리티, 컴포넌트에 테스트가 필요하거나 커버리지를 높여야 할 때 반드시 이 스킬을 사용하세요.
$ARGUMENTS의 코드에 대한 Jest 테스트를 작성합니다 (경로가 없으면 최근 변경된 파일 대상).
인자가 없는 경우:
git diff upstream/master --name-only
변경된 각 .ts / .tsx 파일에 대해 해당하는 .test.ts / .test.tsx 파일이 있는지 확인합니다.
테스트가 없는 파일 목록 — 이것이 우선 타겟입니다.
각 타겟 파일을 완전히 읽고 파악합니다:
의 프로젝트 테스트 패턴을 따릅니다.
.claude/rules/testing.md규칙: 테스트 이름(
describe/test/it문자열)은 반드시 영어로 작성합니다.
import { theUtil } from "./theUtil";
describe("theUtil", () => {
test("should return [expected behavior] given [normal input]", () => {
expect(theUtil(normalInput)).toBe(expected);
});
test("should handle null/undefined input gracefully", () => {
expect(theUtil(null)).toBe(fallback);
});
test("should handle edge cases", () => {
expect(theUtil(edgeCase)).toBe(edgeExpected);
});
});
import { renderHook, act } from "@testing-library/react";
import { useAtom } from "jotai";
import { theAtom } from "./theAtom";
describe("theAtom", () => {
test("should initialize with default value", () => {
const { result } = renderHook(() => useAtom(theAtom));
expect(result.current[0]).toEqual(defaultValue);
});
test("should update when setter is called", () => {
const { result } = renderHook(() => useAtom(theAtom));
act(() => {
result.current[1](newValue);
});
expect(result.current[0]).toEqual(newValue);
});
});
import { renderHook, waitFor } from "@testing-library/react";
import { createWrapper } from "../testUtils"; // QueryClient wrapper
import { useGetXxx } from "./useGetXxx";
describe("useGetXxx", () => {
beforeEach(() => {
global.fetch = jest.fn();
});
afterEach(() => {
jest.resetAllMocks();
});
test("should fetch data with correct endpoint and params", async () => {
(global.fetch as jest.Mock).mockResolvedValueOnce({
ok: true,
json: async () => ({ data: mockData }),
});
const { result } = renderHook(() => useGetXxx(params), {
wrapper: createWrapper(),
});
await waitFor(() => expect(result.current.isSuccess).toBe(true));
expect(global.fetch).toHaveBeenCalledWith(
expect.stringContaining("/api/expected-endpoint"),
expect.any(Object),
);
expect(result.current.data).toEqual(expectedData);
});
test("should not fetch when required params are missing", () => {
const { result } = renderHook(() => useGetXxx(null), {
wrapper: createWrapper(),
});
expect(result.current.isFetching).toBe(false);
expect(global.fetch).not.toHaveBeenCalled();
});
test("should handle API error response", async () => {
(global.fetch as jest.Mock).mockResolvedValueOnce({
ok: false,
status: 500,
json: async () => ({ title: "Internal Server Error" }),
});
const { result } = renderHook(() => useGetXxx(params), {
wrapper: createWrapper(),
});
await waitFor(() => expect(result.current.isError).toBe(true));
});
});
import { loader } from "./loader";
describe("loader", () => {
test("should redirect with correct date format when from/to are invalid", async () => {
const request = new Request(
"http://localhost/page?from=invalid&to=invalid",
);
const response = await loader({ request, params: {} });
expect(response).toBeInstanceOf(Response); // redirect
});
test("should return null for valid date params", async () => {
const now = Date.now();
const request = new Request(
`http://localhost/page?from=${now - 3600000}&to=${now}`,
);
const response = await loader({ request, params: {} });
expect(response).toBeNull();
});
});
각 파일에 대해 다음을 커버하는 것을 목표로 합니다:
enabled 조건 (파라미터 없을 때 페칭 안 함)myHook.ts → myHook.test.tsyarn workspace @pinpoint-fe/ui jest path/to/file.test.ts작성된 테스트와 통과/실패 여부를 보고합니다.