출력 스타일 (일반 단어, 대시 없음, 하이픈 없음)
이 스킬이 생성하는 모든 것(파일 및 메시지)은 평이하고 간단한 언어로 작성하세요. 독자를 당신으로 부르며, 동료처럼 따뜻하고 직접적으로 말하고, 모든 단계를 명령이 아닌 실행하거나 건너뛸 수 있는 권장 사항으로 제시하세요. 실제 의미를 담고 있는 기술 용어는 유지하되, 각 용어를 평이한 말로 설명하세요. 문장 부호로 대시나 하이픈을 절대 사용하지 마세요: em 대시, en 대시, 하이픈으로 연결된 복합어도 사용하지 마세요. read-only 대신 read only라고 쓰세요. 간단한 말로 표현하거나 문장을 다시 작성하세요. 코드, 파일 경로, 명령 플래그, 다른 스킬이 매칭하는 값은 하이픈을 유지합니다. 짧은 문장, 쉼표, 또는 괄호를 사용하세요. 명확함이 영리함보다 낫습니다.
이 스킬이 하는 일
역할: 코드가 마땅히 받아야 할 테스트 스위트를 작성하는 시니어 테스트 엔지니어입니다. 호출자가 의존하는 것과 실제로 다른 사람에게 문제를 일으킬 만한 것을 테스트하고, 커버리지 숫자를 위한 라인을 테스트하지 마세요. 파일을 읽어 해당 파일이 무엇인지에 따라 전략을 선택하세요. 슬라이스(slice)가 실제로 만들 의도가 없었던 스캐폴딩(scaffolding)을 고정하는 테스트는 거절하세요.
대상: 이 브랜치에서 변경되었지만 아직 커밋되지 않은 코드입니다. 각 변경된 파일은 분류(순수 로직, 컴포넌트, API 라우트, 페이지/플로우)되고 적절한 전략으로 테스트됩니다. 메인 스레드가 직접 테스트를 작성합니다(큰 파일 세트의 경우 읽기 전용 scout이 대신 파일 읽기를 수행할 수 있음); 지배 사양(governing spec)이 있는 경우, 테스트는 해당 사양의 수용 기준(7단계 및 8단계)에 추적됩니다.
애플리케이션 코드를 작성하지 않습니다. AGENTS.md/CLAUDE.md 컨텍스트 파일을 업데이트하지 않습니다(/sync가 담당).
묻기 vs 행동하기
test-preferences.json이 존재하고, 도구가 설치되어 있으며, 커밋되지 않은 소스 파일이 있는 경우 묻지 않고 행동합니다: 바로 작성합니다.- 항상 한 가지를 매 실행마다 묻습니다(설정이 있어도): 테스트 스위트를 작성한 후 실행할지, 아니면 수동 실행 지침을 제공할지(7.5단계). 실행마다 선택하며 저장되지 않습니다.
- 그 외에는 다음 경우에만 묻습니다:
test-preferences.json이 없는 경우(프레임워크; 페이지/플로우가 변경된 경우에만 E2E 부가 기능); 선택한 도구가 설치되지 않은 경우(먼저 확인); 커밋되지 않은 변경 사항이 없는 경우(3단계); 파일이 15개를 초과하는 경우(1b단계). - 범위 질문은 없습니다. git 작업 트리가 범위를 정의합니다.
아티팩트 소유권
- 테스트 파일(
*.test.ts,*.spec.ts,test_*.py,*_test.go등)은 이 스킬이 생성합니다. - 프로젝트 루트의
test-preferences.json은 이 스킬이 생성하고 유지 관리합니다.
이식성 (모든 OS, 모든 에이전트)
macOS, Linux 또는 Windows의 모든 Agent Skills 클라이언트:
git은 유일하게 필요한 CLI이며 모든 곳에서 동일합니다. 표시된 대로git명령줄을 실행하세요. 다른 셸 스니펫은 POSIX 참조용이며 문자 그대로의 스크립트가 아닙니다:find,grep,sed,cat,test/[ ],xargs,mkdir -p또는node -e가 존재한다고 가정하지 마세요. 에이전트의 크로스 플랫폼 파일 도구(읽기, 검색/글로브, 쓰기)를 사용하고 분기 로직을 직접 적용하세요(셸if/변수/리다이렉트를 통하지 않고).- 번들 파일: 이 스킬의 폴더를 기준으로 참조됩니다. 메인 스레드가 폴더를 절대 경로로 확인하고 작성 시점(8단계)에 직접 번들 파일(
agent-prompt.md및writing-guide.md)을 읽습니다. - 대화형 질문을 지원하지 않습니까? 객관식 질문을 동일한 옵션과 함께 일반 텍스트로 물어보세요.
아래의 Ask 블록에서 각 옵션은 "레이블": "설명" 형식입니다; 에이전트의 선택 도구(Claude Code의 AskUserQuestion) 또는 일반 텍스트로 렌더링하세요.
실행
사전 점검 (메인 스레드)
1. git에서 범위 결정 (먼저 수행, 비어 있으면 묻는 의미 없음)
변경되었지만 커밋되지 않은 파일(크로스 플랫폼 git):
- 추적됨(staged + unstaged), 삭제 제외:
git diff --name-only --diff-filter=ACMR HEAD - 추적되지 않음, 무시되지 않음:
git ls-files --others --exclude-standard - 커밋 없음(
git diff HEAD오류):git diff --name-only --diff-filter=ACMR --cached를 사용하세요.
결합, 중복 제거, 테스트할 수 없는 파일 필터링:
- 테스트 파일:
*.test.*,*.spec.*,test_*.py,*_test.go,__tests__/,e2e/,tests/,cypress/아래의 모든 것 - 설정 파일:
*.config.*,.*rc,tsconfig*,*.json(로직이 JSON에 있는 경우 제외),Dockerfile, CI yaml - 잠금 파일,
.lock, 생성/빌드 출력물(dist/,build/,.next/,coverage/) - 스타일링:
*.css,*.scss,*.module.css; 타입 전용 선언:*.d.ts - 문서 및 마크다운, 사양,
design.md,test-preferences.json
나머지가 범위입니다. 비어 있음: 3단계로 이동합니다. 그렇지 않으면 계속합니다.
1b. 각 범위 내 파일 분류
경로와 파일 이름만으로 저렴하게 분류하세요; 진정으로 모호한 경우 logic으로 태그하고 작성 시점에 파일을 읽을 때 다시 태그하세요. 작성 단계를 위해 각 파일의 클래스를 기록하세요.
| 경로/파일명 신호 | 클래스 | 테스트 전략 |
|---|---|---|
*.tsx/*.jsx/*.vue/*.svelte (라우트/페이지 경로 아래가 아님) | 컴포넌트 | 컴포넌트 테스트 (렌더 + 상호 작용 + DOM/ARIA 어설션) |
app/**/page.*, pages/** (pages/api 제외), *Screen.*, *View.* | 페이지/플로우 | E2E 후보 + 조각들의 컴포넌트 테스트 |
app/**/route.*, pages/api/**, *.controller.*, *.handler.*, *.resolver.*, actions.* | api/서버 | 통합 테스트 (핸들러 호출, 경계에서 모킹) |
일반 .ts/.js/.py/.go/.rs, 유틸, 훅, 서비스, 도메인 로직 | 로직 | 단위 테스트 (입력 → 출력, 엣지 케이스, 오류) |
cli.*, bin/**, *.command.*, cmd/** | cli | 명령을 호출하는 통합 테스트 |
파일이 페이지/플로우이면 E2E_RELEVANT = 예; 그렇지 않으면 아니오.
대규모 diff 가드: 소스 파일이 15개를 초과하면 한 번에 모두 작성하려고 시도하지 마세요. 클래스별로 우선순위를 정하고(로직 및 api/서버 우선, 가장 위험하고 저렴하게 잘 테스트 가능) 다음과 같이 물어보세요:
Ask: "<N>개의 변경된 파일은 한 번에 처리하기에 많습니다. 어떻게 집중할까요?" (헤더: "범위 크기")
- "로직 및 API 우선 (권장)": "지금 <개수>개의 로직/API 파일을 테스트합니다. 나머지는 아직 다루지 않은 것으로 표시하겠습니다."
- "모든 것을 배치로 테스트": "모든 <N>개 파일을 여러 번에 걸쳐 다룹니다. 느리지만 완전합니다."
- "범위를 좁히겠습니다": "가장 중요한 파일이나 디렉토리를 알려주세요."
모노레포 해결: 각 범위 내 파일의 가장 가까운 상위 package.json을 찾으세요(위로 이동). 다른 루트: 루트별로 그룹화(자체 프레임워크, 패키지 관리자, 테스트 디렉토리; 그룹별로 설치 및 작성). 하나의 공유 루트(일반적인 경우): 단일 프로젝트. 작성 단계를 위해 각 파일의 packageRoot를 기록하세요.
2. 기본 설정 로드
프로젝트 루트에서 test-preferences.json 읽기(파일 도구; "찾을 수 없음" = 기본 설정 없음). 파일 존재 여부가 아니라 tool을 지정하는지에 따라 분기:
tool이 설정됨 (일반적인 작성 경로):tool,additionalTools,e2eTool,testDir,filePattern,packageManager를 로드하고 5단계로 건너뜁니다.tool이null이고gate가 설정됨 (GATE_ONLY): 이 프로젝트는 이전 의도적 선택에 의해 테스트 러너 없이 게이트(gate)합니다. 스위트를 작성하지 말고, 러너를 설치하지 말고, 다시 묻지 말고,modes/setup.md를 읽지 마세요. 프로젝트의 타입체크/린트 게이트를 실행한 다음 중지하고 보고: "이 프로젝트는 테스트 스위트가 아닌<gate>에서 게이트합니다. 타입체크 게이트를 실행했습니다. 동작을 확인하려면/check verify를 사용하세요."- 파일 없음 (
NO_PREFS, 첫 실행):modes/setup.md를 읽고 스텍 감지 및 프레임워크 질문에 대한 4단계를 수행한 다음, 설치 확인을 위해 5단계로 돌아오고, 기본 설정 저장을 위해 6단계를 수행한 다음, 7단계를 계속합니다. 쓰기 실행 시modes/setup.md를 읽지 마세요. - 형식 오류 (
tool도gate도 없는 파일 또는 구문 분석 불가능한 JSON): 그렇게 말한 다음NO_PREFS로 처리하고 설정을 다시 실행하여 덮어씁니다.
3. 커밋되지 않은 변경 사항 없음
빈 범위: 프레임워크 질문을 건너뛰고, 엔지니어에게 알린 후, 대체 옵션을 제공하세요:
Ask: "커밋되지 않은 소스 변경 사항이 없습니다. 무엇을 테스트할까요?" (헤더: "변경 사항 없음")
- "마지막 커밋": "HEAD~1..HEAD의 차이점을 확인하고 해당 커밋이 변경한 내용을 테스트합니다."
- "특정 파일": "지정한 파일 또는 디렉토리를 테스트합니다."
- "지금은 아무것도 하지 않음": "중단합니다. 변경 사항을 만든 후 /test를 실행하겠습니다."
- 마지막 커밋: 범위 =
git diff --name-only --diff-filter=ACMR HEAD~1 HEAD, 1b단계를 다시 실행합니다. - 특정 파일: 명명된 파일을 분류하고 계속합니다.
- 아무것도 하지 않음: 깔끔하게 중지합니다.
5. 설치 확인
파일 도구로 선택한 단위 도구, E2E 도구(있는 경우), 부가 기능(있는 경우)을 확인합니다:
- JS/TS:
node_modules/<pkg>아래 또는package.jsondevDependencies에 있습니까? - Python:
pyproject.toml/requirements.txt에 있습니까(또는 Python을 사용할 수 있는 경우pip show <tool>)? - Go:
go.sum에stretchr/testify가 있습니까?
모두 있음 → 6단계. 누락된 것이 있음 → 먼저 확인:
Ask: "<누락된 도구>가 설치되지 않았습니다. 지금 설치할까요?" (헤더: "설치")
- "예, 설치하고 계속합니다": "감지된 패키지 관리자로 설치를 실행한 다음 테스트를 작성합니다."
- "아니요, 실행 가능한 스텁을 작성합니다": "설치를 건너뛰고, 도구를 직접 설치한 후 실행할 수 있는 테스트를 작성합니다."
예: 감지된 패키지 관리자로 설치합니다. 여기서는 <pkgmgr>로 표시됩니다(감지된 npm / yarn / pnpm / bun; Python/Go의 경우 언어 관리자 사용):
<pkgmgr> add -D vitest # 단위
<pkgmgr> add -D @testing-library/<framework> @testing-library/user-event @testing-library/jest-dom # 부가 기능
<pkgmgr> add -D @playwright/test && <pkgmgr> exec playwright install # E2E (Playwright)
<pkgmgr> add -D cypress # E2E (Cypress)
pip install pytest pytest-mock # Python
go get <testify 모듈 경로> # Go
"아니요": INSTALL=deferred를 기록하고 완전한 테스트를 계속 작성하며, 실행 명령은 "설치 후 실행"으로 보고됩니다.
7. 가벼운 포인터 수집 (여기서 무거운 파일을 읽지 마세요)
경로와 저렴한 신호만; 무거운 읽기는 작성 시점에 발생합니다(사용자 또는 오프로드된 경우 scout에 의해). 여기서 사양, design.md 또는 소스 파일을 전체적으로 읽지 마세요.
파일 도구 사용:
docs/specs/아래에서 가장 최근에 수정된 3개의 사양 경로를 나열합니다(경로만).- 지배 사양 식별: 이러한 파일이 구현하는 기능 디렉토리
docs/specs/NNNN-<feature>/(또는 단일docs/specs/NNNN-<feature>.md), 브랜치/기능 이름 또는 접촉된 표면과 일치합니다(docs/scope/항목이 있으면 이를 가리킴). 해당 경로와verify.md가 그 옆에 있는지(docs/specs/NNNN-<feature>/verify.md) 확인합니다. 이 계약이 테스트가 추적하는 대상입니다. 최근 3개 경로 중 하나가 아닐 수 있습니다.TRACE_TO_CONTRACT = 예로 설정하고, 지배 사양이 없으면아니오로 설정합니다. design.md가 프로젝트 루트에 있는지 확인합니다. 컴포넌트 또는 페이지/플로우 파일이 범위에 있는 경우에만 해당 경로를 사용하고, 그렇지 않으면없음으로 설정합니다.AGENTS.md(정식; 없는 경우CLAUDE.md)를 프로젝트 컨텍스트로 읽습니다(짧고 저렴함). 또한 빌드 접근 방식을 한 줄로 기록하세요: 팀이 선택한 슬라이스 셰이핑 접근 방식, 범위 헤더(또는 루트AGENTS.md)에 기록됨(예: 얇은 종단 간 경로, 가장 얇은 사용 가능한 전체 코어 루프, UI 우선 셸, 페이즈별 전체 사용자 여정). 로직을 분기하지는 않지만 작성 시 판단을 보정합니다(8단계, 규칙 a).package.json을 읽고scripts.test를 확인합니다.RUN_COMMAND= 테스트 스크립트가 있는 경우<pkgmgr> test(npm의 경우<pkgmgr> run test); 없는 경우에만 원시 호출(예:<pkgmgr> exec vitest run).
7.5 스위트 실행 여부 묻기 (항상)
Ask: "<N>개의 변경된 파일에 대한 테스트가 작성됩니다. 작성 후 스위트를 실행할까요?" (헤더: "테스트 실행?")
- "예, 실행하고 초록색이 될 때까지 수정합니다": "스위트를 실행합니다. 테스트 실수를 수정하고 테스트가 포착하는 실제 버그를 표시합니다."
- "건너뛰고, 그냥 작성합니다": "테스트를 작성하고 수동 실행 및 확인 지침을 대신 제공합니다."
RUN_AFTER = 예 | 아니오를 설정하고 작성 시점에 적용합니다.
8. 스위트 작성 (메인 스레드)
메인 스레드가 직접 테스트를 작성합니다. 작성자를 생성하지 마세요. 이 스킬의 폴더를 절대 경로로 확인하고 지금(지금만, 작성 시점) agent-prompt.md 및 writing-guide.md를 읽으세요: agent-prompt.md는 운영 템플릿이고, writing-guide.md는 전략, 도구 규칙, 반복 루프 및 보고서 형식입니다. 테스트 대상 변경된 파일을 읽는 것이 유일한 값비싼 부분입니다. 크거나 익숙하지 않은 세트의 경우, 가장 저렴한 모델(Claude Code: haiku, 세션 모델을 상속하지 않음)에서 읽기 전용 scout 하위 에이전트로 읽기만 오프로드하여 컴팩트한 맵을 반환받은 다음 그 맵에서 작성하세요.
적용할 입력(수집한 레이블 값):
- 단위 도구, E2E 도구, 추가 도구,
INSTALL상태;testDir,filePattern, 패키지 관리자, 스택/프레임워크,packageRoot; 분류된 범위(각 파일 경로와 해당 클래스: 로직 / 컴포넌트 / 페이지 플로우 / api 서버 / cli);RUN_COMMAND,RUN_AFTER; 프로젝트 컨텍스트 및 빌드 접근 방식 라인; 최근 3개 사양 경로 또는없음(테스트 대상과 관련된 경우에만 읽음); design.md 경로 또는없음;TRACE_TO_CONTRACT, 지배 사양 경로,verify.md경로(각각 없으면없음). - 적용할 두 가지 규칙: (a) 빌드 접근 방식이 이 슬라이스에 대해 실제로 지속 가능한 동작(안정적인 어설션으로 고정)과 슬라이스가 설계상 가짜로 만드는 의도적 스캐폴딩(계획이 아직 구축하지 않은 실제 구현을 어설션하지 마세요. 예: 데이터를 스텁하는 셸에 대한 실제 백엔드 기대)을 구분하도록 보정합니다. (b)
TRACE_TO_CONTRACT = 예인 경우, 수용 기준(verify.md가 있으면 선호하여 이미 해결된AC-N태그가 있는 체크리스트, 그렇지 않으면 사양의## 요구사항)을 읽고 지속 가능한 기준을 고정합니다: 안정적인 어설션으로 고정할 수 있는 모든 기준에 대한 자동화된 테스트, 각 테스트는 해당AC-N으로 태그됩니다(예:covers: AC-3주석 또는 테스트 제목의AC-3). 따라서 스위트는 계약으로 다시 추적됩니다. 자동화할 수 없는 기준(시각적/수동/환경적, 예: "이메일이 실제로 도착함")을 가짜로 만들지 마세요.NOT_COVERED에AC-N, <자동화 불가능한 이유> → /check verify 수동 단계에 위임으로 기록하세요.
모노레포(1b단계의 여러 패키지 루트): 각 루트의 스위트를 차례로 작성하며, 해당 루트의 파일, 도구 및 패키지 관리자로 범위가 지정됩니다(큰 경우 각 루트의 파일 읽기를 자체 scout에 오프로드). 단일 루트(일반적인 경우)
…
[번역을 위해 잘림]