Skip to content

[webkit] Sub-resource requests timeout through Cypress proxy causing Vue app not to mount and cy.session() restore to hang in Cypress 15.15.0 #33926

@soni09bhatia

Description

@soni09bhatia

Current behavior

Cypress Version
15.15.0

Browser
webkit

Using:
experimentalWebKitSupport: true

and:
playwright-webkit@1.60.0

Operating System

Local
Windows 10
CI
Ubuntu (Azure DevOps Linux agent)

Node / pnpm Versions
Node: 20.16.0
pnpm: 10.33.0

Description
After upgrading to Cypress 15.x (confirmed on 15.15.0), all tests running in WebKit fail consistently while the same specs pass successfully in Chrome.
The initial HTML document loads successfully (HTTP 200), however the Vue application never mounts because all subsequent sub-resource requests (JS bundles, CSS assets, and Cypress socket connections) timeout through the Cypress proxy.
This results in:
Blank white page
Vue application never mounting
cy.session() restore hanging indefinitely
Subsequent command timeouts cascading through the suite
Chrome execution using the same configuration, specs, infrastructure, and environment works without issue.

Observed Console Errors
Failed to load resource: Timeout was reached

→ https:///bundles/acresi-vue-library/v=
→ https:///bundles/css-layer-order?v=
→ https:///bundles/libraries-css?v=
→ https:///bundles/common/content/common-css?v=
→ https:///bundles/main/content/main-css?v=
→ https:///acresi-vue-library/dist/assets/third-party-css?v=

→ https:///__socket/?EIO=4&transport=polling&t=
Followed by:
Failed to load resource: the server responded with a status of 404

→ https:///__socket/?EIO=4&transport=polling&sid=

→ https:///__cypress/runner/escape.js.map

Important observation:
The initial HTML document request succeeds (200)
Only sub-resource requests fail
Chrome is unaffected
WebKit consistently reproduces the issue

Steps to Reproduce

Enable experimentalWebKitSupport
Use cy.session() inside beforeEach
Register multiple cy.intercept() routes
Execute cy.visit('/Dashboard')
Run the spec using:
cypress run --browser webkit

Expected Behavior
Vue application mounts successfully
JS/CSS bundles load normally
cy.session() restore completes
Tests execute successfully

Actual Behavior
Initial HTML document loads
All subsequent JS/CSS/socket requests timeout
Vue never mounts
Blank white page displayed
cy.session() hangs indefinitely
Tests fail with cascading timeout errors

Failure Modes
Failure 1 — Application Never Renders
AssertionError: Timed out retrying after 20000ms:
Expected to find element: [data-cy="nav-care-network"], but never found it.
Cause:
Main Vue bundle request times out, preventing the application from mounting.

Failure 2 — cy.session() Restore Hangs
CypressError: cy.then() timed out after waiting 20000ms.
Your callback function returned a promise that never resolved.
Stack trace points to:
async () => {
setSessionLogStatus(...SESSION_STEPS.restore));
await navigateAboutBlank();
await sessions.clearCurrentSessionData();
return restoreSession(existingSession);
}
Cause:
Cypress internal __socket polling requests timeout, causing browser communication loss during session restore.

Failure 3 — Cascading Mocha Hook Error
Error: done() called multiple times in hook
This appears to occur after the session restore timeout triggers cleanup logic while the original hook completion is still pending.

Cypress Configuration
module.exports = defineConfig({
chromeWebSecurity: false,
defaultCommandTimeout: 20000,
pageLoadTimeout: 100000,
responseTimeout: 60000,
requestTimeout: 30000,
experimentalSourceRewriting: false,
experimentalWebKitSupport: true,
testIsolation: false,

retries: {
runMode: 1,
openMode: 1,
},
});

Investigation Performed

<style> </style>
Investigation Result
Different playwright-webkit versions Reproduced on multiple versions
CSP / third-party script rewriting Not the cause
experimentalSourceRewriting No impact
Authentication / cookies Login succeeds correctly
Cross-origin resource blocking All requests are same-origin
App-side JS exceptions No uncaught exceptions detected
CI resource starvation Ruled out
Azure agent scaling issues Ruled out

Key Observation
WebKit attempts to resolve Cypress assets against the application origin:
https:///__cypress/runner/escape.js.map
instead of resolving them through the Cypress proxy origin. This suggests a possible WebKit-specific proxy/origin resolution issue affecting Cypress-injected resources and socket communication.

Suspected Root Cause

The Cypress 15.x proxy layer appears unable to properly maintain sub-resource forwarding and internal socket communication in WebKit after the initial HTML document is served.
The issue appears specifically related to Cypress internal stability handling combined with broken WebKit socket communication.

Related Cypress PR — Potential Regression Source
Reference PR:
#33446 - #33446
“fix: prevent hang when waiting on multiple intercepts and navigating”
Released in:
Cypress 15.12.0

What PR #33446 Changed
PR #33446 modified Cypress’s internal stability handling logic.
Previously, Cypress stored a single whenStable callback. Multiple registrations would overwrite previous callbacks.
The fix replaced this with a queue-based implementation:
whenStableQueue.push(fn)
which later releases all waiters during:
isStable(true)
This behavior is correct and improves stability handling in Chrome.

Why This Appears to Regress WebKit
In WebKit, Cypress internal Socket.IO polling requests appear unable to establish reliably through the Cypress proxy:
Failed to load resource: Timeout was reached
→ /__socket/?EIO=4&transport=polling&t=
followed by:
Failed to load resource: 404
→ /__socket/?EIO=4&transport=polling&sid=
These socket failures appear to prevent Cypress from ever reaching a stable state in WebKit.

Behavioral Difference Before vs After 15.12.0

<style> </style>
Scenario Pre-15.12.0 Post-15.12.0
WebKit socket connection fails One waiter could still escape due to callback overwrites All waiters remain queued
isStable(true) resolution Occasionally/unreliably triggered Never triggered
Result Flaky but partially functional execution Complete deadlock and global timeout behavior

Before the queue implementation, the overwrite behavior unintentionally allowed some commands to continue executing even when stability signaling was degraded.
After the queue-based fix, all commands correctly wait for stability resolution. However, because WebKit never appears to reach a stable state once the internal __socket connection fails, the queue is never released.

This results in:

  • cy.visit() completing only for the initial HTML document
  • All subsequent JS/CSS sub-resource requests hanging
  • Vue never mounting
  • cy.session() restore hanging indefinitely
  • Global command timeouts cascading through the suite

Why This Matches Our Test Setup
Our beforeEach hooks register multiple cy.intercept() routes through page object routes() methods.
This creates multiple stability waiters during every test initialization cycle, which aligns directly with the queue-based logic introduced in PR #33446.
Because the queue never resolves in WebKit once socket communication fails, every waiter remains blocked permanently.

Additional Context
The PR itself was marked internally as:
“Medium Risk — Changes core driver stability/wait logic used by retries and command execution, which could affect timing/order of command release in edge cases.”
This WebKit proxy/socket scenario appears consistent with that class of edge case.

Suggested Investigation Areas
Potential areas worth investigating:

  1. WebKit-specific handling of Cypress internal __socket polling
  2. Stability resolution dependency on Socket.IO connectivity
  3. Proxy/origin handling for Cypress-injected resources in WebKit
  4. Adding fallback stability resolution behavior when socket connectivity fails
  5. WebKit-specific timeout/recovery path for whenStableQueue
  6. The issue appears reproducible specifically on remote HTTPS domains running through the Cypress proxy in WebKit.

Current Workaround
Affected tests are currently skipped in WebKit to avoid CI instability:
if (Cypress.isBrowser('webkit')) {
this.skip();
}

Additional Notes

  1. Issue did not occur prior to upgrading to Cypress 15.x
  2. Chrome execution remains fully stable
  3. Reproduced both locally and in CI
  4. CI runs in isolated infrastructure
  5. WebKit stage runs independently in its own scaling pool
  6. Resource contention does not appear to be a contributing factor
  7. The same WebKit test suite worked successfully on Cypress 15.7.0
  8. The issue started immediately after upgrading from 15.7.0 to 15.15.0
  9. No application-side changes were introduced alongside the Cypress upgrade
  10. This strongly suggests a regression introduced somewhere between Cypress 15.7.0 and 15.15.0

InvestigationPerformed.xlsx

Image Image Image

Desired behavior

Expected Behavior**
Vue application mounts successfully
JS/CSS bundles load normally
cy.session() restore completes
Tests execute successfully

Test code to reproduce

Cypress Version

15.15.0

Debug Logs

Other

No response

Metadata

Metadata

Assignees

Labels

TriagedIssue has been routed to backlog. This is not a commitment to have it prioritized by the team.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions