@erclx/canon 4.93.0 → 4.95.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/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/auto-ship/SKILL.md +1 -1
- package/claude/skills/review-pr/REQUIREMENT.md +1 -0
- package/claude/skills/review-pr/SKILL.md +2 -0
- package/claude/skills/test-craft/REQUIREMENT.md +54 -0
- package/claude/skills/test-craft/SKILL.md +77 -0
- package/claude/skills/test-craft/references/adopted.md +44 -0
- package/claude/skills/test-craft/references/component.md +42 -0
- package/claude/skills/test-craft/references/e2e.md +44 -0
- package/claude/skills/test-craft/references/unit.md +49 -0
- package/claude/skills/test-first/REQUIREMENT.md +2 -0
- package/claude/skills/test-first/SKILL.md +4 -2
- package/claude/skills/ui-test/REQUIREMENT.md +7 -2
- package/claude/skills/ui-test/SKILL.md +26 -16
- package/docs/workflow/ai-workflow.md +11 -10
- package/docs/workflow/visual-design-workflow.md +2 -2
- package/governance/rules/core/010-testing.md +4 -2
- package/governance/rules/lib/300-testing-ts.md +4 -0
- package/governance/rules/lib/330-testing-py.md +4 -0
- package/package.json +1 -1
- package/src/claude/cases/misc.ts +5 -0
- package/src/design/components.ts +40 -26
- package/src/teach/fonts.ts +9 -19
|
@@ -123,7 +123,7 @@ If the diff touches UI files (JSX, TSX, Vue, Svelte, HTML, or CSS under `src/`),
|
|
|
123
123
|
|
|
124
124
|
If `ui-test` produces a manual checklist, stop: `❌ UI requires visual verification. Checklist at .canon/tmp/handoff/ui-checklist/<slug>.md, which reaches the pull request once /git-ship runs. Verify manually, then run /git-ship.`
|
|
125
125
|
|
|
126
|
-
If all UI changes are covered by
|
|
126
|
+
If all UI changes are covered by tests, continue.
|
|
127
127
|
|
|
128
128
|
## Step 6: review
|
|
129
129
|
|
|
@@ -20,6 +20,7 @@ A request written under `## For the reviewer` also reached no reader. The author
|
|
|
20
20
|
- Detect the pass from the thread rather than taking it from the caller, matching the heading for equality so a neighboring comment cannot be read as a prior pass
|
|
21
21
|
- Scope a later pass to the commits added since the prior one, once that commit is confirmed to still reach the head
|
|
22
22
|
- Apply the integration, contract, and consumer lenses a self-review structurally cannot
|
|
23
|
+
- Read each test the branch added or changed against `canon:test-craft`'s final filter, scoped to those files and never the suite
|
|
23
24
|
- Post the closing pass even with nothing to report, since a review left unanswered reads as one nobody closed
|
|
24
25
|
- State a withdrawal or a regrade on the thread with the fact that settled it, since a finding dropped in silence reads the same as one nobody answered
|
|
25
26
|
- Key the body file on the pull request number and the head commit, and on the response it answers once the head repeats, so no two passes overwrite each other
|
|
@@ -135,6 +135,8 @@ Review the diff and files for the same axes as `review-branch` (bugs, edge cases
|
|
|
135
135
|
- Contract: does a contract downstream features depend on land correctly, and should the plan itself be questioned?
|
|
136
136
|
- Consumers: when the change touches a resource with more than one consumer, enumerate them and check the rule against each. A rule written for the consumer the change targets can be wrong for a sibling that writes.
|
|
137
137
|
|
|
138
|
+
Read each test file the branch added or changed against the final filter in `canon:test-craft`, which owns what the filter asks. Scope it to those files rather than the suite. A fixed-pause wait is a `should-fix`, since the end to end rules already forbid it, and a test sitting at a higher layer than it needs is `minor` unless it is flaky or slows the gate measurably. Report it rather than proceeding silently when the skill does not resolve.
|
|
139
|
+
|
|
138
140
|
Then read the description's `## Testing` section, which is the one part of a pull request body this session is positioned to falsify. The branch author cannot see what a sibling branch drove the same day, and the arm list is what settles the claim rather than the diff.
|
|
139
141
|
|
|
140
142
|
Test every unchecked box against the testing discipline in `${CLAUDE_SKILL_DIR}/../../standards/pr.md`, which reserves an unchecked box for a capability the agent lacks. Raise the box when it names no human at all, when the human it names is a live agent session, or when it names a person for a step the repository ships a harness for, `scripts/sandbox/run.sh` and `scripts/eval/run.sh` being the two. Cost alone is not an answer, since authorizing a spend is the operator's and performing the run is not. A refusal the author actually met is an answer, and it names which one.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-craft
|
|
3
|
+
description: Why a session writing a test needs a stated layer rule and a quality filter, and where that judgment stops short of the procedures that run it
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test craft requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a session writing a test has no surface telling it which layer the test belongs at or what makes one good. It writes whatever the touched file suggests, and nothing in the toolkit corrects that choice before the test lands.
|
|
11
|
+
|
|
12
|
+
The one surface that did pick a layer picked the expensive one. The UI test skill routed interactions, state transitions, loading, empty, and error states to a browser end to end run, the opposite of every external source read. `test-first` runs red and green with no layer choice and no refactor step. The testing rule states floors on structure and says nothing about layer.
|
|
13
|
+
|
|
14
|
+
The failure is measured on a real target. A single-page portfolio site carried 219 end to end tests against 4 unit test files, an inverted pyramid. Its suite could not raise its worker count without failing between 11 and 24 tests on every retry, because timing-sensitive assertions sat at the layer where CI load decides the result. One copy edit failed three engines because the copy was asserted in a browser run.
|
|
15
|
+
|
|
16
|
+
Moving the guidance into a path-scoped rule does not reach the session that needs it. A path-scoped rule loads when a session reads a matching file and not when it creates one, measured in three headless runs, so a rule scoped to test files is silent on the first test of every feature.
|
|
17
|
+
|
|
18
|
+
## Must
|
|
19
|
+
|
|
20
|
+
- State the smallest-layer rule with a decision guide keyed on what the behavior touches, so a session picks a layer from the behavior rather than from the file it is in
|
|
21
|
+
- Open every test with the question of which production change makes it fail and whether that change is a bug or a decision, since a test with no answer proves nothing
|
|
22
|
+
- State the end to end budget in words: journeys and what only a real browser renders, never a state a component test reaches
|
|
23
|
+
- Carry a final filter the session runs over its own tests, each item a shape it can check: mirror assertion, change detector, assertion on a mock, framework behavior, fixed pause, and the mutation check
|
|
24
|
+
- Hold in the body what every test decision pays for, and defer each layer's specifics to a reference loaded only when a test at that layer is being written
|
|
25
|
+
- Promise a middle layer for behavior a simulated DOM cannot render, naming the real-browser component runners, so a static site is not left choosing between a simulated DOM that computes no layout and a whole-site run
|
|
26
|
+
- Repeat in the end to end reference the two floors a session writing its first spec never loads through the path-scoped rule, being the `scrollend` settle and motion reduced by default
|
|
27
|
+
- Record the external patterns adopted and declined with the reason for each, so a later session extends the position instead of re-deriving it
|
|
28
|
+
- Trigger on writing or changing any test, after implementing as well as before, since regression tests and end to end tests are mostly written after the code exists
|
|
29
|
+
|
|
30
|
+
## Must not
|
|
31
|
+
|
|
32
|
+
- Name a framework or runner in the body. Runner specifics live in the references and in the language testing rules, so the body holds across stacks.
|
|
33
|
+
- Carry a numeric mix across layers. A codebase-wide ratio is a target a session writing one test cannot act on.
|
|
34
|
+
- Restate the structure floors the testing rule already carries, such as arrange, act, assert, one behavior per test, isolation, and no snapshots
|
|
35
|
+
- Restate the settle, guard, and run-scope rules the end to end rules carry, beyond the two floors named above
|
|
36
|
+
- Run the red, green, refactor procedure or decide its order, which `test-first` owns
|
|
37
|
+
- Import an external skill's tone, such as a law stated as absolute or a table of rationalizations with rebuttals
|
|
38
|
+
- Be reached only by an author typing its name. The intended non-author callers are `test-first`'s first step and a description matching any request to write or change a test. A test written in a session that never loaded this skill is the evidence the trigger is too weak, and nothing answers that before the skill has run.
|
|
39
|
+
|
|
40
|
+
## Guards
|
|
41
|
+
|
|
42
|
+
- A behavior spanning more than one row of the decision guide is split into one test per layer rather than asserted whole at the highest layer it touches
|
|
43
|
+
- A test failing the final filter is rewritten or cut, never kept with a note
|
|
44
|
+
|
|
45
|
+
## Out of scope
|
|
46
|
+
|
|
47
|
+
- The red, green, refactor loop and the order it runs in: `test-first`, which loads this skill at its first step
|
|
48
|
+
- Reproducing a failure with no known cause: `systematic-debugging`
|
|
49
|
+
- Structure floors for every test: the core testing rule
|
|
50
|
+
- Runner choice, file suffix, placement, and query conventions: the TypeScript and Python testing rules
|
|
51
|
+
- Settle, guard, and run-scope rules inside an end to end file: the end to end reliability and test scope rules
|
|
52
|
+
- Writing a UI change's tests and its visual checklist after implementation: `ui-test`
|
|
53
|
+
- Grading the tests a pull request adds: `review-pr`
|
|
54
|
+
- Whether the guidance moves where a session puts a test, which needs a measured with-and-without run rather than a rule here
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-craft
|
|
3
|
+
description: Carries the rule that decides which layer a test belongs at, the question each one opens with, the end to end budget, and the final filter a session runs over what it wrote. Use when writing, changing, or judging a test, after implementing as well as before, when adding a regression guard, when choosing between unit, component, or end to end, or when asked "where should this test go", "is this a good test", "should this be an e2e test", or "why is our e2e suite so slow". Do NOT use for the red, green, refactor procedure, which is `test-first`, or for a bug nobody has explained yet, which is `systematic-debugging`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test craft
|
|
7
|
+
|
|
8
|
+
A session with no stated layer writes the test the file it is touching suggests, so a loading state lands in a full browser run and an end to end suite grows past what it guards. This skill carries the judgment: where a test belongs, what it has to prove, and what to cut before handing it over.
|
|
9
|
+
|
|
10
|
+
Load it before writing a test rather than after. A test written at the wrong layer passes review, and moving it later costs a second test.
|
|
11
|
+
|
|
12
|
+
## Open every test with one question
|
|
13
|
+
|
|
14
|
+
Ask what production change makes this test fail, and whether that change is a bug or a decision.
|
|
15
|
+
|
|
16
|
+
- A bug is what the test exists for. Write it.
|
|
17
|
+
- A decision, such as a reworded message or a reordered field, makes the test a change detector. Assert the contract the decision serves, or drop the test.
|
|
18
|
+
- No answer means the test proves nothing yet. Name the break before writing the assertion.
|
|
19
|
+
- Cover the edges of a behavior as well as its main path: the empty input, the boundary value, the refused call. Each edge is its own case at the same layer.
|
|
20
|
+
|
|
21
|
+
## Put the test at the smallest layer that can catch the break
|
|
22
|
+
|
|
23
|
+
Size a test by what it touches rather than by what it covers. Pick the first row that can observe the break:
|
|
24
|
+
|
|
25
|
+
| The behavior touches | Layer |
|
|
26
|
+
| ------------------------------------------------------------------------------------ | ------------------------------------- |
|
|
27
|
+
| Logic with no rendering and no I/O: a parser, a reducer, a formatter, a rule | Unit |
|
|
28
|
+
| A module boundary on one machine: a file, a local database, a handler with its route | Integration, still in the unit runner |
|
|
29
|
+
| Rendered behavior: states, interactions, conditional rendering, validation, focus | Component |
|
|
30
|
+
| A journey across routes, or what only a real browser renders: layout, scroll, motion | End to end |
|
|
31
|
+
|
|
32
|
+
- Read the row off the behavior, never off the file. A component file holding a pure formatter takes a unit test for the formatter.
|
|
33
|
+
- Split a behavior that spans rows. Test the copy at unit and the render at component, rather than asserting both in one browser run.
|
|
34
|
+
- Write the lower test when a higher one catches a break no lower test did. A red end to end run with every unit and component test green names a missing lower test.
|
|
35
|
+
- Reach for a real-browser component test before end to end when a simulated DOM cannot render the behavior. The middle layer exists for layout and scroll too.
|
|
36
|
+
|
|
37
|
+
## Spend end to end on journeys
|
|
38
|
+
|
|
39
|
+
- Cover the journeys a user cannot lose without the product failing, and what no lower layer can render.
|
|
40
|
+
- Never write an end to end test for a state a component test can reach, whether loading, empty, error, or a toggle.
|
|
41
|
+
- Count a new end to end test as a cost every later run pays. A suite grows by quality rather than by count, which is what keeps continuous integration fast.
|
|
42
|
+
- Carry no numeric mix. The right shape follows the architecture, and a ratio across a codebase is a target nobody writing one test can act on.
|
|
43
|
+
|
|
44
|
+
## Keep test code readable over clever
|
|
45
|
+
|
|
46
|
+
- Prefer a descriptive, repeated arrange over a shared helper a reader has to open. A test is read when it fails, by someone who did not write it.
|
|
47
|
+
- Assert through the public surface a caller uses. A test reaching into internals breaks on every refactor and catches nothing a caller sees.
|
|
48
|
+
- Prefer a real collaborator, then a fake, then a stub, and a mock last. A mock asserts how the code is built rather than what it does.
|
|
49
|
+
|
|
50
|
+
## Read the reference for the layer
|
|
51
|
+
|
|
52
|
+
Read the one reference matching the layer the table picked, before writing the first test at it. Skip the other two.
|
|
53
|
+
|
|
54
|
+
- Unit and integration: `${CLAUDE_SKILL_DIR}/references/unit.md`
|
|
55
|
+
- Component: `${CLAUDE_SKILL_DIR}/references/component.md`
|
|
56
|
+
- End to end: `${CLAUDE_SKILL_DIR}/references/e2e.md`
|
|
57
|
+
|
|
58
|
+
Read `${CLAUDE_SKILL_DIR}/references/adopted.md` only when extending this guidance or arguing against a rule in it. It records which external patterns were adopted, which declined, and why.
|
|
59
|
+
|
|
60
|
+
## Run the final filter before handing tests over
|
|
61
|
+
|
|
62
|
+
Check every test written this session against each line. A test that fails one is rewritten or cut, never kept with a note.
|
|
63
|
+
|
|
64
|
+
- **Mirror assertion.** The expected value is computed by the code under test. Write the literal the behavior should produce.
|
|
65
|
+
- **Change detector.** The assertion pins a constant, a message's wording, or a markup shape no caller depends on.
|
|
66
|
+
- **Assertion on a mock.** The test proves a double was called rather than that the behavior happened.
|
|
67
|
+
- **Framework behavior.** The test proves the runtime, the router, or the library works rather than this code's contract.
|
|
68
|
+
- **Fixed pause.** A sleep or timeout stands in for a condition. Settle on the condition instead.
|
|
69
|
+
- **Mutation check.** Break the code under test in three to five plausible ways in your head. At least one test fails for each, or a case is missing.
|
|
70
|
+
|
|
71
|
+
## What this delegates
|
|
72
|
+
|
|
73
|
+
- The red, green, refactor procedure and its order: `test-first`, which loads this skill at its first step
|
|
74
|
+
- Reproducing a failure with no known cause: `systematic-debugging`
|
|
75
|
+
- Test structure floors such as arrange, act, assert, one behavior per test, isolation, and no snapshots: `010-testing`
|
|
76
|
+
- Runner, file suffix, placement, and query conventions per language: `300-testing-ts` and `330-testing-py`
|
|
77
|
+
- Settle, guard, and run-scope rules inside an end to end file: `305-e2e-reliability` and `306-test-scope`
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Adopted and declined
|
|
3
|
+
description: Which external testing patterns this skill adopted, which it declined, and why, so a later session extends the position instead of re-deriving it
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Adopted and declined
|
|
7
|
+
|
|
8
|
+
External sources were read and filtered rather than imported. This file is the record. A later session extending the skill adds to it rather than re-arguing an item already settled here.
|
|
9
|
+
|
|
10
|
+
## Adopted
|
|
11
|
+
|
|
12
|
+
### Choosing the layer
|
|
13
|
+
|
|
14
|
+
**The smallest-layer rule.** Fowler: "Push your tests as far down the test pyramid as you can", and write a lower test when a higher one catches what no lower one did ([Practical Test Pyramid](https://martinfowler.com/articles/practical-test-pyramid.html)). It is the body's layer rule and the reason for the decision table.
|
|
15
|
+
|
|
16
|
+
**Sizing by what a test touches.** Google's small, medium, and large sizes name what a test may touch rather than what it covers ([Software Engineering at Google, ch. 11](https://abseil.io/resources/swe-book/html/ch11.html)). The decision table reads the same way, keyed on what the behavior touches, so it transfers across stacks without naming a runner. The scope names unit, component, and end to end stay as the labels, since those are the names a reader and a file suffix already use.
|
|
17
|
+
|
|
18
|
+
**The component layer carrying UI weight.** Kent C. Dodds's trophy ([Write tests](https://kentcdodds.com/blog/write-tests)) and Testing Library's principle that tests resembling use give more confidence ([guiding principles](https://testing-library.com/docs/guiding-principles)). The pyramid and the trophy are one rule applied to different code: a component's logic is its rendered behavior, so its lowest layer is a rendered test.
|
|
19
|
+
|
|
20
|
+
### Judging a test
|
|
21
|
+
|
|
22
|
+
**The opening question and the final filter.** From `obra/superpowers@5bf4e78`, `skills/test-driven-development/writing-good-tests.md`: name the production change that makes a test fail and whether it is a bug or a decision, then cut mirror assertions, change detectors, assertions on mocks, framework tests, and run the mutation check. Adopted as the body's opening question and final filter, with the fixed pause added from the end to end incidents.
|
|
23
|
+
|
|
24
|
+
**Doubles in preference order and DAMP over DRY.** From `addyosmani/agent-skills@c004a74`, `skills/test-driven-development/SKILL.md`: real, fake, stub, mock, and descriptive test bodies over shared helpers. Adopted in `unit.md`.
|
|
25
|
+
|
|
26
|
+
**Kent Beck's desiderata as background.** The twelve properties at [testdesiderata.com](https://testdesiderata.com/) trade against each other. "Behavioral" and "structure-insensitive" together are the whole of "test behavior, not implementation", which is why the body states that pair as asserting through the public surface.
|
|
27
|
+
|
|
28
|
+
### Per layer
|
|
29
|
+
|
|
30
|
+
**Component query and wait rules.** Role queries first, user events over synthetic ones, one assertion per wait, no side effects inside a wait ([Common mistakes](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)). Adopted in `component.md` with the library names removed from the rules.
|
|
31
|
+
|
|
32
|
+
**Web-first assertions, actionability, config-wide reduced motion, sharding.** From Playwright's own pages ([best practices](https://playwright.dev/docs/best-practices), [actionability](https://playwright.dev/docs/actionability), [TestOptions](https://playwright.dev/docs/api/class-testoptions)). Adopted in `e2e.md`, where the runner is named because the reference is the per-layer home for runner specifics.
|
|
33
|
+
|
|
34
|
+
## Declined
|
|
35
|
+
|
|
36
|
+
**A numeric mix.** Google targets roughly 80% unit, 15% integration, 5% end to end ([same chapter](https://abseil.io/resources/swe-book/html/ch11.html)). A ratio is a codebase-wide target that a session writing one test cannot act on, and web.dev's point that the shape "should fit your architecture" ([Pyramid or Crab](https://web.dev/articles/ta-strategies)) is what a motion-heavy static site needs. The body states the rule and the budget in words instead.
|
|
37
|
+
|
|
38
|
+
**Delete the code written before its test.** `superpowers`'s test-driven skill tells a session to delete implementation written ahead of a failing test. Declined: this toolkit audits the order after the fact with its test-order verb and reports rather than destroys, since deleting working code punishes the session without restoring the evidence the red run would have given.
|
|
39
|
+
|
|
40
|
+
**Rationalization tables and an iron law.** Both external test-driven skills carry an "Iron Law" and a table of excuses with rebuttals. Declined for tone: this toolkit states a rule once with its reason, and a table of arguments against imagined objections costs a read on every load and adds no constraint.
|
|
41
|
+
|
|
42
|
+
**One skill per layer.** A unit skill, a component skill, and an end to end skill each loaded on its own trigger. Declined because the layer has to be chosen before the right skill can load, so the choice ends up restated in all three or in a fourth skill that is this one.
|
|
43
|
+
|
|
44
|
+
**A standard in place of a skill.** The guidance is judgment applied while writing, loaded on intent. A standard governs an artifact a reader checks afterwards, and nobody checks a test file against a layer rule after the fact.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Component tests
|
|
3
|
+
description: Render with real children, query by role, drive with user events, wait on one condition at a time, and move to a real-browser runner for what a simulated DOM cannot render
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Component tests
|
|
7
|
+
|
|
8
|
+
Read this before writing the first test at the component layer. A component's logic is its rendered behavior, so the lowest layer that catches a break in a loading state, an interaction, or a validation message is a rendered component test rather than a browser run across the whole site. Kent C. Dodds's testing trophy makes this the widest band for UI code ([Write tests](https://kentcdodds.com/blog/write-tests)), on the principle Testing Library states: "The more your tests resemble the way your software is used, the more confidence they can give you" ([guiding principles](https://testing-library.com/docs/guiding-principles)).
|
|
9
|
+
|
|
10
|
+
## What belongs here
|
|
11
|
+
|
|
12
|
+
- Every state a component can show: loading, empty, error, populated, disabled.
|
|
13
|
+
- Every interaction that changes what it shows: a toggle, a filter, a form's validation and submit.
|
|
14
|
+
- Conditional rendering, keyboard handling inside the component, and focus moving where it should.
|
|
15
|
+
- Not a journey across routes, and not layout, scroll, or motion a simulated DOM does not compute. Those go to a real-browser component test below, or to end to end.
|
|
16
|
+
|
|
17
|
+
## Render
|
|
18
|
+
|
|
19
|
+
- Render with real children. Stubbing a child hides the break at the seam the user actually meets.
|
|
20
|
+
- Double the network at its edge with a request interceptor rather than mocking the data hook, so the component's own loading and error handling runs.
|
|
21
|
+
- Build the props or the fixture through a factory, keeping the values this case depends on visible.
|
|
22
|
+
|
|
23
|
+
## Query and act like a user
|
|
24
|
+
|
|
25
|
+
- Query by role and accessible name first, then by label, then by visible text. Reach for a test id only when nothing a user perceives identifies the element ([common mistakes](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)).
|
|
26
|
+
- Drive interaction through the user-event API rather than firing synthetic events, so focus, pointer, and keyboard sequences run as a browser would run them ([same](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)).
|
|
27
|
+
- Assert what the user perceives: text, role, state, focus. Never assert a class name, a hook's return value, or an internal state variable.
|
|
28
|
+
|
|
29
|
+
## Wait on one condition
|
|
30
|
+
|
|
31
|
+
- Put one assertion inside each wait. A wait holding several retries on the first and reports the wrong failure ([common mistakes](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)).
|
|
32
|
+
- Never put a side effect inside a wait. It runs once per retry.
|
|
33
|
+
- Prefer the query that waits over a wait wrapping a query that does not.
|
|
34
|
+
|
|
35
|
+
## When a simulated DOM cannot render it
|
|
36
|
+
|
|
37
|
+
A simulated DOM computes no layout, no scroll position, and no animation frame. When the behavior under test is one of those, move to a runner that renders the component in a real browser rather than promoting the test to end to end.
|
|
38
|
+
|
|
39
|
+
- Vitest browser mode runs tests "in the browser natively", with Playwright or WebdriverIO as the provider, and lists React, Vue, Svelte, Angular, Lit, Preact, and Qwik. Astro is not on the list ([Vitest browser mode](https://vitest.dev/guide/browser/)). For a static site, test the client module that drives the behavior against a fixture DOM here.
|
|
40
|
+
- Playwright component testing is stable in plain `@playwright/test` through a mount fixture, and "if your dev server can render it, Playwright can test it" ([Playwright component testing](https://playwright.dev/docs/test-components)). The experimental `-ct-*` packages were removed after 1.62.
|
|
41
|
+
|
|
42
|
+
Either runs in a real browser without navigating the whole site, which keeps the test at the component's cost while observing what only a browser computes.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: End to end tests
|
|
3
|
+
description: Which journeys earn a browser run, how to settle rather than pause, why motion is off by default, and how isolation and sharding keep the suite fast, with two worked failures
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# End to end tests
|
|
7
|
+
|
|
8
|
+
Read this before writing the first end to end test for a change. A browser run across the real site is the most expensive test a project owns and the most exposed to timing, so every one written here has to be one no lower layer could have been.
|
|
9
|
+
|
|
10
|
+
Read the settle, guard, and run-scope rules in the project's end to end reliability and test scope rules once they load. They fire on a read of an existing end to end file, and not on the creation of a new one, so the two floors below are repeated here for the session writing its first spec.
|
|
11
|
+
|
|
12
|
+
## What earns a browser run
|
|
13
|
+
|
|
14
|
+
- A journey a user cannot lose without the product failing, crossing more than one route: sign up, check out, publish ([Practical Test Pyramid](https://martinfowler.com/articles/practical-test-pyramid.html)).
|
|
15
|
+
- Behavior only a real browser computes across the whole page: layout at a breakpoint, scroll position, focus crossing a route, motion.
|
|
16
|
+
- Not a state a component test can reach. Loading, empty, and error states, a toggle, and a validation message belong one layer down, even when the component sits on a page with other end to end coverage.
|
|
17
|
+
- Not copy. Asserting exact wording in a browser run makes every copy edit a failure across every engine the gate runs.
|
|
18
|
+
|
|
19
|
+
Suites dominated by end to end tests inflate both runtime and flake ([Google Testing Blog, 2015](https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html)). Nothing fixes a count ceiling, and the right shape depends on the architecture ([Pyramid or Crab](https://web.dev/articles/ta-strategies)). A site whose behavior is mostly layout and motion carries more browser tests than a form-heavy app, and each one still has to earn its place.
|
|
20
|
+
|
|
21
|
+
## Settle on conditions
|
|
22
|
+
|
|
23
|
+
- Assert with a web-first assertion that retries until the condition holds. A manual visibility check reads once and does not retry ([best practices](https://playwright.dev/docs/best-practices)).
|
|
24
|
+
- Lean on actionability for clicks and fills. An element counts as stable once it "has maintained the same bounding box for at least two consecutive animation frames", so an action waits out an animation on its own ([actionability](https://playwright.dev/docs/actionability)). A read does not wait, so poll it.
|
|
25
|
+
- Never pause for a fixed duration to stand in for a condition. Reserve a fixed window for asserting that nothing happened across it.
|
|
26
|
+
- Settle a smooth scroll on the `scrollend` event. Fall back to a stillness window only when the target was already in view.
|
|
27
|
+
|
|
28
|
+
## Motion off by default
|
|
29
|
+
|
|
30
|
+
- Run with motion reduced unless the test asserts motion, and opt back in per test with `page.emulateMedia({ reducedMotion: 'no-preference' })`.
|
|
31
|
+
- Set it once in the config's `use` block as `reducedMotion: 'reduce'` rather than per test, since the option defaults to `'no-preference'` ([TestOptions](https://playwright.dev/docs/api/class-testoptions)). A site honoring the reduced preference then has nothing to wait out in any test that does not opt back in.
|
|
32
|
+
|
|
33
|
+
## Isolation and speed
|
|
34
|
+
|
|
35
|
+
- Give every test its own state: a fresh context, its own account or seed, nothing left behind for the next test.
|
|
36
|
+
- Speed a slow suite with parallel workers and sharding across machines rather than by cutting waits ([best practices](https://playwright.dev/docs/best-practices)). A suite that fails once workers rise carries timing-sensitive assertions, and those are the tests to move down a layer.
|
|
37
|
+
- Capture a trace on the first retry rather than a video on every run ([best practices](https://playwright.dev/docs/best-practices)).
|
|
38
|
+
- Count the cost before adding a test: its runtime, times every engine in the matrix, times every push. That product is what the gate charges each later change.
|
|
39
|
+
|
|
40
|
+
## Two worked failures
|
|
41
|
+
|
|
42
|
+
**A copy assertion in a browser run.** A portfolio site's home spec asserted the exact wording of its about section. A one-line copy edit then failed three engines in continuous integration, and the deploy waited on it. The production change that broke the test was a decision rather than a bug, which makes the assertion a change detector. The copy belonged in a unit test beside the module that holds it, and the browser run needed at most the section's presence.
|
|
43
|
+
|
|
44
|
+
**A settle that narrowed a failure without removing it.** A focus-ring spec waited on a scripted focus read with a condition wait, replacing a fixed pause. The next push to the trunk still failed one engine on every attempt with the condition timing out, and flaked a second test in the same file, which skipped the deploy. The settle was correct and the layer was wrong: an assertion whose result depends on how loaded the CI machine is keeps failing at the layer where load decides it. Moving the focus behavior to a real-browser component test takes it off the whole-site run.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Unit and integration tests
|
|
3
|
+
description: Doubles in preference order, descriptive over shared setup, table-driven cases, and the mutation check, for tests that run in one process
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Unit and integration tests
|
|
7
|
+
|
|
8
|
+
Read this before writing the first test at the unit or integration layer. A unit test runs in one process with no network, no sleep, and no real I/O. An integration test may touch the local machine, such as a temporary directory or a local database, and nothing beyond it. Google's size vocabulary draws the same line by what a test may touch rather than what it covers ([Software Engineering at Google, ch. 11](https://abseil.io/resources/swe-book/html/ch11.html)).
|
|
9
|
+
|
|
10
|
+
## Doubles
|
|
11
|
+
|
|
12
|
+
Prefer the most real collaborator the test can afford, in this order (`addyosmani/agent-skills@c004a74`, `skills/test-driven-development/SKILL.md`):
|
|
13
|
+
|
|
14
|
+
1. **Real.** The actual collaborator, when it is fast and deterministic. A pure function never needs a double.
|
|
15
|
+
2. **Fake.** A working implementation with a shortcut, such as an in-memory store standing in for a database.
|
|
16
|
+
3. **Stub.** Canned answers to the calls the test makes, with no assertions of its own.
|
|
17
|
+
4. **Mock.** A double that asserts how it was called. Reach for it only when the call itself is the contract, such as a payment that must be sent exactly once.
|
|
18
|
+
|
|
19
|
+
- Double only at a boundary the project does not own or cannot run locally: the network, the clock, randomness, a third-party service.
|
|
20
|
+
- Never assert that a mock exists or was constructed. That proves the test's own setup rather than the code (`obra/superpowers@5bf4e78`, `skills/test-driven-development/writing-good-tests.md`).
|
|
21
|
+
- Control the clock and randomness through an injected source rather than patching a global for the whole file.
|
|
22
|
+
|
|
23
|
+
## Descriptive over shared
|
|
24
|
+
|
|
25
|
+
- Prefer DAMP over DRY in a test body: descriptive and meaningful phrases a reader follows without opening a helper (`addyosmani/agent-skills@c004a74`, `skills/test-driven-development/SKILL.md`).
|
|
26
|
+
- Extract a factory for the data a test builds, and keep the values that matter to this case visible at the call site.
|
|
27
|
+
- Never share mutable state between tests. A test passing only after another one ran is two tests pretending to be one.
|
|
28
|
+
|
|
29
|
+
## Table-driven cases
|
|
30
|
+
|
|
31
|
+
- Write one table when several inputs exercise the same behavior and differ only in value. Each row names the case it proves.
|
|
32
|
+
- Keep a row to input and expected output. A row carrying its own branch of setup is a separate test.
|
|
33
|
+
- Split the table when a case needs a different assertion. A conditional inside the loop body is the loop hiding a second behavior.
|
|
34
|
+
|
|
35
|
+
## Integration at a boundary
|
|
36
|
+
|
|
37
|
+
- Test a module through the interface its callers use, with its real neighbors on the same machine.
|
|
38
|
+
- Use a temporary directory or an isolated database per test, created and removed by the test, never a shared fixture a previous run left behind.
|
|
39
|
+
- Cover the failure path at the boundary: the missing file, the refused write, the malformed record. That is where an integration test earns its extra cost over a unit test.
|
|
40
|
+
|
|
41
|
+
## The mutation check
|
|
42
|
+
|
|
43
|
+
Run it on each new test before calling it done (`obra/superpowers@5bf4e78`, `skills/test-driven-development/writing-good-tests.md`):
|
|
44
|
+
|
|
45
|
+
1. Name three to five plausible breaks in the code under test: an off-by-one, a flipped condition, a dropped branch, a wrong default, a swallowed error.
|
|
46
|
+
2. For each, say which test fails.
|
|
47
|
+
3. A break no test catches is a missing case. Write it, or state why the break is not a bug.
|
|
48
|
+
|
|
49
|
+
A mutation testing tool automates the same check across a codebase. The manual pass here is the version a session writing one test can run.
|
|
@@ -15,6 +15,7 @@ Without this skill, a session implementing a planned change writes the test afte
|
|
|
15
15
|
- Run the test before implementing and confirm it fails for the missing behavior, not for an unrelated mistake in the test itself
|
|
16
16
|
- Implement the minimum the current test demands, and start a new test before extending past it
|
|
17
17
|
- Re-run the test after implementing and confirm the pass is the one the test was written to prove
|
|
18
|
+
- Refactor the implementation and the test once the suite is green, re-running it after each change, since the smallest change that passes leaves duplication and shortcuts the loop exists to remove before they reach history
|
|
18
19
|
|
|
19
20
|
## Must not
|
|
20
21
|
|
|
@@ -29,6 +30,7 @@ Without this skill, a session implementing a planned change writes the test afte
|
|
|
29
30
|
|
|
30
31
|
## Out of scope
|
|
31
32
|
|
|
33
|
+
- Choosing the layer a test belongs at and judging whether it is a good test: `canon:test-craft`, loaded at step 1 rather than restated here
|
|
32
34
|
- Finding the cause of an unexplained failure: `canon:systematic-debugging`
|
|
33
35
|
- Confirming visual output after a change lands: `070-planning.md` states the order and `ui-test` covers it
|
|
34
36
|
- The mechanical audit of whether an implementation reached history ahead of its test: `canon gov test-order`, invoked from `auto-ship`
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: test-first
|
|
3
|
-
description: Write the failing test for a behavior before writing the code that satisfies it, confirm it fails for the right reason,
|
|
3
|
+
description: Write the failing test for a behavior before writing the code that satisfies it, confirm it fails for the right reason, implement the smallest change that turns it green, then refactor with the suite green. Auto-triggers before implementing a planned feature, adding a function or an endpoint, or extending existing behavior whose new shape is already decided. Do NOT use for a failure with no known cause, which is canon:systematic-debugging, or when the test for the behavior already exists and already passes.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Test first
|
|
7
7
|
|
|
8
8
|
## The loop
|
|
9
9
|
|
|
10
|
-
1.
|
|
10
|
+
1. Load `canon:test-craft` and pick the layer the test belongs at before writing it. Then find or write the test at that layer before touching the code it covers. Follow the pairing convention the project already uses, which is commonly a test sitting beside its subject under one name, so that `foo.ts` takes `foo.test.ts` beside it. Report it rather than proceeding silently when `canon:test-craft` does not resolve, and write the test at the smallest layer that can observe the behavior.
|
|
11
11
|
2. Write the test against the behavior as it should exist once the change lands, naming the case for what it proves rather than for the function it calls.
|
|
12
12
|
3. Run only that test and read the failure. Confirm it fails because the behavior is missing, not because of a typo, a missing import, or a signature the test itself got wrong. A test failing for the wrong reason still reads green the moment any code exists to satisfy that wrong reason, so treat any other failure as a defect in the test and fix the test before moving on.
|
|
13
13
|
4. Implement the smallest change that turns the failure into a pass. Do not add behavior the test does not ask for. A second behavior wants its own test written first, not a shortcut folded into the change already open.
|
|
14
14
|
5. Run the test again and confirm it passes for the reason it was written for, not by accident. Then run the surrounding suite so a change made to satisfy this test has not broken another.
|
|
15
|
+
6. Refactor with the suite green. Remove the duplication and the shortcuts step 4 left, in the implementation and in the test, without changing what either does. Run the suite after each change, and undo a change that turns anything red rather than fixing forward.
|
|
15
16
|
|
|
16
17
|
## Extending existing behavior
|
|
17
18
|
|
|
@@ -20,5 +21,6 @@ description: Write the failing test for a behavior before writing the code that
|
|
|
20
21
|
|
|
21
22
|
## What this skill does not cover
|
|
22
23
|
|
|
24
|
+
- Which layer a test belongs at and what makes it a good one. `canon:test-craft` owns that judgment, and step 1 loads it.
|
|
23
25
|
- A failure with no known cause. Route through `canon:systematic-debugging` first, whose own fix phase already writes the reproducing test as part of finding the cause. This skill starts once the shape of the fix or the feature is already decided.
|
|
24
26
|
- Confirming a change looks right once it has landed, which is a separate concern from whether the test passed and runs after implementation rather than before it.
|
|
@@ -9,13 +9,17 @@ description: Why UI changes split into what a browser can assert and what only a
|
|
|
9
9
|
|
|
10
10
|
Without this skill, UI work ships on the confidence of the session that wrote it. What verification does happen mixes the two kinds without noticing, so a checklist item about spacing sits beside one about a form submission, and neither is done properly because they need different work from different people. Tests get written against a config the project does not use, or duplicate what a component test already covers.
|
|
11
11
|
|
|
12
|
+
The automatable half fails the other way. Sending every interaction, state, and form to Playwright leaves the layers unrouted, so a loading state lands in a full browser run and the end to end suite grows on each UI change. A state a component test reaches costs a browser to check, and the cost recurs on every later run.
|
|
13
|
+
|
|
12
14
|
The visual half is where the record is lost. A checklist printed into chat scrolls away before anyone verifies it, so the ship step has nothing to gate on and the work reads as verified because a list was produced. Written from a linked worktree against `pwd`, the file lands where the caller does not look.
|
|
13
15
|
|
|
14
16
|
Writing the checklist correctly to disk does not close the gap either. The file sits under a gitignored folder on the machine that authored it, so a pull request reviewer, on that machine or another, never sees it. A record that only the author can open reads as verified for the same reason a record that never existed does.
|
|
15
17
|
|
|
16
18
|
## Must
|
|
17
19
|
|
|
18
|
-
- Split every change into
|
|
20
|
+
- Split every change into visual-only and automatable before writing anything, then route each automatable one to its layer through `test-craft`
|
|
21
|
+
- Write end to end only for a journey or a behavior only a real browser renders, and component or unit tests for the rest
|
|
22
|
+
- Name a missing component runner in the output and put the state on the checklist
|
|
19
23
|
- Read the project's existing test config and patterns before writing a test against them
|
|
20
24
|
- Assert a user action and its outcome per test, covering the happy path and the key edge cases
|
|
21
25
|
- Run the tests after writing them and fix what fails
|
|
@@ -26,6 +30,7 @@ Writing the checklist correctly to disk does not close the gap either. The file
|
|
|
26
30
|
|
|
27
31
|
- Try to assert a visual property programmatically
|
|
28
32
|
- Re-test what unit or component tests written during implementation already cover
|
|
33
|
+
- Route a state a component test reaches into end to end, or fall back to end to end silently when no runner exists
|
|
29
34
|
- Repeat the full checklist in chat, which is what made it evaporate
|
|
30
35
|
- Stage or commit the checklist, which is gitignored scratch
|
|
31
36
|
- Talk to GitHub directly. Posting the checklist to a pull request belongs to `git-pr`, the sole consumer of the handoff file
|
|
@@ -38,6 +43,6 @@ Writing the checklist correctly to disk does not close the gap either. The file
|
|
|
38
43
|
## Out of scope
|
|
39
44
|
|
|
40
45
|
- Judging whether the UI is any good, which `ux-audit` owns
|
|
41
|
-
-
|
|
46
|
+
- The rules for choosing a layer, which `test-craft` owns
|
|
42
47
|
- Deciding whether an outstanding checklist blocks the ship, which the calling pipeline gates on
|
|
43
48
|
- Performing the visual verification, which needs a person
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ui-test
|
|
3
|
-
description:
|
|
3
|
+
description: Routes each UI change to the test layer that can catch its break, writes end to end tests only for journeys and browser-only behavior, and produces a manual checklist for visual-only items. Use after implementing UI changes, or when asked "what should I test", "what do I verify", or "give me a test checklist". Do NOT use in empty sessions with no implementation context.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# UI test
|
|
@@ -8,26 +8,35 @@ description: Generates and runs Playwright e2e tests for UI changes, with a manu
|
|
|
8
8
|
## Guards
|
|
9
9
|
|
|
10
10
|
- If no implementation context exists in the session, stop: `❌ No implementation context. Describe what you built first.`
|
|
11
|
+
- Load `canon:test-craft` before writing any test, and report it rather than proceeding silently when it does not resolve.
|
|
11
12
|
|
|
12
13
|
## Analysis
|
|
13
14
|
|
|
14
|
-
Review the session to identify what was built or changed. Categorize each change:
|
|
15
|
+
Review the session to identify what was built or changed. Categorize each change, then route it:
|
|
15
16
|
|
|
16
|
-
- **Automatable:** interactions, state transitions, form submissions, keyboard navigation, conditional rendering, error states, empty states, loading states. These become Playwright e2e tests.
|
|
17
17
|
- **Visual-only:** spacing, alignment, color, typography, layout proportions, animation timing. These become a manual checklist.
|
|
18
|
+
- **Journey or browser-only:** a flow across routes, a route change, or a behavior only a real browser renders, such as scroll, focus order across pages, or layout. These become end to end tests.
|
|
19
|
+
- **Everything else:** interactions, state transitions, form submissions, keyboard handling, conditional rendering, loading, empty, and error states. Route these through the `test-craft` layer table to a component test, or to a unit test when the logic renders nothing.
|
|
18
20
|
|
|
19
|
-
Exclude anything already covered by
|
|
21
|
+
Never write an end to end test for a state a component test reaches. Exclude anything already covered by tests written during implementation.
|
|
22
|
+
|
|
23
|
+
## Component and unit tests
|
|
24
|
+
|
|
25
|
+
- Read the project's test config and an existing test at the layer first, and follow its runner, suffix, and placement.
|
|
26
|
+
- Read the `test-craft` component reference before the first component test.
|
|
27
|
+
- Assert each state through what a user sees or does, covering the happy path and the key edges.
|
|
28
|
+
- When the project has no component runner, write the checklist item for that state instead of an end to end test, and name the missing runner in the output. Do not fall back to end to end silently.
|
|
20
29
|
|
|
21
30
|
## E2e tests
|
|
22
31
|
|
|
23
|
-
Write Playwright tests for
|
|
32
|
+
Write Playwright tests for journeys and browser-only behavior only. Follow these rules:
|
|
24
33
|
|
|
25
|
-
-
|
|
34
|
+
- Read the `test-craft` end to end reference before the first one.
|
|
35
|
+
- Add tests to the project's existing `e2e/` layout and naming. If none exists, create `e2e/<feature>.spec.ts`.
|
|
26
36
|
- Use the project's existing Playwright config and test patterns. Read them first.
|
|
27
|
-
- Each test
|
|
28
|
-
- Cover both happy path and key edge cases (empty state, error state, boundary input).
|
|
37
|
+
- Each test performs a user action across the journey and asserts the expected outcome.
|
|
29
38
|
- For Chrome extensions: load the unpacked extension via Playwright's `--load-extension` flag and use the extension's sidepanel or popup URL as the test target.
|
|
30
|
-
- Run
|
|
39
|
+
- Run every test written, at every layer. Fix failures before finishing.
|
|
31
40
|
|
|
32
41
|
Test structure:
|
|
33
42
|
|
|
@@ -41,7 +50,7 @@ test('description of user flow', async ({ page }) => {
|
|
|
41
50
|
|
|
42
51
|
## Manual checklist
|
|
43
52
|
|
|
44
|
-
For visual-only items that cannot be asserted programmatically, produce a checklist. Group by feature area. Use `- [ ]` checkbox syntax.
|
|
53
|
+
For visual-only items that cannot be asserted programmatically, and for any state left without a runner, produce a checklist. Group by feature area. Use `- [ ]` checkbox syntax.
|
|
45
54
|
|
|
46
55
|
```markdown
|
|
47
56
|
**What to verify visually:**
|
|
@@ -51,9 +60,9 @@ For visual-only items that cannot be asserted programmatically, produce a checkl
|
|
|
51
60
|
- [ ] <action> → <expected visual result>
|
|
52
61
|
```
|
|
53
62
|
|
|
54
|
-
If
|
|
63
|
+
If every change is covered by a test, skip the manual checklist:
|
|
55
64
|
|
|
56
|
-
`✅ All changes covered by
|
|
65
|
+
`✅ All changes covered by tests. No manual verification needed.`
|
|
57
66
|
|
|
58
67
|
### Persist the checklist
|
|
59
68
|
|
|
@@ -63,15 +72,16 @@ When a manual checklist is produced, write it directly to `.canon/tmp/handoff/ui
|
|
|
63
72
|
|
|
64
73
|
From a linked worktree the file-editing tools refuse that path, so the checklist goes out through `Bash`. Send the `mkdir -p` and the heredoc as two plain commands rather than joining them with `&&`, which is refused as compound.
|
|
65
74
|
|
|
66
|
-
Skip the file write when
|
|
75
|
+
Skip the file write when every change is covered by tests and no checklist was produced.
|
|
67
76
|
|
|
68
77
|
The `.canon/tmp/` directory is gitignored. Do not stage or commit the file.
|
|
69
78
|
|
|
70
79
|
## Output order
|
|
71
80
|
|
|
72
|
-
1. Write and run
|
|
73
|
-
2.
|
|
81
|
+
1. Write and run the tests, naming each one's layer (report pass/fail)
|
|
82
|
+
2. Name any state left to the checklist for want of a component runner
|
|
83
|
+
3. If a manual checklist was produced, write it to file, then output only the file path in chat:
|
|
74
84
|
`📝 Wrote .canon/tmp/handoff/ui-checklist/<slug>.md`
|
|
75
|
-
|
|
85
|
+
4. If no checklist was needed: `✅ All changes covered by tests. No manual verification needed.`
|
|
76
86
|
|
|
77
87
|
Do not repeat the full checklist in chat.
|
|
@@ -58,7 +58,7 @@ Work in Claude Code directly. It reads `CLAUDE.md` automatically and has full fi
|
|
|
58
58
|
- When the current state is unmeasured and more than one approach is live, invoke `canon:plan-groundwork` first. It opens a track folder under `.canon/groundwork/<nn>-<slug>/` and ends in a decision, which may be to do nothing. Skip it when the approach is already settled.
|
|
59
59
|
- Invoke `canon:plan-feature` to scan for code-level conflicts and ambiguities, confirm approach before proceeding
|
|
60
60
|
- Implement the feature, then Claude Code runs the commands defined in `CLAUDE.md`, fixes failures, and iterates until all pass
|
|
61
|
-
- For UI changes, invoke `canon:ui-test` to
|
|
61
|
+
- For UI changes, invoke `canon:ui-test` to route each change to its test layer and run the tests it writes, with Playwright kept for journeys
|
|
62
62
|
End the session once the feature works and tests pass. Invoke `canon:docs-fold` to capture any decisions made during implementation before closing.
|
|
63
63
|
|
|
64
64
|
The routing test is whether the repository can answer an item today. A session grepping handles the yes, and a groundwork track handles the no.
|
|
@@ -174,7 +174,7 @@ The receipt is collected once every item on it has been decided, and it survives
|
|
|
174
174
|
|
|
175
175
|
### UI polish
|
|
176
176
|
|
|
177
|
-
Verify the change manually in the browser. Invoke `canon:ui-test` if you need
|
|
177
|
+
Verify the change manually in the browser. Invoke `canon:ui-test` if you need tests at the right layer and a visual verification checklist for the session. For the fix itself, describe the change in Claude Code directly.
|
|
178
178
|
|
|
179
179
|
### Quick fix
|
|
180
180
|
|
|
@@ -226,14 +226,15 @@ This section is the corpus the coverage claim is measured against: every name `c
|
|
|
226
226
|
|
|
227
227
|
### Build the feature
|
|
228
228
|
|
|
229
|
-
| Skill | When to use
|
|
230
|
-
| ---------------------------- |
|
|
231
|
-
| `canon:session-worktree` | At the plan-to-execute boundary, to get an isolated tree and branch
|
|
232
|
-
| `canon:auto-ship` | After plan approval, to chain implement, verify, review, draft PR
|
|
233
|
-
| `canon:project-commands` | When the project's own command needs running
|
|
234
|
-
| `canon:test-first` | Before implementing a planned change, to
|
|
235
|
-
| `canon:
|
|
236
|
-
| `canon:
|
|
229
|
+
| Skill | When to use |
|
|
230
|
+
| ---------------------------- | ------------------------------------------------------------------------------- |
|
|
231
|
+
| `canon:session-worktree` | At the plan-to-execute boundary, to get an isolated tree and branch |
|
|
232
|
+
| `canon:auto-ship` | After plan approval, to chain implement, verify, review, draft PR |
|
|
233
|
+
| `canon:project-commands` | When the project's own command needs running |
|
|
234
|
+
| `canon:test-first` | Before implementing a planned change, to run its test red, green, then refactor |
|
|
235
|
+
| `canon:test-craft` | When writing or changing any test, to pick its layer and filter what it asserts |
|
|
236
|
+
| `canon:systematic-debugging` | When a test fails or a bug surfaces, to force root cause first |
|
|
237
|
+
| `canon:ui-test` | After a UI change, to generate layered tests and a visual checklist |
|
|
237
238
|
|
|
238
239
|
### Check the work before it leaves the branch
|
|
239
240
|
|
|
@@ -31,13 +31,13 @@ A cell no source anchors ends in `? verify`, and the preview shows that marker b
|
|
|
31
31
|
### Tools
|
|
32
32
|
|
|
33
33
|
- None beyond Claude Code itself
|
|
34
|
-
- Playwright CLI optional for verifying
|
|
34
|
+
- Playwright CLI optional for verifying journeys across routes and browser-only behavior. See [`ui-test`](../../claude/skills/ui-test/SKILL.md).
|
|
35
35
|
|
|
36
36
|
### Skills
|
|
37
37
|
|
|
38
38
|
- `canon:sketch-design` to trace a design direction from reference images or URLs, before `design-extract`'s greenfield path proposes from a personality paragraph alone
|
|
39
39
|
- `canon:design-extract` to draft `canon/DESIGN.md`, from existing project signals or from requirements alone on day one
|
|
40
|
-
- `canon:ui-test` for
|
|
40
|
+
- `canon:ui-test` for layered test generation after UI changes
|
|
41
41
|
- `canon:ux-audit` for UX gap detection on existing surfaces
|
|
42
42
|
- `canon:ux-measure` for what a running surface costs to paint, read against published thresholds
|
|
43
43
|
- `canon:draft-and-pick` for a call settled by looking, drafting several candidates onto one page and taking your pick
|