@shivaedev/test-story 0.7.0 → 0.7.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.
- package/CHANGELOG.md +6 -0
- package/README.md +68 -47
- package/dist/server/internal/seed.d.ts +1 -1
- package/dist/server/internal/seed.d.ts.map +1 -1
- package/package.json +4 -5
- package/src/server/internal/seed.ts +1 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -8,11 +8,13 @@ When agents write most of the code, test files grow into hundreds of lines nobod
|
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
10
|
bakery.it("steps until the condition holds", [ovenIsLit(), hasDough(3)], function* ({ oven }) {
|
|
11
|
-
|
|
11
|
+
yield* oven.bakesEverything();
|
|
12
|
+
expect(oven.loaves()).toBe(3);
|
|
13
|
+
expect(oven.minutes()).toBe(3);
|
|
12
14
|
});
|
|
13
15
|
```
|
|
14
16
|
|
|
15
|
-
That is a whole test. `bakery.it` comes from the bakery's story kit. The list holds its traits, `ovenIsLit()` and `hasDough(3)`, which are written once and shared by every spec. `oven.bakesEverything()`
|
|
17
|
+
That is a whole test. `bakery.it` comes from the bakery's story kit. The list holds its traits, `ovenIsLit()` and `hasDough(3)`, which are written once and shared by every spec. `oven.bakesEverything()` performs the baking action until the dough is gone; `oven.loaves()` and `oven.minutes()` read separate observations. The spec states both expectations. Every story runs the whole engine, so each test also checks the parts its author never thought to mock, and because a spec reads as English, a sloppy test stands out in review.
|
|
16
18
|
|
|
17
19
|
When a story fails, it prints itself. One of this package's own failing stories expects 2 loaves from one ball of dough, and the test fails with this message:
|
|
18
20
|
|
|
@@ -28,7 +30,7 @@ loaves: expected 1 to be 2 // Object.is equality
|
|
|
28
30
|
given the baker has 1 balls of dough
|
|
29
31
|
1m a loaf comes out of the oven
|
|
30
32
|
✗ the test failed after the line above
|
|
31
|
-
at src/test-support/failingStories.ts:
|
|
33
|
+
at src/test-support/failingStories.ts:12:34
|
|
32
34
|
|
|
33
35
|
The bakery when the test failed:
|
|
34
36
|
{"bowls":1,"capacity":3,"dough":0,"flour":0,"loaves":1,"minute":1,"orders":[],"ovenLit":true,"overfired":false,
|
|
@@ -57,6 +59,22 @@ The work splits into three layers, and each is written by a different hand at a
|
|
|
57
59
|
2. **Once per feature**, traits and verbs in the kit name that feature in domain words.
|
|
58
60
|
3. **In every test**, a spec tells a story with the kit's `it` and checks what a user would see.
|
|
59
61
|
|
|
62
|
+
### The verb shape every kit follows
|
|
63
|
+
|
|
64
|
+
A verb performs one action on the real engine or reads one observation. An action may return its real response, such as an HTTP response; it does not orchestrate a scenario and package the measurements for the spec. A readout reports what happened without deciding whether it was correct. The spec shows each action in order and states every expectation.
|
|
65
|
+
|
|
66
|
+
Acquire real services in `create` or a trait inside the story's per-test Scope, with dependencies provided by `layer`. Keep those services on the engine so verbs use the same running instance; scoped cleanup releases them after the story. Do not build and tear down services inside each verb. When closing a service is the action under test, expose that action separately from acquisition and observation.
|
|
67
|
+
|
|
68
|
+
| Shape to avoid | What to do instead |
|
|
69
|
+
| --- | --- |
|
|
70
|
+
| A verb runs a whole scenario and returns the measurements the spec asserts. | Give each action and observation its own verb; let the spec compose them and compare the observations. |
|
|
71
|
+
| A verb hard-codes the expected outcome or hides assertions. | Return the real response or observation, and put expected values and all assertions in the spec. |
|
|
72
|
+
| A verb does two jobs and returns both results. | Split the jobs into two verbs and show both calls in the spec. |
|
|
73
|
+
| A verb silently does nothing when its target is missing, such as `button?.click()`. | Fail with a message naming the missing target, then perform the action only once the target exists. |
|
|
74
|
+
| An engine default hides what the story declares, such as a lit oven, signed-in user or authorization header. | Start with a neutral engine and name the precondition in a trait or pass the input explicitly in the action. |
|
|
75
|
+
|
|
76
|
+
The bakery below starts with a cold oven and no dough. Its traits declare heat and dough, its baking action returns no report, and its readouts expose loaves and elapsed minutes separately. `runUntil` waits for that one engine action to complete; it does not replace a spec's sequence of actions.
|
|
77
|
+
|
|
60
78
|
### 1. Once per engine: the story kit
|
|
61
79
|
|
|
62
80
|
`storyKit(definition)` from `@shivaedev/test-story/storyKit.ts` turns one definition into the kit. Every type, the engine's, the stages', the verbs' and the services', is inferred from it.
|
|
@@ -97,8 +115,10 @@ export const bakery = storyKit({
|
|
|
97
115
|
},
|
|
98
116
|
},
|
|
99
117
|
oven: {
|
|
100
|
-
bakesEverything: (maxSteps?: number): Effect.Effect<
|
|
101
|
-
story.runUntil((current) => current.dough === 0, { maxSteps })
|
|
118
|
+
bakesEverything: (maxSteps?: number): Effect.Effect<void, BurntLoaf> =>
|
|
119
|
+
story.runUntil((current) => current.dough === 0, { maxSteps }),
|
|
120
|
+
loaves: () => state.loaves,
|
|
121
|
+
minutes: () => state.minute,
|
|
102
122
|
},
|
|
103
123
|
}),
|
|
104
124
|
});
|
|
@@ -118,7 +138,7 @@ This is the bakery kit this package tests itself with. `emptyBakery`, `stillWait
|
|
|
118
138
|
| `after` | Optional. A hook per stage that runs once that stage's traits are applied, even when no trait names the stage, so a value it derives is ready before a later stage reads it. Its typed failure fails the test. |
|
|
119
139
|
| `run` | Optional. What `story.runUntil` needs: `step(engine, tell)` advances the engine once and tells what happened, `maxSteps` caps one run, `failed(engine)` returns a sentence when the engine is in a state it cannot recover from, and `diagnose(engine)` says why it has not finished. |
|
|
120
140
|
| `inspect` | Optional. The part of the engine a failure prints. Without it, the failure prints the whole engine. |
|
|
121
|
-
| `verbs(engine, story)` |
|
|
141
|
+
| `verbs(engine, story)` | One action or one observation per verb. A verb that waits for a stepped engine returns the Effect from `story.runUntil`; the spec reads observations and asserts separately. |
|
|
122
142
|
|
|
123
143
|
Every test of the kit is named `Bakery Story: <its name>`, so `vitest run -t "Bakery Story: "` runs only the bakery's stories with no setup. A project that splits runs by Vitest tags can also tag them:
|
|
124
144
|
|
|
@@ -154,7 +174,7 @@ Start an in-process host in `create` or a stage's `after` hook, such as `after:
|
|
|
154
174
|
|
|
155
175
|
This lets an application's story assert that a request starts its own trace: a request without trace headers starts a root trace, and a request with `traceparent` continues that trace. Host startup and cleanup do not join the story's trace.
|
|
156
176
|
|
|
157
|
-
A kit can collect spans with a native in-memory tracer, or start a fake OTLP receiver and point the application's exporter at it.
|
|
177
|
+
A kit can collect spans with a native in-memory tracer, or start a fake OTLP receiver and point the application's exporter at it. Expose collection, exporter flush and any bounded wait as separate verbs. Assert only after the request span has ended. This small in-memory kit uses Effect's Web Request handler as its host:
|
|
158
178
|
|
|
159
179
|
```ts
|
|
160
180
|
import { Effect, Tracer } from "effect";
|
|
@@ -162,44 +182,48 @@ import { HttpEffect, HttpServerResponse } from "effect/http";
|
|
|
162
182
|
import { expect } from "vitest";
|
|
163
183
|
import { storyKit } from "@shivaedev/test-story/storyKit.ts";
|
|
164
184
|
|
|
165
|
-
const spans: Tracer.NativeSpan[] = [];
|
|
166
|
-
const tracer = Tracer.make({
|
|
167
|
-
span: (options) => {
|
|
168
|
-
const span = new Tracer.NativeSpan(options);
|
|
169
|
-
spans.push(span);
|
|
170
|
-
return span;
|
|
171
|
-
},
|
|
172
|
-
});
|
|
173
|
-
|
|
174
185
|
const app = storyKit({
|
|
175
|
-
around: (effect) => effect.pipe(Effect.withSpan("story")
|
|
186
|
+
around: (effect) => effect.pipe(Effect.withSpan("story")),
|
|
176
187
|
*create() {
|
|
177
|
-
const
|
|
178
|
-
|
|
188
|
+
const spans: Tracer.NativeSpan[] = [];
|
|
189
|
+
const tracer = Tracer.make({
|
|
190
|
+
span: (options) => {
|
|
191
|
+
const span = new Tracer.NativeSpan(options);
|
|
192
|
+
spans.push(span);
|
|
193
|
+
return span;
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
const context = yield* Effect.context<never>().pipe(Effect.withTracer(tracer));
|
|
197
|
+
const handler = HttpEffect.toWebHandlerWith(context)(Effect.succeed(HttpServerResponse.text("ok")));
|
|
198
|
+
return { handler, spans };
|
|
179
199
|
},
|
|
180
200
|
name: "traced application",
|
|
181
201
|
stages: ["ready"],
|
|
182
|
-
verbs: (handler) => ({
|
|
202
|
+
verbs: ({ handler, spans }) => ({
|
|
183
203
|
request: (headers: HeadersInit = {}) => Effect.promise(async () => {
|
|
184
204
|
const response = await handler(new Request("http://app.test/", { headers }));
|
|
185
|
-
|
|
205
|
+
return response.text();
|
|
206
|
+
}),
|
|
207
|
+
requestSpan: () => {
|
|
186
208
|
const span = spans.filter((span) => span.kind === "server").at(-1);
|
|
187
209
|
if (span === undefined) throw new Error("The request exported no server span");
|
|
188
210
|
return span;
|
|
189
|
-
}
|
|
211
|
+
},
|
|
190
212
|
}),
|
|
191
213
|
});
|
|
192
214
|
|
|
193
|
-
app.it("a request is its own root trace", [], function* ({ request }) {
|
|
215
|
+
app.it("a request is its own root trace", [], function* ({ request, requestSpan }) {
|
|
194
216
|
const storySpan = yield* Effect.currentSpan;
|
|
195
|
-
|
|
217
|
+
expect(yield* request()).toBe("ok");
|
|
218
|
+
const span = requestSpan();
|
|
196
219
|
expect(span.parent._tag).toBe("None");
|
|
197
220
|
expect(span.traceId).not.toBe(storySpan.traceId);
|
|
198
221
|
expect(span.status._tag).toBe("Ended");
|
|
199
222
|
});
|
|
200
223
|
|
|
201
|
-
app.it("a request continues its supplied trace", [], function* ({ request }) {
|
|
202
|
-
|
|
224
|
+
app.it("a request continues its supplied trace", [], function* ({ request, requestSpan }) {
|
|
225
|
+
yield* request({ traceparent: "00-1234567890abcdef1234567890abcdef-1234567890abcdef-01" });
|
|
226
|
+
const span = requestSpan();
|
|
203
227
|
expect(span.traceId).toBe("1234567890abcdef1234567890abcdef");
|
|
204
228
|
expect(span.parent).toMatchObject({ value: { spanId: "1234567890abcdef" } });
|
|
205
229
|
});
|
|
@@ -212,15 +236,15 @@ The package's [tracing kit](https://github.com/ShivaeDev/platform/blob/main/pack
|
|
|
212
236
|
Use `otlpReceiver` from `@shivaedev/test-story/otlpReceiver.ts` in a kit's scoped `create` hook. It listens on an allocated loopback port and closes with the story scope. Point the application's real exporter at `${receiver.url}/v1/traces`, then flush the exporter before reading:
|
|
213
237
|
|
|
214
238
|
```ts
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
expect(
|
|
220
|
-
|
|
239
|
+
app.it("exports the work span", [], function* ({ runWork, disposeRuntime, spans, requests }) {
|
|
240
|
+
yield* runWork();
|
|
241
|
+
yield* disposeRuntime();
|
|
242
|
+
expect(spans()).toContainEqual(expect.objectContaining({ name: "CountWords" }));
|
|
243
|
+
expect(requests().some(({ body }) => body.includes(Buffer.from("planted-secret")))).toBe(true);
|
|
244
|
+
});
|
|
221
245
|
```
|
|
222
246
|
|
|
223
|
-
`
|
|
247
|
+
Here `app` is the application's kit. Its `create` acquires the receiver and the real exporter pointed at that receiver, `runWork` performs the traced operation, `disposeRuntime` disposes the exporter's runtime and flushes pending spans, and `spans` and `requests` read the receiver's observations. Each action is visible in the spec. The receiver accepts OTLP/HTTP JSON and protobuf. `spans` flattens all exports into decoded trace and span IDs, parent span IDs, names, numeric OTLP kinds and status codes, attributes, events and links. Attributes retain OTLP key/value objects, including lossless decimal strings for integers; each span also has `resourceAttributes`. `requests` retains every request's unmodified `body` Buffer, parsed `headers`, original `rawHeaders` pairs and `path`. Search all body bytes when checking that a secret was not exported. Optional `path`, `status` (a number or attempt callback) and `answer` configure collector responses for failure stories.
|
|
224
248
|
|
|
225
249
|
For timeout stories, return `undefined` from the `status` callback to accept an export without sending response headers. Set `answer: null` to send headers without completing the response body.
|
|
226
250
|
|
|
@@ -303,7 +327,7 @@ help: a trait throws when the bakery it asks for cannot exist. Give the test tra
|
|
|
303
327
|
|
|
304
328
|
given the oven is lit
|
|
305
329
|
✗ given the baker has 4 balls of dough
|
|
306
|
-
refused at src/test-support/failingStories.ts:
|
|
330
|
+
refused at src/test-support/failingStories.ts:15:57
|
|
307
331
|
given the bakery has 1 bowls
|
|
308
332
|
|
|
309
333
|
The bakery when the test failed:
|
|
@@ -370,7 +394,7 @@ The package wraps between words or JSON fields toward 120 columns and prints the
|
|
|
370
394
|
|
|
371
395
|
### Library package kits
|
|
372
396
|
|
|
373
|
-
A library package has an engine too: its own services or Layer under test. Keep its kit in `src/test-support/`, acquire the real services in `create` with their dependencies supplied by the kit's `layer`, and use real PostgreSQL wherever the package touches it. Traits seed that engine in domain words;
|
|
397
|
+
A library package has an engine too: its own services or Layer under test. Keep its kit in `src/test-support/`, acquire the real services in `create` or a trait inside the story's per-test Scope, with their dependencies supplied by the kit's `layer`, and use real PostgreSQL wherever the package touches it. Traits seed that engine in domain words; each verb calls one action on the package's public API or reads one observation from that same engine. Verbs never create a fresh service just to run a scenario and return its measurements. The same division applies as for an application: the kit owns setup and wiring, and a spec names traits, shows every action through verbs and states each expectation. Following the [root test guidance](https://github.com/ShivaeDev/platform/blob/main/AGENTS.md), reserve plain Vitest tests for pure functions with no engine behind them.
|
|
374
398
|
|
|
375
399
|
The [`backfill` kit](https://github.com/ShivaeDev/platform/blob/main/packages/effect-test-sql/src/test-support/migrationStory.ts) in `effect-test-sql` is a library example. Its `create` returns the package's `migrationSteps(migrations)` API, its worker Layer provides PostgreSQL, and `around: withIsolatedDatabase` isolates each story. The `oldSchema` and `existingContacts` traits put contacts with email addresses into the old schema; the `backfill` verb calls `steps.migrateToLatest`. Its [story](https://github.com/ShivaeDev/platform/blob/main/packages/effect-test-sql/src/server/migrationStory.spec.ts) proves that those existing addresses survive the migration into a new table. It runs only when `PLATFORM_EFFECT_TEST_SQL_TEST_DATABASE_URL` is configured; a skipped story proves nothing.
|
|
376
400
|
|
|
@@ -448,24 +472,21 @@ const socialApp = storyKit({
|
|
|
448
472
|
...socialDefinition,
|
|
449
473
|
outbound: { "github.com": fakeUrl, "api.github.com": fakeUrl },
|
|
450
474
|
verbs: (engine, story) => ({
|
|
451
|
-
|
|
475
|
+
clickGitHubSignIn: () => Effect.promise(async () => {
|
|
452
476
|
story.tell("Alice clicks Sign in with GitHub");
|
|
453
477
|
await engine.screen.click();
|
|
454
|
-
await domNavigate();
|
|
455
478
|
}),
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
})),
|
|
479
|
+
followRedirect: () => Effect.promise(() => domNavigate()),
|
|
480
|
+
heading: () => document.querySelector("h1")?.textContent,
|
|
481
|
+
session: () => Effect.promise(async () => (await engine.fetch("/api/auth/get-session")).json()),
|
|
460
482
|
}),
|
|
461
483
|
});
|
|
462
484
|
|
|
463
|
-
socialApp.it("a social sign-in returns with a cookie session", [], function* ({
|
|
464
|
-
yield*
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
});
|
|
485
|
+
socialApp.it("a social sign-in returns with a cookie session", [], function* ({ clickGitHubSignIn, followRedirect, heading, session }) {
|
|
486
|
+
yield* clickGitHubSignIn();
|
|
487
|
+
yield* followRedirect();
|
|
488
|
+
expect(heading()).toBe("Signed in as alice@social.test");
|
|
489
|
+
expect(yield* session()).toMatchObject({ user: { email: "alice@social.test" } });
|
|
469
490
|
});
|
|
470
491
|
```
|
|
471
492
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect, type Scope } from "effect";
|
|
2
|
-
import type { AnyTestLayer } from "@shivaedev/effect-test/
|
|
2
|
+
import type { AnyTestLayer } from "@shivaedev/effect-test/anyTestLayer.ts";
|
|
3
3
|
import type { EffectClock } from "@shivaedev/effect-test/types.ts";
|
|
4
4
|
import { type AnyEffect, type EffectHook, type Hook } from "#internal/hooked.ts";
|
|
5
5
|
import { type Narration } from "#internal/narration.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../../src/server/internal/seed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,MAAM,EAAE,KAAK,KAAK,EAAU,MAAM,QAAQ,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../../src/server/internal/seed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,MAAM,EAAE,KAAK,KAAK,EAAU,MAAM,QAAQ,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,IAAI,EAAU,MAAM,qBAAqB,CAAC;AACzF,OAAO,EAAE,KAAK,SAAS,EAAa,MAAM,wBAAwB,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAEnG,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5I,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACnG,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1G,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACpD,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IAChD,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,GAAG,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,KAAK,MAAM,CAAC;CAC/D;AAED,eAAO,MAAM,IAAI,6IAuBf,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/test-story",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Tests that read like stories over the real engine: a story kit per engine with its own it, traits per feature, and a failure that prints the story, where it stopped and the engine's state",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/test-story#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -24,9 +24,8 @@
|
|
|
24
24
|
},
|
|
25
25
|
"exports": {
|
|
26
26
|
"./*.ts": {
|
|
27
|
-
"types": "./dist/server/*.d.ts",
|
|
28
27
|
"source": "./src/server/*.ts",
|
|
29
|
-
"
|
|
28
|
+
"types": "./dist/server/*.d.ts",
|
|
30
29
|
"default": "./dist/server/*.js"
|
|
31
30
|
},
|
|
32
31
|
"./internal/*": null,
|
|
@@ -43,11 +42,11 @@
|
|
|
43
42
|
"README.md"
|
|
44
43
|
],
|
|
45
44
|
"dependencies": {
|
|
46
|
-
"@shivaedev/effect-test": "0.
|
|
45
|
+
"@shivaedev/effect-test": "0.6.0"
|
|
47
46
|
},
|
|
48
47
|
"devDependencies": {
|
|
49
48
|
"@effect/vitest": "4.0.4",
|
|
50
|
-
"@shivaedev/quality": "0.
|
|
49
|
+
"@shivaedev/quality": "0.25.0",
|
|
51
50
|
"@types/node": "24.19.2",
|
|
52
51
|
"@typescript/native": "npm:typescript@7.0.2",
|
|
53
52
|
"effect": "4.0.4",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Cause, Context, Effect, type Scope, Tracer } from "effect";
|
|
2
|
-
import type { AnyTestLayer } from "@shivaedev/effect-test/
|
|
2
|
+
import type { AnyTestLayer } from "@shivaedev/effect-test/anyTestLayer.ts";
|
|
3
3
|
import type { EffectClock } from "@shivaedev/effect-test/types.ts";
|
|
4
4
|
import { refusal } from "#internal/errors.ts";
|
|
5
5
|
import { type AnyEffect, type EffectHook, type Hook, hooked } from "#internal/hooked.ts";
|