@kensio/yulin-aws-simulation 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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +4 -4
- package/package.json +1 -1
- package/skills/yulin-aws-simulation/SKILL.md +18 -19
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
|
|
3
3
|
"name": "yulin-aws-simulation",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.10.0",
|
|
5
5
|
"description": "How to test AWS code well with the @kensio/yulin in-process simulator.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Kensio Software",
|
package/README.md
CHANGED
|
@@ -38,10 +38,10 @@ ambiguous with the suffix Secrets Manager appends to an ARN and advised against
|
|
|
38
38
|
already reached production. It caught a wrongly computed Cognito `SECRET_HASH` the stub had happily
|
|
39
39
|
accepted.
|
|
40
40
|
|
|
41
|
-
**Match service errors by `name
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
**Match service errors by `name`.** The SDK exports its exception classes, which invites the wrong
|
|
42
|
+
check. `instanceof` holds only while exactly one copy of the SDK is in play. It passes in production
|
|
43
|
+
and fails against the simulator. `name` is what the wire carries, and is the check that is right in
|
|
44
|
+
both places.
|
|
45
45
|
|
|
46
46
|
**Expect refusals, and treat them as a feature.** Yulin refuses a property it cannot simulate, and
|
|
47
47
|
never quietly ignores one, because silently accepting something that changes real behaviour is
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@ This skill serves the `isolated-testing-style` skill, the general argument for s
|
|
|
17
17
|
stubs.
|
|
18
18
|
|
|
19
19
|
Yulin is deliberately flexible, and plenty of shapes work. What follows is the recommended way to
|
|
20
|
-
get the most out of it,
|
|
20
|
+
get the most out of it, offered as guidance. Each one says what it buys. A situation that does not
|
|
21
21
|
want that trade can go the other way knowingly.
|
|
22
22
|
|
|
23
23
|
## Use what Yulin already gives you
|
|
@@ -41,9 +41,9 @@ exercise, then assert by reading the simulation back. A wrapper around any of th
|
|
|
41
41
|
one thing a reader of the test needs to see, and it has to be maintained forever after.
|
|
42
42
|
|
|
43
43
|
If a sequence genuinely repeats, make it a small function in the same test file, and keep it
|
|
44
|
-
returning the simulation objects themselves
|
|
45
|
-
wants a class, an options interface, or a directory, it has stopped being test setup and
|
|
46
|
-
second product.
|
|
44
|
+
returning the simulation objects themselves. A bespoke return shape starts hiding them. The point at
|
|
45
|
+
which it wants a class, an options interface, or a directory, it has stopped being test setup and
|
|
46
|
+
become a second product.
|
|
47
47
|
|
|
48
48
|
## One synthesized template, for tests, local dev and production
|
|
49
49
|
|
|
@@ -119,8 +119,8 @@ both already in production:
|
|
|
119
119
|
- A Cognito `SECRET_HASH` computed the wrong way. The stub had accepted that too, because a stub is
|
|
120
120
|
never going to verify a signature.
|
|
121
121
|
|
|
122
|
-
Intercept the class
|
|
123
|
-
|
|
122
|
+
Intercept the class in most cases, since the code under test usually constructs its own clients.
|
|
123
|
+
Intercept an instance when only one client should reach the simulation.
|
|
124
124
|
|
|
125
125
|
Each `SimSdk` owns a `SimAws`, reachable as `simSdk.simAws` for seeding and inspecting state. Pass
|
|
126
126
|
an existing one with `new SimSdk({ simAws })` to share.
|
|
@@ -129,8 +129,8 @@ an existing one with `new SimSdk({ simAws })` to share.
|
|
|
129
129
|
|
|
130
130
|
Interception replaces `send` on the thing it is given. It has to be given the client the code under
|
|
131
131
|
test actually calls. The wrapper clients are where this bites. A `DynamoDBDocumentClient` built over
|
|
132
|
-
a `DynamoDBClient` is what the code sends through.
|
|
133
|
-
intercepting
|
|
132
|
+
a `DynamoDBClient` is what the code sends through. The document client is the one that needs
|
|
133
|
+
intercepting.
|
|
134
134
|
|
|
135
135
|
```typescript
|
|
136
136
|
using simSdk = new SimSdk();
|
|
@@ -200,7 +200,7 @@ This is where simulation pays off over stubs a second time. A call-count asserti
|
|
|
200
200
|
today's implementation. A state assertion holds however the handler is rewritten, and it fails if
|
|
201
201
|
the call was made in a way the real service would have rejected.
|
|
202
202
|
|
|
203
|
-
## Match service errors by name
|
|
203
|
+
## Match service errors by name
|
|
204
204
|
|
|
205
205
|
```typescript
|
|
206
206
|
// Wrong. Passes in production, fails against the simulator.
|
|
@@ -215,8 +215,8 @@ one copy of the SDK package is in play. Two copies in the module graph, a bundle
|
|
|
215
215
|
raising its own classes, and it silently stops matching. Yulin's errors carry the service's real
|
|
216
216
|
error names and SDK-shaped `$metadata`, but they are not instances of the SDK classes.
|
|
217
217
|
|
|
218
|
-
This is worth fixing in production code,
|
|
219
|
-
carries. The `name` check is the one that is right in both places. A version skew between two
|
|
218
|
+
This is worth fixing in production code, and working around it in tests hides it. `name` is what the
|
|
219
|
+
wire carries. The `name` check is the one that is right in both places. A version skew between two
|
|
220
220
|
`@aws-sdk/client-*` packages breaks `instanceof` in production too, just less predictably than the
|
|
221
221
|
simulator does.
|
|
222
222
|
|
|
@@ -232,7 +232,7 @@ properties from the synthesized template until it deploys, keeping a list, then
|
|
|
232
232
|
upstream.
|
|
233
233
|
|
|
234
234
|
```typescript
|
|
235
|
-
// A throwaway transform used to find the floor
|
|
235
|
+
// A throwaway transform used to find the floor. Delete it afterwards.
|
|
236
236
|
function stripUntilItDeploys(template: CfnTemplateBodyRecord): CfnTemplateBodyRecord {
|
|
237
237
|
// Remove one refused property, re-run, record the next refusal, repeat.
|
|
238
238
|
// Keep the list. Raise it as one issue.
|
|
@@ -249,9 +249,8 @@ trusting a test that depends on the setting.
|
|
|
249
249
|
|
|
250
250
|
## Raise gaps upstream, and weight false passes far above false refusals
|
|
251
251
|
|
|
252
|
-
Fix gaps on [the Yulin repository](https://github.com/KensioSoftware/yulin)
|
|
253
|
-
|
|
254
|
-
gap.
|
|
252
|
+
Fix gaps on [the Yulin repository](https://github.com/KensioSoftware/yulin) at source. A local
|
|
253
|
+
workaround has to be maintained in every project that hits the same gap.
|
|
255
254
|
|
|
256
255
|
When reporting, the asymmetry matters more than the volume:
|
|
257
256
|
|
|
@@ -272,7 +271,7 @@ with the property and the template that carries it.
|
|
|
272
271
|
|
|
273
272
|
Vitest gives each test file its own worker, so module-level state is already isolated between files.
|
|
274
273
|
Deploy a stack once for the file and let the tests share it. Isolation inside the file comes from
|
|
275
|
-
randomised names
|
|
274
|
+
randomised names. Rebuilding the environment buys nothing.
|
|
276
275
|
|
|
277
276
|
```typescript
|
|
278
277
|
let simAws: SimAws;
|
|
@@ -303,9 +302,9 @@ same state is the beginning of the harness this skill opens by arguing against.
|
|
|
303
302
|
|
|
304
303
|
## Run the handler as a real simulated Lambda
|
|
305
304
|
|
|
306
|
-
Yulin can run an in-process handler as a function
|
|
307
|
-
|
|
308
|
-
the template are exercised too.
|
|
305
|
+
Yulin can run an in-process handler as a function inside the simulation, in place of a direct call
|
|
306
|
+
from the test. Its SDK calls are routed into the simulation as the execution role. The IAM policies
|
|
307
|
+
in the template are exercised too.
|
|
309
308
|
|
|
310
309
|
Bind a handler to a template function at deploy time with `bindings`:
|
|
311
310
|
|