ワンクリックで
write-test
// 변경되었거나 테스트가 없는 Pinpoint 프론트엔드 코드에 대한 Jest 테스트를 작성합니다. 훅, 아톰, 유틸리티, 컴포넌트에 테스트가 필요하거나 커버리지를 높여야 할 때 반드시 이 스킬을 사용하세요.
// 변경되었거나 테스트가 없는 Pinpoint 프론트엔드 코드에 대한 Jest 테스트를 작성합니다. 훅, 아톰, 유틸리티, 컴포넌트에 테스트가 필요하거나 커버리지를 높여야 할 때 반드시 이 스킬을 사용하세요.
영어와 한국어 로케일 파일 모두에 i18n 번역 키를 추가합니다. 사용자 노출 문자열을 추가하거나, 번역 키가 누락되었거나, 새 UI 텍스트를 국제화할 때 반드시 이 스킬을 사용하세요.
useGetXxx 패턴에 따라 새 React Query API 훅을 생성합니다. 새 백엔드 API를 연동하거나, 엔드포인트에 대한 훅이 필요하거나, 데이터 페칭 로직을 추가할 때 반드시 이 스킬을 사용하세요.
프로젝트의 shadcn/ui + Tailwind 패턴에 따라 새 React 컴포넌트를 생성합니다. UI 프리미티브(버튼, 다이얼로그 등) 또는 도메인 컴포넌트(ServerMap, Inspector 등)를 새로 만들 때 반드시 이 스킬을 사용하세요.
Pinpoint 프로젝트 패턴에 따라 새 페이지를 생성합니다. 애플리케이션에 새 라우트/페이지를 추가하거나, 새 화면을 만들거나, 기존 라우팅 구조에 페이지를 추가할 때 반드시 이 스킬을 사용하세요.
web-frontend, web, web-starter Maven 모듈을 skipTests 옵션으로 순차 빌드합니다.
Pinpoint 프론트엔드 PR 전 QA 게이트. 빌드/테스트를 실행하고 변경된 코드에 대한 동작 QA를 수행합니다. 커밋하거나 PR을 올리기 전에 반드시 이 스킬을 먼저 실행하세요.
| name | write-test |
| description | 변경되었거나 테스트가 없는 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작성된 테스트와 통과/실패 여부를 보고합니다.