@apogeelabs/the-agency 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -10,9 +10,9 @@ Before generating any tests, complete these steps in order:
|
|
|
10
10
|
|
|
11
11
|
1. **Branch analysis** (Coverage-Driven Test Planning): Read the source, enumerate every branch, map each to a test scenario.
|
|
12
12
|
2. **Superfluous test check** (Superfluous Test Prevention): Verify each planned scenario covers a distinct branch, not the same branch with different values.
|
|
13
|
-
3. **Execution location check** (CRITICAL RULE
|
|
14
|
-
4. **Mock configuration check** (CRITICAL RULE
|
|
15
|
-
5. **Callback invocation check** (CRITICAL RULE
|
|
13
|
+
3. **Execution location check** (CRITICAL RULE 1): Execute methods under test in `beforeEach()`, not in `it()` blocks.
|
|
14
|
+
4. **Mock configuration check** (CRITICAL RULE 2): Configure mock behavior in `beforeEach`, not at module level.
|
|
15
|
+
5. **Callback invocation check** (CRITICAL RULE 3): Use `mockImplementation` for callbacks, not `mock.calls[N][M]()`.
|
|
16
16
|
|
|
17
17
|
Once tests are generated:
|
|
18
18
|
|
|
@@ -21,7 +21,7 @@ Once tests are generated:
|
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
24
|
-
## CRITICAL RULE
|
|
24
|
+
## CRITICAL RULE 1: Test Execution Location
|
|
25
25
|
|
|
26
26
|
⚠️ **NON-NEGOTIABLE RULE** ⚠️
|
|
27
27
|
|
|
@@ -97,7 +97,7 @@ Before writing any test suite, verify:
|
|
|
97
97
|
|
|
98
98
|
---
|
|
99
99
|
|
|
100
|
-
## CRITICAL RULE
|
|
100
|
+
## CRITICAL RULE 2: Mock Configuration Location
|
|
101
101
|
|
|
102
102
|
⚠️ **NON-NEGOTIABLE RULE** ⚠️
|
|
103
103
|
|
|
@@ -152,7 +152,7 @@ const mockLuxon = {
|
|
|
152
152
|
|
|
153
153
|
---
|
|
154
154
|
|
|
155
|
-
## CRITICAL RULE
|
|
155
|
+
## CRITICAL RULE 3: Callback Invocation via mockImplementation
|
|
156
156
|
|
|
157
157
|
⚠️ **NON-NEGOTIABLE RULE** ⚠️
|
|
158
158
|
|
|
@@ -329,7 +329,7 @@ describe("when status is inactive", () => {
|
|
|
329
329
|
- Inner `describe` blocks handle specific scenarios ("when X condition")
|
|
330
330
|
- **Test descriptions**:
|
|
331
331
|
- `describe` blocks handle the "when" conditions/scenarios
|
|
332
|
-
- `it` blocks focus purely on "should" assertions (no conditions). See **CRITICAL RULE
|
|
332
|
+
- `it` blocks focus purely on "should" assertions (no conditions). See **CRITICAL RULE 1** above.
|
|
333
333
|
- Avoid redundancy - don't repeat conditions in both `describe` and `it`
|
|
334
334
|
- **Grouping logic**:
|
|
335
335
|
- Group related test cases under shared setup scenarios
|
|
@@ -366,7 +366,7 @@ describe("when status is inactive", () => {
|
|
|
366
366
|
- **State initialization**: Variables initialized in `beforeEach`
|
|
367
367
|
- **Fresh state guarantee**:
|
|
368
368
|
- Call `jest.clearAllMocks()` and `jest.resetModules()` in outer `beforeEach`
|
|
369
|
-
- **Do NOT use `jest.resetAllMocks()`** in the outer `beforeEach` — it wipes implementations, which breaks module-level `mockReturnThis()` chains (see CRITICAL RULE
|
|
369
|
+
- **Do NOT use `jest.resetAllMocks()`** in the outer `beforeEach` — it wipes implementations, which breaks module-level `mockReturnThis()` chains (see CRITICAL RULE 2 exception)
|
|
370
370
|
- Use `mockReset()` on **individual mocks** when a nested `beforeEach` needs to replace behavior already configured by an outer `beforeEach`
|
|
371
371
|
- **Never use `mockRestore()`** — it only applies to `jest.spyOn`, which this codebase does not use
|
|
372
372
|
|
|
@@ -385,14 +385,14 @@ Am I in the **outer** `beforeEach`?
|
|
|
385
385
|
|
|
386
386
|
## Mocking Strategy
|
|
387
387
|
|
|
388
|
-
- **Module-level mock declarations**: Dependencies mocked above test suites with bare `jest.fn()` — see **CRITICAL RULE
|
|
388
|
+
- **Module-level mock declarations**: Dependencies mocked above test suites with bare `jest.fn()` — see **CRITICAL RULE 2** for configuration rules
|
|
389
389
|
- **Mock behavior configuration**: Configured per scenario in `beforeEach` blocks
|
|
390
390
|
- **Mock naming**: Consistent mock prefix (e.g., `mockLogger`, `mockGetMessageBroker`)
|
|
391
391
|
- **Selective mocking**: Mock only the methods being used unless it significantly raises complexity
|
|
392
392
|
- **Mock verification**: Always verify mock calls when behavior depends on them
|
|
393
393
|
- **Mock realism**: Ensure mocks behave like real implementations (same async patterns, error types)
|
|
394
394
|
- **Mock methods**:
|
|
395
|
-
- Use `mockImplementation` when invoking callbacks passed to the mocked function — see **CRITICAL RULE
|
|
395
|
+
- Use `mockImplementation` when invoking callbacks passed to the mocked function — see **CRITICAL RULE 3**
|
|
396
396
|
- Use `mockResolvedValue` for async returns
|
|
397
397
|
- Use `mockReturnValue` for sync returns
|
|
398
398
|
- Prefer "Once" versions when appropriate (`mockResolvedValueOnce`, etc.)
|
|
@@ -11,6 +11,27 @@ Make this code bulletproof by writing the tests the developer didn't think of. A
|
|
|
11
11
|
|
|
12
12
|
You have NO knowledge of how this code was written. You are seeing it for the first time. You are NOT rewriting the developer's tests — you're adding what's missing.
|
|
13
13
|
|
|
14
|
+
## Tooling — Non-Negotiable
|
|
15
|
+
|
|
16
|
+
**Use ONLY the repo's established tooling to run and verify tests.** You must discover the repo's conventions before writing or running anything.
|
|
17
|
+
|
|
18
|
+
### Discovery (do this FIRST, before writing any tests)
|
|
19
|
+
|
|
20
|
+
1. Read `package.json` (root and any relevant workspace package). Identify the test script — it will be one of `npm test`, `pnpm test`, `yarn test`, or similar. That is your test runner. Period.
|
|
21
|
+
2. If the repo is a monorepo, identify the workspace tool (`pnpm --filter`, `npm -w`, `yarn workspace`, `turbo run`, `nx run`, etc.) and use that to scope test runs to the relevant package.
|
|
22
|
+
3. Read the test framework config (e.g., `jest.config.ts`, `vitest.config.ts`, `.mocharc.*`) to understand module resolution, transforms, and path aliases.
|
|
23
|
+
4. Read `.ai/UnitTestGeneration.md` and `.ai/UnitTestExamples.md` if they exist. These are your style guide. Follow them exactly.
|
|
24
|
+
|
|
25
|
+
### The Rules
|
|
26
|
+
|
|
27
|
+
- **Run tests with the repo's test script.** `npm test`, `pnpm test`, `pnpm --filter <pkg> test`, etc. Whatever `package.json` says.
|
|
28
|
+
- **DO NOT use `node -e`, `npx tsx`, `npx jest`, `ts-node`, or any ad-hoc command to run, compile, or verify code.** Ever. No exceptions. The repo has a test runner. Use it.
|
|
29
|
+
- **DO NOT improvise test runners or verification methods.** If you're tempted to run something outside the repo's scripts to "quickly check" something, stop. Use the test script.
|
|
30
|
+
- **DO NOT install packages, add dependencies, or modify package.json.** You write tests using what's already available.
|
|
31
|
+
- **When running tests, scope them.** Don't run the entire test suite when you only need to verify one file. Use the test runner's built-in filtering (e.g., `pnpm test -- --testPathPattern=path/to/file` for Jest, or equivalent).
|
|
32
|
+
|
|
33
|
+
If you catch yourself about to type `node -e` or `npx tsx` or anything that isn't the repo's test script, you are doing it wrong. Back away from the keyboard.
|
|
34
|
+
|
|
14
35
|
## Input
|
|
15
36
|
|
|
16
37
|
1. Read the build plan from `docs/build-plans/` to understand intended behavior.
|
|
@@ -97,12 +118,14 @@ Map every branch (`if`/`else`, `try`/`catch`, `switch`, early returns) in the so
|
|
|
97
118
|
|
|
98
119
|
## Process
|
|
99
120
|
|
|
100
|
-
1.
|
|
101
|
-
2.
|
|
102
|
-
3.
|
|
103
|
-
4.
|
|
104
|
-
5.
|
|
105
|
-
6. Write
|
|
121
|
+
1. **Discover repo tooling.** Follow the Tooling — Non-Negotiable section above. Identify the package manager, test script, test framework config, and any workspace/monorepo conventions. Do this BEFORE reading any source code.
|
|
122
|
+
2. Audit existing tests. Catalog what's covered.
|
|
123
|
+
3. Identify gaps by category.
|
|
124
|
+
4. Prioritize: likely to happen OR catastrophic if it does.
|
|
125
|
+
5. **Before writing any test**, verify it against the anti-patterns above. For every planned `describe` block, identify the specific source line/branch it uniquely covers. If you cannot, drop it.
|
|
126
|
+
6. Write tests. Follow the existing test framework and patterns exactly.
|
|
127
|
+
7. Run tests using the repo's test script. Fix any failures before proceeding.
|
|
128
|
+
8. Write your report.
|
|
106
129
|
|
|
107
130
|
## Output
|
|
108
131
|
|
|
@@ -146,9 +169,10 @@ Actual bugs discovered during test hardening.
|
|
|
146
169
|
|
|
147
170
|
## Verification
|
|
148
171
|
|
|
149
|
-
Before writing the report, verify:
|
|
172
|
+
Before writing the report, verify by **reading your own code and the source code** — not by running ad-hoc commands:
|
|
150
173
|
|
|
151
|
-
1. Every new `describe` block covers a code path no existing test covers.
|
|
174
|
+
1. Every new `describe` block covers a code path no existing test covers. Verify this by reading the source, not by running coverage tools.
|
|
152
175
|
2. No tests target `.tsx` files or barrel exports.
|
|
153
176
|
3. Tests are added to existing test files, not new ones.
|
|
154
177
|
4. No existing tests were modified.
|
|
178
|
+
5. All tests pass when run with the repo's test script. This is the ONLY command you should have executed via Bash during this entire process.
|
|
@@ -67,27 +67,50 @@ The developer can accept the default or specify another branch. Use whatever the
|
|
|
67
67
|
|
|
68
68
|
## Step 3: Gather Diff
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
Fetch the latest state of the target branch from the remote so comparisons reflect what's actually on the remote, not a potentially stale local copy:
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
-
git
|
|
73
|
+
git fetch origin $TARGET
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 3.1: Resolve Comparison Ref
|
|
77
|
+
|
|
78
|
+
Default to `origin/$TARGET` (the remote tracking ref) for all diff and log comparisons. Before proceeding, check whether a local copy of the target branch exists and is ahead of the remote:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
git rev-list --count origin/$TARGET..$TARGET 2>/dev/null
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- **If the command fails** (no local branch exists), or **returns 0** (local is behind or even with remote): use `origin/$TARGET` silently. No prompt needed.
|
|
85
|
+
- **If the count is greater than 0**: the local branch has commits not yet on the remote. Ask the developer:
|
|
86
|
+
|
|
87
|
+
> **Your local `{$TARGET}` is {count} commit(s) ahead of `origin/{$TARGET}`.** Use local or remote for comparison? (default: remote)
|
|
88
|
+
|
|
89
|
+
Use whichever ref the developer chooses as `$COMPARE_REF` for all subsequent diff and log commands. If they accept the default or don't respond, use `origin/$TARGET`.
|
|
90
|
+
|
|
91
|
+
### 3.2: Check for Commits
|
|
92
|
+
|
|
93
|
+
Check that there are commits ahead of the comparison ref:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
git log --oneline $COMPARE_REF..HEAD
|
|
74
97
|
```
|
|
75
98
|
|
|
76
99
|
**If no commits are returned**, stop and output:
|
|
77
100
|
|
|
78
|
-
> **No commits ahead of `{$
|
|
101
|
+
> **No commits ahead of `{$COMPARE_REF}`. Nothing to PR.** You may need to rebase.
|
|
79
102
|
|
|
80
|
-
Gather
|
|
103
|
+
### 3.3: Gather Change Data
|
|
81
104
|
|
|
82
105
|
```bash
|
|
83
106
|
# File list with change stats
|
|
84
|
-
git diff --stat $
|
|
107
|
+
git diff --stat $COMPARE_REF...HEAD
|
|
85
108
|
|
|
86
109
|
# Full diff
|
|
87
|
-
git diff $
|
|
110
|
+
git diff $COMPARE_REF...HEAD
|
|
88
111
|
|
|
89
112
|
# Commit log (excluding merges)
|
|
90
|
-
git log --no-merges --oneline $
|
|
113
|
+
git log --no-merges --oneline $COMPARE_REF..HEAD
|
|
91
114
|
```
|
|
92
115
|
|
|
93
116
|
## Step 4: Categorize and Filter Files
|
|
@@ -50,19 +50,52 @@ gh pr view --json number,title,baseRefName,headRefName,body,additions,deletions,
|
|
|
50
50
|
|
|
51
51
|
## Step 3: Gather Diff Information
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
### 3.1: Resolve Comparison Ref
|
|
54
|
+
|
|
55
|
+
Fetch the latest state of the base branch from the remote:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git fetch origin $baseRefName
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Default to using the remote for comparison (via `gh pr diff`). Before proceeding, check whether the local copy of the base branch is ahead of the remote:
|
|
54
62
|
|
|
55
63
|
```bash
|
|
56
|
-
|
|
57
|
-
|
|
64
|
+
git rev-list --count origin/$baseRefName..$baseRefName 2>/dev/null
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- **If the command fails** (no local branch exists), or **returns 0** (local is behind or even with remote): use the remote. No prompt needed.
|
|
68
|
+
- **If the count is greater than 0**: the local branch has commits not yet on the remote. Ask the developer:
|
|
69
|
+
|
|
70
|
+
> **Your local `{baseRefName}` is {count} commit(s) ahead of `origin/{baseRefName}`.** Use local or remote for comparison? (default: remote)
|
|
71
|
+
|
|
72
|
+
Store the choice as `$DIFF_MODE` — either `remote` (default) or `local`.
|
|
73
|
+
|
|
74
|
+
### 3.2: Get the Diff
|
|
75
|
+
|
|
76
|
+
**If `$DIFF_MODE` is `remote`** (the 95% case):
|
|
58
77
|
|
|
59
|
-
|
|
78
|
+
Use `gh pr diff` to get the full diff as GitHub sees it. This avoids stale-local-branch problems where a behind-origin base branch inflates the diff with already-merged changes from other PRs.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
60
81
|
gh pr diff
|
|
61
82
|
```
|
|
62
83
|
|
|
63
|
-
**
|
|
84
|
+
**If `$DIFF_MODE` is `local`:**
|
|
64
85
|
|
|
65
|
-
|
|
86
|
+
Use local git to diff against the local base branch:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
git diff $baseRefName...HEAD
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
⚠️ Note: local diffs may differ slightly from GitHub's view in repos with complex merge histories.
|
|
93
|
+
|
|
94
|
+
### 3.3: Stats and Commit Messages
|
|
95
|
+
|
|
96
|
+
File-level stats (additions, deletions, file count) are already available from the `gh pr view --json` output captured in Step 2 — don't duplicate that work here.
|
|
97
|
+
|
|
98
|
+
**For commit messages**, use the `commits` array already captured in Step 2 — that is the authoritative commit list for this PR. Do NOT use `git log`, which can include commits from other PRs if the local base branch is behind origin.
|
|
66
99
|
|
|
67
100
|
## Step 4: Categorize and Filter Files
|
|
68
101
|
|