@kensio/isolated-testing-style 1.9.0 → 1.10.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://anthropic.com/claude-code/plugin.schema.json",
3
3
  "name": "isolated-testing-style",
4
- "version": "1.9.0",
4
+ "version": "1.10.0",
5
5
  "description": "An opinionated testing style built on simulated collaborators and randomised data.",
6
6
  "author": {
7
7
  "name": "Kensio Software",
package/README.md CHANGED
@@ -28,14 +28,13 @@ simulator asserts that it called the service correctly. A stub answers whatever
28
28
  answer. It agrees with your understanding of the API by construction, and cannot find the case where
29
29
  that understanding is wrong.
30
30
 
31
- **Get isolation from the data, not from setup and teardown.** Randomised values from faker mean two
32
- tests cannot collide. There is nothing to tear down and no ordering to depend on. A shared
33
- environment built the way production is built is closer to production than a minimal one rebuilt per
34
- test, and it is faster.
31
+ **Take isolation from randomised data.** Randomised values from faker mean two tests cannot collide.
32
+ There is nothing to tear down and no ordering to depend on. A shared environment built the way
33
+ production is built is closer to production than a minimal one rebuilt per test, and it is faster.
35
34
 
36
- **Assert behaviour, not call counts.** To prove a value is cached, delete the underlying resource
37
- and show the cached value survives. To prove a retry, make the first call fail and the second
38
- succeed. Both hold however the code is implemented. That is what makes refactoring safe.
35
+ **Assert observable behaviour.** To prove a value is cached, delete the underlying resource and show
36
+ the cached value survives. To prove a retry, make the first call fail and the second succeed. Both
37
+ hold however the code is implemented. That is what makes refactoring safe.
39
38
 
40
39
  **Never pin a value computed by the code under test.** Pinning a hash you generated by running the
41
40
  same function only proves the function is deterministic. It keeps passing after the function becomes
@@ -44,8 +43,8 @@ wrong. Pin against an independent authority, or let a real implementation valida
44
43
  **Put test support beside the code.** Factories and helpers live in a test-support module next to
45
44
  what they support. Test files hold tests.
46
45
 
47
- **Comment test bodies with Given, When and Then**, saying why the lines are there, not restating
48
- them.
46
+ **Comment test bodies with Given, When and Then**, saying why the lines are there. A comment that
47
+ restates the code adds nothing.
49
48
 
50
49
  ## The other two skills
51
50
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kensio/isolated-testing-style",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "An opinionated testing style built on simulated collaborators and randomised data.",
5
5
  "keywords": [
6
6
  "claude",
@@ -6,7 +6,7 @@ description: Write tests that start from given/when/then, use real collaborators
6
6
  # Isolated testing style
7
7
 
8
8
  An opinionated way of writing tests. The examples are TypeScript and vitest, but the rules are about
9
- test design, not about any framework. Each rule exists because of a specific failure it would have
9
+ test design and hold for any framework. Each rule exists because of a specific failure it would have
10
10
  caught.
11
11
 
12
12
  ## Start with Given, When, Then
@@ -28,14 +28,14 @@ what should result. That is a smaller question than "how do I test this?", and y
28
28
  answer it before you can answer the bigger one.
29
29
 
30
30
  **It designs the interface.** Filling in `// When` forces you to name the single action under test,
31
- in the caller's vocabulary, not the implementation's. A step you cannot write as one `// When` is
32
- usually telling you the interface is wrong, not the test.
31
+ in the caller's vocabulary. A step you cannot write as one `// When` usually means the interface is
32
+ wrong.
33
33
 
34
34
  **It keeps the test readable as documentation.** Tests are read far more often than they are
35
35
  written, and without the structure it is easy to produce a body where essential behaviour and
36
36
  incidental setup look alike.
37
37
 
38
- Then fill each comment in with the case, not with a restatement of the code:
38
+ Then fill each comment in with the case it covers, and never with a restatement of the code:
39
39
 
40
40
  ```typescript
41
41
  it("refuses an order once the offer has closed", async () => {
@@ -96,11 +96,11 @@ quirk to work around.
96
96
 
97
97
  ## Keep setup cheap and independent
98
98
 
99
- Tangled shared fixtures come from economics, not from indiscipline. Teams share setup roughly in
100
- proportion to how expensive it is to build. When getting a test into the right state means threading
101
- through a web of existing fixtures, reusing what is already there is the rational move, and each
102
- reuse adds another edge to the graph. That is how a suite arrives at setup that no one dares to
103
- touch.
99
+ Tangled shared fixtures come from economics. Discipline has little to do with it. Teams share setup
100
+ roughly in proportion to how expensive it is to build. When getting a test into the right state
101
+ means threading through a web of existing fixtures, reusing what is already there is the rational
102
+ move, and each reuse adds another edge to the graph. That is how a suite arrives at setup that no
103
+ one dares to touch.
104
104
 
105
105
  The fix is to share differently. Shared factories for test entities are exactly what you want. A
106
106
  factory that constructs a type is worth writing once and using everywhere. What has to be avoided is
@@ -109,7 +109,7 @@ those factories getting tangled up with each other. Each piece of setup should s
109
109
  Independence comes from taking dependencies explicitly rather than reaching for ambient state. A
110
110
  factory that is handed what it needs stays pure, and the test decides what to hand it.
111
111
  `@kensio/part-factory` builds this in. Factories take a `dependencies` object as a second argument
112
- at call time. A factory that needs a simulated AWS is given one rather than going looking for one.
112
+ at call time. A factory that needs a simulated AWS is handed one, and never goes looking.
113
113
 
114
114
  ```typescript
115
115
  // Given an order that exists in this test's own simulated AWS.
@@ -121,12 +121,12 @@ A factory built that way can be shared as widely as you like and still stand on
121
121
  everything it does is independent of what another factory did first. Prefer collaborators and
122
122
  factories that need only instantiation, with no side effects, no cleanup and no coordination.
123
123
 
124
- For a step specific to one test rather than a reusable factory, ask whether the step belongs to the
125
- test or the test belongs to the step. A helper confined to one file can be pulled back inline later
126
- if it stops earning its place, whereas a fixture that a large part of the suite is built on cannot.
127
- It is that reversibility worth preserving, not locality for its own sake.
124
+ For a step specific to one test, ask whether the step belongs to the test or the test belongs to the
125
+ step. A helper confined to one file can be pulled back inline later if it stops earning its place,
126
+ whereas a fixture that a large part of the suite is built on cannot. Reversibility is the thing to
127
+ preserve, and locality on its own earns little.
128
128
 
129
- ## Get isolation from the data, not from setup and teardown
129
+ ## Take isolation from randomised data
130
130
 
131
131
  Randomised values make collisions impossible. No teardown is required, and there is no ordering to
132
132
  depend on. Randomised is enough. Guaranteed uniqueness is unnecessary, and a UUID has no realistic
@@ -174,7 +174,7 @@ Faker is the source of these values. Prefer a generator that produces a realisti
174
174
  kind (`faker.internet.email()`, `faker.string.uuid()`, `faker.company.name()`) over a counter or a
175
175
  literal with a suffix. The test data also exercises the shapes production data has.
176
176
 
177
- ## Assert behaviour, not call counts
177
+ ## Assert observable behaviour
178
178
 
179
179
  A call count asserts how the code is written today. A behaviour assertion holds however it is
180
180
  written, which is what lets you refactor.
@@ -228,9 +228,9 @@ Two ways out, in order of preference:
228
228
  published test vector, or a value produced by a different implementation.
229
229
 
230
230
  The same rule covers snapshot tests of anything the code under test formats. A snapshot records what
231
- the code does, not what it should do.
231
+ the code does, and stays silent on what it should do.
232
232
 
233
- ## Nothing at the top level but imports
233
+ ## Keep the top level to imports
234
234
 
235
235
  In an ideal vitest or jest file, the only things outside the top-level `describe()` are the imports.
236
236
  State, construction and helpers all live inside it. The file reads as a description of behaviour and
@@ -248,14 +248,14 @@ describe("placing an order", () => {
248
248
  });
249
249
  ```
250
250
 
251
- This is mostly a consequence of the other rules, not an extra one. What usually accumulates at the
252
- top level of a test file is module-level state the tests share, a mutable handle that exists so
253
- `afterEach` can reach it, and hoisted mock registrations. The rules above have already turned down
254
- all three. So a top level that will not stay empty is a useful signal that something further up has
255
- slipped. Imported factories are fine here. They arrive as imports precisely because they stand on
256
- their own.
251
+ This is mostly a consequence of the other rules and adds little on its own. What usually accumulates
252
+ at the top level of a test file is module-level state the tests share, a mutable handle that exists
253
+ so `afterEach` can reach it, and hoisted mock registrations. The rules above have already turned
254
+ down all three. So a top level that will not stay empty is a useful signal that something further up
255
+ has slipped. Imported factories are fine here. They arrive as imports precisely because they stand
256
+ on their own.
257
257
 
258
- ## Put test support beside the code, not in the test file
258
+ ## Put test support beside the code
259
259
 
260
260
  A test file should hold tests. Where support lives depends on what it is for.
261
261
 
@@ -275,8 +275,9 @@ A step written for **one test** stays in that test's file, inside the `describe`
275
275
  when another test wants it is fine. Make it independent first, so what spreads is a self-contained
276
276
  factory (not a dependency on how some other test left things).
277
277
 
278
- If a test file is mostly setup, that is a signal. The fix is usually cheaper construction, not a
279
- shared fixture. Scroll the file and see how much of it is `it(...)` bodies making assertions.
278
+ If a test file is mostly setup, that is a signal. The fix is usually cheaper construction. A shared
279
+ fixture treats the symptom. Scroll the file and see how much of it is `it(...)` bodies making
280
+ assertions.
280
281
 
281
282
  ## Tools that help
282
283