@kensio/yulin 1.21.7 → 1.21.8

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.
Files changed (47) hide show
  1. package/README.md +22 -2
  2. package/dist/service/ses/command/authorize/sim-ses-authorizer.d.ts +9 -0
  3. package/dist/service/ses/command/authorize/sim-ses-authorizer.js +18 -2
  4. package/dist/service/ses/command/send/sim-ses-send-email.js +2 -1
  5. package/docs/README.md +7 -0
  6. package/docs/ai-skill/README.md +6 -1
  7. package/docs/sdk/README.md +15 -0
  8. package/docs/services/acm/README.md +24 -40
  9. package/docs/services/apigateway/README.md +52 -71
  10. package/docs/services/apigatewayv2/README.md +55 -74
  11. package/docs/services/athena/README.md +17 -26
  12. package/docs/services/backup/README.md +29 -39
  13. package/docs/services/bedrock/README.md +38 -52
  14. package/docs/services/cloudformation/README.md +43 -55
  15. package/docs/services/cloudfront/README.md +69 -95
  16. package/docs/services/cloudwatch/README.md +40 -54
  17. package/docs/services/cognito/README.md +30 -45
  18. package/docs/services/dynamodb/README.md +34 -51
  19. package/docs/services/ecr/README.md +36 -77
  20. package/docs/services/ecs/README.md +26 -46
  21. package/docs/services/elbv2/README.md +19 -29
  22. package/docs/services/eventbridge/README.md +14 -18
  23. package/docs/services/firehose/README.md +24 -32
  24. package/docs/services/glue/README.md +41 -78
  25. package/docs/services/iam/README.md +13 -15
  26. package/docs/services/kinesis/README.md +53 -93
  27. package/docs/services/kms/README.md +22 -32
  28. package/docs/services/lambda/README.md +53 -79
  29. package/docs/services/logs/README.md +41 -50
  30. package/docs/services/organizations/README.md +50 -85
  31. package/docs/services/personalize/README.md +28 -44
  32. package/docs/services/rekognition/README.md +26 -38
  33. package/docs/services/route53/README.md +17 -17
  34. package/docs/services/s3/README.md +47 -51
  35. package/docs/services/scheduler/README.md +41 -52
  36. package/docs/services/secretsmanager/README.md +27 -42
  37. package/docs/services/ses/README.md +24 -34
  38. package/docs/services/sns/README.md +18 -26
  39. package/docs/services/sqs/README.md +14 -14
  40. package/docs/services/ssm/README.md +13 -17
  41. package/docs/services/stepfunctions/README.md +18 -20
  42. package/docs/services/sts/README.md +32 -45
  43. package/docs/services/wafv2/README.md +12 -17
  44. package/docs/testing/README.md +228 -0
  45. package/docs/time/README.md +10 -0
  46. package/llms.txt +1 -0
  47. package/package.json +1 -1
@@ -0,0 +1,228 @@
1
+ # Test suite setup
2
+
3
+ Run one Yulin environment for an application's test suite. Create the simulation, deploy the
4
+ application's infrastructure, and install AWS SDK interception once. Every test then interacts with
5
+ the same simulated account and resources.
6
+
7
+ This is the recommended setup. It matches the way a suite uses a shared AWS account or a
8
+ container-based simulator such as LocalStack. Creating a new Yulin environment for every test or
9
+ test file is supported, but it should be reserved for cases that need a blank simulated account.
10
+
11
+ The simulated clock is the main exception. A suite-wide `SimAws` has one clock, so a test that moves
12
+ it changes time for every resource in that environment. Keep the majority of tests in the shared
13
+ environment without changing its clock. Put clock-controlling tests in a smaller isolated group.
14
+
15
+ ## Split the Vitest suite
16
+
17
+ Yulin holds state in the process that created it. Vitest must run the Yulin tests in one worker for
18
+ all shared files to reach the same environment. Give that project disabled file parallelism and file
19
+ isolation, then load a setup module before each test file.
20
+
21
+ The second project below matches files ending in `.clock.test.ts`. Those tests do not load the shared
22
+ setup and can create isolated Yulin environments:
23
+
24
+ ```typescript testing-vitest-config
25
+ import { defineConfig } from "vitest/config";
26
+
27
+ export default defineConfig({
28
+ test: {
29
+ environment: "node",
30
+ projects: [
31
+ {
32
+ extends: true,
33
+ test: {
34
+ name: "shared Yulin",
35
+ include: ["test/**/*.test.ts"],
36
+ exclude: ["test/**/*.clock.test.ts"],
37
+ fileParallelism: false,
38
+ isolate: false,
39
+ setupFiles: ["./test/setup-yulin.ts"],
40
+ },
41
+ },
42
+ {
43
+ extends: true,
44
+ test: {
45
+ name: "isolated Yulin clock",
46
+ include: ["test/**/*.clock.test.ts"],
47
+ },
48
+ },
49
+ ],
50
+ },
51
+ });
52
+ ```
53
+
54
+ Vitest executes a `setupFiles` entry before every test file. With isolation disabled, modules
55
+ imported by that entry stay cached in the worker. Put the Yulin initialization in an imported module
56
+ to make it run once.
57
+
58
+ See Vitest's documentation for [`setupFiles`](https://vitest.dev/config/setupfiles),
59
+ [`fileParallelism`](https://vitest.dev/config/fileparallelism), and
60
+ [`isolate`](https://vitest.dev/config/isolate).
61
+
62
+ ## Create and deploy the shared environment
63
+
64
+ Put the suite environment in a module such as `test/yulin-environment.ts`. Intercept client classes
65
+ used by the application and deploy its synthesized CDK cloud assembly:
66
+
67
+ ```typescript testing-shared-yulin-environment
68
+ import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
69
+ import { S3Client } from "@aws-sdk/client-s3";
70
+ import type { SimAws } from "@kensio/yulin";
71
+ import { SimSdk } from "@kensio/yulin/sdk";
72
+
73
+ interface YulinTestEnvironment {
74
+ readonly simAws: SimAws;
75
+ readonly simSdk: SimSdk;
76
+ readonly uploadsBucketName: string;
77
+ }
78
+
79
+ type YulinTestGlobal = typeof globalThis & {
80
+ yulinEnvironment?: Promise<YulinTestEnvironment>;
81
+ };
82
+
83
+ const testGlobal = globalThis as YulinTestGlobal;
84
+
85
+ // oxlint-disable-next-line unicorn-js/prefer-top-level-await -- The shared promise prevents setup from running again before another test file.
86
+ export const yulin = await (testGlobal.yulinEnvironment ??= startYulin());
87
+
88
+ async function startYulin(): Promise<YulinTestEnvironment> {
89
+ const simSdk = new SimSdk();
90
+ simSdk.intercept(DynamoDBClient);
91
+ simSdk.intercept(S3Client);
92
+
93
+ const stacks = await simSdk.simAws.cloudFormation().deployCdkOut({
94
+ directoryPath: "cdk.out",
95
+ stackNames: ["ApplicationStack"],
96
+ });
97
+ const appStack = stacks.get("ApplicationStack");
98
+
99
+ if (appStack === undefined) {
100
+ throw new Error("ApplicationStack was not deployed");
101
+ }
102
+
103
+ process.once("exit", () => {
104
+ simSdk.restoreAll();
105
+ });
106
+
107
+ return {
108
+ simAws: simSdk.simAws,
109
+ simSdk,
110
+ uploadsBucketName: appStack.output("UploadsBucketName"),
111
+ };
112
+ }
113
+ ```
114
+
115
+ Use the same templates that the application deploys. `deployCdkOut(...)` can deploy the whole cloud
116
+ assembly or the named application Stacks. Read generated resource names from stack outputs or
117
+ resource accessors after deployment.
118
+
119
+ The configured setup entry only needs to import that module:
120
+
121
+ ```typescript
122
+ // test/setup-yulin.ts
123
+ import "./yulin-environment.js";
124
+ ```
125
+
126
+ Do not put the initialization directly in `setup-yulin.ts`. Vitest executes that file for every test
127
+ file, even when isolation is disabled.
128
+
129
+ ## Use the environment from every test
130
+
131
+ Application code continues to construct and send through ordinary AWS SDK clients. Class-level
132
+ interception routes all of them to the suite's Yulin environment.
133
+
134
+ A test that needs direct access can import the shared environment:
135
+
136
+ ```typescript
137
+ import { randomUUID } from "node:crypto";
138
+
139
+ import {
140
+ GetObjectCommand,
141
+ PutObjectCommand,
142
+ S3Client,
143
+ } from "@aws-sdk/client-s3";
144
+ import { expect, it } from "vitest";
145
+
146
+ import { yulin } from "../yulin-environment.js";
147
+
148
+ it("stores an upload", async () => {
149
+ const key = `test-uploads/${randomUUID()}.txt`;
150
+ const s3 = new S3Client({ region: "eu-west-2" });
151
+
152
+ await s3.send(
153
+ new PutObjectCommand({
154
+ Bucket: yulin.uploadsBucketName,
155
+ Key: key,
156
+ Body: "an upload",
157
+ }),
158
+ );
159
+
160
+ const stored = await yulin.simAws
161
+ .region("eu-west-2")
162
+ .s3()
163
+ .getObject(
164
+ new GetObjectCommand({
165
+ Bucket: yulin.uploadsBucketName,
166
+ Key: key,
167
+ }),
168
+ );
169
+
170
+ expect(await stored?.Body?.transformToString()).toBe("an upload");
171
+ });
172
+ ```
173
+
174
+ The `SimAws` object is mainly useful for preparing input state and reading state back in assertions.
175
+ Exercise the application through its normal interfaces whenever possible.
176
+
177
+ ## Keep tests independent in shared state
178
+
179
+ Shared infrastructure does not require tests to depend on one another. Give each test's records,
180
+ object keys, user names, and other mutable data unique values. Read CloudFormation-generated names
181
+ from the deployed stack. Avoid assertions that assume the simulated account contains no other data.
182
+
183
+ Keep `beforeEach` for the records a test needs. A per-file `beforeAll` can prepare data used by every
184
+ test in that file. Leave the suite's stacks and SDK interception in place until the worker exits.
185
+
186
+ Tests run sequentially with `fileParallelism: false`. If a test uses `it.concurrent`, its data still
187
+ needs unique identifiers because those cases share the same environment at the same time.
188
+
189
+ ## Give clock-controlling tests their own environment
190
+
191
+ Every service in a `SimAws` reads the same simulated clock. Calling `advanceBy(...)` can expire
192
+ credentials, delete resources whose retention period has passed, and run scheduled work anywhere in
193
+ the environment. Resetting the clock afterwards cannot reverse those changes.
194
+
195
+ Tests in the shared project should treat the clock as read-only. Put a test that calls `freeze()`,
196
+ `setTo(...)`, `advanceBy(...)`, or `resume()` in a `.clock.test.ts` file and create a fresh environment
197
+ inside the test:
198
+
199
+ ```typescript
200
+ import { SimAws, SimFixedClock } from "@kensio/yulin";
201
+ import { it } from "vitest";
202
+
203
+ it("expires a session", async () => {
204
+ const simAws = new SimAws({
205
+ clock: new SimFixedClock(new Date("2026-09-04T09:00:00.000Z")),
206
+ });
207
+
208
+ // Deploy only the infrastructure this clock-controlling test needs.
209
+
210
+ await simAws.clock().advanceBy({ minutes: 20 });
211
+
212
+ // Assert the behaviour after the time change.
213
+ });
214
+ ```
215
+
216
+ Create a `SimSdk` around that `SimAws` when application code uses SDK clients. Restore its
217
+ interceptions at the end of the test. The [simulated time guide](https://yulinsim.dev/time/) describes
218
+ what moving the clock runs and changes.
219
+
220
+ ## When to create another environment
221
+
222
+ A fresh `SimAws` or `SimSdk` is useful when the empty environment is part of the behaviour under
223
+ test, or when the test needs to control simulated time. Yulin's own service unit tests are another
224
+ example because they test resource creation and account isolation directly.
225
+
226
+ Vitest workers cannot share an in-memory `SimAws`. A suite that keeps file parallelism creates one
227
+ environment per worker. Put Yulin-based application tests in a Vitest project with
228
+ `fileParallelism: false` when the rest of the unit suite should remain parallel.
@@ -3,6 +3,16 @@
3
3
  Each `SimAws` has its own clock. Yulin uses that clock for resource timestamps, expiry checks, and
4
4
  scheduled work.
5
5
 
6
+ ## Isolate tests that control time
7
+
8
+ A shared [test suite environment](https://yulinsim.dev/testing/) also has one shared clock. Most
9
+ tests should use that environment without calling `freeze()`, `setTo(...)`, `advanceBy(...)`, or
10
+ `resume()`.
11
+
12
+ Put tests that control simulated time in a separate test group. Give each of those tests its own
13
+ `SimAws` or `SimSdk`, along with the infrastructure it needs. A clock change then affects only that
14
+ test's environment. The rest of the suite can keep sharing one deployment and SDK interception.
15
+
6
16
  ## Start at a known time
7
17
 
8
18
  A new simulation follows the system clock by default. Pass a `SimFixedClock` when a test needs an
package/llms.txt CHANGED
@@ -57,4 +57,5 @@ The same pages are on the web at https://yulinsim.dev/ for whichever release is
57
57
  - [Non-AWS dependencies](docs/non-aws-dependencies/README.md): Dependencies Yulin does not simulate usage docs
58
58
  - [Serving on localhost](docs/serve/README.md): Serving simulated AWS on localhost usage docs
59
59
  - [Simulated time](docs/time/README.md): Simulated time usage docs
60
+ - [Test suite setup](docs/testing/README.md): Sharing one Yulin environment across a test suite
60
61
  - [Terraform](docs/terraform/README.md): Deploying Terraform into simulated AWS usage docs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kensio/yulin",
3
- "version": "1.21.7",
3
+ "version": "1.21.8",
4
4
  "description": "AWS system behaviour simulation for isolated unit testing",
5
5
  "repository": "https://github.com/KensioSoftware/yulin",
6
6
  "homepage": "https://yulinsim.dev/",