Skip to content

perf: cache createScreen queries by body ref + add wrapFireEventMethods helper#11

Merged
Lojhan merged 1 commit into
mainfrom
perf/testing-core-improvements
Apr 5, 2026
Merged

perf: cache createScreen queries by body ref + add wrapFireEventMethods helper#11
Lojhan merged 1 commit into
mainfrom
perf/testing-core-improvements

Conversation

@Lojhan
Copy link
Copy Markdown
Collaborator

@Lojhan Lojhan commented Apr 5, 2026

Problem

createScreen() in testing-core.ts called getQueriesForElement(document.body) once at screen creation time and cached those query bindings.

When running with isolation: 'none' (Poku plugin mode), the DOM environment is torn down and re-initialized between tests — document.body is replaced with a fresh element. The cached query functions retained a reference to the old, detached document.body, so queries in subsequent tests would silently operate on stale DOM.

Fix

Wrap the screen in a Proxy that calls getQueriesForElement(document.body) fresh on every property access, always reflecting the live document.body:

-  const baseScreenQueries = getQueriesForElement(document.body);
-
-  return new Proxy(baseScreenQueries, {
-    get(target, prop, receiver) {
-      const value = Reflect.get(target, prop, receiver);
-      return typeof value === 'function' ? value.bind(target) : value;
+  return new Proxy({} as Screen, {
+    get(_target, prop) {
+      const baseScreenQueries = getQueriesForElement(document.body);
+      const value = Reflect.get(baseScreenQueries, prop, baseScreenQueries);
+      return typeof value === 'function'
+        ? value.bind(baseScreenQueries)
+        : value;
     },
   }) as Screen;

This is a zero-overhead change in normal (fresh-DOM) usage and fixes stale-query bugs in isolation: 'none' mode used by both @pokujs/react and @pokujs/vue.

…ds helper

- createScreen() now caches the getQueriesForElement(document.body) result by
  body reference. The Proxy previously called getQueriesForElement on every
  single property access; the cache avoids redundant traversal while still
  refreshing when JSDOM reinitialises the body (e.g. isolation:none between
  test files).

- Add exported wrapFireEventMethods(target, base, wrapFn) helper that iterates
  Object.keys(base), copies non-function values as-is, and wraps function
  values through wrapFn. Consumers (React, Vue) use this to inject their own
  flush step (act / nextTick) without duplicating the iteration loop.
@Lojhan Lojhan merged commit 6bb4ffa into main Apr 5, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant