@reckona/mreact-test-utils 0.0.16 → 0.0.18

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/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @reckona/mreact-test-utils
2
2
 
3
3
  `@reckona/mreact-test-utils` provides compact integration-test helpers for the
4
- mreact app router. It wraps temporary app directories, build artifacts, request
5
- helpers, and HTML assertions.
4
+ mreact app router and component-level reactive DOM tests. It wraps temporary app
5
+ directories, request helpers, reactive update flushing, and HTML assertions.
6
6
 
7
7
  ## Basic Usage
8
8
 
@@ -19,11 +19,36 @@ const response = await fixture.render("/");
19
19
  const html = await responseText(response);
20
20
  ```
21
21
 
22
+ For component-level tests, mount reactive DOM output directly and use `act()` to flush pending reactive work:
23
+
24
+ ```ts
25
+ import { bindText } from "@reckona/mreact-reactive-dom";
26
+ import { act, createCellMock, render } from "@reckona/mreact-test-utils";
27
+
28
+ const count = createCellMock(0);
29
+ const view = render(() => {
30
+ const text = document.createTextNode("");
31
+ bindText(text, () => count.get());
32
+ return text;
33
+ });
34
+
35
+ await act(() => {
36
+ count.set(1);
37
+ });
38
+
39
+ view.container.textContent;
40
+ // "1"
41
+ ```
42
+
22
43
  ## Core APIs
23
44
 
24
45
  - `createAppFixture()` creates a temporary app and `.mreact/` build output.
25
46
  - `fixture.render()` sends requests through the router using `Request` / `Response`.
26
47
  - `fixture.write()` adds or updates route files in the fixture app.
48
+ - `render()` mounts reactive DOM output into a container and returns `{ container, rerender, unmount }`.
49
+ - `act()` runs sync or async mutations and waits for reactive effects to settle.
50
+ - `flushReactive()` drains pending reactive effects without wrapping a mutation.
51
+ - `createCellMock()` and `createComputedMock()` create real reactive primitives for focused unit tests.
27
52
  - `responseText()` reads a response body as a string.
28
53
 
29
54
  ## Use Cases
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { type Cell, type ReadonlyCell } from "@reckona/mreact-reactive-core";
2
+ import { type RenderValue } from "@reckona/mreact-reactive-dom";
1
3
  import { type RenderAppRequestOptions } from "@reckona/mreact-router";
2
4
  export interface AppFixture {
3
5
  readonly appDir: string;
@@ -16,7 +18,21 @@ export interface DehydratedQueryState {
16
18
  updatedAt: number;
17
19
  }>;
18
20
  }
21
+ export interface ComponentRenderResult {
22
+ readonly container: HTMLElement;
23
+ rerender(value: ComponentRenderInput): void;
24
+ unmount(): void;
25
+ }
26
+ export type ComponentRenderInput = RenderValue | (() => RenderValue);
27
+ export interface ComponentRenderOptions {
28
+ container?: HTMLElement | undefined;
29
+ }
19
30
  export declare function createAppFixture(prefix?: string): Promise<AppFixture>;
20
31
  export declare function responseText(response: Response): Promise<string>;
32
+ export declare function render(value: ComponentRenderInput, options?: ComponentRenderOptions): ComponentRenderResult;
33
+ export declare function act<T>(fn: () => Promise<T> | T): Promise<T>;
34
+ export declare function flushReactive(): Promise<void>;
35
+ export declare function createCellMock<T>(initial: T): Cell<T>;
36
+ export declare function createComputedMock<T>(fn: () => T): ReadonlyCell<T>;
21
37
  export declare function readQueryState(html: string): DehydratedQueryState | undefined;
22
38
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoB,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAExF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvF,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtD;AAED,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,uBAAuB,EAAE,QAAQ,GAAG,SAAS,CAAC,GAAG;IAC1F,OAAO,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,OAAO,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;QAC7B,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;CACJ;AAKD,wBAAsB,gBAAgB,CAAC,MAAM,SAAuB,GAAG,OAAO,CAAC,UAAU,CAAC,CAyBzF;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAEtE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAQ7E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,IAAI,EACT,KAAK,YAAY,EAClB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAA4B,KAAK,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC1F,OAAO,EAAoB,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAExF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvF,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtD;AAED,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,uBAAuB,EAAE,QAAQ,GAAG,SAAS,CAAC,GAAG;IAC1F,OAAO,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,OAAO,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;QAC7B,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC5C,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG,CAAC,MAAM,WAAW,CAAC,CAAC;AAErE,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CACrC;AAKD,wBAAsB,gBAAgB,CAAC,MAAM,SAAuB,GAAG,OAAO,CAAC,UAAU,CAAC,CAyBzF;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAEtE;AAED,wBAAgB,MAAM,CACpB,KAAK,EAAE,oBAAoB,EAC3B,OAAO,GAAE,sBAA2B,GACnC,qBAAqB,CAgBvB;AAED,wBAAsB,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAIjE;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnD;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAErD;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAElE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAQ7E"}
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
2
2
  import { tmpdir } from "node:os";
3
3
  import { dirname, join } from "node:path";
4
+ import { batchAsync, cell, computed, } from "@reckona/mreact-reactive-core";
5
+ import { flushEffects } from "@reckona/mreact-reactive-core/testing";
6
+ import { createRoot } from "@reckona/mreact-reactive-dom";
4
7
  import { renderAppRequest } from "@reckona/mreact-router";
5
8
  const queryStateScriptPattern = /<script\b[^>]*\bid=(?:"__mreact_query_state"|'__mreact_query_state')[^>]*>([\s\S]*?)<\/script>/i;
6
9
  export async function createAppFixture(prefix = "mreact-app-fixture") {
@@ -29,6 +32,36 @@ export async function createAppFixture(prefix = "mreact-app-fixture") {
29
32
  export async function responseText(response) {
30
33
  return response.text();
31
34
  }
35
+ export function render(value, options = {}) {
36
+ const container = options.container ?? document.createElement("div");
37
+ let current = value;
38
+ let dispose = mountComponent(container, current);
39
+ return {
40
+ container,
41
+ rerender(next) {
42
+ dispose();
43
+ current = next;
44
+ dispose = mountComponent(container, current);
45
+ },
46
+ unmount() {
47
+ dispose();
48
+ },
49
+ };
50
+ }
51
+ export async function act(fn) {
52
+ const result = await batchAsync(fn);
53
+ await flushReactive();
54
+ return result;
55
+ }
56
+ export async function flushReactive() {
57
+ await flushEffects();
58
+ }
59
+ export function createCellMock(initial) {
60
+ return cell(initial);
61
+ }
62
+ export function createComputedMock(fn) {
63
+ return computed(fn);
64
+ }
32
65
  export function readQueryState(html) {
33
66
  const encoded = queryStateScriptPattern.exec(html)?.[1];
34
67
  if (encoded === undefined) {
@@ -44,4 +77,7 @@ function unescapeJsonForHtml(value) {
44
77
  .replaceAll("\\u2028", "\u2028")
45
78
  .replaceAll("\\u2029", "\u2029");
46
79
  }
80
+ function mountComponent(container, value) {
81
+ return createRoot(container, () => (typeof value === "function" ? value() : value));
82
+ }
47
83
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAgC,MAAM,wBAAwB,CAAC;AAsBxF,MAAM,uBAAuB,GAC3B,iGAAiG,CAAC;AAEpG,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAAM,GAAG,oBAAoB;IAClE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC;IAE3D,OAAO;QACL,MAAM;QACN,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,EAAE;YACvB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,mBAAmB,CAAC;YACrD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;YACpE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,CAAC;YAEzE,KAAK,OAAO,CAAC;YACb,KAAK,QAAQ,CAAC;YAEd,OAAO,gBAAgB,CAAC;gBACtB,GAAG,aAAa;gBAChB,MAAM;gBACN,OAAO;aACR,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ;YACxB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAChC,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAChD,MAAM,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAClC,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAkB;IACnD,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,OAAO,GAAG,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAExD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAyB,CAAC;AAC1E,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,OAAO,KAAK;SACT,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC;SAC1B,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC;SAC1B,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC;SAC1B,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC;SAC/B,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AACrC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reckona/mreact-test-utils",
3
- "version": "0.0.16",
3
+ "version": "0.0.18",
4
4
  "description": "Integration test helpers for mreact app-router applications.",
5
5
  "keywords": [
6
6
  "fixtures",
@@ -39,6 +39,8 @@
39
39
  "access": "public"
40
40
  },
41
41
  "dependencies": {
42
- "@reckona/mreact-router": "0.0.16"
42
+ "@reckona/mreact-reactive-core": "0.0.18",
43
+ "@reckona/mreact-reactive-dom": "0.0.18",
44
+ "@reckona/mreact-router": "0.0.18"
43
45
  }
44
46
  }