Skip to content
Open
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
dc16aef
fix: Browser will freeze when sync request is intercepted
alexsch01 Nov 10, 2025
9182b4e
Update CHANGELOG.md
alexsch01 Nov 10, 2025
4801766
Update CHANGELOG.md
alexsch01 Nov 10, 2025
7b4f2e7
prevent cross origin cookies from breaking sync requests
alexsch01 Nov 11, 2025
02f6105
Update xmlHttpRequest.ts
alexsch01 Nov 12, 2025
7f0d6c6
Update xmlHttpRequest.ts
alexsch01 Nov 12, 2025
12a25e4
fix lint
alexsch01 Nov 12, 2025
6a21ef2
Merge branch 'develop' into fix-browser-freeze
alexsch01 Nov 14, 2025
a837527
Update intercepted-request.ts
alexsch01 Nov 18, 2025
3cdaa5f
Update response-middleware.ts
alexsch01 Nov 18, 2025
c27f137
Merge branch 'develop' into fix-browser-freeze
alexsch01 Nov 18, 2025
247da30
grammar fix
alexsch01 Nov 18, 2025
6664756
better warning
alexsch01 Nov 18, 2025
a9e67e1
Blank
alexsch01 Nov 18, 2025
5a65b0c
Update intercepted-request.ts
alexsch01 Nov 18, 2025
7d4a48b
Update response-middleware.ts
alexsch01 Nov 18, 2025
88c83e1
Update xmlHttpRequest.ts
alexsch01 Nov 18, 2025
29b4dc7
Merge branch 'develop' into fix-browser-freeze
jennifer-shehane Nov 19, 2025
775edee
Alexsch01 patch 1
alexsch01 Nov 19, 2025
844904d
Update xmlHttpRequest.ts
alexsch01 Nov 19, 2025
be6a22f
Update main.js
alexsch01 Nov 19, 2025
cda831d
this is correct now
alexsch01 Nov 20, 2025
f846e8e
move sync intercept and move patches
mschile Nov 20, 2025
da1d38f
Merge branch 'develop' into fix-browser-freeze
jennifer-shehane Nov 20, 2025
931b4fe
add unit test for proxy
alexsch01 Nov 21, 2025
82707fc
Create intercept_sync_request.cy.ts
alexsch01 Nov 21, 2025
cfabc45
Create sync_request_with_cookie.cy.ts
alexsch01 Nov 21, 2025
ad809b6
lint
alexsch01 Nov 21, 2025
48807a6
Update intercept_sync_request.cy.ts
alexsch01 Nov 22, 2025
8adc9d1
Update intercept_sync_request.cy.ts
alexsch01 Nov 22, 2025
39a2fa3
Update sync_request_with_cookie.cy.ts
alexsch01 Nov 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ _Released 11/18/2025 (PENDING)_
- Fixed an issue where [`cy.wrap()`](https://docs.cypress.io/api/commands/wrap) would cause infinite recursion and freeze the Cypress App when called with objects containing circular references. Fixes [#24715](https://github.com/cypress-io/cypress/issues/24715). Addressed in [#32917](https://github.com/cypress-io/cypress/pull/32917).
- Fixed an issue where top changes on test retries could cause attempt numbers to show up more than one time in the reporter and cause attempts to be lost in Test Replay. Addressed in [#32888](https://github.com/cypress-io/cypress/pull/32888).
- Fixed an issue where stack traces that are used to determine a test's invocation details are sometimes incorrect. Addressed in [#32699](https://github.com/cypress-io/cypress/pull/32699)
- Fixed an issue where the browser will freeze when Cypress intercepts a synchronous request and a routeHandler is used. Fixes [#32874](https://github.com/cypress-io/cypress/issues/32874). Addressed in [#32925](https://github.com/cypress-io/cypress/pull/32925).
- Fixed an issue where larger than expected config values were causing issues in certain cases when recording to the Cypress Cloud. Addressed in [#32957](https://github.com/cypress-io/cypress/pull/32957)


Expand Down
7 changes: 7 additions & 0 deletions packages/net-stubbing/lib/server/intercepted-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { BackendRoute, NetStubbingState } from './types'
import { emit, sendStaticResponse } from './util'
import type CyServer from '@packages/server'
import type { BackendStaticResponse } from '../internal-types'
import { styleText } from 'util'

export class InterceptedRequest {
id: string
Expand Down Expand Up @@ -72,6 +73,12 @@ export class InterceptedRequest {
return
}

if (this.req.isSyncRequest) {
process.stdout.write(styleText('yellow', 'WARNING: sync request was not intercepted\n'))

return
}

for (const route of this.req.matchingRoutes) {
if (route.disabled) {
continue
Expand Down
5 changes: 5 additions & 0 deletions packages/proxy/lib/http/request-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,16 @@ const ExtractCypressMetadataHeaders: RequestMiddleware = function () {

this.req.isAUTFrame = !!this.req.headers['x-cypress-is-aut-frame']
this.req.isFromExtraTarget = !!this.req.headers['x-cypress-is-from-extra-target']
this.req.isSyncRequest = !!this.req.headers['x-cypress-is-sync-request']

if (this.req.headers['x-cypress-is-aut-frame']) {
delete this.req.headers['x-cypress-is-aut-frame']
}

if (this.req.headers['x-cypress-is-sync-request']) {
delete this.req.headers['x-cypress-is-sync-request']
}

span?.setAttributes({
isAUTFrame: this.req.isAUTFrame,
isFromExtraTarget: this.req.isFromExtraTarget,
Expand Down
9 changes: 9 additions & 0 deletions packages/proxy/lib/http/response-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { hasServiceWorkerHeader, isVerboseTelemetry as isVerbose } from '.'
import { CookiesHelper } from './util/cookies'
import * as rewriter from './util/rewriter'
import { doesTopNeedToBeSimulated } from './util/top-simulation'
import { styleText } from 'util'

import type Debug from 'debug'
import type { CookieOptions } from 'express'
Expand Down Expand Up @@ -719,6 +720,14 @@ const MaybeCopyCookiesFromIncomingRes: ResponseMiddleware = async function () {
return this.next()
}

if (this.req.isSyncRequest) {
process.stdout.write(styleText('yellow', 'WARNING: cross-origin cookies may not have been applied\n'))

span?.end()

return this.next()
}

// we want to set the cookies via automation so they exist in the browser
// itself. however, firefox will hang if we try to use the extension
// to set cookies on a url that's in-flight, so we send the cookies down to
Expand Down
1 change: 1 addition & 0 deletions packages/proxy/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export type CypressIncomingRequest = Request & {
* Stack-ordered list of `cy.intercept()`s matching this request.
*/
matchingRoutes?: BackendRoute[]
isSyncRequest: boolean
}

export type RequestCredentialLevel = 'same-origin' | 'include' | 'omit' | boolean
Expand Down
12 changes: 12 additions & 0 deletions packages/runner/injection/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,15 @@ Cypress.on('app:timers:pause', timers.pause)
timers.wrap()

Cypress.action('app:window:before:load', window)

const originalXmlHttpRequestOpen = window.XMLHttpRequest.prototype.open

window.XMLHttpRequest.prototype.open = function (...args) {
const result = originalXmlHttpRequestOpen.apply(this, args)

if (args.length > 2 && !args[2]) {
this.setRequestHeader('x-cypress-is-sync-request', 'true')
}

return result
}
39 changes: 27 additions & 12 deletions packages/runner/injection/patches/xmlHttpRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,37 @@ export const patchXmlHttpRequest = (window: Window) => {
// we need to store a reference here to what we need in the send method
this._url = captureFullRequestUrl(args[1], window)
} finally {
return originalXmlHttpRequestOpen.apply(this, args as any)
const result = originalXmlHttpRequestOpen.apply(this, args as any)

if (args.length > 2 && !args[2]) {
this.setRequestHeader('x-cypress-is-sync-request', 'true')
this._isSyncRequest = true
} else {
this._isSyncRequest = false
}

return result
}
}

window.XMLHttpRequest.prototype.send = async function (...args) {
try {
// if the option is specified, communicate it to the the server to the proxy can make the request aware if it needs to potentially apply cross origin cookies
// if the option isn't set, we can imply the default as we know the "resourceType" in the proxy
await requestSentWithCredentials({
url: this._url,
resourceType: 'xhr',
credentialStatus: this.withCredentials,
})
} finally {
// if our internal logic errors for whatever reason, do NOT block the end user and continue the request
window.XMLHttpRequest.prototype.send = function (...args) {
if (this._isSyncRequest) {
return originalXmlHttpRequestSend.apply(this, args)
}

return (async () => {
try {
// if the option is specified, communicate it to the the server to the proxy can make the request aware if it needs to potentially apply cross origin cookies
// if the option isn't set, we can imply the default as we know the "resourceType" in the proxy
await requestSentWithCredentials({
url: this._url,
resourceType: 'xhr',
credentialStatus: this.withCredentials,
})
} finally {
// if our internal logic errors for whatever reason, do NOT block the end user and continue the request
return originalXmlHttpRequestSend.apply(this, args)
}
})()
}
}