@kensio/part-factory-test-data 1.3.0 → 1.6.1

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": "part-factory-test-data",
4
- "version": "1.3.0",
4
+ "version": "1.6.1",
5
5
  "description": "How to build test data with @kensio/part-factory: keeping in the factory everything a test does not care about, passing dependencies at call time so factories stay independent and shareable, and choosing between its static, dynamic, variant and mapped factories.",
6
6
  "author": {
7
7
  "name": "Kensio Software",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kensio/part-factory-test-data",
3
- "version": "1.3.0",
3
+ "version": "1.6.1",
4
4
  "description": "How to build test data with @kensio/part-factory: keeping in the factory everything a test does not care about, passing dependencies at call time so factories stay independent and shareable, and choosing between its static, dynamic, variant and mapped factories.",
5
5
  "keywords": [
6
6
  "claude",
@@ -5,7 +5,7 @@ description: Build test data with @kensio/part-factory, keeping in the factory e
5
5
 
6
6
  # Building test data with Part Factory
7
7
 
8
- [Part Factory](https://partfactory.dev/) (`@kensio/part-factory`) builds typed objects for tests: a
8
+ [Part Factory](https://partfactory.dev/) (`@kensio/part-factory`) builds typed objects for tests. A
9
9
  factory holds the defaults, and `make(overrides)` returns an object with the overrides applied down
10
10
  through the nested structure.
11
11
 
@@ -17,10 +17,10 @@ test cheap enough that nobody reaches for a shared fixture in the first place.
17
17
 
18
18
  ## Say only what the test is about
19
19
 
20
- A factory defines every value the test does not care about, so the test can state only the values it
21
- does. That is the whole point of one.
20
+ A factory defines every value the test ignores. The test can state only the values it does. That is
21
+ the whole point of one.
22
22
 
23
- Without it, a test opens with twenty lines of construction and it is not clear which of them the
23
+ Without it, a test opens with twenty lines of construction and it is unclear which of them the
24
24
  assertions actually depend on. With it, the lines that are there are the lines that matter:
25
25
 
26
26
  ```typescript
@@ -37,26 +37,26 @@ it("charges VAT on the order total", () => {
37
37
  ```
38
38
 
39
39
  The prices are written down because the assertion is arithmetic on them. The order id, the customer
40
- id and the dates are not, because the test would read the same whatever they were. The rule is that
41
- simple: **if an assertion depends on a value, put it in the test; otherwise let the factory supply
42
- it.**
40
+ id and the dates stay with the factory, because the test would read the same whatever they were. The
41
+ rule is that simple: **if an assertion depends on a value, put it in the test. Otherwise let the
42
+ factory supply it.**
43
43
 
44
44
  This also removes a pressure that quietly damages production types. When constructing an object by
45
- hand is painful, the tempting fix is to mark its required fields optional so tests can skip them
46
- weakening the type for every caller in order to serve the tests. A factory makes the setup cheap, so
47
- the type can go on saying what is actually required.
45
+ hand is painful, the tempting fix is to mark its required fields optional so tests can skip them,
46
+ weakening the type for every caller in order to serve the tests. A factory makes the setup cheap.
47
+ The type can go on saying what is actually required.
48
48
 
49
49
  ## Overrides are a deep partial
50
50
 
51
51
  Overrides merge into the defaults rather than replacing them, all the way down the nested structure.
52
- That is what makes "state only what matters" possible: a test can set one field three levels deep
52
+ That is what makes "state only what matters" possible. A test can set one field three levels deep
53
53
  and leave its siblings alone.
54
54
 
55
55
  Two consequences worth knowing:
56
56
 
57
57
  - Arrays override by index, so `{ lines: [{ price: 1000 }] }` replaces the first default line and
58
58
  leaves any others in place.
59
- - An empty array does not clear the defaults. To assert on emptiness, build the case some other way
59
+ - An empty array leaves the defaults in place. To assert on emptiness, build the case some other way
60
60
  rather than expecting `{ lines: [] }` to do it.
61
61
 
62
62
  ## Which factory
@@ -64,8 +64,8 @@ Two consequences worth knowing:
64
64
  - **`StaticFactory`** when the defaults are fixed values. The simplest thing that works, and the
65
65
  right default choice.
66
66
  - **`DynamicFactory`** when the defaults have to be generated fresh for each object. Pair it with
67
- [`@faker-js/faker`](https://fakerjs.dev/). This is what gives tests their isolation: a random
68
- email or a UUID means two tests cannot collide, so neither needs tearing down.
67
+ [`@faker-js/faker`](https://fakerjs.dev/). This is what gives tests their isolation. A random
68
+ email or a UUID means two tests cannot collide, so tearing down is unnecessary.
69
69
  - **`VariantFactory`** for a named variation of a base factory, when the variation is a concept the
70
70
  tests talk about. `closedOfferFactory` reads better in ten tests than
71
71
  `offerFactory.make({ closesAt: aMinuteAgo })` written ten times.
@@ -95,8 +95,8 @@ in the test is shorter and says more.
95
95
 
96
96
  ## Reach for MappedFactory only when the map is a real transformation
97
97
 
98
- `MappedFactory` earns its place when the thing you want to override is not shaped like the thing you
99
- want back. Good cases:
98
+ `MappedFactory` earns its place when the thing you want to override has a different shape from the
99
+ thing you want back. Good cases:
100
100
 
101
101
  - Parts to an encoded form body: `{ email, password }` mapped to a
102
102
  `application/x-www-form-urlencoded` string.
@@ -106,11 +106,11 @@ want back. Good cases:
106
106
 
107
107
  If the mapping function is copying fields across into an object of the same shape, you wanted a
108
108
  `DynamicFactory`. An identity map adds a type parameter, a second function and a layer of
109
- indirection, and buys nothing.
109
+ indirection, and buys little.
110
110
 
111
111
  ## Pass dependencies at call time
112
112
 
113
- A factory that needs something from the outside world a store, a client, a configured host
113
+ A factory that needs something from the outside world (a store, a client, a configured host)
114
114
  declares it as a third type parameter and receives it as the second argument to `make`:
115
115
 
116
116
  ```typescript
@@ -128,12 +128,12 @@ const order = await storedOrderFactory.make({ total: 5000 }, { orders });
128
128
  ```
129
129
 
130
130
  Dependencies are given at call time rather than held by the factory, and are used as they are given,
131
- never fetched or awaited. That is what keeps a factory shareable: it holds no state of its own,
132
- reaches for nothing ambient, and cannot depend on what another factory did first. A factory built
131
+ never fetched or awaited. That is what keeps a factory shareable. It holds no state of its own,
132
+ reaches for no ambient state, and cannot depend on what another factory did first. A factory built
133
133
  this way can be used in every test file in the codebase and still stand on its own.
134
134
 
135
- Keep each dependency as narrow as the factory actually needs. An `OrderStore` is a dependency; the
136
- whole application is not. A wide dependency is how state starts leaking between tests that were
135
+ Keep each dependency as narrow as the factory actually needs. An `OrderStore` is a dependency. The
136
+ whole application never is. A wide dependency is how state starts leaking between tests that were
137
137
  supposed to be independent.
138
138
 
139
139
  ## Do not wrap a factory in a function that applies overrides
@@ -145,7 +145,7 @@ export function makeCustomer(overrides: Partial<Customer> = {}): Customer {
145
145
  }
146
146
  ```
147
147
 
148
- `make(overrides)` already is that function, and it does the job better: its overrides are partial
148
+ `make(overrides)` already is that function, and it does the job better. Its overrides are partial
149
149
  all the way down the nested structure, where the spread above replaces a nested object whole.
150
150
 
151
151
  A wrapper that does anything more than pass overrides through is a signal to read rather than to
@@ -155,17 +155,17 @@ write. It usually means one of two things:
155
155
  computing, or deriving one field from another. Move that into a `DynamicFactory` defaults
156
156
  function, which receives the overrides, or into a `MappedFactory` map.
157
157
  - **The output type is fighting you.** The wrapper is casting, widening or filling in a field the
158
- type demands but the test does not care about. Fix the type, or use `MappedFactory` so the parts
159
- and the output are allowed to differ.
158
+ type demands but the test ignores. Fix the type, or use `MappedFactory` so the parts and the
159
+ output are allowed to differ.
160
160
 
161
- The same goes for a wrapper that exists to pass a dependency: declare it on the factory instead.
161
+ The same goes for a wrapper that exists to pass a dependency. Declare it on the factory instead.
162
162
 
163
163
  ## Factories belong beside the type they construct
164
164
 
165
165
  A library that defines an event, a message or a payload shape should export a factory for it.
166
166
  Otherwise every consumer hand-rolls the literal, and every copy drifts.
167
167
 
168
- The worked example: an AWS Lambda function URL invocation event, payload format 2.0. It is around
168
+ The worked example is an AWS Lambda function URL invocation event, payload format 2.0. It is around
169
169
  thirty lines, of which two matter to any given test.
170
170
 
171
171
  ```json
@@ -186,7 +186,7 @@ thirty lines, of which two matter to any given test.
186
186
  ```
187
187
 
188
188
  Hand-writing that in three test files gives three copies that drift as the shape changes. It also
189
- carries a real trap: the path is in the event twice, as `rawPath` and as `requestContext.http.path`,
189
+ carries a real trap. The path is in the event twice, as `rawPath` and as `requestContext.http.path`,
190
190
  and the query string is in it twice, as `rawQueryString` and as `queryStringParameters`. A test that
191
191
  sets one and not the other passes against a handler reading the field the test set, and fails in
192
192
  production against the same handler reading the other one.