@wardic/test 1.0.0-rc.4 → 1.0.0-rc.5

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/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  * Nothing is drawn on a page: an app's components are tested with `DomLive`
8
8
  * under the test runner's fake timers, as https://wardic.dev/guides/testing shows.
9
9
  */
10
- export declare const VERSION = "1.0.0-rc.4";
10
+ export declare const VERSION = "1.0.0-rc.5";
11
11
  export * as TestClock from "./clock.ts";
12
12
  export * as TestRenderer from "./renderer.ts";
13
13
  export * as TestProbe from "./probe.ts";
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@
8
8
  * under the test runner's fake timers, as https://wardic.dev/guides/testing shows.
9
9
  */
10
10
  // The testing guide: #558.
11
- export const VERSION = "1.0.0-rc.4";
11
+ export const VERSION = "1.0.0-rc.5";
12
12
  export * as TestClock from "./clock.js";
13
13
  export * as TestRenderer from "./renderer.js";
14
14
  export * as TestProbe from "./probe.js";
package/dist/layer.d.ts CHANGED
@@ -8,12 +8,13 @@ import type * as Probe from "@wardic/core/Probe";
8
8
  import * as ReducedMotion from "@wardic/core/ReducedMotion";
9
9
  import * as RefreshFrameSource from "@wardic/core/RefreshFrameSource";
10
10
  import type * as Renderer from "@wardic/core/Renderer";
11
+ import type * as ScrollSource from "@wardic/core/ScrollSource";
11
12
  import * as Layer from "effect/Layer";
12
13
  import { AtomRegistry } from "effect/reactivity";
13
14
  /**
14
15
  * The full headless environment: deterministic Clock (driven by `frames`), a Refresh frame
15
- * source that never calls back, recording Renderer, static Probe, silent InputSource, core's real
16
- * interpolator registry, a fresh AtomRegistry for reading Probe atoms
16
+ * source that never calls back, recording Renderer, static Probe and ScrollSource, silent
17
+ * InputSource, core's real interpolator registry, a fresh AtomRegistry for reading Probe atoms
17
18
  * (`viewport`, `prefersReducedMotion`), and a fresh Drag activity, so one test's
18
19
  * drag never blocks another's hover or press, and core's Frame loop over that
19
20
  * Clock. Provide this in place of `DomLive` to test animation code without a
@@ -21,7 +22,7 @@ import { AtomRegistry } from "effect/reactivity";
21
22
  * app's components are tested with `DomLive` under the test runner's fake timers instead
22
23
  * (https://wardic.dev/guides/testing).
23
24
  */
24
- export declare const testLayer: (frames?: ReadonlyArray<number>) => Layer.Layer<Clock.Clock | RefreshFrameSource.RefreshFrameSource | FrameLoop.FrameLoop | Renderer.Renderer | Probe.Probe | InputSource.InputSource | InterpolatorRegistry.InterpolatorRegistry | ReducedMotion.PositionalKeys | DefaultTransition.DefaultTransition | Announcer.Announcer | AtomRegistry.AtomRegistry>;
25
+ export declare const testLayer: (frames?: ReadonlyArray<number>) => Layer.Layer<Clock.Clock | RefreshFrameSource.RefreshFrameSource | FrameLoop.FrameLoop | Renderer.Renderer | Probe.Probe | ScrollSource.ScrollSource | InputSource.InputSource | InterpolatorRegistry.InterpolatorRegistry | ReducedMotion.PositionalKeys | DefaultTransition.DefaultTransition | Announcer.Announcer | AtomRegistry.AtomRegistry>;
25
26
  /** `testLayer()` with an empty clock — for tests that drive their own frames. It never ticks on its own. */
26
- export declare const TestLive: Layer.Layer<Announcer.Announcer | AtomRegistry.AtomRegistry | Clock.Clock | DefaultTransition.DefaultTransition | FrameLoop.FrameLoop | InputSource.InputSource | InterpolatorRegistry.InterpolatorRegistry | ReducedMotion.PositionalKeys | Probe.Probe | RefreshFrameSource.RefreshFrameSource | Renderer.Renderer, never, never>;
27
+ export declare const TestLive: Layer.Layer<Announcer.Announcer | AtomRegistry.AtomRegistry | Clock.Clock | DefaultTransition.DefaultTransition | FrameLoop.FrameLoop | InputSource.InputSource | InterpolatorRegistry.InterpolatorRegistry | ReducedMotion.PositionalKeys | Probe.Probe | RefreshFrameSource.RefreshFrameSource | Renderer.Renderer | ScrollSource.ScrollSource, never, never>;
27
28
  //# sourceMappingURL=layer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"layer.d.ts","sourceRoot":"","sources":["../src/layer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAA;AACnD,OAAO,KAAK,KAAK,KAAK,MAAM,oBAAoB,CAAA;AAChD,OAAO,KAAK,iBAAiB,MAAM,gCAAgC,CAAA;AAEnE,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAA;AACnD,OAAO,KAAK,KAAK,WAAW,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,oBAAoB,MAAM,mCAAmC,CAAA;AAEzE,OAAO,KAAK,KAAK,KAAK,MAAM,oBAAoB,CAAA;AAChD,OAAO,KAAK,aAAa,MAAM,4BAA4B,CAAA;AAC3D,OAAO,KAAK,kBAAkB,MAAM,iCAAiC,CAAA;AACrE,OAAO,KAAK,KAAK,QAAQ,MAAM,uBAAuB,CAAA;AAEtD,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAahD;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,SAAS,YACZ,aAAa,CAAC,MAAM,CAAC,KAC5B,KAAK,CAAC,KAAK,CACV,KAAK,CAAC,KAAK,GACX,kBAAkB,CAAC,kBAAkB,GACrC,SAAS,CAAC,SAAS,GACnB,QAAQ,CAAC,QAAQ,GACjB,KAAK,CAAC,KAAK,GACX,WAAW,CAAC,WAAW,GACvB,oBAAoB,CAAC,oBAAoB,GACzC,aAAa,CAAC,cAAc,GAC5B,iBAAiB,CAAC,iBAAiB,GACnC,SAAS,CAAC,SAAS,GACnB,YAAY,CAAC,YAAY,CAsB1B,CAAA;AAEH,4GAA4G;AAC5G,eAAO,MAAM,QAAQ,qUAAc,CAAA"}
1
+ {"version":3,"file":"layer.d.ts","sourceRoot":"","sources":["../src/layer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAA;AACnD,OAAO,KAAK,KAAK,KAAK,MAAM,oBAAoB,CAAA;AAChD,OAAO,KAAK,iBAAiB,MAAM,gCAAgC,CAAA;AAEnE,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAA;AACnD,OAAO,KAAK,KAAK,WAAW,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,oBAAoB,MAAM,mCAAmC,CAAA;AAEzE,OAAO,KAAK,KAAK,KAAK,MAAM,oBAAoB,CAAA;AAChD,OAAO,KAAK,aAAa,MAAM,4BAA4B,CAAA;AAC3D,OAAO,KAAK,kBAAkB,MAAM,iCAAiC,CAAA;AACrE,OAAO,KAAK,KAAK,QAAQ,MAAM,uBAAuB,CAAA;AACtD,OAAO,KAAK,KAAK,YAAY,MAAM,2BAA2B,CAAA;AAE9D,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAahD;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,SAAS,YACZ,aAAa,CAAC,MAAM,CAAC,KAC5B,KAAK,CAAC,KAAK,CACV,KAAK,CAAC,KAAK,GACX,kBAAkB,CAAC,kBAAkB,GACrC,SAAS,CAAC,SAAS,GACnB,QAAQ,CAAC,QAAQ,GACjB,KAAK,CAAC,KAAK,GACX,YAAY,CAAC,YAAY,GACzB,WAAW,CAAC,WAAW,GACvB,oBAAoB,CAAC,oBAAoB,GACzC,aAAa,CAAC,cAAc,GAC5B,iBAAiB,CAAC,iBAAiB,GACnC,SAAS,CAAC,SAAS,GACnB,YAAY,CAAC,YAAY,CAsB1B,CAAA;AAEH,4GAA4G;AAC5G,eAAO,MAAM,QAAQ,iWAAc,CAAA"}
package/dist/layer.js CHANGED
@@ -21,8 +21,8 @@ import * as TestRenderer from "./renderer.js";
21
21
  const stillFrames = { requestFrame: constUndefined, cancelFrame: constVoid };
22
22
  /**
23
23
  * The full headless environment: deterministic Clock (driven by `frames`), a Refresh frame
24
- * source that never calls back, recording Renderer, static Probe, silent InputSource, core's real
25
- * interpolator registry, a fresh AtomRegistry for reading Probe atoms
24
+ * source that never calls back, recording Renderer, static Probe and ScrollSource, silent
25
+ * InputSource, core's real interpolator registry, a fresh AtomRegistry for reading Probe atoms
26
26
  * (`viewport`, `prefersReducedMotion`), and a fresh Drag activity, so one test's
27
27
  * drag never blocks another's hover or press, and core's Frame loop over that
28
28
  * Clock. Provide this in place of `DomLive` to test animation code without a
package/dist/layer.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"layer.js","sourceRoot":"","sources":["../src/layer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAA;AAEnD,OAAO,KAAK,iBAAiB,MAAM,gCAAgC,CAAA;AACnE,OAAO,KAAK,YAAY,MAAM,2BAA2B,CAAA;AACzD,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAA;AAEnD,OAAO,KAAK,oBAAoB,MAAM,mCAAmC,CAAA;AACzE,OAAO,KAAK,WAAW,MAAM,0BAA0B,CAAA;AAEvD,OAAO,KAAK,aAAa,MAAM,4BAA4B,CAAA;AAC3D,OAAO,KAAK,kBAAkB,MAAM,iCAAiC,CAAA;AAErE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3D,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,SAAS,MAAM,YAAY,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,YAAY,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,YAAY,CAAA;AACvC,OAAO,KAAK,YAAY,MAAM,eAAe,CAAA;AAE7C;;;;GAIG;AACH,MAAM,WAAW,GAA6B,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,CAAA;AAEtG;;;;;;;;;;GAUG;AACH,kFAAkF;AAClF,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,MAAM,GAA0B,EAAE,EAalC,EAAE,CACF,SAAS,CAAC,KAAK,CAAC,IAAI,CAClB,KAAK,CAAC,YAAY,CAChB,KAAK,CAAC,QAAQ,CACZ,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,EACvB,kBAAkB,CAAC,KAAK,CAAC,WAAW,CAAC,EACrC,YAAY,CAAC,KAAK,EAClB,SAAS,CAAC,KAAK,EAAE,EACjB,SAAS,CAAC,KAAK,EAAE,EACjB,oBAAoB,CAAC,KAAK;AAC1B,0EAA0E;AAC1E,aAAa,CAAC,cAAc;AAC5B,gFAAgF;AAChF,iBAAiB,CAAC,cAAc;AAChC,wDAAwD;AACxD,SAAS,CAAC,WAAW,EACrB,YAAY,CAAC,KAAK,EAClB,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,YAAY,CAAC,IAAI,CAAC,EACxD,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,WAAW,CAAC,IAAI,CAAC,CACtD,CACF,CACF,CAAA;AAEH,4GAA4G;AAC5G,MAAM,CAAC,MAAM,QAAQ,GAAG,SAAS,EAAE,CAAA"}
1
+ {"version":3,"file":"layer.js","sourceRoot":"","sources":["../src/layer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAA;AAEnD,OAAO,KAAK,iBAAiB,MAAM,gCAAgC,CAAA;AACnE,OAAO,KAAK,YAAY,MAAM,2BAA2B,CAAA;AACzD,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAA;AAEnD,OAAO,KAAK,oBAAoB,MAAM,mCAAmC,CAAA;AACzE,OAAO,KAAK,WAAW,MAAM,0BAA0B,CAAA;AAEvD,OAAO,KAAK,aAAa,MAAM,4BAA4B,CAAA;AAC3D,OAAO,KAAK,kBAAkB,MAAM,iCAAiC,CAAA;AAGrE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3D,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,SAAS,MAAM,YAAY,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,YAAY,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,YAAY,CAAA;AACvC,OAAO,KAAK,YAAY,MAAM,eAAe,CAAA;AAE7C;;;;GAIG;AACH,MAAM,WAAW,GAA6B,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,CAAA;AAEtG;;;;;;;;;;GAUG;AACH,kFAAkF;AAClF,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,MAAM,GAA0B,EAAE,EAclC,EAAE,CACF,SAAS,CAAC,KAAK,CAAC,IAAI,CAClB,KAAK,CAAC,YAAY,CAChB,KAAK,CAAC,QAAQ,CACZ,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,EACvB,kBAAkB,CAAC,KAAK,CAAC,WAAW,CAAC,EACrC,YAAY,CAAC,KAAK,EAClB,SAAS,CAAC,KAAK,EAAE,EACjB,SAAS,CAAC,KAAK,EAAE,EACjB,oBAAoB,CAAC,KAAK;AAC1B,0EAA0E;AAC1E,aAAa,CAAC,cAAc;AAC5B,gFAAgF;AAChF,iBAAiB,CAAC,cAAc;AAChC,wDAAwD;AACxD,SAAS,CAAC,WAAW,EACrB,YAAY,CAAC,KAAK,EAClB,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,YAAY,CAAC,IAAI,CAAC,EACxD,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,WAAW,CAAC,IAAI,CAAC,CACtD,CACF,CACF,CAAA;AAEH,4GAA4G;AAC5G,MAAM,CAAC,MAAM,QAAQ,GAAG,SAAS,EAAE,CAAA"}
package/dist/probe.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as Probe from "@wardic/core/Probe";
2
+ import * as ScrollSource from "@wardic/core/ScrollSource";
2
3
  import * as Effect from "effect/Effect";
3
4
  import * as Layer from "effect/Layer";
4
5
  import { AtomRegistry } from "effect/reactivity";
@@ -12,8 +13,8 @@ export interface Options {
12
13
  readonly prefersReducedMotion?: boolean;
13
14
  /** Whether the Environment is shown: `true` when left out. */
14
15
  readonly visible?: boolean;
15
- /** Every container's scroll, as `scroll` gives it: a page that doesn't scroll when left out. */
16
- readonly scroll?: Probe.Scroll;
16
+ /** Every container's scroll, as the `ScrollSource` gives it: a page that doesn't scroll when left out. */
17
+ readonly scroll?: ScrollSource.Scroll;
17
18
  /**
18
19
  * Script of intersection (in-view) booleans replayed by `observeIntersection`, an **Input feed**
19
20
  * that ends after it. Mirrors the InputSource test harness: omitted (or empty) means it
@@ -24,9 +25,10 @@ export interface Options {
24
25
  /**
25
26
  * A static Probe: fixed bounds/viewport. `observeIntersection` replays the
26
27
  * optional `intersection` script to each subscriber (empty by default, so it
27
- * emits nothing); `observeResize` stays empty.
28
+ * emits nothing); `observeResize` stays empty. With it, a `ScrollSource`
29
+ * whose every container reads `scroll`, as the Probe's `scroll` did until #518.
28
30
  */
29
- export declare const layer: (options?: Options) => Layer.Layer<Probe.Probe>;
31
+ export declare const layer: (options?: Options) => Layer.Layer<Probe.Probe | ScrollSource.ScrollSource>;
30
32
  /**
31
33
  * A push-based Probe for tests that need to interleave intersection
32
34
  * (in-view/out-of-view) transitions with other effects on their own schedule —
@@ -39,8 +41,8 @@ export declare const layer: (options?: Options) => Layer.Layer<Probe.Probe>;
39
41
  * measure/viewport/prefersReducedMotion/observeResize behave as in {@link layer}.
40
42
  */
41
43
  export declare const pushable: (options?: Options) => Effect.Effect<{
42
- readonly layer: Layer.Layer<Probe.Probe>;
44
+ readonly layer: Layer.Layer<Probe.Probe | ScrollSource.ScrollSource>;
43
45
  readonly pushIntersection: (inView: boolean) => Effect.Effect<void>;
44
- readonly pushScroll: (scroll: Probe.Scroll) => Effect.Effect<void, never, AtomRegistry.AtomRegistry>;
46
+ readonly pushScroll: (scroll: ScrollSource.Scroll) => Effect.Effect<void, never, AtomRegistry.AtomRegistry>;
45
47
  }>;
46
48
  //# sourceMappingURL=probe.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../src/probe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,oBAAoB,CAAA;AAE3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAErC,OAAO,EAAQ,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAWtD,yCAAyC;AAEzC,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAA;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACvE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAA;IACvC,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,gGAAgG;IAChG,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAA;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;CAC/C;AAED;;;;GAIG;AACH,eAAO,MAAM,KAAK,aAAa,OAAO,KAAQ,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAMpE,CAAA;AAeD;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,QAAQ,aAAa,OAAO,KAAQ,MAAM,CAAC,MAAM,CAAC;IAC7D,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACxC,QAAQ,CAAC,gBAAgB,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACnE,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,YAAY,CAAC,CAAA;CACrG,CAUG,CAAA"}
1
+ {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../src/probe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,oBAAoB,CAAA;AAC3C,OAAO,KAAK,YAAY,MAAM,2BAA2B,CAAA;AAEzD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAErC,OAAO,EAAQ,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAWtD,yCAAyC;AAGzC,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAA;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACvE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAA;IACvC,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,0GAA0G;IAC1G,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,MAAM,CAAA;IACrC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;CAC/C;AAED;;;;;GAKG;AACH,eAAO,MAAM,KAAK,aAAa,OAAO,KAAQ,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,YAAY,CAAC,YAAY,CAShG,CAAA;AAeD;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,QAAQ,aAAa,OAAO,KAAQ,MAAM,CAAC,MAAM,CAAC;IAC7D,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,YAAY,CAAC,YAAY,CAAC,CAAA;IACpE,QAAQ,CAAC,gBAAgB,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACnE,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,YAAY,CAAC,CAAA;CAC5G,CAUG,CAAA"}
package/dist/probe.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as Probe from "@wardic/core/Probe";
2
+ import * as ScrollSource from "@wardic/core/ScrollSource";
2
3
  import * as Arr from "effect/Array";
3
4
  import * as Effect from "effect/Effect";
4
5
  import * as Layer from "effect/Layer";
@@ -14,27 +15,26 @@ const toIntersection = (intersecting) => ({ intersecting });
14
15
  /**
15
16
  * A static Probe: fixed bounds/viewport. `observeIntersection` replays the
16
17
  * optional `intersection` script to each subscriber (empty by default, so it
17
- * emits nothing); `observeResize` stays empty.
18
+ * emits nothing); `observeResize` stays empty. With it, a `ScrollSource`
19
+ * whose every container reads `scroll`, as the Probe's `scroll` did until #518.
18
20
  */
19
21
  export const layer = (options = {}) => {
20
22
  const { intersection = [], scroll = STILL_SCROLL } = options;
21
- return Layer.succeed(Probe.Probe, {
22
- ...fixed(options, Atom.make(scroll)),
23
+ return Layer.mergeAll(Layer.succeed(Probe.Probe, {
24
+ ...fixed(options),
23
25
  observeIntersection: () => Feeds.script(Arr.map(intersection, toIntersection)),
24
- });
26
+ }), scrollLayer(Atom.make(scroll)));
25
27
  };
26
- /**
27
- * Both Probes' fixed part: the bounds, the viewport, the preference and the page's visibility, each defaulted, no resizes,
28
- * and one scroll Atom for every container, target and offset (#234).
29
- */
30
- const fixed = ({ bounds = ZERO_BOUNDS, viewport = VIEWPORT, prefersReducedMotion = false, visible = true }, scroll) => ({
28
+ /** Both Probes' fixed part: the bounds, the viewport, the preference and the page's visibility, each defaulted, and no resizes. */
29
+ const fixed = ({ bounds = ZERO_BOUNDS, viewport = VIEWPORT, prefersReducedMotion = false, visible = true }) => ({
31
30
  measure: () => Effect.sync(() => bounds),
32
31
  viewport: Atom.make(viewport),
33
32
  prefersReducedMotion: Atom.make(prefersReducedMotion),
34
33
  visible: Atom.make(visible),
35
- scroll: () => Effect.succeed(scroll),
36
34
  observeResize: () => Stream.empty,
37
35
  });
36
+ /** One scroll Atom for every container, target and offset (#234). */
37
+ const scrollLayer = (scroll) => Layer.succeed(ScrollSource.ScrollSource, { scroll: () => Effect.succeed(scroll) });
38
38
  /**
39
39
  * A push-based Probe for tests that need to interleave intersection
40
40
  * (in-view/out-of-view) transitions with other effects on their own schedule —
@@ -52,7 +52,7 @@ export const pushable = (options = {}) => Effect.sync(() => {
52
52
  const { scroll = STILL_SCROLL } = options;
53
53
  const scrollAtom = Atom.make(scroll);
54
54
  return {
55
- layer: Layer.succeed(Probe.Probe, { ...fixed(options, scrollAtom), observeIntersection: () => intersections.feed }),
55
+ layer: Layer.mergeAll(Layer.succeed(Probe.Probe, { ...fixed(options), observeIntersection: () => intersections.feed }), scrollLayer(scrollAtom)),
56
56
  pushIntersection: (inView) => intersections.push(toIntersection(inView)),
57
57
  pushScroll: (next) => AtomRegistry.AtomRegistry.use((registry) => Effect.sync(() => registry.set(scrollAtom, next))),
58
58
  };
package/dist/probe.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"probe.js","sourceRoot":"","sources":["../src/probe.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"probe.js","sourceRoot":"","sources":["../src/probe.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wardic/test",
3
- "version": "1.0.0-rc.4",
3
+ "version": "1.0.0-rc.5",
4
4
  "description": "Headless testing Layers for Wardic: a clock that replays the frames you give it, a renderer that records what it's asked to draw, and input you push, so animation code runs without a browser.",
5
5
  "keywords": [
6
6
  "animation",
@@ -48,7 +48,7 @@
48
48
  "typecheck:tests": "../../node_modules/typescript-7/bin/tsc -p tsconfig.test.json"
49
49
  },
50
50
  "dependencies": {
51
- "@wardic/core": "1.0.0-rc.4"
51
+ "@wardic/core": "1.0.0-rc.5"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "effect": "^4.1.1"
package/src/index.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  * under the test runner's fake timers, as https://wardic.dev/guides/testing shows.
9
9
  */
10
10
  // The testing guide: #558.
11
- export const VERSION = "1.0.0-rc.4"
11
+ export const VERSION = "1.0.0-rc.5"
12
12
 
13
13
  export * as TestClock from "./clock.ts"
14
14
  export * as TestRenderer from "./renderer.ts"
package/src/layer.ts CHANGED
@@ -10,6 +10,7 @@ import type * as Probe from "@wardic/core/Probe"
10
10
  import * as ReducedMotion from "@wardic/core/ReducedMotion"
11
11
  import * as RefreshFrameSource from "@wardic/core/RefreshFrameSource"
12
12
  import type * as Renderer from "@wardic/core/Renderer"
13
+ import type * as ScrollSource from "@wardic/core/ScrollSource"
13
14
  import { constUndefined, constVoid } from "effect/Function"
14
15
  import * as Layer from "effect/Layer"
15
16
  import { AtomRegistry } from "effect/reactivity"
@@ -27,8 +28,8 @@ const stillFrames: RefreshFrameSource.Shape = { requestFrame: constUndefined, ca
27
28
 
28
29
  /**
29
30
  * The full headless environment: deterministic Clock (driven by `frames`), a Refresh frame
30
- * source that never calls back, recording Renderer, static Probe, silent InputSource, core's real
31
- * interpolator registry, a fresh AtomRegistry for reading Probe atoms
31
+ * source that never calls back, recording Renderer, static Probe and ScrollSource, silent
32
+ * InputSource, core's real interpolator registry, a fresh AtomRegistry for reading Probe atoms
32
33
  * (`viewport`, `prefersReducedMotion`), and a fresh Drag activity, so one test's
33
34
  * drag never blocks another's hover or press, and core's Frame loop over that
34
35
  * Clock. Provide this in place of `DomLive` to test animation code without a
@@ -45,6 +46,7 @@ export const testLayer = (
45
46
  | FrameLoop.FrameLoop
46
47
  | Renderer.Renderer
47
48
  | Probe.Probe
49
+ | ScrollSource.ScrollSource
48
50
  | InputSource.InputSource
49
51
  | InterpolatorRegistry.InterpolatorRegistry
50
52
  | ReducedMotion.PositionalKeys
package/src/probe.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as Probe from "@wardic/core/Probe"
2
+ import * as ScrollSource from "@wardic/core/ScrollSource"
2
3
  import * as Arr from "effect/Array"
3
4
  import * as Effect from "effect/Effect"
4
5
  import * as Layer from "effect/Layer"
@@ -9,21 +10,22 @@ import * as Feeds from "./feeds.ts"
9
10
  const ZERO_BOUNDS: Probe.Bounds = { x: 0, y: 0, width: 0, height: 0, top: 0, right: 0, bottom: 0, left: 0 }
10
11
  const VIEWPORT = { width: 1024, height: 768 }
11
12
  /** A page that doesn't scroll: no range, and progress 1, as Motion reads a container with none. */
12
- const STILL_SCROLL: Probe.Scroll = { x: { current: 0, length: 0, progress: 1 }, y: { current: 0, length: 0, progress: 1 } }
13
+ const STILL_SCROLL: ScrollSource.Scroll = { x: { current: 0, length: 0, progress: 1 }, y: { current: 0, length: 0, progress: 1 } }
13
14
 
14
15
  /** A scripted in-view boolean as the Probe reports it, with no platform record. */
15
16
  const toIntersection = (intersecting: boolean): Probe.Intersection => ({ intersecting })
16
17
 
17
18
  /** Options for the static test Probe. */
18
- // visible: #443 (`pageVisible` until #610). scroll: #234. intersection, an Input feed: #318.
19
+ // visible: #443 (`pageVisible` until #610). scroll: #234, a `ScrollSource` of its own since #518.
20
+ // intersection, an Input feed: #318.
19
21
  export interface Options {
20
22
  readonly bounds?: Probe.Bounds
21
23
  readonly viewport?: { readonly width: number; readonly height: number }
22
24
  readonly prefersReducedMotion?: boolean
23
25
  /** Whether the Environment is shown: `true` when left out. */
24
26
  readonly visible?: boolean
25
- /** Every container's scroll, as `scroll` gives it: a page that doesn't scroll when left out. */
26
- readonly scroll?: Probe.Scroll
27
+ /** Every container's scroll, as the `ScrollSource` gives it: a page that doesn't scroll when left out. */
28
+ readonly scroll?: ScrollSource.Scroll
27
29
  /**
28
30
  * Script of intersection (in-view) booleans replayed by `observeIntersection`, an **Input feed**
29
31
  * that ends after it. Mirrors the InputSource test harness: omitted (or empty) means it
@@ -35,29 +37,33 @@ export interface Options {
35
37
  /**
36
38
  * A static Probe: fixed bounds/viewport. `observeIntersection` replays the
37
39
  * optional `intersection` script to each subscriber (empty by default, so it
38
- * emits nothing); `observeResize` stays empty.
40
+ * emits nothing); `observeResize` stays empty. With it, a `ScrollSource`
41
+ * whose every container reads `scroll`, as the Probe's `scroll` did until #518.
39
42
  */
40
- export const layer = (options: Options = {}): Layer.Layer<Probe.Probe> => {
43
+ export const layer = (options: Options = {}): Layer.Layer<Probe.Probe | ScrollSource.ScrollSource> => {
41
44
  const { intersection = [], scroll = STILL_SCROLL } = options
42
- return Layer.succeed(Probe.Probe, {
43
- ...fixed(options, Atom.make(scroll)),
44
- observeIntersection: () => Feeds.script(Arr.map(intersection, toIntersection)),
45
- })
45
+ return Layer.mergeAll(
46
+ Layer.succeed(Probe.Probe, {
47
+ ...fixed(options),
48
+ observeIntersection: () => Feeds.script(Arr.map(intersection, toIntersection)),
49
+ }),
50
+ scrollLayer(Atom.make(scroll)),
51
+ )
46
52
  }
47
53
 
48
- /**
49
- * Both Probes' fixed part: the bounds, the viewport, the preference and the page's visibility, each defaulted, no resizes,
50
- * and one scroll Atom for every container, target and offset (#234).
51
- */
52
- const fixed = ({ bounds = ZERO_BOUNDS, viewport = VIEWPORT, prefersReducedMotion = false, visible = true }: Options, scroll: Atom.Atom<Probe.Scroll>) => ({
54
+ /** Both Probes' fixed part: the bounds, the viewport, the preference and the page's visibility, each defaulted, and no resizes. */
55
+ const fixed = ({ bounds = ZERO_BOUNDS, viewport = VIEWPORT, prefersReducedMotion = false, visible = true }: Options) => ({
53
56
  measure: () => Effect.sync(() => bounds),
54
57
  viewport: Atom.make(viewport),
55
58
  prefersReducedMotion: Atom.make(prefersReducedMotion),
56
59
  visible: Atom.make(visible),
57
- scroll: () => Effect.succeed(scroll),
58
60
  observeResize: () => Stream.empty,
59
61
  })
60
62
 
63
+ /** One scroll Atom for every container, target and offset (#234). */
64
+ const scrollLayer = (scroll: Atom.Atom<ScrollSource.Scroll>): Layer.Layer<ScrollSource.ScrollSource> =>
65
+ Layer.succeed(ScrollSource.ScrollSource, { scroll: () => Effect.succeed(scroll) })
66
+
61
67
  /**
62
68
  * A push-based Probe for tests that need to interleave intersection
63
69
  * (in-view/out-of-view) transitions with other effects on their own schedule —
@@ -71,17 +77,17 @@ const fixed = ({ bounds = ZERO_BOUNDS, viewport = VIEWPORT, prefersReducedMotion
71
77
  */
72
78
  // The hub: #318. No yield: ADR-0032. Scroll: #234.
73
79
  export const pushable = (options: Options = {}): Effect.Effect<{
74
- readonly layer: Layer.Layer<Probe.Probe>
80
+ readonly layer: Layer.Layer<Probe.Probe | ScrollSource.ScrollSource>
75
81
  readonly pushIntersection: (inView: boolean) => Effect.Effect<void>
76
- readonly pushScroll: (scroll: Probe.Scroll) => Effect.Effect<void, never, AtomRegistry.AtomRegistry>
82
+ readonly pushScroll: (scroll: ScrollSource.Scroll) => Effect.Effect<void, never, AtomRegistry.AtomRegistry>
77
83
  }> =>
78
84
  Effect.sync(() => {
79
85
  const intersections = Feeds.hub<Probe.Intersection>()
80
86
  const { scroll = STILL_SCROLL } = options
81
87
  const scrollAtom = Atom.make(scroll)
82
88
  return {
83
- layer: Layer.succeed(Probe.Probe, { ...fixed(options, scrollAtom), observeIntersection: () => intersections.feed }),
89
+ layer: Layer.mergeAll(Layer.succeed(Probe.Probe, { ...fixed(options), observeIntersection: () => intersections.feed }), scrollLayer(scrollAtom)),
84
90
  pushIntersection: (inView: boolean) => intersections.push(toIntersection(inView)),
85
- pushScroll: (next: Probe.Scroll) => AtomRegistry.AtomRegistry.use((registry) => Effect.sync(() => registry.set(scrollAtom, next))),
91
+ pushScroll: (next: ScrollSource.Scroll) => AtomRegistry.AtomRegistry.use((registry) => Effect.sync(() => registry.set(scrollAtom, next))),
86
92
  }
87
93
  })