Skip to content

chore: create infrastructure to support backend function in cy.prompt #31803

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Jun 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 0 additions & 10 deletions cli/types/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1826,11 +1826,6 @@ declare namespace Cypress {
*/
prevUntil<E extends Node = HTMLElement>(element: E | JQuery<E>, filter?: string, options?: Partial<Loggable & Timeoutable>): Chainable<JQuery<E>>

/**
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I also took this opportunity to remove these types. We won't officially add them until we are ready to release the experiment

* TODO: add docs
*/
prompt(message: string, options?: Partial<Loggable & Timeoutable>): Chainable<Subject>

/**
* Read a file and yield its contents.
*
Expand Down Expand Up @@ -3163,11 +3158,6 @@ declare namespace Cypress {
* @default false
*/
experimentalStudio: boolean
/**
* Enables the prompt command feature.
* @default false
*/
experimentalPromptCommand: boolean
/**
* Adds support for testing in the WebKit browser engine used by Safari. See https://on.cypress.io/webkit-experiment for more information.
* @default false
Expand Down
16 changes: 1 addition & 15 deletions packages/app/src/runner/event-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -798,21 +798,7 @@ export class EventManager {
},
)

/**
* Call a backend request for the requesting spec bridge since we cannot have websockets in the spec bridges.
* Return it's response.
*/
Cypress.primaryOriginCommunicator.on('backend:request', async ({ args }, { source, responseEvent }) => {
let response

try {
response = await Cypress.backend(...args)
} catch (error) {
response = { error }
}

Cypress.primaryOriginCommunicator.toSource(source, responseEvent, response)
})
Cypress.handlePrimaryOriginSocketEvent(Cypress, 'backend:request')

/**
* Call an automation request for the requesting spec bridge since we cannot have websockets in the spec bridges.
Expand Down
1 change: 1 addition & 0 deletions packages/driver/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const baseConfig: Cypress.ConfigOptions = {
experimentalStudio: true,
experimentalMemoryManagement: true,
experimentalWebKitSupport: true,
// @ts-expect-error - this will not error when we actually release the experimentalPromptCommand flag
experimentalPromptCommand: true,
hosts: {
'foobar.com': '127.0.0.1',
Expand Down
10 changes: 9 additions & 1 deletion packages/driver/cypress/e2e/commands/prompt.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@ describe('src/cy/commands/prompt', () => {
return
}

cy.visit('/fixtures/dom.html')
cy.visit('http://www.foobar.com:3500/fixtures/dom.html')

// TODO: add more tests when cy.prompt is built out, but for now this just
// verifies that the command executes without throwing an error
// @ts-expect-error - this will not error when we actually release the experimentalPromptCommand flag
cy.prompt('Hello, world!')

cy.visit('http://www.barbaz.com:3500/fixtures/dom.html')

cy.origin('http://www.barbaz.com:3500', () => {
// @ts-expect-error - this will not error when we actually release the experimentalPromptCommand flag
cy.prompt('Hello, world!')
})
})
})
62 changes: 31 additions & 31 deletions packages/driver/cypress/e2e/e2e/origin/patches.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
describe('from the AUT', () => {
beforeEach(() => {
cy.intercept('/test-request').as('testRequest')
cy.stub(Cypress, 'backend').log(false).callThrough()
cy.stub(Cypress, 'backendRequestHandler').log(false).callThrough()

cy.visit('/fixtures/primary-origin.html')
cy.get('a[data-cy="xhr-fetch-requests"]').click()
Expand All @@ -87,7 +87,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout

cy.wait('@testRequest')
cy.then(() => {
expect(Cypress.backend).to.have.been.calledWith('request:sent:with:credentials', {
expect(Cypress.backendRequestHandler).to.have.been.calledWith('backend:request', 'request:sent:with:credentials', {
url: 'http://www.foobar.com:3500/test-request',
resourceType: 'fetch',
credentialStatus: assertCredentialStatus,
Expand All @@ -107,7 +107,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout

cy.wait('@testRequest')
cy.then(() => {
expect(Cypress.backend).to.have.been.calledWith('request:sent:with:credentials', {
expect(Cypress.backendRequestHandler).to.have.been.calledWith('backend:request', 'request:sent:with:credentials', {
url: 'http://www.foobar.com:3500/test-request',
resourceType: 'fetch',
credentialStatus: assertCredentialStatus,
Expand All @@ -127,7 +127,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout

cy.wait('@testRequest')
cy.then(() => {
expect(Cypress.backend).to.have.been.calledWith('request:sent:with:credentials', {
expect(Cypress.backendRequestHandler).to.have.been.calledWith('backend:request', 'request:sent:with:credentials', {
url: 'http://www.foobar.com:3500/test-request',
resourceType: 'fetch',
credentialStatus: assertCredentialStatus,
Expand All @@ -152,7 +152,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
)

cy.then(() => {
expect(Cypress.backend).not.to.have.been.calledWithMatch('request:sent:with:credentials')
expect(Cypress.backendRequestHandler).not.to.have.been.calledWithMatch('backend:request', 'request:sent:with:credentials')
})
})

Expand All @@ -171,7 +171,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
)

cy.then(() => {
expect(Cypress.backend).to.have.been.calledWith('request:sent:with:credentials', {
expect(Cypress.backendRequestHandler).to.have.been.calledWith('backend:request', 'request:sent:with:credentials', {
url: 'http://app.foobar.com:3500/test-request',
resourceType: 'fetch',
credentialStatus: 'include',
Expand All @@ -184,7 +184,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
describe('from the spec bridge', () => {
beforeEach(() => {
cy.intercept('/test-request').as('testRequest')
cy.stub(Cypress, 'backend').log(false).callThrough()
cy.stub(Cypress, 'backendRequestHandler').log(false).callThrough()

cy.visit('/fixtures/primary-origin.html')
cy.get('a[data-cy="xhr-fetch-requests"]').click()
Expand Down Expand Up @@ -216,7 +216,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
})

cy.then(() => {
expect(Cypress.backend).to.have.been.calledWith('request:sent:with:credentials', {
expect(Cypress.backendRequestHandler).to.have.been.calledWith('backend:request', 'request:sent:with:credentials', {
url: 'http://www.foobar.com:3500/test-request-credentials',
resourceType: 'fetch',
credentialStatus: assertCredentialStatus,
Expand Down Expand Up @@ -246,7 +246,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
})

cy.then(() => {
expect(Cypress.backend).to.have.been.calledWith('request:sent:with:credentials', {
expect(Cypress.backendRequestHandler).to.have.been.calledWith('backend:request', 'request:sent:with:credentials', {
url: 'http://www.foobar.com:3500/test-request-credentials',
resourceType: 'fetch',
credentialStatus: assertCredentialStatus,
Expand Down Expand Up @@ -274,7 +274,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
})

cy.then(() => {
expect(Cypress.backend).to.have.been.calledWith('request:sent:with:credentials', {
expect(Cypress.backendRequestHandler).to.have.been.calledWith('backend:request', 'request:sent:with:credentials', {
url: 'http://www.foobar.com:3500/test-request-credentials',
resourceType: 'fetch',
credentialStatus: assertCredentialStatus,
Expand All @@ -297,7 +297,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
})

cy.then(() => {
expect(Cypress.backend).not.to.have.been.calledWithMatch('request:sent:with:credentials')
expect(Cypress.backendRequestHandler).not.to.have.been.calledWithMatch('backend:request', 'request:sent:with:credentials')
})
})
})
Expand Down Expand Up @@ -326,7 +326,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
})

cy.then(() => {
expect(Cypress.backend).to.have.been.calledWith('request:sent:with:credentials', {
expect(Cypress.backendRequestHandler).to.have.been.calledWith('backend:request', 'request:sent:with:credentials', {
url: 'http://app.foobar.com:3500/test-request',
resourceType: 'fetch',
credentialStatus: 'include',
Expand All @@ -339,13 +339,13 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
// manually remove the spec bridge iframe to ensure Cypress.state('window') is not already set
window.top?.document.getElementById('Spec\ Bridge:\ foobar.com')?.remove()

cy.stub(Cypress, 'backend').log(false).callThrough()
cy.stub(Cypress, 'backendRequestHandler').log(false).callThrough()

cy.visit('/fixtures/primary-origin.html')
cy.get('a[data-cy="xhr-fetch-requests-onload"]').click()

cy.then(() => {
expect(Cypress.backend).to.have.been.calledWith('request:sent:with:credentials', {
expect(Cypress.backendRequestHandler).to.have.been.calledWith('backend:request', 'request:sent:with:credentials', {
url: 'http://localhost:3500/foo.bar.baz.json',
resourceType: 'fetch',
credentialStatus: 'same-origin',
Expand All @@ -354,7 +354,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
})

it('does not patch fetch in the spec window or the AUT if the AUT is on the primary', () => {
cy.stub(Cypress, 'backend').log(false).callThrough()
cy.stub(Cypress, 'backendRequestHandler').log(false).callThrough()
cy.visit('fixtures/xhr-fetch-requests.html')

cy.window().then((win) => {
Expand All @@ -371,14 +371,14 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
cy.then(async () => {
await fetch('/test-request')

expect(Cypress.backend).not.to.have.been.calledWithMatch('request:sent:with:credentials')
expect(Cypress.backendRequestHandler).not.to.have.been.calledWithMatch('request:sent:with:credentials')
})

// expect AUT to NOT be patched in primary
cy.window().then(async (win) => {
await win.fetch('/test-request')

expect(Cypress.backend).not.to.have.been.calledWithMatch('request:sent:with:credentials')
expect(Cypress.backendRequestHandler).not.to.have.been.calledWithMatch('request:sent:with:credentials')
})
})
})
Expand All @@ -387,7 +387,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
describe('from the AUT', () => {
beforeEach(() => {
cy.intercept('/test-request').as('testRequest')
cy.stub(Cypress, 'backend').log(false).callThrough()
cy.stub(Cypress, 'backendRequestHandler').log(false).callThrough()

cy.visit('/fixtures/primary-origin.html')
cy.get('a[data-cy="xhr-fetch-requests"]').click()
Expand All @@ -409,7 +409,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout

cy.wait('@testRequest')
cy.then(() => {
expect(Cypress.backend).to.have.been.calledWith('request:sent:with:credentials', {
expect(Cypress.backendRequestHandler).to.have.been.calledWith('backend:request', 'request:sent:with:credentials', {
url: 'http://www.foobar.com:3500/test-request',
resourceType: 'xhr',
credentialStatus: withCredentials,
Expand All @@ -431,7 +431,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
})

cy.then(() => {
expect(Cypress.backend).to.have.been.calledWithMatch('request:sent:with:credentials')
expect(Cypress.backendRequestHandler).to.have.been.calledWithMatch('backend:request', 'request:sent:with:credentials')
})
})
})
Expand All @@ -449,7 +449,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
})

cy.then(() => {
expect(Cypress.backend).to.have.been.calledWith('request:sent:with:credentials', {
expect(Cypress.backendRequestHandler).to.have.been.calledWith('backend:request', 'request:sent:with:credentials', {
url: 'http://app.foobar.com:3500/test-request',
resourceType: 'xhr',
credentialStatus: true,
Expand All @@ -461,9 +461,9 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
describe('from the spec bridge', () => {
beforeEach(() => {
cy.intercept('/test-request').as('testRequest')
cy.stub(Cypress, 'backend').log(false).callThrough()
cy.stub(Cypress, 'backendRequestHandler').log(false).callThrough()
cy.origin('http://www.foobar.com:3500', () => {
cy.stub(Cypress, 'backend').log(false).callThrough()
cy.stub(Cypress, 'backendRequestHandler').log(false).callThrough()
})

cy.visit('/fixtures/primary-origin.html')
Expand Down Expand Up @@ -501,7 +501,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
})

cy.then(() => {
expect(Cypress.backend).to.have.been.calledWith('request:sent:with:credentials', {
expect(Cypress.backendRequestHandler).to.have.been.calledWith('backend:request', 'request:sent:with:credentials', {
url: 'http://www.foobar.com:3500/test-request-credentials',
resourceType: 'xhr',
credentialStatus: withCredentials,
Expand All @@ -523,7 +523,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
})

cy.then(() => {
expect(Cypress.backend).to.have.been.calledWithMatch('request:sent:with:credentials')
expect(Cypress.backendRequestHandler).to.have.been.calledWithMatch('backend:request', 'request:sent:with:credentials')
})
})

Expand Down Expand Up @@ -553,7 +553,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
})

cy.then(() => {
expect(Cypress.backend).to.have.been.calledWith('request:sent:with:credentials', {
expect(Cypress.backendRequestHandler).to.have.been.calledWith('backend:request', 'request:sent:with:credentials', {
url: 'http://app.foobar.com:3500/test-request',
resourceType: 'xhr',
credentialStatus: true,
Expand All @@ -567,13 +567,13 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
// manually remove the spec bridge iframe to ensure Cypress.state('window') is not already set
window.top?.document.getElementById('Spec\ Bridge:\ foobar.com')?.remove()

cy.stub(Cypress, 'backend').log(false).callThrough()
cy.stub(Cypress, 'backendRequestHandler').log(false).callThrough()

cy.visit('/fixtures/primary-origin.html')
cy.get('a[data-cy="xhr-fetch-requests-onload"]').click()

cy.then(() => {
expect(Cypress.backend).to.have.been.calledWith('request:sent:with:credentials', {
expect(Cypress.backendRequestHandler).to.have.been.calledWith('backend:request', 'request:sent:with:credentials', {
url: 'http://localhost:3500/foo.bar.baz.json',
resourceType: 'xhr',
credentialStatus: false,
Expand All @@ -582,7 +582,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
})

it('does not patch xmlHttpRequest in the spec window or the AUT if the AUT is on the primary', () => {
cy.stub(Cypress, 'backend').log(false).callThrough()
cy.stub(Cypress, 'backendRequestHandler').log(false).callThrough()
cy.visit('fixtures/xhr-fetch-requests.html')

cy.window().then((win) => {
Expand Down Expand Up @@ -614,7 +614,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
xhr.send()
})

expect(Cypress.backend).not.to.have.been.calledWithMatch('request:sent:with:credentials')
expect(Cypress.backendRequestHandler).not.to.have.been.calledWithMatch('backend:request', 'request:sent:with:credentials')
})

// expect AUT to NOT be patched in primary
Expand All @@ -636,7 +636,7 @@ describe('src/cross-origin/patches', { browser: '!webkit', defaultCommandTimeout
xhr.send()
})

expect(Cypress.backend).not.to.have.been.calledWithMatch('request:sent:with:credentials')
expect(Cypress.backendRequestHandler).not.to.have.been.calledWithMatch('backend:request', 'request:sent:with:credentials')
})
})
})
Expand Down
1 change: 1 addition & 0 deletions packages/driver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"chai-subset": "1.6.0",
"clone": "2.1.2",
"common-tags": "1.8.0",
"component-emitter": "1.3.0",
"compression": "1.8.0",
"cookie-parser": "1.4.5",
"core-js-pure": "3.21.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/driver/src/cross-origin/communicator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ export class SpecBridgeCommunicator extends EventEmitter {
}: {
event: string
data?: Cypress.ObjectLike
options: {syncGlobals: boolean}
options?: {syncGlobals: boolean}
timeout: number
}) {
return new Promise<T>((resolve, reject) => {
Expand Down
9 changes: 7 additions & 2 deletions packages/driver/src/cross-origin/cypress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { bindToListeners } from '../cy/listeners'
import { handleOriginFn } from './origin_fn'
import { FINAL_SNAPSHOT_NAME } from '../cy/snapshots'
import { handleLogs } from './events/logs'
import { handleSocketEvents } from './events/socket'
import { handleCrossOriginSocketEvent, handleDefaultCrossOriginSocketEvents } from './events/socket'
import { handleSpecWindowEvents } from './events/spec_window'
import { handleErrorEvent } from './events/errors'
import { handleScreenshots } from './events/screenshots'
Expand Down Expand Up @@ -120,6 +120,12 @@ const setup = ({ cypressConfig, env, isProtocolEnabled }: { cypressConfig: Cypre

const { state, config } = Cypress

// These need to happen before the commands are created so that commands can
// use things like Cypress.backend during their creation.
handleDefaultCrossOriginSocketEvents(Cypress)

Cypress.handleCrossOriginSocketEvent = handleCrossOriginSocketEvent

// @ts-ignore
Cypress.Commands = $Commands.create(Cypress, cy, state, config)
// @ts-ignore
Expand All @@ -141,7 +147,6 @@ const setup = ({ cypressConfig, env, isProtocolEnabled }: { cypressConfig: Cypre

handleOriginFn(Cypress, cy)
handleLogs(Cypress)
handleSocketEvents(Cypress)
handleSpecWindowEvents(cy)
handleMiscEvents(Cypress, cy)
handleScreenshots(Cypress)
Expand Down
Loading