@shivaedev/effect-test 0.6.0 → 0.7.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/CHANGELOG.md +6 -0
- package/README.md +5 -13
- package/dist/internal/environmentFor.d.ts +5 -0
- package/dist/internal/environmentFor.d.ts.map +1 -0
- package/dist/internal/environmentFor.js +16 -0
- package/dist/internal/environmentFor.js.map +1 -0
- package/dist/internal/runEffectTest.d.ts +5 -0
- package/dist/internal/runEffectTest.d.ts.map +1 -0
- package/dist/internal/runEffectTest.js +18 -0
- package/dist/internal/runEffectTest.js.map +1 -0
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/vitest.d.ts +1 -1
- package/dist/vitest.d.ts.map +1 -1
- package/dist/vitest.js +2 -17
- package/dist/vitest.js.map +1 -1
- package/package.json +4 -5
- package/src/internal/environmentFor.ts +24 -0
- package/src/internal/runEffectTest.ts +26 -0
- package/src/types.ts +2 -2
- package/src/vitest.ts +2 -24
- package/docs/north-star.md +0 -43
- package/docs/roadmap.md +0 -24
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.0 - 2026-10-18
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Pass a UTC `DateTime` to the existing `clock` option to pin a story or Effect fixture before its per-test setup runs. The exported `EffectClock` type now accepts `DateTime.Utc` alongside `"test"` and `"live"`. Hosts, workers and screens acquired with the story's Effect Context share native `Clock` / `TestClock`, including explicit `TestClock.adjust` advances; application code using `Clock` or `DateTime.now` needs no changes.
|
|
8
|
+
|
|
3
9
|
## 0.6.0 - 2026-10-18
|
|
4
10
|
|
|
5
11
|
### Breaking
|
package/README.md
CHANGED
|
@@ -64,8 +64,7 @@ effectApp("reads the fixture's services", function* (harness, context) {
|
|
|
64
64
|
|
|
65
65
|
The Layer supplies `Token`. `makeHarness` runs for the test and reads that same service; the generator receives its result and can also yield `Token` directly. Harness fields and provided services keep their types. A body that requires a service the Layer does not provide does not type-check.
|
|
66
66
|
|
|
67
|
-
A fixture that needs no services uses `Layer.empty`. This separate module
|
|
68
|
-
replaces the token fixture above:
|
|
67
|
+
A fixture that needs no services uses `Layer.empty`. This separate module replaces the token fixture above:
|
|
69
68
|
|
|
70
69
|
```ts
|
|
71
70
|
import { expect } from "@effect/vitest";
|
|
@@ -142,7 +141,7 @@ effectApp.each(["alpha", "beta"])("checks %s", function* (item, harness, context
|
|
|
142
141
|
});
|
|
143
142
|
```
|
|
144
143
|
|
|
145
|
-
This uses the token fixture from the first example. Case and harness types are inferred.
|
|
144
|
+
This uses the token fixture from the first example. Case and harness types are inferred. A synchronous DOM fixture test can return `Effect.sync(() => expect(harness.token).toBe("from-layer"))`; the harness, services and per-test Scope are the same for both body forms.
|
|
146
145
|
|
|
147
146
|
### Choosing which clock runs the test
|
|
148
147
|
|
|
@@ -154,9 +153,9 @@ effectApp("reads live time", function* () {
|
|
|
154
153
|
}, { clock: "live" });
|
|
155
154
|
```
|
|
156
155
|
|
|
157
|
-
The override changes the per-test environment used by the wrapper, harness and body.
|
|
156
|
+
The override changes the per-test environment used by the wrapper, harness and body. A UTC `DateTime` also works as `clock`: it selects native TestClock and sets its initial instant before the wrapper or harness runs. `TestClock.adjust` advances that clock explicitly. For example, `{ clock: DateTime.makeUnsafe("2026-10-17T12:34:56.000Z") }` pins time to that UTC instant; import `DateTime` from `effect`. The same option is available on a fixture's factory.
|
|
158
157
|
|
|
159
|
-
Worker acquisition is separate: a Layer that reads the default Clock while it is being built sees live time, even when its tests use TestClock.
|
|
158
|
+
Worker acquisition is separate: a Layer that reads the default Clock while it is being built sees live time, even when its tests use TestClock.
|
|
160
159
|
|
|
161
160
|
### Waiting for a typed readiness condition
|
|
162
161
|
|
|
@@ -226,11 +225,7 @@ Import the module that defines the name; the package has no root entry.
|
|
|
226
225
|
| `@shivaedev/effect-test/anyTestLayer.ts` | `AnyTestLayer` and `buildTestLayer(layer, scope)`, an Effect that builds the Layer's service Context in the supplied scope. |
|
|
227
226
|
| `@shivaedev/effect-test/types.ts` | `EffectClock`, `EffectTestOptions`, `EffectTestBody`, `EffectTest`, `EffectTester`, `MakeEffectItOptions`, `MakeEffectItResult`, `EffectItTest`, `EffectItTester` and `EffectIt`. |
|
|
228
227
|
|
|
229
|
-
`
|
|
230
|
-
|
|
231
|
-
`it.effect` and `it.live` take `(name, body, options?)`; options are a timeout or Vitest test options. A regular body takes the context; an `each` body takes the case. These testers and `effectApp` expose `each`, `fails`, `only`, `runIf`, `skip` and `skipIf`.
|
|
232
|
-
|
|
233
|
-
`EventuallyOptions` has `interval?: Duration.Input` and `times?: number`. The default interval is `"10 millis"`; omitting `times` leaves retries unbounded.
|
|
228
|
+
`eventually` waits `"10 millis"` between attempts by default; omitting `times` leaves retries unbounded.
|
|
234
229
|
|
|
235
230
|
### Install, setup and limits
|
|
236
231
|
|
|
@@ -241,7 +236,4 @@ pnpm add --save-dev @shivaedev/effect-test @effect/vitest@4.0.4 effect@4.0.4 vit
|
|
|
241
236
|
The package declares `effect` as a peer and `@effect/vitest` as an optional peer. The Vitest runner modules require `@effect/vitest`; install it when using them. The package requires Node.js 24 or later. Use peer versions compatible with the package's `package.json`.
|
|
242
237
|
|
|
243
238
|
- Define a fixture tester in test support and import it from Vitest tests. Calling `makeEffectIt` declares a Vitest fixture; it is not an application runtime factory.
|
|
244
|
-
- The Layer is shared within its worker fixture. Reset application state in the harness or compose the fixture's own isolation wrapper when tests need it.
|
|
245
|
-
- TestClock controls its Effect environment. It does not establish how external timers, real HTTP or a database behave.
|
|
246
239
|
- An unbounded readiness poll can run until Vitest ends the test. Set a retry budget when the condition may never become true.
|
|
247
|
-
- Compiler tests prove service requirements and inferred types; runtime tests prove the exercised clock and failure paths. Neither is evidence that a consumer's composed application has been validated.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Layer } from "effect";
|
|
2
|
+
import * as TestConsole from "effect/testing/TestConsole";
|
|
3
|
+
import type { EffectClock } from "#types.ts";
|
|
4
|
+
export declare function environmentFor(clock: EffectClock): Layer.Layer<TestConsole.TestConsole, never, never>;
|
|
5
|
+
//# sourceMappingURL=environmentFor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environmentFor.d.ts","sourceRoot":"","sources":["../../src/internal/environmentFor.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,EAAE,MAAM,QAAQ,CAAC;AAExD,OAAO,KAAK,WAAW,MAAM,4BAA4B,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAK7C,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,sDAehD"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Clock, DateTime, Effect, Layer } from "effect";
|
|
2
|
+
import * as TestClock from "effect/testing/TestClock";
|
|
3
|
+
import * as TestConsole from "effect/testing/TestConsole";
|
|
4
|
+
const TestClockEnvironment = Layer.mergeAll(TestConsole.layer, TestClock.layer());
|
|
5
|
+
const LiveClockEnvironment = TestConsole.layer;
|
|
6
|
+
export function environmentFor(clock) {
|
|
7
|
+
if (typeof clock === "string") {
|
|
8
|
+
return clock === "live" ? LiveClockEnvironment : TestClockEnvironment;
|
|
9
|
+
}
|
|
10
|
+
return Layer.mergeAll(TestConsole.layer, Layer.effect(Clock.Clock, Effect.gen(function* () {
|
|
11
|
+
const testClock = yield* TestClock.make();
|
|
12
|
+
yield* testClock.setTime(DateTime.toEpochMillis(clock));
|
|
13
|
+
return testClock;
|
|
14
|
+
})));
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=environmentFor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environmentFor.js","sourceRoot":"","sources":["../../src/internal/environmentFor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACxD,OAAO,KAAK,SAAS,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,WAAW,MAAM,4BAA4B,CAAC;AAG1D,MAAM,oBAAoB,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;AAClF,MAAM,oBAAoB,GAAG,WAAW,CAAC,KAAK,CAAC;AAE/C,MAAM,UAAU,cAAc,CAAC,KAAkB;IAChD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,oBAAoB,CAAC;IACvE,CAAC;IACD,OAAO,KAAK,CAAC,QAAQ,CACpB,WAAW,CAAC,KAAK,EACjB,KAAK,CAAC,MAAM,CACX,KAAK,CAAC,KAAK,EACX,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAC1C,KAAK,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;QACxD,OAAO,SAAS,CAAC;IAClB,CAAC,CAAC,CACF,CACD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { TestContext } from "@effect/vitest";
|
|
2
|
+
import { Effect, type Scope } from "effect";
|
|
3
|
+
import type { EffectClock } from "#types.ts";
|
|
4
|
+
export declare function runEffectTest<A, E>(effect: Effect.Effect<A, E, Scope.Scope>, context: TestContext, clock: EffectClock): Promise<A>;
|
|
5
|
+
//# sourceMappingURL=runEffectTest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runEffectTest.d.ts","sourceRoot":"","sources":["../../src/internal/runEffectTest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAS,MAAM,EAAQ,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAG7C,wBAAgB,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,CAoBlI"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Cause, Effect, Exit } from "effect";
|
|
2
|
+
import { environmentFor } from "./environmentFor.js";
|
|
3
|
+
export function runEffectTest(effect, context, clock) {
|
|
4
|
+
const result = Effect.runPromise(Effect.gen(function* () {
|
|
5
|
+
const exit = yield* Effect.exit(effect);
|
|
6
|
+
if (Exit.isFailure(exit)) {
|
|
7
|
+
for (const error of Cause.prettyErrors(exit.cause)) {
|
|
8
|
+
yield* Effect.logError(error);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return yield* exit;
|
|
12
|
+
}).pipe(Effect.scoped, Effect.provide(environmentFor(clock))), { signal: context.signal });
|
|
13
|
+
// Vitest's timeout stops awaiting the body while Effect is still closing its Scope.
|
|
14
|
+
const settled = result.then(() => undefined, () => undefined);
|
|
15
|
+
context.onTestFinished(() => settled, 0);
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=runEffectTest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runEffectTest.js","sourceRoot":"","sources":["../../src/internal/runEffectTest.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAc,MAAM,QAAQ,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,MAAM,UAAU,aAAa,CAAO,MAAwC,EAAE,OAAoB,EAAE,KAAkB;IACrH,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAC/B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpD,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC;QACF,CAAC;QACD,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC;IACpB,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,EAC7D,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAC1B,CAAC;IACF,oFAAoF;IACpF,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAC1B,GAAG,EAAE,CAAC,SAAS,EACf,GAAG,EAAE,CAAC,SAAS,CACf,CAAC;IACF,OAAO,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC;AACf,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { TestContext, TestOptions } from "@effect/vitest";
|
|
2
|
-
import type { Effect, Layer, Scope } from "effect";
|
|
2
|
+
import type { DateTime, Effect, Layer, Scope } from "effect";
|
|
3
3
|
import type { TestAPI } from "vitest";
|
|
4
4
|
import type { AnyTestLayer } from "./anyTestLayer.ts";
|
|
5
|
-
export type EffectClock = "test" | "live";
|
|
5
|
+
export type EffectClock = "test" | "live" | DateTime.Utc;
|
|
6
6
|
export type EffectTestOptions = TestOptions & {
|
|
7
7
|
readonly clock?: EffectClock;
|
|
8
8
|
};
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/vitest.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Layer } from "effect";
|
|
1
|
+
import { type Layer } from "effect";
|
|
2
2
|
import { type AnyTestLayer } from "./anyTestLayer.ts";
|
|
3
3
|
import type { MakeEffectItOptions, MakeEffectItResult } from "./types.ts";
|
|
4
4
|
export declare const makeEffectIt: <THarness, TTestLayer extends AnyTestLayer>(options: MakeEffectItOptions<THarness, TTestLayer>) => MakeEffectItResult<THarness, Layer.Success<TTestLayer>>;
|
package/dist/vitest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vitest.d.ts","sourceRoot":"","sources":["../src/vitest.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"vitest.d.ts","sourceRoot":"","sources":["../src/vitest.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,KAAK,KAAK,EAAS,MAAM,QAAQ,CAAC;AAEvE,OAAO,EAAE,KAAK,YAAY,EAAkB,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAA4E,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAgDpJ,eAAO,MAAM,YAAY,GAAI,QAAQ,EAAE,UAAU,SAAS,YAAY,WAC5D,mBAAmB,CAAC,QAAQ,EAAE,UAAU,CAAC,KAChD,kBAAkB,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAuExD,CAAC"}
|
package/dist/vitest.js
CHANGED
|
@@ -1,29 +1,14 @@
|
|
|
1
1
|
import { it as effectIt } from "@effect/vitest";
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import * as TestConsole from "effect/testing/TestConsole";
|
|
2
|
+
import { Effect, Exit, Scope } from "effect";
|
|
3
|
+
import { runEffectTest } from "#internal/runEffectTest.ts";
|
|
5
4
|
import { buildTestLayer } from "./anyTestLayer.js";
|
|
6
5
|
const fixtureName = "__effectTestContext";
|
|
7
|
-
const TestClockEnvironment = Layer.mergeAll(TestConsole.layer, TestClock.layer());
|
|
8
|
-
const LiveClockEnvironment = TestConsole.layer;
|
|
9
|
-
function environmentFor(clock) {
|
|
10
|
-
return clock === "live" ? LiveClockEnvironment : TestClockEnvironment;
|
|
11
|
-
}
|
|
12
6
|
function restoreContext(fixture, context) {
|
|
13
7
|
return {
|
|
14
8
|
...context,
|
|
15
9
|
[fixtureName]: fixture,
|
|
16
10
|
};
|
|
17
11
|
}
|
|
18
|
-
const runEffectTest = (effect, context, clock) => Effect.runPromise(Effect.gen(function* () {
|
|
19
|
-
const exit = yield* Effect.exit(effect);
|
|
20
|
-
if (Exit.isFailure(exit)) {
|
|
21
|
-
for (const error of Cause.prettyErrors(exit.cause)) {
|
|
22
|
-
yield* Effect.logError(error);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return yield* exit;
|
|
26
|
-
}).pipe(Effect.scoped, Effect.provide(environmentFor(clock))), { signal: context.signal });
|
|
27
12
|
function splitOptions(options) {
|
|
28
13
|
if (typeof options === "number") {
|
|
29
14
|
return { clock: undefined, vitest: { timeout: options } };
|
package/dist/vitest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vitest.js","sourceRoot":"","sources":["../src/vitest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,IAAI,QAAQ,EAAsC,MAAM,gBAAgB,CAAC;AACpF,OAAO,
|
|
1
|
+
{"version":3,"file":"vitest.js","sourceRoot":"","sources":["../src/vitest.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/effect-test",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Generic Effect Vitest runner with worker-scoped Layers and TestClock",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/effect-test#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"types": "./dist/*.d.ts",
|
|
29
29
|
"default": "./dist/*.js"
|
|
30
30
|
},
|
|
31
|
+
"./internal/*": null,
|
|
31
32
|
"./package.json": "./package.json"
|
|
32
33
|
},
|
|
33
34
|
"files": [
|
|
@@ -36,17 +37,15 @@
|
|
|
36
37
|
"!src/**/*.test.ts",
|
|
37
38
|
"!src/**/*.spec.ts",
|
|
38
39
|
"!src/**/test-support",
|
|
39
|
-
"docs",
|
|
40
40
|
"CHANGELOG.md",
|
|
41
41
|
"README.md"
|
|
42
42
|
],
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@effect/vitest": "4.0.4",
|
|
45
|
-
"@shivaedev/quality": "0.
|
|
45
|
+
"@shivaedev/quality": "0.27.1",
|
|
46
46
|
"@types/node": "24.19.2",
|
|
47
|
-
"@typescript/native": "npm:typescript@7.0.2",
|
|
48
47
|
"effect": "4.0.4",
|
|
49
|
-
"typescript": "
|
|
48
|
+
"typescript": "7.0.2",
|
|
50
49
|
"vitest": "5.0.3"
|
|
51
50
|
},
|
|
52
51
|
"peerDependencies": {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Clock, DateTime, Effect, Layer } from "effect";
|
|
2
|
+
import * as TestClock from "effect/testing/TestClock";
|
|
3
|
+
import * as TestConsole from "effect/testing/TestConsole";
|
|
4
|
+
import type { EffectClock } from "#types.ts";
|
|
5
|
+
|
|
6
|
+
const TestClockEnvironment = Layer.mergeAll(TestConsole.layer, TestClock.layer());
|
|
7
|
+
const LiveClockEnvironment = TestConsole.layer;
|
|
8
|
+
|
|
9
|
+
export function environmentFor(clock: EffectClock) {
|
|
10
|
+
if (typeof clock === "string") {
|
|
11
|
+
return clock === "live" ? LiveClockEnvironment : TestClockEnvironment;
|
|
12
|
+
}
|
|
13
|
+
return Layer.mergeAll(
|
|
14
|
+
TestConsole.layer,
|
|
15
|
+
Layer.effect(
|
|
16
|
+
Clock.Clock,
|
|
17
|
+
Effect.gen(function* () {
|
|
18
|
+
const testClock = yield* TestClock.make();
|
|
19
|
+
yield* testClock.setTime(DateTime.toEpochMillis(clock));
|
|
20
|
+
return testClock;
|
|
21
|
+
}),
|
|
22
|
+
),
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { TestContext } from "@effect/vitest";
|
|
2
|
+
import { Cause, Effect, Exit, type Scope } from "effect";
|
|
3
|
+
import type { EffectClock } from "#types.ts";
|
|
4
|
+
import { environmentFor } from "./environmentFor.ts";
|
|
5
|
+
|
|
6
|
+
export function runEffectTest<A, E>(effect: Effect.Effect<A, E, Scope.Scope>, context: TestContext, clock: EffectClock): Promise<A> {
|
|
7
|
+
const result = Effect.runPromise(
|
|
8
|
+
Effect.gen(function* () {
|
|
9
|
+
const exit = yield* Effect.exit(effect);
|
|
10
|
+
if (Exit.isFailure(exit)) {
|
|
11
|
+
for (const error of Cause.prettyErrors(exit.cause)) {
|
|
12
|
+
yield* Effect.logError(error);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return yield* exit;
|
|
16
|
+
}).pipe(Effect.scoped, Effect.provide(environmentFor(clock))),
|
|
17
|
+
{ signal: context.signal },
|
|
18
|
+
);
|
|
19
|
+
// Vitest's timeout stops awaiting the body while Effect is still closing its Scope.
|
|
20
|
+
const settled = result.then(
|
|
21
|
+
() => undefined,
|
|
22
|
+
() => undefined,
|
|
23
|
+
);
|
|
24
|
+
context.onTestFinished(() => settled, 0);
|
|
25
|
+
return result;
|
|
26
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { TestContext, TestOptions } from "@effect/vitest";
|
|
2
|
-
import type { Effect, Layer, Scope } from "effect";
|
|
2
|
+
import type { DateTime, Effect, Layer, Scope } from "effect";
|
|
3
3
|
import type { TestAPI } from "vitest";
|
|
4
4
|
import type { AnyTestLayer } from "./anyTestLayer.ts";
|
|
5
5
|
|
|
6
|
-
export type EffectClock = "test" | "live";
|
|
6
|
+
export type EffectClock = "test" | "live" | DateTime.Utc;
|
|
7
7
|
|
|
8
8
|
export type EffectTestOptions = TestOptions & {
|
|
9
9
|
readonly clock?: EffectClock;
|
package/src/vitest.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { it as effectIt, type TestContext, type TestOptions } from "@effect/vitest";
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import * as TestConsole from "effect/testing/TestConsole";
|
|
2
|
+
import { type Context, Effect, Exit, type Layer, Scope } from "effect";
|
|
3
|
+
import { runEffectTest } from "#internal/runEffectTest.ts";
|
|
5
4
|
import { type AnyTestLayer, buildTestLayer } from "./anyTestLayer.ts";
|
|
6
5
|
import type { EffectClock, EffectTest, EffectTestBody, EffectTester, EffectTestOptions, MakeEffectItOptions, MakeEffectItResult } from "./types.ts";
|
|
7
6
|
|
|
@@ -13,13 +12,6 @@ type EffectFixture<TProvided> = TestContext & {
|
|
|
13
12
|
|
|
14
13
|
type FixtureTest<TProvided> = (name: string, options: TestOptions, body: (context: EffectFixture<TProvided>) => Promise<unknown>) => void;
|
|
15
14
|
|
|
16
|
-
const TestClockEnvironment = Layer.mergeAll(TestConsole.layer, TestClock.layer());
|
|
17
|
-
const LiveClockEnvironment = TestConsole.layer;
|
|
18
|
-
|
|
19
|
-
function environmentFor(clock: EffectClock) {
|
|
20
|
-
return clock === "live" ? LiveClockEnvironment : TestClockEnvironment;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
15
|
function restoreContext<TProvided>(
|
|
24
16
|
fixture: Context.Context<TProvided>,
|
|
25
17
|
context: Omit<EffectFixture<TProvided>, typeof fixtureName>,
|
|
@@ -30,20 +22,6 @@ function restoreContext<TProvided>(
|
|
|
30
22
|
};
|
|
31
23
|
}
|
|
32
24
|
|
|
33
|
-
const runEffectTest = <A, E>(effect: Effect.Effect<A, E, Scope.Scope>, context: TestContext, clock: EffectClock): Promise<A> =>
|
|
34
|
-
Effect.runPromise(
|
|
35
|
-
Effect.gen(function* () {
|
|
36
|
-
const exit = yield* Effect.exit(effect);
|
|
37
|
-
if (Exit.isFailure(exit)) {
|
|
38
|
-
for (const error of Cause.prettyErrors(exit.cause)) {
|
|
39
|
-
yield* Effect.logError(error);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return yield* exit;
|
|
43
|
-
}).pipe(Effect.scoped, Effect.provide(environmentFor(clock))),
|
|
44
|
-
{ signal: context.signal },
|
|
45
|
-
);
|
|
46
|
-
|
|
47
25
|
function splitOptions(options: number | EffectTestOptions | undefined): {
|
|
48
26
|
readonly vitest: TestOptions;
|
|
49
27
|
readonly clock: EffectClock | undefined;
|
package/docs/north-star.md
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# North star
|
|
2
|
-
|
|
3
|
-
## The problem
|
|
4
|
-
|
|
5
|
-
An Effect test needs more than a Promise runner. It needs the application's services, a scope for work that must be released, a clock it can control and a way to wait for a typed readiness condition. When each database or transport fixture writes that machinery, small differences become differences in correctness: a clock advances in one helper but waits in another, a retry catches a defect, or a service is acquired at the wrong lifetime.
|
|
6
|
-
|
|
7
|
-
The package gives those fixtures one runner. A test names its work as a generator, and a fixture supplies its Layer and the value the test receives. The test still uses Effect's services, failure channel and clock, and Vitest still declares and reports the test.
|
|
8
|
-
|
|
9
|
-
## The ideal
|
|
10
|
-
|
|
11
|
-
A test contains the work specific to that test. Shared service acquisition, per-test harness construction and an optional wrapper are defined once in test support. A plain Effect test needs no custom fixture: its generator goes directly to `it.effect` or `it.live`.
|
|
12
|
-
|
|
13
|
-
The boundary between worker and test is explicit. A worker owns the acquired service Context, while a test owns its harness and execution scope. A shared database service does not imply fresh database contents, and a fresh harness does not imply a freshly acquired service. The fixture that owns application state chooses how to reset or transact it.
|
|
14
|
-
|
|
15
|
-
Time is part of the Effect environment. A controlled test clock makes a readiness poll cheap and inspectable; live time remains an explicit choice for work that needs it. A typed readiness failure means “try again”. A defect means something broke, and interruption means the run must stop. These are different outcomes and the runner must keep them different.
|
|
16
|
-
|
|
17
|
-
## What good looks like
|
|
18
|
-
|
|
19
|
-
- A generator reaches the application's real services instead of converting them into a separate testing API.
|
|
20
|
-
- A Layer, a harness and a wrapper are enough to define a reusable fixture. Their types are inferred, and a body cannot silently ask for a service the fixture does not provide.
|
|
21
|
-
- Resource lifetimes are visible in the design and backed by tests at the boundaries where this package adds behavior.
|
|
22
|
-
- Clock selection does not imply control over resources that were acquired in a different environment.
|
|
23
|
-
- A failed assertion is retried only when the author explicitly makes it a typed, retryable failure.
|
|
24
|
-
- Downstream fixture authors reuse the runner and own their domain setup.
|
|
25
|
-
|
|
26
|
-
## Trade-offs
|
|
27
|
-
|
|
28
|
-
When goals conflict, preserve native Effect semantics first, keep one runner second, preserve deliberate worker and test lifetimes third, prove readable behavior fourth, and keep the adapter small fifth.
|
|
29
|
-
|
|
30
|
-
**Shared acquisition costs less and requires state discipline.** A worker Layer avoids rebuilding expensive services for every test. That places application-state isolation in the fixture that understands the state. Adding a hidden reset would conceal the lifetime rather than solve it.
|
|
31
|
-
|
|
32
|
-
**Controlled time and live time solve different problems.** A test clock helps a test advance the Effects in its environment. It does not make external timers or a worker's already-running fibers deterministic. Prefer a precise limit over a broad promise of determinism.
|
|
33
|
-
|
|
34
|
-
**Composition keeps responsibility local.** An `around` wrapper can establish a transaction or tracing boundary for the harness and body. This package owns how the wrapper fits the runner; the package that supplies a transaction owns its rollback semantics.
|
|
35
|
-
|
|
36
|
-
**Types are a contract, not runtime evidence.** Compiler tests establish which requirements, harness fields and table cases a body may use. Runtime tests establish what runs, when it runs and which failure escapes. Neither substitutes for the other.
|
|
37
|
-
|
|
38
|
-
## What it leaves out
|
|
39
|
-
|
|
40
|
-
- Database rollback, migrations, seeded application state and transport caller construction. Those belong to their integrations or application test support.
|
|
41
|
-
- Domain traits, verbs, engine stepping and story failure narration. `@shivaedev/test-story` owns that layer above this runner.
|
|
42
|
-
- A replacement for Vitest's reporting, selection or configuration, or for Effect's Context, Scope and scheduling.
|
|
43
|
-
- Evidence of real HTTP, PostgreSQL, browser or deployment behavior from a controlled-clock unit test. Composed examples and host-boundary validation belong to the framework.
|
package/docs/roadmap.md
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Roadmap
|
|
2
|
-
|
|
3
|
-
This roadmap owns the test runner, its public contracts and its package tests. The [framework roadmap](https://github.com/ShivaeDev/platform/blob/main/docs/framework/roadmap.md) owns composed fixtures, application adoption and host or deployment validation. The same status is recorded in one place.
|
|
4
|
-
|
|
5
|
-
## Built
|
|
6
|
-
|
|
7
|
-
- [x] `it.effect` and `it.live` accept generator bodies and Effect-returning bodies over the upstream testers. Tests cover the controlled and live clocks, table cases, expected failure, conditional skipping and plain Vitest tests.
|
|
8
|
-
- [x] `makeEffectIt` supplies the Layer's services, an inferred harness and Vitest's test context to the generator. Tests cover wrapper entry, harness values and table cases.
|
|
9
|
-
- [x] Default TestClock, factory live-clock selection and per-test overrides in either direction. Acquisition-time tests distinguish the worker Layer's live clock from the harness and body's test clock.
|
|
10
|
-
- [x] `Layer.empty` runs without a placeholder service. Compiler tests reject a service the empty Layer does not provide and retain harness, service and table-case types.
|
|
11
|
-
- [x] `eventually` retries typed failures on both clock paths. Tests count initial attempts and retries, preserve the final typed failure, reject thrown assertion retries, accept assertions captured with `Effect.try`, and preserve interruption.
|
|
12
|
-
- [x] Packed-consumer compiler fixtures exercise the published runner modules and retained harness types.
|
|
13
|
-
|
|
14
|
-
## Next
|
|
15
|
-
|
|
16
|
-
- [ ] Add direct acquisition-count and finalizer assertions for worker Layer reuse and release, including acquisition failure.
|
|
17
|
-
- [ ] Assert per-test scope cleanup and wrapper ordering around harness construction as well as the body.
|
|
18
|
-
- [ ] Cover a timer fiber started during worker acquisition and a fixture that explicitly supplies its own Clock, so the clock boundary has direct regression evidence.
|
|
19
|
-
- [ ] Cover the runner's TestConsole environment, tester variants and `buildTestLayer` with assertions dedicated to the behavior this package adds.
|
|
20
|
-
|
|
21
|
-
## Open questions
|
|
22
|
-
|
|
23
|
-
- Should composed application fixtures gain any API here, or remain framework examples and downstream helpers? The runner keeps the composition points small; new fixture APIs need a repeated job that the existing Layer, harness and wrapper cannot express.
|
|
24
|
-
- Which lifecycle and clock properties need local regression tests, and which should rely on the upstream Vitest and Effect contracts? The next items identify the gaps in this package's own evidence without changing its public API.
|