audit
無料Run comprehensive code audit for architecture, dead code, and test quality. Use when reviewing overall codebase health, checking for architectural violations, or before marking a feature complete.
日本語の概要は準備中です。原文の説明を表示しています。
How to write good tests. Use when writing tests, improving test coverage, or evaluating test quality. Also invoked by other skills — BDD at RED phase, tdd-review at GREEN gate, refactor at PROTECT phase, and debug. Core test quality knowledge across all workflows.
インストール方法を見るインストールする前に、エージェントに与えられる指示の中身を確認できます。
Tests prove the system behaves correctly. Every test — unit, integration, E2E, eval — must verify observable behavior, not implementation details.
Core Principle: TEST BEHAVIOR, NOT IMPLEMENTATION
What this means: At every test level, assert on what the system does (outputs, side effects, user-visible outcomes) — never on how it does it (internal state, mock call counts, private methods).
Why: Tests coupled to implementation break on every refactor. Behavioral tests survive refactoring because behavior doesn't change — only the internals do.
Scope preference: When multiple test types can verify a behavior, prefer the highest scope that covers the behavior with acceptable feedback speed. Higher scope = more confidence that the real system works.
Prefer (highest confidence):
E2E → proves the user can do the thing
Integration → proves components work together
Unit → proves the algorithm is correct
Fallback (lowest scope):
When to drop to a lower scope:
When to stay at higher scope:
Announce your decision: "Test type: [unit/integration/E2E/eval] because [reason]."
For the full decision tree, bug detection matrix, and edge cases: .safeword/guides/testing-guide.md
Non-negotiable at every test level. Violating these produces tests that pass but catch nothing.
// WRONG — tests internal state
expect(component.state.count).toBe(1);
expect(mockFn).toHaveBeenCalledWith("internal-detail");
// RIGHT — tests observable behavior
expect(screen.getByText("Count: 1")).toBeVisible();
expect(result).toEqual({ total: 42 });
This applies at EVERY level:
If your assertion would pass for ANY input, it asserts nothing.
// WRONG — asserts nothing useful
expect(() => processData(input)).not.toThrow();
expect(result).toBeTruthy();
expect(result).toBeDefined();
// RIGHT — asserts specific behavior
expect(processData(input)).toEqual({ status: "ok", count: 3 });
expect(result.errors).toHaveLength(0);
A new test that passes immediately is testing nothing — or testing something that already works (no value added). For new behavior: RED then GREEN. For existing code: if a characterization test fails, you found a bug.
If a test name has "and" in it, split it. Each test verifies ONE observable outcome.
// WRONG
it('validates input and saves to database', ...);
// RIGHT
it('rejects input missing required field', ...);
it('saves valid input to database', ...);
No test depends on another test's side effects. Fresh state per test. Run in any order.
The most common ways AI-generated tests go wrong. Watch for all of them.
| Pattern | Problem | Fix |
|---|---|---|
| Coverage theater | High line coverage, tests catch no bugs | Every test should fail if you break the behavior it guards |
| Mock everything | Tests only verify mock wiring, not real behavior | Use real dependencies where practical; mock only external services |
| Duplicate tests | 20 tests with same structure, different values | Use parameterized/table-driven tests: it.each(...) |
| Happy-path only | Misses edge cases where real bugs live | Always include: empty input, boundary values, error paths |
| Hardcoded magic values | Timestamps, IDs, paths break across environments | Use builders, relative values, or factories |
| Snapshot overuse | Large snapshots pass review without scrutiny | Prefer targeted assertions; snapshots only for large stable structures |
| Testing private methods | Couples tests to implementation | Test through the public API |
| Exact UI text matching | Breaks on copy changes | Use regex /submit/i or data-testid attributes |
| Bug-locking | Tests written against buggy code encode the bug | Write tests BEFORE implementation (TDD), or verify behavior is correct first |
| Scope defaulting | AI defaults to unit tests for everything | Ask "what's the highest scope with acceptable feedback speed?" first |
Test the contract (inputs → outputs), not the internals.
// Behavioral: asserts on output
it("applies 20% discount for VIP users", () => {
expect(calculateDiscount(100, { tier: "VIP" })).toBe(80);
});
// Non-behavioral: asserts on internal call
it("calls applyRate with 0.2", () => {
calculateDiscount(100, { tier: "VIP" });
expect(applyRate).toHaveBeenCalledWith(0.2);
});
Test that components produce correct combined outcomes with real dependencies.
// Behavioral: asserts on combined outcome
it('returns user profile with computed permissions', async () => {
const response = await api.get('/users/1/profile');
expect(response.data.permissions).toContain('edit_posts');
});
// Non-behavioral: asserts on which services were called
it('calls UserService then PermissionService', async () => { ... });
Test what the user can see and do. E2E tests are naturally behavioral — lean into this.
// Behavioral: user-visible outcome
test("user creates account and sees dashboard", async ({ page }) => {
await page.goto("/signup");
await page.fill('[name="email"]', "test@example.com");
await page.fill('[name="password"]', "secure123");
await page.click('button:has-text("Sign Up")');
await expect(page).toHaveURL("/dashboard");
await expect(page.getByText("Welcome")).toBeVisible();
});
Grade what the output achieves, not the path the model took. Use deterministic assertions first, LLM-as-judge second.
# Deterministic assertion (cheap, run every commit)
- type: javascript
value: JSON.parse(output).intent === 'order_pizza'
# LLM-as-judge (for subjective quality, run on PR/schedule)
- type: llm-rubric
value: |
PASS: Correctly identifies pizza order, confirms size and type
FAIL: Wrong intent, ignores key details, or generic response
Eval-specific principles:
Before writing any test, find existing tests near the code under test. Match their imports, describe/it structure, helpers, and patterns. Don't introduce new conventions into an established test suite.
If no existing tests: use AAA pattern (Arrange-Act-Assert).
List planned tests before coding. For each test, name:
Aim for: happy path + edge cases + error cases + at least one test the implementation could plausibly get wrong.
Write one test → run it → verify it fails (or passes for characterization) → move to next. Never write all tests at once then run them.
function buildUser(overrides = {}) {
return { id: "test-1", name: "Test User", role: "member", ...overrides };
}
it("applies VIP discount", () => {
const user = buildUser({ role: "vip" });
expect(calculateDiscount(user)).toBe(0.2);
});
// WRONG
await sleep(3000);
await page.waitForTimeout(500);
// RIGHT — wait for condition
await expect.poll(() => getStatus()).toBe("ready");
await waitFor(() => expect(element).toBeVisible());
// WRONG
it("works correctly");
it("should handle edge case");
// RIGHT — describes the behavior
it("returns 401 when API key is missing");
it("preserves user input after validation error");
| Need | Action |
|---|---|
| Full test type selection guide | .safeword/guides/testing-guide.md |
| Test definition template (BDD) | .safeword/templates/test-definitions-feature.md |
| Test quality review | /audit |
| Feature-level TDD with scenarios | /bdd |
| Debugging failing tests | /debug |
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Run comprehensive code audit for architecture, dead code, and test quality. Use when reviewing overall codebase health, checking for architectural violations, or before marking a feature complete.
日本語の概要は準備中です。原文の説明を表示しています。
Behavior-first feature development — use when building new capabilities, continuing feature work, or when work introduces new state or multiple user flows. Discovers desired behavior through examples and scenarios before implementation. Do NOT use for bug fixes, typos, or small isolated changes.
日本語の概要は準備中です。原文の説明を表示しています。
Use when the user wants to explore options, weigh approaches, or think through uncertainty before committing to a direction. Collaborative brainstorming and rubber ducking — divergence-first thinking partner.
日本語の概要は準備中です。原文の説明を表示しています。
Kill zombie dev servers and test processes. Use when ports are blocked, processes are hanging, or test runners won't start.
日本語の概要は準備中です。原文の説明を表示しています。
Root cause debugging before fixes. Use when investigating bugs, diagnosing test failures, troubleshooting unexpected behavior, or when previous fix attempts failed. Enforces investigate-first discipline.
日本語の概要は準備中です。原文の説明を表示しています。
Extract tacit knowledge through non-obvious microquestions — things only the user knows that can't be found in code, docs, or research. Use when you're about to guess at intent, context, or constraints during SAFEWORD's understanding flow. Also use when user says 'ask me', 'what do you need to know', or when another skill (bdd, brainstorm, debug) needs user context before proceeding. Do NOT use for questions answerable by reading the codebase or searching the web.
日本語の概要は準備中です。原文の説明を表示しています。