From d711c1fd27d55700d1ef63dfc3fac544509010a9 Mon Sep 17 00:00:00 2001 From: lojhan Date: Thu, 22 Oct 2026 13:05:53 +0000 Subject: [PATCH 1/3] fix: stabilize scoped React rendering across runtimes --- .github/workflows/ci_framework-majors.yml | 2 +- CHANGELOG.md | 37 +- README.md | 18 +- benchmark/REPORT.md | 49 +- benchmark/poku.config.js | 2 +- benchmark/results.json | 2 +- benchmark/run.mjs | 12 +- benchmark/tests/poku/concurrency.test.jsx | 2 +- benchmark/tests/poku/context.test.jsx | 2 +- benchmark/tests/poku/counter.test.jsx | 2 +- benchmark/tests/poku/hooks.test.jsx | 8 +- benchmark/tests/poku/lifecycle.test.jsx | 2 +- deno.json | 5 +- deno.lock | 647 +--------------------- package.json | 2 +- src/index.ts | 9 +- src/plugin-command.ts | 10 +- src/plugin-metrics.ts | 3 +- src/plugin-setup.ts | 1 - src/plugin-types.ts | 7 +- src/plugin.ts | 7 +- src/react-testing.ts | 222 ++++---- src/runtime-options.ts | 5 +- tests/plugin-command.test.ts | 2 +- tests/plugin-internals.test.ts | 6 +- tests/react-hooks.test.tsx | 18 + 26 files changed, 217 insertions(+), 865 deletions(-) delete mode 100644 src/plugin-setup.ts diff --git a/.github/workflows/ci_framework-majors.yml b/.github/workflows/ci_framework-majors.yml index 606c288..101d905 100644 --- a/.github/workflows/ci_framework-majors.yml +++ b/.github/workflows/ci_framework-majors.yml @@ -58,4 +58,4 @@ jobs: @types/react-dom@${{ matrix.react-major }} - name: 🔬 React ${{ matrix.react-major }} - run: npm test \ No newline at end of file + run: npm test diff --git a/CHANGELOG.md b/CHANGELOG.md index 20aced4..4caa764 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,65 +2,56 @@ ## [1.5.1](https://github.com/pokujs/react/compare/react-v1.5.0...react-v1.5.1) (2026-04-22) - ### Bug Fixes -* use --preload for Bun instead of --import ([#22](https://github.com/pokujs/react/issues/22)) ([bd4a8dc](https://github.com/pokujs/react/commit/bd4a8dc0babcb711982da1fed58769fa20009f10)) +- use --preload for Bun instead of --import ([#22](https://github.com/pokujs/react/issues/22)) ([bd4a8dc](https://github.com/pokujs/react/commit/bd4a8dc0babcb711982da1fed58769fa20009f10)) ## [1.5.0](https://github.com/pokujs/react/compare/react-v1.4.0...react-v1.5.0) (2026-04-20) - ### Features -* add concurrent scope isolation ([#19](https://github.com/pokujs/react/issues/19)) ([f8d7370](https://github.com/pokujs/react/commit/f8d73708d8adf8d32ec43d9eb94e54b43e969763)) +- add concurrent scope isolation ([#19](https://github.com/pokujs/react/issues/19)) ([f8d7370](https://github.com/pokujs/react/commit/f8d73708d8adf8d32ec43d9eb94e54b43e969763)) ## [1.4.0](https://github.com/pokujs/react/compare/react-v1.3.0...react-v1.4.0) (2026-04-05) - ### Features -* extract shared DOM/testing core to @pokujs/dom + benchmark suite ([#14](https://github.com/pokujs/react/issues/14)) ([cc60962](https://github.com/pokujs/react/commit/cc6096274a4b736d24031e5523668cf8320f956e)) -* optimize react testing runtime and add prettier ([#6](https://github.com/pokujs/react/issues/6)) ([424194b](https://github.com/pokujs/react/commit/424194b2c5bdc5f8c3d3c7a41bc91b50d51dd38c)) -* refactor plugin internals and stabilize isolation:none ([#8](https://github.com/pokujs/react/issues/8)) ([cd2d93d](https://github.com/pokujs/react/commit/cd2d93d41f913c0a581663a8f9e261c2c6574f27)) - +- extract shared DOM/testing core to @pokujs/dom + benchmark suite ([#14](https://github.com/pokujs/react/issues/14)) ([cc60962](https://github.com/pokujs/react/commit/cc6096274a4b736d24031e5523668cf8320f956e)) +- optimize react testing runtime and add prettier ([#6](https://github.com/pokujs/react/issues/6)) ([424194b](https://github.com/pokujs/react/commit/424194b2c5bdc5f8c3d3c7a41bc91b50d51dd38c)) +- refactor plugin internals and stabilize isolation:none ([#8](https://github.com/pokujs/react/issues/8)) ([cd2d93d](https://github.com/pokujs/react/commit/cd2d93d41f913c0a581663a8f9e261c2c6574f27)) ### Bug Fixes -* add missing @pokujs/dom dependency and update to ^1.0.1 ([5b82a9a](https://github.com/pokujs/react/commit/5b82a9ab26cc187e6edd0a0d76d74acd01d6ba2a)) -* add repository metadata required for npm provenance ([#4](https://github.com/pokujs/react/issues/4)) ([f20b16a](https://github.com/pokujs/react/commit/f20b16a9ab72bb957743c7739a926d0bfb851f68)) -* clarify Deno compatibility guidance in README ([#2](https://github.com/pokujs/react/issues/2)) ([ee28792](https://github.com/pokujs/react/commit/ee28792965b9cc9dacc8bee2fc96a5f84088f2d1)) -* update package repository URL ([#12](https://github.com/pokujs/react/issues/12)) ([3da8523](https://github.com/pokujs/react/commit/3da85234d70a7ec846a48ea7b066bf82e50763bb)) - +- add missing @pokujs/dom dependency and update to ^1.0.1 ([5b82a9a](https://github.com/pokujs/react/commit/5b82a9ab26cc187e6edd0a0d76d74acd01d6ba2a)) +- add repository metadata required for npm provenance ([#4](https://github.com/pokujs/react/issues/4)) ([f20b16a](https://github.com/pokujs/react/commit/f20b16a9ab72bb957743c7739a926d0bfb851f68)) +- clarify Deno compatibility guidance in README ([#2](https://github.com/pokujs/react/issues/2)) ([ee28792](https://github.com/pokujs/react/commit/ee28792965b9cc9dacc8bee2fc96a5f84088f2d1)) +- update package repository URL ([#12](https://github.com/pokujs/react/issues/12)) ([3da8523](https://github.com/pokujs/react/commit/3da85234d70a7ec846a48ea7b066bf82e50763bb)) ### Performance Improvements -* replace manual fireEvent loop with shared wrapFireEventMethods ([#16](https://github.com/pokujs/react/issues/16)) ([1f86e4d](https://github.com/pokujs/react/commit/1f86e4db4d0e20dab72149131ddbb248d628c57d)) +- replace manual fireEvent loop with shared wrapFireEventMethods ([#16](https://github.com/pokujs/react/issues/16)) ([1f86e4d](https://github.com/pokujs/react/commit/1f86e4db4d0e20dab72149131ddbb248d628c57d)) ## [1.3.0](https://github.com/pokujs/react/compare/v1.2.1...v1.3.0) (2026-04-05) - ### Features -* extract shared DOM/testing core to @pokujs/dom + benchmark suite ([#14](https://github.com/pokujs/react/issues/14)) ([cc60962](https://github.com/pokujs/react/commit/cc6096274a4b736d24031e5523668cf8320f956e)) - +- extract shared DOM/testing core to @pokujs/dom + benchmark suite ([#14](https://github.com/pokujs/react/issues/14)) ([cc60962](https://github.com/pokujs/react/commit/cc6096274a4b736d24031e5523668cf8320f956e)) ### Bug Fixes -* add missing @pokujs/dom dependency and update to ^1.0.1 ([5b82a9a](https://github.com/pokujs/react/commit/5b82a9ab26cc187e6edd0a0d76d74acd01d6ba2a)) +- add missing @pokujs/dom dependency and update to ^1.0.1 ([5b82a9a](https://github.com/pokujs/react/commit/5b82a9ab26cc187e6edd0a0d76d74acd01d6ba2a)) ## [1.2.1](https://github.com/pokujs/react/compare/v1.2.0...v1.2.1) (2026-04-03) - ### Bug Fixes -* update package repository URL ([#12](https://github.com/pokujs/react/issues/12)) ([3da8523](https://github.com/pokujs/react/commit/3da85234d70a7ec846a48ea7b066bf82e50763bb)) +- update package repository URL ([#12](https://github.com/pokujs/react/issues/12)) ([3da8523](https://github.com/pokujs/react/commit/3da85234d70a7ec846a48ea7b066bf82e50763bb)) ## [1.2.0](https://github.com/Lojhan/poku-react-testing/compare/v1.1.0...v1.2.0) (2026-04-01) - ### Features -* refactor plugin internals and stabilize isolation:none ([#8](https://github.com/Lojhan/poku-react-testing/issues/8)) ([cd2d93d](https://github.com/Lojhan/poku-react-testing/commit/cd2d93d41f913c0a581663a8f9e261c2c6574f27)) +- refactor plugin internals and stabilize isolation:none ([#8](https://github.com/Lojhan/poku-react-testing/issues/8)) ([cd2d93d](https://github.com/Lojhan/poku-react-testing/commit/cd2d93d41f913c0a581663a8f9e261c2c6574f27)) ## [1.1.0](https://github.com/Lojhan/poku-react-testing/compare/v1.0.1...v1.1.0) (2026-03-31) diff --git a/README.md b/README.md index 0ad27b3..1032e7e 100644 --- a/README.md +++ b/README.md @@ -82,8 +82,8 @@ npm i -D jsdom ```js // poku.config.js -import { defineConfig } from 'poku'; import { reactTestingPlugin } from '@pokujs/react/plugin'; +import { defineConfig } from 'poku'; export default defineConfig({ plugins: [ @@ -98,8 +98,8 @@ export default defineConfig({ ```tsx // tests/my-component.test.tsx -import { afterEach, assert, test } from 'poku'; import { cleanup, render, screen } from '@pokujs/react'; +import { afterEach, assert, test } from 'poku'; afterEach(cleanup); @@ -115,13 +115,13 @@ test('renders a heading', () => { ### Library Support -| Package | Supported range | -| ------- | :-------------: | -| `react` | `>=18` | -| `react-dom` | `>=18` | -| `poku` | `>=4.1.0` | -| `happy-dom` | `>=20` | -| `jsdom` | `>=22` | +| Package | Supported range | +| ----------- | :-------------: | +| `react` | `>=18` | +| `react-dom` | `>=18` | +| `poku` | `>=4.1.0` | +| `happy-dom` | `>=20` | +| `jsdom` | `>=22` | ### Isolation Support diff --git a/benchmark/REPORT.md b/benchmark/REPORT.md index 35acef2..0c368bc 100644 --- a/benchmark/REPORT.md +++ b/benchmark/REPORT.md @@ -4,42 +4,42 @@ ## Environment -| Property | Value | -|---|---| -| Node.js | v22.5.1 | -| Platform | darwin 25.4.0 | -| CPU | Apple M3 Pro | -| CPU Cores | 12 | -| Total RAM | 18.0 GB | -| Runs/scenario | 7 (trim ±1) | +| Property | Value | +| ------------- | ------------- | +| Node.js | v22.5.1 | +| Platform | darwin 25.4.0 | +| CPU | Apple M3 Pro | +| CPU Cores | 12 | +| Total RAM | 18.0 GB | +| Runs/scenario | 7 (trim ±1) | ## Scenarios Each scenario runs the **same 9 React tests** across 5 test files: -| Test File | Tests | -|---|---| -| 'counter.test.jsx' | 1 — stateful counter, event interaction | -| 'hooks.test.jsx' | 2 — custom hook harness + `renderHook` | -| 'lifecycle.test.jsx' | 2 — `rerender`, `unmount` + effect cleanup | -| 'context.test.jsx' | 1 — `createContext` + wrapper injection | -| 'concurrency.test.jsx' | 2 — React 19 `use()` + `useTransition` | +| Test File | Tests | +| ---------------------- | ------------------------------------------ | +| 'counter.test.jsx' | 1 — stateful counter, event interaction | +| 'hooks.test.jsx' | 2 — custom hook harness + `renderHook` | +| 'lifecycle.test.jsx' | 2 — `rerender`, `unmount` + effect cleanup | +| 'context.test.jsx' | 1 — `createContext` + wrapper injection | +| 'concurrency.test.jsx' | 2 — React 19 `use()` + `useTransition` | ### Frameworks under test -| Combination | DOM layer | Assertion style | -|---|---|---| -| poku + @pokujs/react | happy-dom | `assert.strictEqual` | -| poku + @pokujs/react | jsdom | `assert.strictEqual` | -| jest 29 + @testing-library/react | jsdom (jest-environment-jsdom) | `expect().toBe()` | -| vitest 3 + @testing-library/react | jsdom | `expect().toBe()` | -| vitest 3 + @testing-library/react | happy-dom | `expect().toBe()` | +| Combination | DOM layer | Assertion style | +| --------------------------------- | ------------------------------ | -------------------- | +| poku + @pokujs/react | happy-dom | `assert.strictEqual` | +| poku + @pokujs/react | jsdom | `assert.strictEqual` | +| jest 29 + @testing-library/react | jsdom (jest-environment-jsdom) | `expect().toBe()` | +| vitest 3 + @testing-library/react | jsdom | `expect().toBe()` | +| vitest 3 + @testing-library/react | happy-dom | `expect().toBe()` | ## Results | Scenario | Mean | Min | Max | Stdev | Peak RSS | vs poku+happy-dom | -|--------------------|--------|--------|--------|--------|----------|-------------------| -| poku + happy-dom | 0.115s | 0.112s | 0.109s | 0.004s | 127.4 MB | *(baseline)* | +| ------------------ | ------ | ------ | ------ | ------ | -------- | ----------------- | +| poku + happy-dom | 0.115s | 0.112s | 0.109s | 0.004s | 127.4 MB | _(baseline)_ | | poku + jsdom | 0.294s | 0.280s | 0.299s | 0.007s | 172.1 MB | +157% | | jest + jsdom | 0.843s | 0.768s | 0.879s | 0.041s | 198.8 MB | +636% | | vitest + jsdom | 0.968s | 0.951s | 0.986s | 0.011s | 147.8 MB | +745% | @@ -101,6 +101,7 @@ processes with minimal bootstrap — means cold-start overhead is proportional t files, not to the framework's own initialization. **jest** carries the heaviest startup cost due to: + 1. Babel transformation of every TSX file on first run (no persistent cache in this benchmark) 2. 'jest-worker' process pool initialisation 3. JSDOM environment setup per test file diff --git a/benchmark/poku.config.js b/benchmark/poku.config.js index afca985..5e09369 100644 --- a/benchmark/poku.config.js +++ b/benchmark/poku.config.js @@ -1,5 +1,5 @@ -import { defineConfig } from 'poku'; import { reactTestingPlugin } from '@pokujs/react/plugin'; +import { defineConfig } from 'poku'; const dom = process.env.POKU_REACT_TEST_DOM; if (!dom) { diff --git a/benchmark/results.json b/benchmark/results.json index f05480b..3889a10 100644 --- a/benchmark/results.json +++ b/benchmark/results.json @@ -78,4 +78,4 @@ "failures": 0 } ] -} \ No newline at end of file +} diff --git a/benchmark/run.mjs b/benchmark/run.mjs index d34fb62..ac905fa 100644 --- a/benchmark/run.mjs +++ b/benchmark/run.mjs @@ -121,9 +121,7 @@ function runOnce(args, cwd, extraEnv = {}) { } const plainStdout = (result.stdout ?? '').replace(/\u001b\[[0-9;]*m/g, ''); - const reportedDurationMatch = plainStdout.match( - /Duration\s+›\s+([\d.]+)ms/ - ); + const reportedDurationMatch = plainStdout.match(/Duration\s+›\s+([\d.]+)ms/); const reportedDurationMs = reportedDurationMatch ? Number(reportedDurationMatch[1]) : null; @@ -143,13 +141,7 @@ function runOnce(args, cwd, extraEnv = {}) { // ─── scenario runner ──────────────────────────────────────────────────────── -function benchmarkScenario( - label, - args, - cwd, - extraEnv = {}, - options = {} -) { +function benchmarkScenario(label, args, cwd, extraEnv = {}, options = {}) { process.stdout.write(` ${pad(label, 36)}`); const measurements = []; diff --git a/benchmark/tests/poku/concurrency.test.jsx b/benchmark/tests/poku/concurrency.test.jsx index dea6f4a..e662f66 100644 --- a/benchmark/tests/poku/concurrency.test.jsx +++ b/benchmark/tests/poku/concurrency.test.jsx @@ -1,5 +1,5 @@ -import { afterEach, assert, test } from 'poku'; import { cleanup, fireEvent, render, screen } from '@pokujs/react'; +import { afterEach, assert, test } from 'poku'; import React, { Suspense, use, useState, useTransition } from 'react'; afterEach(cleanup); diff --git a/benchmark/tests/poku/context.test.jsx b/benchmark/tests/poku/context.test.jsx index b89e70e..74a9dde 100644 --- a/benchmark/tests/poku/context.test.jsx +++ b/benchmark/tests/poku/context.test.jsx @@ -1,5 +1,5 @@ -import { afterEach, assert, test } from 'poku'; import { cleanup, render, screen } from '@pokujs/react'; +import { afterEach, assert, test } from 'poku'; import React, { createContext, useContext } from 'react'; afterEach(cleanup); diff --git a/benchmark/tests/poku/counter.test.jsx b/benchmark/tests/poku/counter.test.jsx index 6188b4d..08a30ac 100644 --- a/benchmark/tests/poku/counter.test.jsx +++ b/benchmark/tests/poku/counter.test.jsx @@ -1,5 +1,5 @@ -import { afterEach, assert, test } from 'poku'; import { cleanup, fireEvent, render, screen } from '@pokujs/react'; +import { afterEach, assert, test } from 'poku'; import React, { useState } from 'react'; afterEach(cleanup); diff --git a/benchmark/tests/poku/hooks.test.jsx b/benchmark/tests/poku/hooks.test.jsx index 47104a3..2fe8b89 100644 --- a/benchmark/tests/poku/hooks.test.jsx +++ b/benchmark/tests/poku/hooks.test.jsx @@ -1,11 +1,5 @@ +import { cleanup, fireEvent, render, renderHook, screen } from '@pokujs/react'; import { afterEach, assert, test } from 'poku'; -import { - cleanup, - fireEvent, - render, - renderHook, - screen, -} from '@pokujs/react'; import React, { useMemo, useState } from 'react'; afterEach(cleanup); diff --git a/benchmark/tests/poku/lifecycle.test.jsx b/benchmark/tests/poku/lifecycle.test.jsx index f53598f..ba1700f 100644 --- a/benchmark/tests/poku/lifecycle.test.jsx +++ b/benchmark/tests/poku/lifecycle.test.jsx @@ -1,5 +1,5 @@ -import { afterEach, assert, test } from 'poku'; import { cleanup, render, screen } from '@pokujs/react'; +import { afterEach, assert, test } from 'poku'; import React, { useEffect } from 'react'; afterEach(cleanup); diff --git a/deno.json b/deno.json index 858ca79..fde86a1 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,3 @@ { - "nodeModulesDir": "auto", - "imports": { - "@pokujs/dom": "npm:@pokujs/dom@^1.2.0" - } + "nodeModulesDir": "manual" } diff --git a/deno.lock b/deno.lock index 87d2076..5320d71 100644 --- a/deno.lock +++ b/deno.lock @@ -1,37 +1,16 @@ { "version": "5", "specifiers": { - "npm:@happy-dom/global-registrator@^20.8.9": "20.8.9", "npm:@ianvs/prettier-plugin-sort-imports@^4.7.0": "4.7.1_prettier@3.8.1", - "npm:@pokujs/dom@^1.2.0": "1.2.0_happy-dom@20.8.9_jsdom@26.1.0_poku@4.2.0", - "npm:@testing-library/dom@^10.4.1": "10.4.1", - "npm:@types/jsdom@^28.0.1": "28.0.1", - "npm:@types/node@^25.5.0": "25.5.2", "npm:@types/react-dom@^19.2.3": "19.2.3_@types+react@19.2.14", "npm:@types/react@^19.2.14": "19.2.14", "npm:cross-env@^10.1.0": "10.1.0", - "npm:happy-dom@^20.8.9": "20.8.9", - "npm:jsdom@^26.1.0": "26.1.0", - "npm:poku@*": "4.2.0", "npm:prettier@^3.6.2": "3.8.1", "npm:react-dom@^19.2.5": "19.2.5_react@19.2.5", "npm:react@^19.2.5": "19.2.5", - "npm:rimraf@^6.0.1": "6.1.3", - "npm:tsup@^8.5.0": "8.5.1_typescript@6.0.2_esbuild@0.27.7_tsx@4.21.0", - "npm:tsx@^4.21.0": "4.21.0", - "npm:typescript@^6.0.2": "6.0.2" + "npm:rimraf@^6.0.1": "6.1.3" }, "npm": { - "@asamuzakjp/css-color@3.2.0_@csstools+css-parser-algorithms@3.0.5__@csstools+css-tokenizer@3.0.4_@csstools+css-tokenizer@3.0.4": { - "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", - "dependencies": [ - "@csstools/css-calc", - "@csstools/css-color-parser", - "@csstools/css-parser-algorithms", - "@csstools/css-tokenizer", - "lru-cache@10.4.3" - ] - }, "@babel/code-frame@7.29.0": { "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dependencies": [ @@ -66,9 +45,6 @@ ], "bin": true }, - "@babel/runtime@7.29.2": { - "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==" - }, "@babel/template@7.28.6": { "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dependencies": [ @@ -96,34 +72,6 @@ "@babel/helper-validator-identifier" ] }, - "@csstools/color-helpers@5.1.0": { - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==" - }, - "@csstools/css-calc@2.1.4_@csstools+css-parser-algorithms@3.0.5__@csstools+css-tokenizer@3.0.4_@csstools+css-tokenizer@3.0.4": { - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "dependencies": [ - "@csstools/css-parser-algorithms", - "@csstools/css-tokenizer" - ] - }, - "@csstools/css-color-parser@3.1.0_@csstools+css-parser-algorithms@3.0.5__@csstools+css-tokenizer@3.0.4_@csstools+css-tokenizer@3.0.4": { - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", - "dependencies": [ - "@csstools/color-helpers", - "@csstools/css-calc", - "@csstools/css-parser-algorithms", - "@csstools/css-tokenizer" - ] - }, - "@csstools/css-parser-algorithms@3.0.5_@csstools+css-tokenizer@3.0.4": { - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", - "dependencies": [ - "@csstools/css-tokenizer" - ] - }, - "@csstools/css-tokenizer@3.0.4": { - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==" - }, "@epic-web/invariant@1.0.0": { "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==" }, @@ -257,13 +205,6 @@ "os": ["win32"], "cpu": ["x64"] }, - "@happy-dom/global-registrator@20.8.9": { - "integrity": "sha512-DtZeRRHY9A/bisTJziUBBPrdnPui7+R185G/hzi6/Boymhqh7/wi53AY+IvQHS1+7OPaqfO/1XNpngNwthLz+A==", - "dependencies": [ - "@types/node@25.5.2", - "happy-dom" - ] - }, "@ianvs/prettier-plugin-sort-imports@4.7.1_prettier@3.8.1": { "integrity": "sha512-jmTNYGlg95tlsoG3JLCcuC4BrFELJtLirLAkQW/71lXSyOhVt/Xj7xWbbGcuVbNq1gwWgSyMrPjJc9Z30hynVw==", "dependencies": [ @@ -295,19 +236,6 @@ "@jridgewell/sourcemap-codec" ] }, - "@pokujs/dom@1.2.0_happy-dom@20.8.9_jsdom@26.1.0_poku@4.2.0": { - "integrity": "sha512-RafJKjW+7skIPF6dl2GLV7nMnvPJzIkWd6nNehJOq3m82OahEDWWBfeWvX/PumZj9liq11/JCMsifUvywfJhAQ==", - "dependencies": [ - "@testing-library/dom", - "happy-dom", - "jsdom", - "poku" - ], - "optionalPeers": [ - "happy-dom", - "jsdom" - ] - }, "@rollup/rollup-android-arm-eabi@4.60.1": { "integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==", "os": ["android"], @@ -433,46 +361,6 @@ "os": ["win32"], "cpu": ["x64"] }, - "@testing-library/dom@10.4.1": { - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", - "dependencies": [ - "@babel/code-frame", - "@babel/runtime", - "@types/aria-query", - "aria-query", - "dom-accessibility-api", - "lz-string", - "picocolors", - "pretty-format" - ] - }, - "@types/aria-query@5.0.4": { - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==" - }, - "@types/estree@1.0.8": { - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==" - }, - "@types/jsdom@28.0.1": { - "integrity": "sha512-GJq2QE4TAZ5ajSoCasn5DOFm8u1mI3tIFvM5tIq3W5U/RTB6gsHwc6Yhpl91X9VSDOUVblgXmG+2+sSvFQrdlw==", - "dependencies": [ - "@types/node@22.15.15", - "@types/tough-cookie", - "parse5", - "undici-types@7.24.7" - ] - }, - "@types/node@22.15.15": { - "integrity": "sha512-R5muMcZob3/Jjchn5LcO8jdKwSCbzqmPB6ruBxMcf9kbxtniZHP327s6C37iOfuw8mbKK3cAQa7sEl7afLrQ8A==", - "dependencies": [ - "undici-types@6.21.0" - ] - }, - "@types/node@25.5.2": { - "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==", - "dependencies": [ - "undici-types@7.18.2" - ] - }, "@types/react-dom@19.2.3_@types+react@19.2.14": { "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dependencies": [ @@ -485,40 +373,6 @@ "csstype" ] }, - "@types/tough-cookie@4.0.5": { - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==" - }, - "@types/whatwg-mimetype@3.0.2": { - "integrity": "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==" - }, - "@types/ws@8.18.1": { - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "dependencies": [ - "@types/node@22.15.15" - ] - }, - "acorn@8.16.0": { - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "bin": true - }, - "agent-base@7.1.4": { - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==" - }, - "ansi-regex@5.0.1": { - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles@5.2.0": { - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" - }, - "any-promise@1.3.0": { - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" - }, - "aria-query@5.3.0": { - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dependencies": [ - "dequal" - ] - }, "balanced-match@4.0.4": { "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==" }, @@ -528,31 +382,6 @@ "balanced-match" ] }, - "bundle-require@5.1.0_esbuild@0.27.7": { - "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==", - "dependencies": [ - "esbuild", - "load-tsconfig" - ] - }, - "cac@6.7.14": { - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==" - }, - "chokidar@4.0.3": { - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dependencies": [ - "readdirp" - ] - }, - "commander@4.1.1": { - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" - }, - "confbox@0.1.8": { - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==" - }, - "consola@3.4.2": { - "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==" - }, "cross-env@10.1.0": { "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==", "dependencies": [ @@ -569,105 +398,20 @@ "which" ] }, - "cssstyle@4.6.0": { - "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", - "dependencies": [ - "@asamuzakjp/css-color", - "rrweb-cssom" - ] - }, "csstype@3.2.3": { "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" }, - "data-urls@5.0.0": { - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", - "dependencies": [ - "whatwg-mimetype@4.0.0", - "whatwg-url" - ] - }, "debug@4.4.3": { "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dependencies": [ "ms" ] }, - "decimal.js@10.6.0": { - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==" - }, - "dequal@2.0.3": { - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" - }, - "dom-accessibility-api@0.5.16": { - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==" - }, - "entities@6.0.1": { - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==" - }, - "entities@7.0.1": { - "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==" - }, - "esbuild@0.27.7": { - "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", - "optionalDependencies": [ - "@esbuild/aix-ppc64", - "@esbuild/android-arm", - "@esbuild/android-arm64", - "@esbuild/android-x64", - "@esbuild/darwin-arm64", - "@esbuild/darwin-x64", - "@esbuild/freebsd-arm64", - "@esbuild/freebsd-x64", - "@esbuild/linux-arm", - "@esbuild/linux-arm64", - "@esbuild/linux-ia32", - "@esbuild/linux-loong64", - "@esbuild/linux-mips64el", - "@esbuild/linux-ppc64", - "@esbuild/linux-riscv64", - "@esbuild/linux-s390x", - "@esbuild/linux-x64", - "@esbuild/netbsd-arm64", - "@esbuild/netbsd-x64", - "@esbuild/openbsd-arm64", - "@esbuild/openbsd-x64", - "@esbuild/openharmony-arm64", - "@esbuild/sunos-x64", - "@esbuild/win32-arm64", - "@esbuild/win32-ia32", - "@esbuild/win32-x64" - ], - "scripts": true, - "bin": true - }, - "fdir@6.5.0_picomatch@4.0.4": { - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dependencies": [ - "picomatch" - ], - "optionalPeers": [ - "picomatch" - ] - }, - "fix-dts-default-cjs-exports@1.0.1": { - "integrity": "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==", - "dependencies": [ - "magic-string", - "mlly", - "rollup" - ] - }, "fsevents@2.3.3": { "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "os": ["darwin"], "scripts": true }, - "get-tsconfig@4.13.7": { - "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", - "dependencies": [ - "resolve-pkg-maps" - ] - }, "glob@13.0.6": { "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dependencies": [ @@ -676,109 +420,19 @@ "path-scurry" ] }, - "happy-dom@20.8.9": { - "integrity": "sha512-Tz23LR9T9jOGVZm2x1EPdXqwA37G/owYMxRwU0E4miurAtFsPMQ1d2Jc2okUaSjZqAFz2oEn3FLXC5a0a+siyA==", - "dependencies": [ - "@types/node@25.5.2", - "@types/whatwg-mimetype", - "@types/ws", - "entities@7.0.1", - "whatwg-mimetype@3.0.0", - "ws" - ] - }, - "html-encoding-sniffer@4.0.0": { - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", - "dependencies": [ - "whatwg-encoding" - ] - }, - "http-proxy-agent@7.0.2": { - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dependencies": [ - "agent-base", - "debug" - ] - }, - "https-proxy-agent@7.0.6": { - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dependencies": [ - "agent-base", - "debug" - ] - }, - "iconv-lite@0.6.3": { - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": [ - "safer-buffer" - ] - }, - "is-potential-custom-element-name@1.0.1": { - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" - }, "isexe@2.0.0": { "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, - "joycon@3.1.1": { - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==" - }, "js-tokens@4.0.0": { "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, - "jsdom@26.1.0": { - "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", - "dependencies": [ - "cssstyle", - "data-urls", - "decimal.js", - "html-encoding-sniffer", - "http-proxy-agent", - "https-proxy-agent", - "is-potential-custom-element-name", - "nwsapi", - "parse5", - "rrweb-cssom", - "saxes", - "symbol-tree", - "tough-cookie", - "w3c-xmlserializer", - "webidl-conversions", - "whatwg-encoding", - "whatwg-mimetype@4.0.0", - "whatwg-url", - "ws", - "xml-name-validator" - ] - }, "jsesc@3.1.0": { "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "bin": true }, - "lilconfig@3.1.3": { - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==" - }, - "lines-and-columns@1.2.4": { - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "load-tsconfig@0.2.5": { - "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==" - }, - "lru-cache@10.4.3": { - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" - }, "lru-cache@11.2.7": { "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==" }, - "lz-string@1.5.0": { - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "bin": true - }, - "magic-string@0.30.21": { - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dependencies": [ - "@jridgewell/sourcemap-codec" - ] - }, "minimatch@10.2.5": { "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dependencies": [ @@ -788,100 +442,29 @@ "minipass@7.1.3": { "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==" }, - "mlly@1.8.2": { - "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", - "dependencies": [ - "acorn", - "pathe", - "pkg-types", - "ufo" - ] - }, "ms@2.1.3": { "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "mz@2.7.0": { - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dependencies": [ - "any-promise", - "object-assign", - "thenify-all" - ] - }, - "nwsapi@2.2.23": { - "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==" - }, - "object-assign@4.1.1": { - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" - }, "package-json-from-dist@1.0.1": { "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" }, - "parse5@7.3.0": { - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "dependencies": [ - "entities@6.0.1" - ] - }, "path-key@3.1.1": { "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, "path-scurry@2.0.2": { "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "dependencies": [ - "lru-cache@11.2.7", + "lru-cache", "minipass" ] }, - "pathe@2.0.3": { - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==" - }, "picocolors@1.1.1": { "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, - "picomatch@4.0.4": { - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==" - }, - "pirates@4.0.7": { - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==" - }, - "pkg-types@1.3.1": { - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", - "dependencies": [ - "confbox", - "mlly", - "pathe" - ] - }, - "poku@4.2.0": { - "integrity": "sha512-GygMGFGgEJ9kfs6Z+QPg/ODs9OF3oGHN8+hYIxtBox3pwYISO+Vu660vH1e+YzjpGoaoy2o5y6YwE1tX5yZx3Q==", - "bin": true - }, - "postcss-load-config@6.0.1_tsx@4.21.0": { - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dependencies": [ - "lilconfig", - "tsx" - ], - "optionalPeers": [ - "tsx" - ] - }, "prettier@3.8.1": { "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "bin": true }, - "pretty-format@27.5.1": { - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dependencies": [ - "ansi-regex", - "ansi-styles", - "react-is" - ] - }, - "punycode@2.3.1": { - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" - }, "react-dom@19.2.5_react@19.2.5": { "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==", "dependencies": [ @@ -889,21 +472,9 @@ "scheduler" ] }, - "react-is@17.0.2": { - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - }, "react@19.2.5": { "integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==" }, - "readdirp@4.1.2": { - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==" - }, - "resolve-from@5.0.0": { - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" - }, - "resolve-pkg-maps@1.0.0": { - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==" - }, "rimraf@6.1.3": { "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", "dependencies": [ @@ -912,53 +483,6 @@ ], "bin": true }, - "rollup@4.60.1": { - "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", - "dependencies": [ - "@types/estree" - ], - "optionalDependencies": [ - "@rollup/rollup-android-arm-eabi", - "@rollup/rollup-android-arm64", - "@rollup/rollup-darwin-arm64", - "@rollup/rollup-darwin-x64", - "@rollup/rollup-freebsd-arm64", - "@rollup/rollup-freebsd-x64", - "@rollup/rollup-linux-arm-gnueabihf", - "@rollup/rollup-linux-arm-musleabihf", - "@rollup/rollup-linux-arm64-gnu", - "@rollup/rollup-linux-arm64-musl", - "@rollup/rollup-linux-loong64-gnu", - "@rollup/rollup-linux-loong64-musl", - "@rollup/rollup-linux-ppc64-gnu", - "@rollup/rollup-linux-ppc64-musl", - "@rollup/rollup-linux-riscv64-gnu", - "@rollup/rollup-linux-riscv64-musl", - "@rollup/rollup-linux-s390x-gnu", - "@rollup/rollup-linux-x64-gnu", - "@rollup/rollup-linux-x64-musl", - "@rollup/rollup-openbsd-x64", - "@rollup/rollup-openharmony-arm64", - "@rollup/rollup-win32-arm64-msvc", - "@rollup/rollup-win32-ia32-msvc", - "@rollup/rollup-win32-x64-gnu", - "@rollup/rollup-win32-x64-msvc", - "fsevents" - ], - "bin": true - }, - "rrweb-cssom@0.8.0": { - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==" - }, - "safer-buffer@2.1.2": { - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "saxes@6.0.0": { - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dependencies": [ - "xmlchars" - ] - }, "scheduler@0.27.0": { "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==" }, @@ -975,184 +499,20 @@ "shebang-regex@3.0.0": { "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" }, - "source-map@0.7.6": { - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==" - }, - "sucrase@3.35.1": { - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "dependencies": [ - "@jridgewell/gen-mapping", - "commander", - "lines-and-columns", - "mz", - "pirates", - "tinyglobby", - "ts-interface-checker" - ], - "bin": true - }, - "symbol-tree@3.2.4": { - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" - }, - "thenify-all@1.6.0": { - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dependencies": [ - "thenify" - ] - }, - "thenify@3.3.1": { - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dependencies": [ - "any-promise" - ] - }, - "tinyexec@0.3.2": { - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==" - }, - "tinyglobby@0.2.15_picomatch@4.0.4": { - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dependencies": [ - "fdir", - "picomatch" - ] - }, - "tldts-core@6.1.86": { - "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==" - }, - "tldts@6.1.86": { - "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", - "dependencies": [ - "tldts-core" - ], - "bin": true - }, - "tough-cookie@5.1.2": { - "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", - "dependencies": [ - "tldts" - ] - }, - "tr46@5.1.1": { - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", - "dependencies": [ - "punycode" - ] - }, - "tree-kill@1.2.2": { - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "bin": true - }, - "ts-interface-checker@0.1.13": { - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" - }, - "tsup@8.5.1_typescript@6.0.2_esbuild@0.27.7_tsx@4.21.0": { - "integrity": "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==", - "dependencies": [ - "bundle-require", - "cac", - "chokidar", - "consola", - "debug", - "esbuild", - "fix-dts-default-cjs-exports", - "joycon", - "picocolors", - "postcss-load-config", - "resolve-from", - "rollup", - "source-map", - "sucrase", - "tinyexec", - "tinyglobby", - "tree-kill", - "typescript" - ], - "optionalPeers": [ - "typescript" - ], - "bin": true - }, - "tsx@4.21.0": { - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", - "dependencies": [ - "esbuild", - "get-tsconfig" - ], - "optionalDependencies": [ - "fsevents" - ], - "bin": true - }, - "typescript@6.0.2": { - "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", - "bin": true - }, - "ufo@1.6.3": { - "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==" - }, - "undici-types@6.21.0": { - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" - }, - "undici-types@7.18.2": { - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==" - }, - "undici-types@7.24.7": { - "integrity": "sha512-XA+gOBkzYD3C74sZowtCLTpgtaCdqZhqCvR6y9LXvrKTt/IVU6bz49T4D+BPi475scshCCkb0IklJRw6T1ZlgQ==" - }, - "w3c-xmlserializer@5.0.0": { - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "dependencies": [ - "xml-name-validator" - ] - }, - "webidl-conversions@7.0.0": { - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" - }, - "whatwg-encoding@3.1.1": { - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "dependencies": [ - "iconv-lite" - ], - "deprecated": true - }, - "whatwg-mimetype@3.0.0": { - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==" - }, - "whatwg-mimetype@4.0.0": { - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==" - }, - "whatwg-url@14.2.0": { - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", - "dependencies": [ - "tr46", - "webidl-conversions" - ] - }, "which@2.0.2": { "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dependencies": [ "isexe" ], "bin": true - }, - "ws@8.20.0": { - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==" - }, - "xml-name-validator@5.0.0": { - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==" - }, - "xmlchars@2.2.0": { - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" } }, "workspace": { - "dependencies": [ - "npm:@pokujs/dom@^1.2.0" - ], "packageJson": { "dependencies": [ "npm:@happy-dom/global-registrator@^20.8.9", "npm:@ianvs/prettier-plugin-sort-imports@^4.7.0", + "npm:@pokujs/dom@^1.3.0", "npm:@testing-library/dom@^10.4.1", "npm:@types/jsdom@^28.0.1", "npm:@types/node@^25.5.0", @@ -1161,6 +521,7 @@ "npm:cross-env@^10.1.0", "npm:happy-dom@^20.8.9", "npm:jsdom@^26.1.0", + "npm:poku@^4.3.0", "npm:prettier@^3.6.2", "npm:react-dom@^19.2.5", "npm:react@^19.2.5", diff --git a/package.json b/package.json index a736c6d..28325a3 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "test:major:19": "npm install --no-save react@19 react-dom@19 @types/react@19 @types/react-dom@19 && npm test", "test:multi-major": "npm run test:major:18 && npm run test:major:19", "clean": "rimraf dist", - "build": "tsup src/index.ts src/plugin.ts src/react-testing.ts src/dom-setup-happy.ts src/dom-setup-jsdom.ts --format esm --dts --target node20 --sourcemap --clean --tsconfig tsconfig.tsup.json", + "build": "tsup src/index.ts src/plugin.ts src/react-testing.ts src/dom-setup-happy.ts src/dom-setup-jsdom.ts --format esm --dts --target node20 --sourcemap --clean --no-splitting --no-config --tsconfig tsconfig.tsup.json", "typecheck": "tsc -p tsconfig.build.json --noEmit", "format": "prettier --write .", "format:check": "prettier --check .", diff --git a/src/index.ts b/src/index.ts index 1376b6e..7f16a23 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,5 +14,12 @@ export { render, renderHook, screen, + waitFor, } from './react-testing.ts'; -export * from './react-testing.ts'; +export type { + RenderHookOptions, + RenderHookResult, + RenderOptions, + RenderResult, +} from './react-testing.ts'; +export * from '@testing-library/dom'; diff --git a/src/plugin-command.ts b/src/plugin-command.ts index a1c6e1d..d20d9da 100644 --- a/src/plugin-command.ts +++ b/src/plugin-command.ts @@ -1,13 +1,13 @@ +import type { BuildRunnerCommandInput } from '@pokujs/dom'; import type { ReactDomAdapter } from './plugin-types.ts'; +import { existsSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; import { buildRunnerCommand as buildCoreRunnerCommand, canHandleRuntime, createDomSetupPathResolver, - type BuildRunnerCommandInput, } from '@pokujs/dom'; -import { dirname, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { existsSync } from 'node:fs'; const currentDir = dirname(fileURLToPath(import.meta.url)); @@ -20,7 +20,7 @@ const resolveSetupModulePath = (baseName: string) => { const happyDomSetupPath = resolveSetupModulePath('dom-setup-happy'); const jsdomSetupPath = resolveSetupModulePath('dom-setup-jsdom'); -const reactExtensions = new Set(['.tsx', '.jsx']); +const reactExtensions = new Set(['.ts', '.tsx', '.js', '.jsx']); export const resolveDomSetupPath = createDomSetupPathResolver( '@pokujs/react', diff --git a/src/plugin-metrics.ts b/src/plugin-metrics.ts index eff23cb..78a4bbe 100644 --- a/src/plugin-metrics.ts +++ b/src/plugin-metrics.ts @@ -28,7 +28,8 @@ export const isRenderMetricBatchMessage = (message: unknown) => export const buildRuntimeOptionArgs = ( options: ReactTestingPluginOptions, metricsOptions: NormalizedMetricsOptions -) => buildCoreRuntimeOptionArgs(options, metricsOptions, runtimeOptionArgPrefixes); +) => + buildCoreRuntimeOptionArgs(options, metricsOptions, runtimeOptionArgPrefixes); export const printMetricsSummary = (summary: ReactMetricsSummary) => printCoreMetricsSummary(summary, '@pokujs/react'); diff --git a/src/plugin-setup.ts b/src/plugin-setup.ts deleted file mode 100644 index 5142530..0000000 --- a/src/plugin-setup.ts +++ /dev/null @@ -1 +0,0 @@ -export { setupInProcessEnvironment } from '@pokujs/dom'; diff --git a/src/plugin-types.ts b/src/plugin-types.ts index 1330644..9af6051 100644 --- a/src/plugin-types.ts +++ b/src/plugin-types.ts @@ -2,8 +2,6 @@ import type { DomAdapter, MetricsOptions, MetricsSummary, - NormalizedMetricsOptions, - RenderMetric, TestingPluginOptions, } from '@pokujs/dom'; @@ -12,7 +10,4 @@ export type ReactMetricsSummary = MetricsSummary; export type ReactMetricsOptions = MetricsOptions; export type ReactTestingPluginOptions = TestingPluginOptions; -export type { - NormalizedMetricsOptions, - RenderMetric, -}; +export type { NormalizedMetricsOptions, RenderMetric } from '@pokujs/dom'; diff --git a/src/plugin.ts b/src/plugin.ts index a3ac48a..0023986 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -1,13 +1,11 @@ +import type { FrameworkDescriptor } from '@pokujs/dom'; import type { ReactDomAdapter, ReactMetricsOptions, ReactMetricsSummary, ReactTestingPluginOptions, } from './plugin-types.ts'; -import { - createFrameworkTestingPluginFactory, -} from '@pokujs/dom'; -import type { FrameworkDescriptor } from '@pokujs/dom'; +import { createFrameworkTestingPluginFactory } from '@pokujs/dom'; import { buildRunnerCommand, canHandleRuntime, @@ -29,6 +27,7 @@ const descriptor: FrameworkDescriptor = { runtimeArgBase: 'poku-react', metricMessageType: 'POKU_REACT_RENDER_METRIC', metricBatchMessageType: 'POKU_REACT_RENDER_METRIC_BATCH', + testFileExtensions: ['.ts', '.tsx', '.js', '.jsx'], }; const { createTestingPlugin } = createFrameworkTestingPluginFactory( diff --git a/src/react-testing.ts b/src/react-testing.ts index 8b6b061..9a6ccd7 100644 --- a/src/react-testing.ts +++ b/src/react-testing.ts @@ -1,115 +1,93 @@ import type { fireEvent as baseFireEvent, BoundFunctions, + PrettyDOMOptions, Screen, } from '@testing-library/dom'; -import type { ComponentType, PropsWithChildren, ReactElement } from 'react'; +import type { ComponentType, ReactElement, ReactNode } from 'react'; import type { Root } from 'react-dom/client'; -import { getQueriesForElement, queries } from '@testing-library/dom'; -import * as domTestingLibrary from '@testing-library/dom'; -import * as pokuDom from '@pokujs/dom'; -import React from 'react'; -import { createRoot } from 'react-dom/client'; +import { createRequire } from 'node:module'; import { + configureDomTestingLibrary, + createAsFragment, + createDebug, createRenderMetricsEmitter, + createScopedRegistry, createScreen, + createWaitFor, getNow, wrapFireEventMethods, } from '@pokujs/dom'; +import { + configure as configureTestingLibrary, + getQueriesForElement, + queries, +} from '@testing-library/dom'; +import * as domTestingLibrary from '@testing-library/dom'; +import React from 'react'; import { parseRuntimeOptions } from './runtime-options.ts'; -const { act } = React; - -export { act }; - -type WrapperComponent = ComponentType>; - -type InternalMounted = { - root: Root | null; - container: Element | null; - ownsContainer: boolean; -}; - -const fallbackMountedRoots = new Set(); - -type ScopeSlot = { - readonly value: T; -}; - -type ScopeLike = { - getOrCreateSlot(key: symbol, init: () => T): ScopeSlot; - getSlot?(key: symbol): ScopeSlot | undefined; - addCleanup?(fn: () => void | Promise): void; -}; - -type DomScopeApi = { - defineSlotKey?: (name: string) => symbol; - getOrCreateScope?: () => ScopeLike | undefined; - getCurrentScope?: () => ScopeLike | undefined; -}; - -const domScopeApi = pokuDom as unknown as DomScopeApi; - -const MOUNTED_ROOTS_SLOT_KEY = - typeof domScopeApi.defineSlotKey === 'function' - ? domScopeApi.defineSlotKey>( - '@pokujs/react.mounted-roots' - ) - : undefined; - -const CLEANUP_STATE_SLOT_KEY = - typeof domScopeApi.defineSlotKey === 'function' - ? domScopeApi.defineSlotKey<{ registered: boolean }>( - '@pokujs/react.cleanup-registered' - ) - : undefined; - -const cleanupMountedRoots = (mountedRoots: Set) => { - for (const mounted of [...mountedRoots]) { - unmountMounted(mountedRoots, mounted); +// Lazily load `react-dom/client` on first `render()` call rather than at module +// import time. If a user imports `reactTestingPlugin` from the `@pokujs/react` +// barrel inside `poku.config.js` under `isolation: 'none'`, the config module is +// evaluated before `plugin.setup()` installs `window` and `document`. Eagerly +// importing `react-dom/client` before `window` exists causes React DOM to cache +// `canUseDOM = false` and permanently disable its synthetic event system. +let cachedCreateRoot: typeof import('react-dom/client').createRoot | undefined; +const getCreateRoot = (): typeof import('react-dom/client').createRoot => { + if (!cachedCreateRoot) { + const req = createRequire(import.meta.url); + const reactDomClient = req( + 'react-dom/client' + ) as typeof import('react-dom/client'); + cachedCreateRoot = reactDomClient.createRoot; } + return cachedCreateRoot; }; -const getScopedMountedRoots = (): Set | undefined => { - if (!MOUNTED_ROOTS_SLOT_KEY) return undefined; - if (typeof domScopeApi.getOrCreateScope !== 'function') return undefined; - - const scope = domScopeApi.getOrCreateScope(); - if (!scope) return undefined; - - const mountedRoots = scope.getOrCreateSlot(MOUNTED_ROOTS_SLOT_KEY, () => - new Set() - ).value; - - if (!CLEANUP_STATE_SLOT_KEY || typeof scope.addCleanup !== 'function') { - return mountedRoots; - } +const { act } = React; - const cleanupState = scope.getOrCreateSlot(CLEANUP_STATE_SLOT_KEY, () => ({ - registered: false, - })).value; +export { act }; - if (!cleanupState.registered) { - cleanupState.registered = true; - scope.addCleanup(() => { - cleanupMountedRoots(mountedRoots); - metrics.flushMetricBuffer(); +// Wire @testing-library/dom's asyncWrapper and eventWrapper to React's act() +// so that waitFor(), findBy*(), and fireEvent work without React act() warnings. +const testingLibraryConfig = { + asyncWrapper: async (cb: () => Promise) => { + const reactGlobal = globalThis as typeof globalThis & { + IS_REACT_ACT_ENVIRONMENT?: boolean | undefined; + }; + const previousActEnvironment = reactGlobal.IS_REACT_ACT_ENVIRONMENT; + reactGlobal.IS_REACT_ACT_ENVIRONMENT = false; + try { + const result = await cb(); + await new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, 0); + }); + return result; + } finally { + reactGlobal.IS_REACT_ACT_ENVIRONMENT = previousActEnvironment; + } + }, + eventWrapper: (cb: () => unknown) => { + let result: unknown; + act(() => { + result = cb(); }); - } - - return mountedRoots; + return result; + }, }; -const getMountedRoots = (): Set => - getScopedMountedRoots() ?? fallbackMountedRoots; +configureTestingLibrary(testingLibraryConfig); +configureDomTestingLibrary(testingLibraryConfig); -const getCurrentScopedMountedRoots = (): Set | undefined => { - if (!MOUNTED_ROOTS_SLOT_KEY) return undefined; - if (typeof domScopeApi.getCurrentScope !== 'function') return undefined; +type WrapperComponent = ComponentType<{ children: ReactNode }>; - const scope = domScopeApi.getCurrentScope(); - const slot = scope?.getSlot?.>(MOUNTED_ROOTS_SLOT_KEY); - return slot?.value; +type InternalMounted = { + root: Root | null; + container: Element | null; + ownsContainer: boolean; }; const unmountMounted = ( @@ -131,6 +109,26 @@ const unmountMounted = ( } }; +const cleanupMountedRoots = (mountedRoots: Set) => { + for (const mounted of [...mountedRoots]) { + unmountMounted(mountedRoots, mounted); + } +}; + +const metrics = createRenderMetricsEmitter({ + runtimeOptions: () => parseRuntimeOptions(), + metricsStateKey: Symbol.for('@pokujs/react.metrics-runtime-state'), + metricsBatchMessageType: 'POKU_REACT_RENDER_METRIC_BATCH', +}); + +const registry = createScopedRegistry({ + name: '@pokujs/react.mounted-roots', + onCleanup: (mountedRoots) => { + cleanupMountedRoots(mountedRoots); + metrics.flushMetricBuffer(); + }, +}); + const getComponentName = (ui: ReactElement) => { const uiType = ui.type; if (!uiType) return 'AnonymousComponent'; @@ -140,13 +138,6 @@ const getComponentName = (ui: ReactElement) => { return typed.displayName || typed.name || 'AnonymousComponent'; }; -const runtimeOptions = parseRuntimeOptions(); -const metrics = createRenderMetricsEmitter({ - runtimeOptions, - metricsStateKey: Symbol.for('@pokujs/react.metrics-runtime-state'), - metricsBatchMessageType: 'POKU_REACT_RENDER_METRIC_BATCH', -}); - const wrapUi = (ui: ReactElement, Wrapper?: WrapperComponent) => Wrapper ? React.createElement(Wrapper, null, ui) : ui; @@ -162,20 +153,26 @@ export type RenderResult = BoundFunctions & { baseElement: HTMLElement; rerender: (ui: ReactElement) => void; unmount: () => void; + asFragment: () => DocumentFragment; + debug: ( + element?: Array | Element | HTMLDocument, + maxLength?: number, + options?: PrettyDOMOptions + ) => void; }; export const render = ( ui: ReactElement, options: RenderOptions = {} ): RenderResult => { - const mountedRoots = getMountedRoots(); - const baseElement = options.baseElement || document.body; + const mountedRoots = registry.getItems(); + const baseElement = options.baseElement || options.container || document.body; const container = options.container || document.createElement('div'); const ownsContainer = !options.container; if (ownsContainer) baseElement.appendChild(container); - const root = createRoot(container); + const root = getCreateRoot()(container); const mounted: InternalMounted = { root, container, ownsContainer }; mountedRoots.add(mounted); @@ -214,6 +211,8 @@ export const render = ( baseElement, rerender, unmount, + asFragment: createAsFragment(container), + debug: createDebug(baseElement), }; }; @@ -229,23 +228,19 @@ export type RenderHookResult = { unmount: () => void; }; -export const renderHook = < - Result, - Props extends Record = Record, ->( - hook: (props: Props) => Result, +export const renderHook = ( + hook: (initialProps: Props) => Result, options: RenderHookOptions = {} ): RenderHookResult => { let currentResult!: Result; + let currentProps = options.initialProps as Props; - const HookHarness = (props: Props) => { - currentResult = hook(props); + const HookHarness = () => { + currentResult = hook(currentProps); return null; }; - const initialProps = options.initialProps ?? ({} as Props); - const view = render(React.createElement(HookHarness, initialProps), options); - let currentProps = initialProps; + const view = render(React.createElement(HookHarness), options); const resultRef: { current: Result } = { get current() { @@ -259,17 +254,17 @@ export const renderHook = < }, rerender(nextProps = currentProps) { currentProps = nextProps; - view.rerender(React.createElement(HookHarness, nextProps)); + view.rerender(React.createElement(HookHarness)); }, unmount: view.unmount, }; }; export const cleanup = () => { - const scopedMountedRoots = getCurrentScopedMountedRoots(); + const scopedMountedRoots = registry.getScopedItems(); if (scopedMountedRoots) cleanupMountedRoots(scopedMountedRoots); - cleanupMountedRoots(fallbackMountedRoots); + cleanupMountedRoots(registry.fallbackItems); metrics.flushMetricBuffer(); }; @@ -291,11 +286,14 @@ wrapFireEventMethods( baseFireEventInstance as unknown as Record, (invoke: () => unknown) => { let result: unknown; - act(() => { result = invoke(); }); + act(() => { + result = invoke(); + }); return result; } ); export const fireEvent = wrappedFireEvent; +export const waitFor = createWaitFor(domTestingLibrary.waitFor); export * from '@testing-library/dom'; diff --git a/src/runtime-options.ts b/src/runtime-options.ts index 8a13e2f..789bf8a 100644 --- a/src/runtime-options.ts +++ b/src/runtime-options.ts @@ -3,9 +3,8 @@ import { parseRuntimeOptions as parseCoreRuntimeOptions, } from '@pokujs/dom'; -export const runtimeOptionArgPrefixes = createRuntimeOptionArgPrefixes( - 'poku-react' -); +export const runtimeOptionArgPrefixes = + createRuntimeOptionArgPrefixes('poku-react'); export const parseRuntimeOptions = (argv: string[] = process.argv) => parseCoreRuntimeOptions(runtimeOptionArgPrefixes, argv); diff --git a/tests/plugin-command.test.ts b/tests/plugin-command.test.ts index 10fa327..6e498d9 100644 --- a/tests/plugin-command.test.ts +++ b/tests/plugin-command.test.ts @@ -71,7 +71,7 @@ test('buildRunnerCommand injects --preload for Bun (not --import)', async () => assert.strictEqual(result.shouldHandle, true); assert.deepStrictEqual(result.command, [ 'bun', - '--preload /tmp/react-dom-setup.ts', + '--preload=/tmp/react-dom-setup.ts', 'tests/example.test.tsx', ]); }); diff --git a/tests/plugin-internals.test.ts b/tests/plugin-internals.test.ts index 5a2ee43..4631d81 100644 --- a/tests/plugin-internals.test.ts +++ b/tests/plugin-internals.test.ts @@ -59,7 +59,7 @@ test('buildRunnerCommand injects dom setup for bun without tsx import', async () assert.strictEqual(result.shouldHandle, true); assert.deepStrictEqual(result.command, [ 'bun', - '--preload /tmp/dom-setup.ts', + '--preload=/tmp/dom-setup.ts', 'tests/example.test.tsx', '--poku-react-metrics=1', ]); @@ -100,11 +100,11 @@ test('buildRunnerCommand leaves unsupported runtime unchanged', async () => { }); test('buildRunnerCommand leaves non-react extension unchanged', async () => { - const original = ['node', 'tests/example.test.ts']; + const original = ['node', 'tests/example.test.mjs']; const result = __internal.buildRunnerCommand({ runtime: 'node', command: original, - file: 'tests/example.test.ts', + file: 'tests/example.test.mjs', domSetupPath: '/tmp/dom-setup.ts', runtimeOptionArgs: [], }); diff --git a/tests/react-hooks.test.tsx b/tests/react-hooks.test.tsx index 575dfb3..274b3d3 100644 --- a/tests/react-hooks.test.tsx +++ b/tests/react-hooks.test.tsx @@ -71,3 +71,21 @@ test('renderHook.rerender keeps result.current live after destructuring', async assert.strictEqual(result.current, 'second'); }); + +test('renderHook supports zero-arg hooks and primitive initialProps, plus asFragment/screen.debug', () => { + const zeroArg = renderHook(() => useToggle()); + assert.strictEqual(zeroArg.result.current.enabled, false); + + const primitiveProp = renderHook((count: number) => count * 2, { + initialProps: 5, + }); + assert.strictEqual(primitiveProp.result.current, 10); + primitiveProp.rerender(7); + assert.strictEqual(primitiveProp.result.current, 14); + + const view = render(); + const fragment = view.asFragment(); + assert.strictEqual(fragment.querySelector('button')?.textContent, 'Toggle'); + assert.strictEqual(typeof screen.debug, 'function'); + assert.strictEqual(typeof view.debug, 'function'); +}); From 004efc4299949e51dd7ee791adf749ca403be912 Mon Sep 17 00:00:00 2001 From: lojhan Date: Thu, 22 Oct 2026 17:20:18 +0000 Subject: [PATCH 2/3] fix: require the published scoped DOM helpers --- package-lock.json | 106 ++++++++++++++++++++++------------------------ package.json | 3 +- 2 files changed, 52 insertions(+), 57 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3639cfa..43886cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,13 +9,12 @@ "version": "1.5.1", "license": "MIT", "dependencies": { - "@pokujs/dom": "^1.3.0", + "@pokujs/dom": "^1.3.2", "@testing-library/dom": "^10.4.1" }, "devDependencies": { "@happy-dom/global-registrator": "^20.8.9", "@ianvs/prettier-plugin-sort-imports": "^4.7.0", - "@pokujs/dom": "^1.3.0", "@types/jsdom": "^28.0.1", "@types/node": "^25.5.0", "@types/react": "^19.2.14", @@ -62,7 +61,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@csstools/css-calc": "^2.1.3", @@ -209,7 +208,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", - "dev": true, + "devOptional": true, "funding": [ { "type": "github", @@ -229,7 +228,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "dev": true, + "devOptional": true, "funding": [ { "type": "github", @@ -253,7 +252,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", - "dev": true, + "devOptional": true, "funding": [ { "type": "github", @@ -281,7 +280,7 @@ "version": "3.0.5", "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", - "dev": true, + "devOptional": true, "funding": [ { "type": "github", @@ -304,7 +303,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", - "dev": true, + "devOptional": true, "funding": [ { "type": "github", @@ -858,10 +857,9 @@ } }, "node_modules/@pokujs/dom": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@pokujs/dom/-/dom-1.3.1.tgz", - "integrity": "sha512-ge4Lxx5tLUiiugftvD7Qk6HEPnoY/IRXJ5uOTFLxyEvog2q1wqCUQNLznIA3uvaEjoH+fPwOZgHX3nPqQkrzQg==", - "dev": true, + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@pokujs/dom/-/dom-1.3.2.tgz", + "integrity": "sha512-YtIHIkAS58jMrmDeVx6s2FYVI3+u0S724Ym8Uemd5ISkHP9kW6sroBieOL4xKo3eG/xfl8EW6JUfb9PlFg7q3g==", "license": "MIT", "dependencies": { "@pokujs/scope-hooks": "^1.1.0", @@ -891,7 +889,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@pokujs/scope-hooks/-/scope-hooks-1.1.0.tgz", "integrity": "sha512-EhUy0aP4k+mMoHxd6eK+Cjuo5YFcpSKfySgT/1+6u7D3UD37JKAbb8cAvnyzhLi+Vfb4y9CQgcyiHksGYtGMZw==", - "dev": true, "license": "MIT", "engines": { "bun": ">=1.x.x", @@ -1302,7 +1299,7 @@ "version": "25.6.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~7.19.0" @@ -1312,7 +1309,7 @@ "version": "7.19.2", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/react": { @@ -1346,14 +1343,14 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/whatwg-mimetype/-/whatwg-mimetype-3.0.2.tgz", "integrity": "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/ws": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -1376,7 +1373,7 @@ "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 14" @@ -1548,7 +1545,7 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@asamuzakjp/css-color": "^3.2.0", @@ -1569,7 +1566,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "whatwg-mimetype": "^4.0.0", @@ -1583,7 +1580,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=18" @@ -1593,7 +1590,7 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -1611,7 +1608,7 @@ "version": "10.6.0", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/dequal": { @@ -1633,7 +1630,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -1764,7 +1761,7 @@ "version": "20.9.0", "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.9.0.tgz", "integrity": "sha512-GZZ9mKe8r646NUAf/zemnGbjYh4Bt8/MqASJY+pSm5ZDtc3YQox+4gsLI7yi1hba6o+eCsGxpHn5+iEVn31/FQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/node": ">=20.0.0", @@ -1782,7 +1779,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "whatwg-encoding": "^3.1.1" @@ -1795,7 +1792,7 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.0", @@ -1809,7 +1806,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -1823,7 +1820,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -1836,7 +1833,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/isexe": { @@ -1866,7 +1863,7 @@ "version": "26.1.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "cssstyle": "^4.2.1", @@ -1906,7 +1903,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=18" @@ -1959,7 +1956,7 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/lz-string": { @@ -2024,7 +2021,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/mz": { @@ -2043,7 +2040,7 @@ "version": "2.2.23", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/object-assign": { @@ -2067,7 +2064,7 @@ "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "entities": "^6.0.0" @@ -2080,7 +2077,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -2178,7 +2175,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/poku/-/poku-4.3.0.tgz", "integrity": "sha512-s6xHA93lzirvScBuW5UxUAbx4Cw6C/5MEMTe/27jTtLkDmIsWNpUH2CiMbSOKMxLGj7C3JoM2zfacu3kCrlk3Q==", - "dev": true, "license": "MIT", "bin": { "poku": "lib/bin/index.js" @@ -2271,7 +2267,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -2409,21 +2405,21 @@ "version": "0.8.0", "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "xmlchars": "^2.2.0" @@ -2512,7 +2508,7 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/thenify": { @@ -2566,7 +2562,7 @@ "version": "6.1.86", "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "tldts-core": "^6.1.86" @@ -2579,14 +2575,14 @@ "version": "6.1.86", "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/tough-cookie": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "tldts": "^6.1.32" @@ -2599,7 +2595,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "punycode": "^2.3.1" @@ -2730,7 +2726,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "xml-name-validator": "^5.0.0" @@ -2743,7 +2739,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -2754,7 +2750,7 @@ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "iconv-lite": "0.6.3" @@ -2767,7 +2763,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=12" @@ -2777,7 +2773,7 @@ "version": "14.2.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "tr46": "^5.1.0", @@ -2807,7 +2803,7 @@ "version": "8.21.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz", "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -2829,7 +2825,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=18" @@ -2839,7 +2835,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true, + "devOptional": true, "license": "MIT" } } diff --git a/package.json b/package.json index 28325a3..2ea9ebb 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "provenance": true }, "dependencies": { - "@pokujs/dom": "^1.3.0", + "@pokujs/dom": "^1.3.2", "@testing-library/dom": "^10.4.1" }, "peerDependencies": { @@ -104,7 +104,6 @@ "devDependencies": { "@happy-dom/global-registrator": "^20.8.9", "@ianvs/prettier-plugin-sort-imports": "^4.7.0", - "@pokujs/dom": "^1.3.0", "@types/jsdom": "^28.0.1", "@types/node": "^25.5.0", "@types/react": "^19.2.14", From 368d49a9f8afb2e72d1a99f0729d12f4e7da23bf Mon Sep 17 00:00:00 2001 From: lojhan Date: Thu, 22 Oct 2026 17:23:30 +0000 Subject: [PATCH 3/3] test: isolate DOM adapters for React 18 compatibility --- run.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.test.ts b/run.test.ts index 1bb466c..568bf5a 100644 --- a/run.test.ts +++ b/run.test.ts @@ -14,7 +14,7 @@ assert.strictEqual(happyCode, 0, 'happy-dom suite'); if (typeof Deno === 'undefined') { const jsdomCode = await poku('tests', { noExit: true, - isolation: 'none', + isolation: 'process', plugins: [reactTestingPlugin({ dom: 'jsdom' })], });