testing — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited testing (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
React Testing Library 기반 테스트 작성 모범 관례 및 안티패턴 회피 가이드.
Testing Library의 철학: 사용자가 사용하는 방식대로 테스트하라
Testing Library는 다양한 쿼리를 제공하지만, 접근성과 사용자 경험을 반영하는 순서로 사용해야 함.
상세 가이드: references/query-priority.md
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
test('사용자가 폼을 제출할 수 있다', async () => {
const user = userEvent.setup();
render(<LoginForm />);
await user.type(screen.getByRole('textbox', { name: /이메일/i }), '[email protected]');
await user.type(screen.getByLabelText(/비밀번호/i), 'password123');
await user.click(screen.getByRole('button', { name: /로그인/i }));
expect(await screen.findByText(/환영합니다/i)).toBeInTheDocument();
});핵심:
userEvent.setup() 호출 후 사용await 필수// ❌ 나쁜 예 - fireEvent 사용
fireEvent.click(button);
fireEvent.change(input, { target: { value: "text" } });
// ✅ 좋은 예 - userEvent 사용
await user.click(button);
await user.type(input, "text");상세 가이드: references/user-events.md
// ✅ 좋은 예 - findBy 사용
const successMessage = await screen.findByText(/저장되었습니다/i);
expect(successMessage).toBeInTheDocument();findBy = getBy + waitFor 조합 (자동으로 요소 나타날 때까지 대기)
// 복잡한 비동기 검증
await waitFor(() => {
expect(screen.getByRole("alert")).toHaveTextContent("성공");
});
// 여러 조건 검증
await waitFor(() => {
expect(mockFn).toHaveBeenCalledTimes(1);
expect(screen.queryByText(/로딩 중/i)).not.toBeInTheDocument();
});// ❌ 나쁜 예 - 임의의 timeout
await new Promise((resolve) => setTimeout(resolve, 1000));
// ❌ 나쁜 예 - act() 수동 사용 (보통 불필요)
await act(async () => {
// ...
});
// ✅ 좋은 예 - findBy 또는 waitFor
await screen.findByText(/완료/i);상세 가이드: references/async-patterns.md
// ❌ 나쁜 예 - 내부 상태 접근
expect(component.state.isOpen).toBe(true);
wrapper.find(".internal-class").simulate("click");
// ✅ 좋은 예 - 사용자 관점 검증
expect(screen.getByRole("dialog")).toBeVisible();
await user.click(screen.getByRole("button", { name: /열기/i }));// ❌ 나쁜 예 - container.querySelector
const { container } = render(<MyComponent />);
const button = container.querySelector('.my-button');
// ✅ 좋은 예 - screen 쿼리
const button = screen.getByRole('button', { name: /제출/i });// ❌ 나쁜 예 - 동기 요소에 waitFor
await waitFor(() => {
expect(screen.getByText("Hello")).toBeInTheDocument();
});
// ✅ 좋은 예 - 동기 요소는 즉시 검증
expect(screen.getByText("Hello")).toBeInTheDocument();getBy*는 요소를 못 찾으면 throw하므로 toBeInTheDocument()는 기술적으로 중복이다. 하지만 제거하지 마라 — 리팩토링 후 남은 쿼리가 아니라 의도적인 존재 검증임을 코드 독자에게 전달하는 역할을 한다.
// ❌ 나쁜 예 - assertion 없이 쿼리만 남김
screen.getByRole("button", { name: /제출/i });
// ✅ 좋은 예 - 명시적 assertion으로 의도 전달
expect(screen.getByRole("button", { name: /제출/i })).toBeInTheDocument();단, 존재 검증이 아닌 다른 속성을 검증할 때는 toBeInTheDocument()를 추가할 필요 없다:
// ✅ 좋은 예 - 다른 matcher로 충분
expect(screen.getByRole("button", { name: /제출/i })).toBeDisabled();
// ❌ 나쁜 예 - 중복 assertion
expect(screen.getByRole("button", { name: /제출/i })).toBeInTheDocument();
expect(screen.getByRole("button", { name: /제출/i })).toBeDisabled();전체 안티패턴 목록: references/common-mistakes.md
테스트 환경 설정이 필요한 경우 다음 템플릿 참조:
assets/vitest.config.ts - Vitest 설정 (React 플러그인, 커버리지 포함)assets/test-setup.ts - Vitest 글로벌 설정assets/msw-setup.ts - MSW 핸들러 및 서버 설정~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.