Skip to content

fix: skip frames that cannot run scripts instead of hanging - #1478

Draft
scottmries wants to merge 1 commit into
developfrom
fix/sandboxed-iframe-hang
Draft

scottmries wants to merge 1 commit into
developfrom
fix/sandboxed-iframe-hang

Conversation

@scottmries

Copy link
Copy Markdown
Contributor

Details

A same-origin iframe sandboxed without allow-scripts accepts injected code, but its timers never fire. axe.runPartial needs timers, so analyze() never finished in that frame:

Package Before After
Playwright Hangs About 1 second
Puppeteer Hangs About 1 second
WebDriverJS Waits for the script timeout (30 seconds by default) About 1 second
WebdriverIO Waits for the script timeout (30 seconds by default) About 1 second

Before running axe in a child frame, each package now checks that a setTimeout callback fires within 1 second. If it does not, the frame is skipped and the frame-tested rule reports it as incomplete. Frames that can run scripts pay one extra round trip.

WebdriverIO needs two limits. Classic WebDriver blocks later commands until a stuck script hits the script timeout, so the check lowers that timeout to 1 second and then restores the user's value. WebDriver BiDi ignores the script timeout, so the check also gives up from Node after 1 second.

QA notes

  1. Serve a page with a footer that contains <iframe sandbox="allow-same-origin" src="/legal.html"></iframe>. The iframe page should contain an <img> without alt.
  2. Run analyze() with each package in its default mode.
  3. Expect analyze() to finish in a few seconds, and expect incomplete to include frame-tested for the iframe.
  4. Add allow-scripts to the sandbox attribute and run again. Expect image-alt in violations with a target inside the iframe.

Closes: #1469

A same-origin iframe sandboxed without allow-scripts accepts injected
code, but its timers never fire. axe.runPartial needs timers, so
analyze() in Playwright and Puppeteer waited forever on that frame.
WebDriverJS and WebdriverIO waited for the script timeout, 30 seconds by
default.

Before running axe in a child frame, each package now checks that a
setTimeout callback fires within 1 second. If it does not, the frame is
skipped and reported as incomplete by the frame-tested rule.

Closes: #1469

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

A moderate Playwright timeout-scope issue remains unresolved.

0 open findings

What changed in this PR

Prevents analysis from hanging on sandboxed iframes that cannot run timers by skipping them and reporting incomplete frame coverage.

Changes:

  • Adds timer-readiness checks across all browser integrations.
  • Preserves and restores WebDriver script timeouts.
  • Adds regression tests for skipped frames and timeout handling.
File Description
packages/​webdriverjs/​test/​axe-webdriverjs.spec.ts Tests incomplete-frame reporting and timeout restoration.
packages/​webdriverjs/​src/​index.ts Applies timer checks to child frames.
packages/​webdriverjs/​src/​browser.ts Adds script-timeout timer probing.
packages/​webdriverio/​test/​axe-webdriverio.spec.ts Tests incomplete-frame reporting and timeout restoration.
packages/​webdriverio/​src/​utils.ts Handles timer probing for classic and BiDi modes.
packages/​webdriverio/​src/​types.ts Adds script-timeout typing.
packages/​webdriverio/​src/​index.ts Applies timer checks to child frames.
packages/​puppeteer/​test/​axe-puppeteer.spec.ts Tests sandboxed-frame handling.
packages/​puppeteer/​src/​browser.ts Adds timer-aware frame readiness checks.
packages/​playwright/​test/​axe-playwright.spec.ts Tests incomplete-frame reporting.
packages/​playwright/​src/​index.ts Integrates child-frame timer validation.
packages/​playwright/​src/​browser.ts Provides the timer probe.

🧠 Review effort: Lite


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

This branch has not been deployed

No deployments
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.

@axe-core/playwright: non-legacy analyze() hangs on a sandboxed iframe without allow-scripts

2 participants