@shivaedev/effect-test 0.7.1 → 0.8.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 CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.1 - 2026-10-25
4
+
5
+ ### Fixed
6
+
7
+ - Close shared test service Layers before their test file completes so database cleanup finishes before Vitest starts terminating the fork.
8
+
9
+ ## 0.8.0 - 2026-10-25
10
+
11
+ ### Breaking
12
+
13
+ - Move `@shivaedev/effect-test/vitest.ts` to `@shivaedev/effect-test/makeEffectIt.ts`. Change imports to `@shivaedev/effect-test/makeEffectIt.ts`; the exported `makeEffectIt` function is unchanged.
14
+
15
+ ## 0.7.2 - 2026-10-24
16
+
17
+ ### Changed
18
+
19
+ - Require Effect and its companion packages at exactly 4.0.5. Generated applications use the same versions.
20
+
3
21
  ## 0.7.1 - 2026-10-18
4
22
 
5
23
  ### Fixed
package/README.md CHANGED
@@ -27,9 +27,9 @@ That is a whole test. The body starts at time zero and advances its clock by one
27
27
 
28
28
  There are two ways to enter the runner. `it.effect` and `it.live` are the ordinary testers: their body receives Vitest's test context and uses services it provides inside its own Effect. `makeEffectIt` defines a tester for a reusable fixture: its body receives a harness first, then the test context, and can yield the services its Layer provides.
29
29
 
30
- A **Layer** describes how to acquire the fixture's services. `makeEffectIt` builds it in a Vitest worker fixture and retains the resulting Effect **Context**, the map from service keys to service values. A **harness** is the value made for one test using those services. It can hold a service, a fixture identifier or the domain entry points the test needs. The **test context** is Vitest's context, with the test's name, assertion helpers and hooks; it is a different thing from Effect's Context.
30
+ A **Layer** describes how to acquire the fixture's services. `makeEffectIt` builds it in a Vitest file fixture and retains the resulting Effect **Context**, the map from service keys to service values. A **harness** is the value made for one test using those services. It can hold a service, a fixture identifier or the domain entry points the test needs. The **test context** is Vitest's context, with the test's name, assertion helpers and hooks; it is a different thing from Effect's Context.
31
31
 
32
- Keep the two lifetimes separate. The worker owns the acquired Layer and its scope. Each test makes its harness and runs its body in a separate scope. Harnesses, wrappers, generator bodies and `each` bodies may acquire resources through that Scope; their finalizers run on success, failure and interruption. Scope is available per test and is not added to the worker Context. A shared service can retain mutable state across tests; a fresh harness alone does not reset it. Put application-state isolation in the fixture that owns that state, such as a database transaction wrapper.
32
+ Keep the two lifetimes separate. The file owns the acquired Layer and its scope; its finalizers finish before Vitest reports the file complete. Each test makes its harness and runs its body in a separate scope. Harnesses, wrappers, generator bodies and `each` bodies may acquire resources through that Scope; their finalizers run on success, failure and interruption. Scope is available per test and is not added to the file Context. A shared service can retain mutable state across tests; a fresh harness alone does not reset it. Put application-state isolation in the fixture that owns that state, such as a database transaction wrapper.
33
33
 
34
34
  The work usually splits into two parts:
35
35
 
@@ -41,7 +41,7 @@ The work usually splits into two parts:
41
41
  ```ts
42
42
  import { expect } from "@effect/vitest";
43
43
  import { Clock, Context, Effect, Layer } from "effect";
44
- import { makeEffectIt } from "@shivaedev/effect-test/vitest.ts";
44
+ import { makeEffectIt } from "@shivaedev/effect-test/makeEffectIt.ts";
45
45
 
46
46
  class Token extends Context.Service<Token, string>()("test/Token") {}
47
47
 
@@ -69,7 +69,7 @@ A fixture that needs no services uses `Layer.empty`. This separate module replac
69
69
  ```ts
70
70
  import { expect } from "@effect/vitest";
71
71
  import { Effect, Layer } from "effect";
72
- import { makeEffectIt } from "@shivaedev/effect-test/vitest.ts";
72
+ import { makeEffectIt } from "@shivaedev/effect-test/makeEffectIt.ts";
73
73
 
74
74
  const { effectApp } = makeEffectIt({
75
75
  layer: Layer.empty,
@@ -90,7 +90,7 @@ This alternative token fixture adds a tracing wrapper:
90
90
  ```ts
91
91
  import { expect } from "@effect/vitest";
92
92
  import { Context, Effect, Layer } from "effect";
93
- import { makeEffectIt } from "@shivaedev/effect-test/vitest.ts";
93
+ import { makeEffectIt } from "@shivaedev/effect-test/makeEffectIt.ts";
94
94
 
95
95
  class Token extends Context.Service<Token, string>()("test/Token") {}
96
96
 
@@ -107,7 +107,7 @@ effectApp("reads the harness", function* (token) {
107
107
 
108
108
  `around` receives the Effect that makes the harness and then runs the body. The wrapper also has the Layer's services. This is where a fixture composes its tracing or transaction boundary. The database package owns whether that transaction rolls back; this runner does not add a database policy. The later examples use the first token fixture, whose harness contains `token` and `name`.
109
109
 
110
- `@shivaedev/effect-prisma` and `@shivaedev/effect-trpc` build their testing helpers on this factory. `@shivaedev/test-story` builds domain stories above it and owns traits, verbs, engine stepping and failure narration. Use those helpers when the test needs their vocabulary; use this runner when defining the fixture underneath. An application-owned story kit can lease PostgreSQL through its worker Layer, use `around` for real-commit resets or local rollback, and acquire servers, native RPC clients and React roots through per-test Scope. The [order feature kit](https://github.com/ShivaeDev/platform/tree/main/packages/effect-react/src/test-support/order-example) demonstrates that composition; [test-story’s kit guide](https://github.com/ShivaeDev/platform/tree/main/packages/test-story#whole-stack-application-kits) explains the application’s isolation, seed and screen responsibilities.
110
+ `@shivaedev/effect-prisma` and `@shivaedev/effect-trpc` build their testing helpers on this factory. `@shivaedev/test-story` builds domain stories above it and owns traits, verbs, engine stepping and failure narration. Use those helpers when the test needs their vocabulary; use this runner when defining the fixture underneath. An application-owned story kit can lease PostgreSQL through its file Layer, use `around` for real-commit resets or local rollback, and acquire servers, native RPC clients and React roots through per-test Scope. The [order feature kit](https://github.com/ShivaeDev/platform/tree/main/packages/effect-react/src/test-support/order-example) demonstrates that composition; [test-story’s kit guide](https://github.com/ShivaeDev/platform/tree/main/packages/test-story#whole-stack-application-kits) explains the application’s isolation, seed and screen responsibilities.
111
111
 
112
112
  ### 2. In every test: the generator
113
113
 
@@ -157,6 +157,10 @@ The override changes the per-test environment used by the wrapper, harness and b
157
157
 
158
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.
159
159
 
160
+ A `Clock.Clock` supplied by the fixture's Layer takes precedence over the runner's default Clock in the wrapper, harness and body. Reads and sleeps use that fixture Clock, including explicit advancement when it is a native TestClock.
161
+
162
+ Both test and live clock fixtures install a fresh native TestConsole for each test. `Console.log` from `effect` is captured by `TestConsole.logLines` from `effect/testing/TestConsole`; one test's output does not carry into the next.
163
+
160
164
  ### Waiting for a typed readiness condition
161
165
 
162
166
  `eventually(effect, options)` retries the Effect's typed failures until it succeeds or uses its retry budget. It uses the active Clock: under TestClock it advances time with `TestClock.adjust`; under live time it retries with `Schedule.spaced`.
@@ -219,7 +223,7 @@ Import the module that defines the name; the package has no root entry.
219
223
  | Module | Exports |
220
224
  | --- | --- |
221
225
  | `@shivaedev/effect-test/it.ts` | `it`, with generator-aware `effect` and `live` testers. |
222
- | `@shivaedev/effect-test/vitest.ts` | `makeEffectIt({ layer, makeHarness, around?, clock? })`, returning `{ effectApp }`. |
226
+ | `@shivaedev/effect-test/makeEffectIt.ts` | `makeEffectIt({ layer, makeHarness, around?, clock? })`, returning `{ effectApp }`. |
223
227
  | `@shivaedev/effect-test/eventually.ts` | `eventually(effect, options?)` and `EventuallyOptions`. |
224
228
  | `@shivaedev/effect-test/withLive.ts` | `withLive(effect)`, a live-time region under either clock. |
225
229
  | `@shivaedev/effect-test/anyTestLayer.ts` | `AnyTestLayer` and `buildTestLayer(layer, scope)`, an Effect that builds the Layer's service Context in the supplied scope. |
@@ -230,7 +234,7 @@ Import the module that defines the name; the package has no root entry.
230
234
  ### Install, setup and limits
231
235
 
232
236
  ```sh
233
- pnpm add --save-dev @shivaedev/effect-test @effect/vitest@4.0.4 effect@4.0.4 vitest@5.0.3
237
+ pnpm add --save-dev @shivaedev/effect-test @effect/vitest@4.0.5 effect@4.0.5 vitest@5.0.3
234
238
  ```
235
239
 
236
240
  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`.
@@ -3,5 +3,5 @@ export interface EventuallyOptions {
3
3
  readonly interval?: Duration.Input;
4
4
  readonly times?: number;
5
5
  }
6
- export declare const eventually: <A, E, R>(effect: Effect.Effect<A, E, R>, options?: EventuallyOptions) => Effect.Effect<A, E, R>;
6
+ export declare const eventually: <A, E, R>(effect: Effect.Effect<A, E, R>, options?: EventuallyOptions | undefined) => Effect.Effect<A, E, R>;
7
7
  //# sourceMappingURL=eventually.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"eventually.d.ts","sourceRoot":"","sources":["../src/eventually.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,QAAQ,EAAE,MAAM,EAAoB,MAAM,QAAQ,CAAC;AAGxE,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACxB;AAoCD,eAAO,MAAM,UAAU,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,YAAY,iBAAiB,KAAG,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAMpH,CAAC"}
1
+ {"version":3,"file":"eventually.d.ts","sourceRoot":"","sources":["../src/eventually.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,QAAQ,EAAE,MAAM,EAAoB,MAAM,QAAQ,CAAC;AAGxE,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACxB;AAsCD,eAAO,MAAM,UAAU,GAAgC,CAAC,EAAE,CAAC,EAAE,CAAC,oGAQ5D,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { Clock, Effect, Result, Schedule } from "effect";
2
2
  import * as TestClock from "effect/testing/TestClock";
3
- const defaultInterval = "10 millis";
3
+ const DEFAULT_INTERVAL = "10 millis";
4
4
  function isTestClock(clock) {
5
5
  return "adjust" in clock;
6
6
  }
@@ -12,26 +12,24 @@ function retryOnLiveClock(effect, interval, times) {
12
12
  times,
13
13
  });
14
14
  }
15
- function retryOnTestClock(effect, interval, times) {
16
- return Effect.gen(function* () {
17
- let retriesLeft = times;
18
- for (;;) {
19
- const result = yield* Effect.result(effect);
20
- if (Result.isSuccess(result)) {
21
- return result.success;
22
- }
23
- if (retriesLeft === 0) {
24
- return yield* Effect.fail(result.failure);
25
- }
26
- if (retriesLeft !== undefined) {
27
- retriesLeft -= 1;
28
- }
29
- yield* TestClock.adjust(interval);
15
+ const retryOnTestClock = Effect.fnUntraced(function* (effect, interval, times) {
16
+ let retriesLeft = times;
17
+ for (;;) {
18
+ const result = yield* Effect.result(effect);
19
+ if (Result.isSuccess(result)) {
20
+ return result.success;
30
21
  }
31
- });
32
- }
33
- export const eventually = (effect, options) => Effect.gen(function* () {
34
- const interval = options?.interval ?? defaultInterval;
22
+ if (retriesLeft === 0) {
23
+ return yield* Effect.fail(result.failure);
24
+ }
25
+ if (retriesLeft !== undefined) {
26
+ retriesLeft -= 1;
27
+ }
28
+ yield* TestClock.adjust(interval);
29
+ }
30
+ });
31
+ export const eventually = Effect.fnUntraced(function* (effect, options) {
32
+ const interval = options?.interval ?? DEFAULT_INTERVAL;
35
33
  const clock = yield* Clock.Clock;
36
34
  const retry = isTestClock(clock) ? retryOnTestClock : retryOnLiveClock;
37
35
  return yield* retry(effect, interval, options?.times);
@@ -1 +1 @@
1
- {"version":3,"file":"eventually.js","sourceRoot":"","sources":["../src/eventually.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAiB,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACxE,OAAO,KAAK,SAAS,MAAM,0BAA0B,CAAC;AAOtD,MAAM,eAAe,GAAG,WAAW,CAAC;AAEpC,SAAS,WAAW,CAAC,KAAkB;IACtC,OAAO,QAAQ,IAAI,KAAK,CAAC;AAC1B,CAAC;AAED,SAAS,gBAAgB,CAAU,MAA8B,EAAE,QAAwB,EAAE,KAAyB;IACrH,OAAO,KAAK,KAAK,SAAS;QACzB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACjD,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE;YACrB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;YACnC,KAAK;SACL,CAAC,CAAC;AACN,CAAC;AAED,SAAS,gBAAgB,CAAU,MAA8B,EAAE,QAAwB,EAAE,KAAyB;IACrH,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC1B,IAAI,WAAW,GAAG,KAAK,CAAC;QACxB,SAAS,CAAC;YACT,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC5C,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC9B,OAAO,MAAM,CAAC,OAAO,CAAC;YACvB,CAAC;YACD,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC3C,CAAC;YACD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC/B,WAAW,IAAI,CAAC,CAAC;YAClB,CAAC;YACD,KAAK,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACnC,CAAC;IACF,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,CAAU,MAA8B,EAAE,OAA2B,EAA0B,EAAE,CAC1H,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACnB,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,eAAe,CAAC;IACtD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IACjC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACvE,OAAO,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"eventually.js","sourceRoot":"","sources":["../src/eventually.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAiB,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACxE,OAAO,KAAK,SAAS,MAAM,0BAA0B,CAAC;AAOtD,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAErC,SAAS,WAAW,CAAC,KAAkB;IACtC,OAAO,QAAQ,IAAI,KAAK,CAAC;AAC1B,CAAC;AAED,SAAS,gBAAgB,CAAU,MAA8B,EAAE,QAAwB,EAAE,KAAyB;IACrH,OAAO,KAAK,KAAK,SAAS;QACzB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACjD,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE;YACrB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;YACnC,KAAK;SACL,CAAC,CAAC;AACN,CAAC;AAED,MAAM,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EACnD,MAA8B,EAC9B,QAAwB,EACxB,KAAyB;IAEzB,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,SAAS,CAAC;QACT,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,OAAO,MAAM,CAAC,OAAO,CAAC;QACvB,CAAC;QACD,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC3C,CAAC;QACD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC/B,WAAW,IAAI,CAAC,CAAC;QAClB,CAAC;QACD,KAAK,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;AACF,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EACpD,MAA8B,EAC9B,OAA2B;IAE3B,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,gBAAgB,CAAC;IACvD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IACjC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACvE,OAAO,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { type Layer } from "effect";
2
+ import { type AnyTestLayer } from "./anyTestLayer.ts";
3
+ import type { MakeEffectItOptions, MakeEffectItResult } from "./types.ts";
4
+ export declare function makeEffectIt<THarness, TTestLayer extends AnyTestLayer>(options: MakeEffectItOptions<THarness, TTestLayer>): MakeEffectItResult<THarness, Layer.Success<TTestLayer>>;
5
+ //# sourceMappingURL=makeEffectIt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"makeEffectIt.d.ts","sourceRoot":"","sources":["../src/makeEffectIt.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,wBAAgB,YAAY,CAAC,QAAQ,EAAE,UAAU,SAAS,YAAY,EACrE,OAAO,EAAE,mBAAmB,CAAC,QAAQ,EAAE,UAAU,CAAC,GAChD,kBAAkB,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAuEzD"}
@@ -2,11 +2,11 @@ import { it as effectIt } from "@effect/vitest";
2
2
  import { Effect, Exit, Scope } from "effect";
3
3
  import { runEffectTest } from "#internal/runEffectTest.ts";
4
4
  import { buildTestLayer } from "./anyTestLayer.js";
5
- const fixtureName = "__effectTestContext";
5
+ const FIXTURE_NAME = "__effectTestContext";
6
6
  function restoreContext(fixture, context) {
7
7
  return {
8
8
  ...context,
9
- [fixtureName]: fixture,
9
+ [FIXTURE_NAME]: fixture,
10
10
  };
11
11
  }
12
12
  function splitOptions(options) {
@@ -20,7 +20,7 @@ function splitOptions(options) {
20
20
  return { clock, vitest };
21
21
  }
22
22
  function makeFixtureIt(layer) {
23
- return effectIt.extend(fixtureName, { scope: "worker" }, async ({}, { onCleanup }) => {
23
+ return effectIt.extend(FIXTURE_NAME, { scope: "file" }, async ({}, { onCleanup }) => {
24
24
  const scope = Effect.runSync(Scope.make());
25
25
  onCleanup(() => Effect.runPromise(Scope.close(scope, Exit.void)));
26
26
  try {
@@ -32,7 +32,7 @@ function makeFixtureIt(layer) {
32
32
  }
33
33
  });
34
34
  }
35
- export const makeEffectIt = (options) => {
35
+ export function makeEffectIt(options) {
36
36
  const fixtureIt = makeFixtureIt(options.layer);
37
37
  const defaultClock = options.clock ?? "test";
38
38
  function run(body, context) {
@@ -42,7 +42,7 @@ export const makeEffectIt = (options) => {
42
42
  return yield* Effect.isEffect(result) ? result : Effect.gen(() => result);
43
43
  });
44
44
  const wrapped = options.around?.(ready) ?? ready;
45
- return wrapped.pipe(Effect.provide(context[fixtureName]));
45
+ return wrapped.pipe(Effect.provide(context[FIXTURE_NAME]));
46
46
  }
47
47
  function register(current) {
48
48
  return (name, body, testOptions) => {
@@ -88,5 +88,5 @@ export const makeEffectIt = (options) => {
88
88
  skipIf: (condition) => register(fixtureIt.skipIf(condition)),
89
89
  });
90
90
  return { effectApp };
91
- };
92
- //# sourceMappingURL=vitest.js.map
91
+ }
92
+ //# sourceMappingURL=makeEffectIt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"makeEffectIt.js","sourceRoot":"","sources":["../src/makeEffectIt.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shivaedev/effect-test",
3
- "version": "0.7.1",
4
- "description": "Generic Effect Vitest runner with worker-scoped Layers and TestClock",
3
+ "version": "0.8.1",
4
+ "description": "Generic Effect Vitest runner with file-scoped Layers and TestClock",
5
5
  "homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/effect-test#readme",
6
6
  "bugs": {
7
7
  "url": "https://github.com/ShivaeDev/platform/issues"
@@ -41,16 +41,16 @@
41
41
  "README.md"
42
42
  ],
43
43
  "devDependencies": {
44
- "@effect/vitest": "4.0.4",
45
- "@shivaedev/quality": "0.27.1",
44
+ "@effect/vitest": "4.0.5",
45
+ "@shivaedev/quality": "0.38.0",
46
46
  "@types/node": "24.19.2",
47
- "effect": "4.0.4",
47
+ "effect": "4.0.5",
48
48
  "typescript": "7.0.2",
49
- "vitest": "5.0.3"
49
+ "vitest": "5.0.5"
50
50
  },
51
51
  "peerDependencies": {
52
- "@effect/vitest": "4.0.4",
53
- "effect": "4.0.4"
52
+ "@effect/vitest": "4.0.5",
53
+ "effect": "4.0.5"
54
54
  },
55
55
  "peerDependenciesMeta": {
56
56
  "@effect/vitest": {
package/src/eventually.ts CHANGED
@@ -6,7 +6,7 @@ export interface EventuallyOptions {
6
6
  readonly times?: number;
7
7
  }
8
8
 
9
- const defaultInterval = "10 millis";
9
+ const DEFAULT_INTERVAL = "10 millis";
10
10
 
11
11
  function isTestClock(clock: Clock.Clock): clock is TestClock.TestClock {
12
12
  return "adjust" in clock;
@@ -21,29 +21,33 @@ function retryOnLiveClock<A, E, R>(effect: Effect.Effect<A, E, R>, interval: Dur
21
21
  });
22
22
  }
23
23
 
24
- function retryOnTestClock<A, E, R>(effect: Effect.Effect<A, E, R>, interval: Duration.Input, times: number | undefined): Effect.Effect<A, E, R> {
25
- return Effect.gen(function* () {
26
- let retriesLeft = times;
27
- for (;;) {
28
- const result = yield* Effect.result(effect);
29
- if (Result.isSuccess(result)) {
30
- return result.success;
31
- }
32
- if (retriesLeft === 0) {
33
- return yield* Effect.fail(result.failure);
34
- }
35
- if (retriesLeft !== undefined) {
36
- retriesLeft -= 1;
37
- }
38
- yield* TestClock.adjust(interval);
24
+ const retryOnTestClock = Effect.fnUntraced(function* <A, E, R>(
25
+ effect: Effect.Effect<A, E, R>,
26
+ interval: Duration.Input,
27
+ times: number | undefined,
28
+ ): Effect.fn.Return<A, E, R> {
29
+ let retriesLeft = times;
30
+ for (;;) {
31
+ const result = yield* Effect.result(effect);
32
+ if (Result.isSuccess(result)) {
33
+ return result.success;
39
34
  }
40
- });
41
- }
35
+ if (retriesLeft === 0) {
36
+ return yield* Effect.fail(result.failure);
37
+ }
38
+ if (retriesLeft !== undefined) {
39
+ retriesLeft -= 1;
40
+ }
41
+ yield* TestClock.adjust(interval);
42
+ }
43
+ });
42
44
 
43
- export const eventually = <A, E, R>(effect: Effect.Effect<A, E, R>, options?: EventuallyOptions): Effect.Effect<A, E, R> =>
44
- Effect.gen(function* () {
45
- const interval = options?.interval ?? defaultInterval;
46
- const clock = yield* Clock.Clock;
47
- const retry = isTestClock(clock) ? retryOnTestClock : retryOnLiveClock;
48
- return yield* retry(effect, interval, options?.times);
49
- });
45
+ export const eventually = Effect.fnUntraced(function* <A, E, R>(
46
+ effect: Effect.Effect<A, E, R>,
47
+ options?: EventuallyOptions,
48
+ ): Effect.fn.Return<A, E, R> {
49
+ const interval = options?.interval ?? DEFAULT_INTERVAL;
50
+ const clock = yield* Clock.Clock;
51
+ const retry = isTestClock(clock) ? retryOnTestClock : retryOnLiveClock;
52
+ return yield* retry(effect, interval, options?.times);
53
+ });
@@ -4,21 +4,21 @@ import { runEffectTest } from "#internal/runEffectTest.ts";
4
4
  import { type AnyTestLayer, buildTestLayer } from "./anyTestLayer.ts";
5
5
  import type { EffectClock, EffectTest, EffectTestBody, EffectTester, EffectTestOptions, MakeEffectItOptions, MakeEffectItResult } from "./types.ts";
6
6
 
7
- const fixtureName = "__effectTestContext";
7
+ const FIXTURE_NAME = "__effectTestContext";
8
8
 
9
9
  type EffectFixture<TProvided> = TestContext & {
10
- readonly [fixtureName]: Context.Context<TProvided>;
10
+ readonly [FIXTURE_NAME]: Context.Context<TProvided>;
11
11
  };
12
12
 
13
13
  type FixtureTest<TProvided> = (name: string, options: TestOptions, body: (context: EffectFixture<TProvided>) => Promise<unknown>) => void;
14
14
 
15
15
  function restoreContext<TProvided>(
16
16
  fixture: Context.Context<TProvided>,
17
- context: Omit<EffectFixture<TProvided>, typeof fixtureName>,
17
+ context: Omit<EffectFixture<TProvided>, typeof FIXTURE_NAME>,
18
18
  ): EffectFixture<TProvided> {
19
19
  return {
20
20
  ...context,
21
- [fixtureName]: fixture,
21
+ [FIXTURE_NAME]: fixture,
22
22
  };
23
23
  }
24
24
 
@@ -37,7 +37,7 @@ function splitOptions(options: number | EffectTestOptions | undefined): {
37
37
  }
38
38
 
39
39
  function makeFixtureIt<TLayer extends AnyTestLayer>(layer: TLayer) {
40
- return effectIt.extend(fixtureName, { scope: "worker" }, async ({}, { onCleanup }) => {
40
+ return effectIt.extend(FIXTURE_NAME, { scope: "file" }, async ({}, { onCleanup }) => {
41
41
  const scope = Effect.runSync(Scope.make());
42
42
  onCleanup(() => Effect.runPromise(Scope.close(scope, Exit.void)));
43
43
 
@@ -50,9 +50,9 @@ function makeFixtureIt<TLayer extends AnyTestLayer>(layer: TLayer) {
50
50
  });
51
51
  }
52
52
 
53
- export const makeEffectIt = <THarness, TTestLayer extends AnyTestLayer>(
53
+ export function makeEffectIt<THarness, TTestLayer extends AnyTestLayer>(
54
54
  options: MakeEffectItOptions<THarness, TTestLayer>,
55
- ): MakeEffectItResult<THarness, Layer.Success<TTestLayer>> => {
55
+ ): MakeEffectItResult<THarness, Layer.Success<TTestLayer>> {
56
56
  type Provided = Layer.Success<TTestLayer>;
57
57
  const fixtureIt = makeFixtureIt(options.layer);
58
58
  const defaultClock = options.clock ?? "test";
@@ -64,7 +64,7 @@ export const makeEffectIt = <THarness, TTestLayer extends AnyTestLayer>(
64
64
  return yield* Effect.isEffect(result) ? result : Effect.gen(() => result);
65
65
  });
66
66
  const wrapped = options.around?.(ready) ?? ready;
67
- return wrapped.pipe(Effect.provide(context[fixtureName]));
67
+ return wrapped.pipe(Effect.provide(context[FIXTURE_NAME]));
68
68
  }
69
69
 
70
70
  function register(current: FixtureTest<Provided>): EffectTest<THarness, Provided> {
@@ -123,4 +123,4 @@ export const makeEffectIt = <THarness, TTestLayer extends AnyTestLayer>(
123
123
  });
124
124
 
125
125
  return { effectApp };
126
- };
126
+ }
package/dist/vitest.d.ts DELETED
@@ -1,5 +0,0 @@
1
- import { type Layer } from "effect";
2
- import { type AnyTestLayer } from "./anyTestLayer.ts";
3
- import type { MakeEffectItOptions, MakeEffectItResult } from "./types.ts";
4
- export declare const makeEffectIt: <THarness, TTestLayer extends AnyTestLayer>(options: MakeEffectItOptions<THarness, TTestLayer>) => MakeEffectItResult<THarness, Layer.Success<TTestLayer>>;
5
- //# sourceMappingURL=vitest.d.ts.map
@@ -1 +0,0 @@
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"}
@@ -1 +0,0 @@
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,EAAgB,MAAM,EAAE,IAAI,EAAc,KAAK,EAAE,MAAM,QAAQ,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAqB,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGtE,MAAM,WAAW,GAAG,qBAAqB,CAAC;AAQ1C,SAAS,cAAc,CACtB,OAAmC,EACnC,OAA2D;IAE3D,OAAO;QACN,GAAG,OAAO;QACV,CAAC,WAAW,CAAC,EAAE,OAAO;KACtB,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,OAA+C;IAIpE,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC;IAC3D,CAAC;IACD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACzC,CAAC;IACD,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;IACrC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC1B,CAAC;AAED,SAAS,aAAa,CAA8B,KAAa;IAChE,OAAO,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE;QACpF,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3C,SAAS,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAElE,IAAI,CAAC;YACJ,OAAO,MAAM,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YACvD,MAAM,KAAK,CAAC;QACb,CAAC;IACF,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAC3B,OAAkD,EACQ,EAAE;IAE5D,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC;IAE7C,SAAS,GAAG,CAAI,IAA2C,EAAE,OAAgC;QAC5F,MAAM,KAAK,GAAsD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YACpF,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YACpD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACtC,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;QACjD,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,SAAS,QAAQ,CAAC,OAA8B;QAC/C,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE;YAClC,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;YACxC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,YAAY,CAAC;YAC1C,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;gBAClI,MAAM,OAAO,GAAG,cAAc,CAAC,mBAAmB,EAAE;oBACnD,QAAQ;oBACR,KAAK;oBACL,MAAM;oBACN,YAAY;oBACZ,cAAc;oBACd,MAAM;oBACN,IAAI;oBACJ,IAAI;iBACJ,CAAC,CAAC;gBACH,OAAO,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;YAC1D,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAqC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE;QACtF,IAAI,EACH,CAAQ,KAAuB,EAAE,EAAE,CACnC,CACC,IAAY,EACZ,IAA6I,EAC7I,WAAwC,EACvC,EAAE;YACH,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;YACxC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,YAAY,CAAC;YAC1C,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CACnB,IAAI,EACJ,KAAK,CAAC,MAAM,EACZ,CAAC,IAAI,EAAE,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;gBAC5G,MAAM,OAAO,GAAG,cAAc,CAAC,mBAAmB,EAAE;oBACnD,QAAQ;oBACR,KAAK;oBACL,MAAM;oBACN,YAAY;oBACZ,cAAc;oBACd,MAAM;oBACN,IAAI;oBACJ,IAAI;iBACJ,CAAC,CAAC;gBACH,OAAO,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;YAC/H,CAAC,CACD,CAAC;QACH,CAAC;QACF,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC;QAChC,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC;QAC9B,KAAK,EAAE,CAAC,SAAkB,EAAE,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACnE,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC;QAC9B,MAAM,EAAE,CAAC,SAAkB,EAAE,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;KACrE,CAAC,CAAC;IAEH,OAAO,EAAE,SAAS,EAAE,CAAC;AACtB,CAAC,CAAC"}