Skip to content

fix(dom): keep readiness gate async-free so TestCafe t.eval accepts the bundle#2346

Open
prklm10 wants to merge 1 commit into
masterfrom
fix/PER-10121-dom-async-free-bundle
Open

fix(dom): keep readiness gate async-free so TestCafe t.eval accepts the bundle#2346
prklm10 wants to merge 1 commit into
masterfrom
fix/PER-10121-dom-async-free-bundle

Conversation

@prklm10

@prklm10 prklm10 commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Fixes PER-10121

Root cause

The @percy/dom bundle is injected into the browser verbatim by SDKs. @percy/testcafe/index.js:29 does:

await t.eval(new Function(await utils.fetchPercyDOM()), { boundTestRun: t });

TestCafe's t.eval/ClientFunction machinery statically rejects any async/await or generator syntax in the evaluated source.

The readiness gate shipped in 1.31.14 (PER-7348, #2184) added two async functions — runAllChecks and waitForReady in packages/dom/src/readiness.js — which are the only async/await in the entire dom source. Because the rollup babel target (browsers: ['last 2 versions and supports async-functions']) intentionally does not down-level async, those tokens flow straight into dist/bundle.js. Every @percy/testcafe snapshot then fails with:

eval code, arguments or dependencies cannot contain generators or "async/await" syntax (use Promises instead).
  at percySnapshot (node_modules/@percy/testcafe/index.js:29:13)

and the build finalizes with Failure: Snapshot command was not called. Playwright/other SDKs are unaffected because they don't route the bundle through TestCafe's restrictive evaluator.

Bundle token profile (published):

Version size async await generators
1.31.13 (last good) 47 KB 0 0 0
1.31.14 101 KB 2 2 0
1.32.4 (latest) 105 KB 2 2 0

Fix

Rewrite runAllChecks and waitForReady to explicit Promise chains (return Promise.all(...), Promise.race(...).catch(...).then(...)). Behavior is unchanged — both were already Promise-returning at every call site (runAllChecks(...).then(...), await waitForReady(...)), and the try/catch → .catch/.then mapping preserves the timeout/abort/post-processing semantics exactly. The rebuilt bundle is back to 0 async / 0 await / 0 generators, matching the 1.31.13 profile that TestCafe accepts.

Add a package-local packages/dom/src/.eslintrc that forbids async/await/generators via no-restricted-syntax, so this browser-injection contract can't silently regress again (which is exactly how it shipped).

Testing

  • Full @percy/dom suite green: 902 tests pass, including the readiness suite (waitForReady returns a Promise, stays sync even when readiness config is present, timeout/graceful-degradation cases).
  • Rebuilt dist/bundle.js verified async/await/generator-free.
  • ESLint guard verified: fails an async sample with the PER-10121 message, passes the rewritten readiness.js.

🤖 Generated with Claude Code

…he bundle

The @percy/dom bundle is injected into the browser verbatim by SDKs. TestCafe's
`t.eval` (used by @percy/testcafe/index.js) statically rejects any async/await or
generator syntax in the evaluated source. The readiness gate added in 1.31.14
(PER-7348) introduced two `async` functions into the bundle, which broke every
@percy/testcafe snapshot with:

  eval code, arguments or dependencies cannot contain generators or "async/await"
  syntax (use Promises instead).

Rewrite `runAllChecks` and `waitForReady` to explicit Promise chains (behavior
unchanged — both were already Promise-returning at every call site) so the bundle
is async-free again, matching the pre-1.31.14 (1.31.13) profile.

Add a package-local .eslintrc in packages/dom/src that forbids async/await and
generators via no-restricted-syntax, so this contract can't silently regress.

Fixes PER-10121

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@prklm10
prklm10 requested a review from a team as a code owner July 20, 2026 09:36
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