Skip to content

Commit

Permalink
fix: make sure scrollTo, window, document, title, go, reload, locatio…
Browse files Browse the repository at this point in the history
…n, hash, and url commands can communicate with the AUT (#30858)
  • Loading branch information
AtofStryker authored Jan 13, 2025
1 parent 2f01310 commit 249cfde
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 32 deletions.
1 change: 1 addition & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ in this [GitHub issue](https://github.com/cypress-io/cypress/issues/30447). Addr
- Elements whose parent elements has `overflow: clip` and no height/width will now correctly show as hidden. Fixed in [#29778](https://github.com/cypress-io/cypress/pull/29778). Fixes [#23852](https://github.com/cypress-io/cypress/issues/23852).
- The CSS pseudo-class `:dir()` is now supported when testing in Electron. Addresses [#29766](https://github.com/cypress-io/cypress/issues/29766).
- Fixed an issue where the spec filename was not updating correctly when changing specs in `open` mode. Fixes [#30852](https://github.com/cypress-io/cypress/issues/30852).
- `cy.origin()` now correctly errors when the [`cy.window()`](https://docs.cypress.io/api/commands/window), [`cy.document()`](https://docs.cypress.io/api/commands/document), [`cy.title()`](https://docs.cypress.io/api/commands/title), [`cy.url()`](https://docs.cypress.io/api/commands/url), [`cy.location()`](https://docs.cypress.io/api/commands/location) ,[`cy.hash()`](https://docs.cypress.io/api/commands/hash), [`cy.go()`](https://docs.cypress.io/api/commands/go), [`cy.reload()`](https://docs.cypress.io/api/commands/reload), and [`cy.scrollTo()`](https://docs.cypress.io/api/commands/scrollTo) commands are used outside of the `cy.origin()` command after the AUT has navigated away from the primary origin. Fixes [#30848](https://github.com/cypress-io/cypress/issues/30848). Fixed in [#30858](https://github.com/cypress-io/cypress/pull/30858).

**Misc:**

Expand Down
104 changes: 95 additions & 9 deletions packages/driver/cypress/e2e/e2e/origin/commands/actions.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,23 +190,109 @@ context('cy.origin actions', { browser: '!webkit' }, () => {

context('cross-origin AUT errors', () => {
// We only need to check .get here because the other commands are chained off of it.
// the exceptions are window(), document(), title(), url(), hash(), location(), go(), reload(), and scrollTo()
const assertOriginFailure = (err: Error, done: () => void) => {
expect(err.message).to.include(`The command was expected to run against origin \`http://localhost:3500\` but the application is at origin \`http://www.foobar.com:3500\`.`)
expect(err.message).to.include(`This commonly happens when you have either not navigated to the expected origin or have navigated away unexpectedly.`)
expect(err.message).to.include(`Using \`cy.origin()\` to wrap the commands run on \`http://www.foobar.com:3500\` will likely fix this issue.`)
expect(err.message).to.include(`cy.origin('http://www.foobar.com:3500', () => {\`\n\` <commands targeting http://www.foobar.com:3500 go here>\`\n\`})`)

// make sure that the secondary origin failures do NOT show up as spec failures or AUT failures
expect(err.message).not.to.include(`The following error originated from your test code, not from Cypress`)
expect(err.message).not.to.include(`The following error originated from your application code, not from Cypress`)
done()
}

it('.get()', { defaultCommandTimeout: 50 }, (done) => {
cy.on('fail', (err) => {
expect(err.message).to.include(`Timed out retrying after 50ms:`)
expect(err.message).to.include(`The command was expected to run against origin \`http://localhost:3500\` but the application is at origin \`http://www.foobar.com:3500\`.`)
expect(err.message).to.include(`This commonly happens when you have either not navigated to the expected origin or have navigated away unexpectedly.`)
expect(err.message).to.include(`Using \`cy.origin()\` to wrap the commands run on \`http://www.foobar.com:3500\` will likely fix this issue.`)
expect(err.message).to.include(`cy.origin('http://www.foobar.com:3500', () => {\`\n\` <commands targeting http://www.foobar.com:3500 go here>\`\n\`})`)

// make sure that the secondary origin failures do NOT show up as spec failures or AUT failures
expect(err.message).not.to.include(`The following error originated from your test code, not from Cypress`)
expect(err.message).not.to.include(`The following error originated from your application code, not from Cypress`)
done()
assertOriginFailure(err, done)
})

cy.get('a[data-cy="dom-link"]').click()
cy.get('#button')
})

it('.window()', (done) => {
cy.on('fail', (err) => {
assertOriginFailure(err, done)
})

cy.get('a[data-cy="dom-link"]').click()
cy.window()
})

it('.document()', (done) => {
cy.on('fail', (err) => {
assertOriginFailure(err, done)
})

cy.get('a[data-cy="dom-link"]').click()
cy.document()
})

it('.title()', (done) => {
cy.on('fail', (err) => {
assertOriginFailure(err, done)
})

cy.get('a[data-cy="dom-link"]').click()
cy.title()
})

it('.url()', (done) => {
cy.on('fail', (err) => {
assertOriginFailure(err, done)
})

cy.get('a[data-cy="dom-link"]').click()
cy.url()
})

it('.hash()', (done) => {
cy.on('fail', (err) => {
assertOriginFailure(err, done)
})

cy.get('a[data-cy="dom-link"]').click()
cy.hash()
})

it('.location()', (done) => {
cy.on('fail', (err) => {
assertOriginFailure(err, done)
})

cy.get('a[data-cy="dom-link"]').click()
cy.location()
})

it('.go()', (done) => {
cy.on('fail', (err) => {
assertOriginFailure(err, done)
})

cy.get('a[data-cy="dom-link"]').click()
cy.go('back')
})

it('.reload()', (done) => {
cy.on('fail', (err) => {
assertOriginFailure(err, done)
})

cy.get('a[data-cy="dom-link"]').click()
cy.reload()
})

it('.scrollTo()', (done) => {
cy.on('fail', (err) => {
assertOriginFailure(err, done)
})

cy.get('a[data-cy="dom-link"]').click()
cy.scrollTo('bottom')
})
})

context('#consoleProps', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@ context('cy.origin viewport', { browser: '!webkit' }, () => {

cy.window().its('innerHeight').should('eq', 480)
cy.window().its('innerWidth').should('eq', 320)
})

cy.window().then((win) => {
win.location.href = 'http://www.idp.com:3500/fixtures/primary-origin.html'
cy.window().then((win) => {
win.location.href = 'http://www.idp.com:3500/fixtures/primary-origin.html'
})
})

cy.origin('http://www.idp.com:3500', () => {
Expand Down
10 changes: 5 additions & 5 deletions packages/driver/cypress/e2e/e2e/origin/navigation.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,11 @@ describe('event timing', { browser: '!webkit' }, () => {

cy.origin('http://www.foobar.com:3500', () => {
cy.log('inside cy.origin foobar')
})

// This command is run from localhost against the cross-origin aut. Updating href is one of the few allowed commands. See https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#location
cy.window().then((win) => {
win.location.href = 'http://www.idp.com:3500/fixtures/primary-origin.html'
// Updating href is one of the few allowed commands. See https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#location
// However, not everything on the window is accessible. Therefore, we force window() to only run on the same origin as the AUT context
cy.window().then((win) => {
win.location.href = 'http://www.idp.com:3500/fixtures/primary-origin.html'
})
})

cy.origin('http://www.idp.com:3500', () => {
Expand Down
3 changes: 3 additions & 0 deletions packages/driver/src/cy/commands/actions/scroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@ export default (Commands, Cypress, cy, state) => {
const subjectChain = cy.subjectChain()

const ensureScrollability = () => {
// Make sure the scroll command can communicate with the AUT
Cypress.ensure.commandCanCommunicateWithAUT(cy)

try {
subject = cy.getSubjectFromChain(subjectChain)

Expand Down
9 changes: 9 additions & 0 deletions packages/driver/src/cy/commands/location.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import $errUtils from '../../cypress/error_utils'

export default (Commands, Cypress, cy) => {
Commands.addQuery('url', function url (options: Partial<Cypress.UrlOptions> = {}) {
// Make sure the url command can communicate with the AUT.
// otherwise, it yields an empty string
Cypress.ensure.commandCanCommunicateWithAUT(cy)
this.set('timeout', options.timeout)

Cypress.log({ message: '', hidden: options.log === false, timeout: options.timeout })
Expand All @@ -16,6 +19,8 @@ export default (Commands, Cypress, cy) => {
})

Commands.addQuery('hash', function url (options: Partial<Cypress.Loggable & Cypress.Timeoutable> = {}) {
// Make sure the hash command can communicate with the AUT.
Cypress.ensure.commandCanCommunicateWithAUT(cy)
this.set('timeout', options.timeout)

Cypress.log({ message: '', hidden: options.log === false, timeout: options.timeout })
Expand All @@ -26,6 +31,10 @@ export default (Commands, Cypress, cy) => {
Commands.addQuery('location', function location (key, options: Partial<Cypress.Loggable & Cypress.Timeoutable> = {}) {
// normalize arguments allowing key + options to be undefined
// key can represent the options

// Make sure the location command can communicate with the AUT.
// otherwise the command just yields 'null' and the reason may be unclear to the user.
Cypress.ensure.commandCanCommunicateWithAUT(cy)
if (_.isObject(key)) {
options = key
}
Expand Down
7 changes: 7 additions & 0 deletions packages/driver/src/cy/commands/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,10 @@ export default (Commands, Cypress, cy, state, config) => {
cleanup()
}

// Make sure the reload command can communicate with the AUT.
// if we failed for any other reason, we need to display the correct error to the user.
Cypress.ensure.commandCanCommunicateWithAUT(cy)

return null
})
},
Expand Down Expand Up @@ -700,6 +704,9 @@ export default (Commands, Cypress, cy, state, config) => {
cleanup()
}

// Make sure the go command can communicate with the AUT.
Cypress.ensure.commandCanCommunicateWithAUT(cy)

return null
})
}
Expand Down
7 changes: 7 additions & 0 deletions packages/driver/src/cy/commands/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,18 @@ export default (Commands, Cypress, cy, state) => {
}

Commands.addQuery('title', function title (options: Partial<Cypress.Loggable & Cypress.Timeoutable> = {}) {
// Make sure the window command can communicate with the AUT.
// otherwise, it yields an empty string
Cypress.ensure.commandCanCommunicateWithAUT(cy)
this.set('timeout', options.timeout)
Cypress.log({ timeout: options.timeout, hidden: options.log === false })

return () => (state('document')?.title || '')
})

Commands.addQuery('window', function windowFn (options: Partial<Cypress.Loggable & Cypress.Timeoutable> = {}) {
// Make sure the window command can communicate with the AUT.
Cypress.ensure.commandCanCommunicateWithAUT(cy)
this.set('timeout', options.timeout)
Cypress.log({
hidden: options.log === false,
Expand All @@ -114,6 +119,8 @@ export default (Commands, Cypress, cy, state) => {
})

Commands.addQuery('document', function documentFn (options: Partial<Cypress.Loggable & Cypress.Timeoutable> = {}) {
// Make sure the document command can communicate with the AUT.
Cypress.ensure.commandCanCommunicateWithAUT(cy)
this.set('timeout', options.timeout)
Cypress.log({
hidden: options.log === false,
Expand Down
6 changes: 3 additions & 3 deletions packages/graphql/schemas/cloud.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ type CloudProjectNotFound {
}

union CloudProjectResult =
CloudProject
| CloudProject
| CloudProjectNotFound
| CloudProjectUnauthorized

Expand Down Expand Up @@ -456,7 +456,7 @@ type CloudProjectSpec implements Node {
}

union CloudProjectSpecFlakyResult =
CloudFeatureNotEnabled
| CloudFeatureNotEnabled
| CloudProjectSpecFlakyStatus

type CloudProjectSpecFlakyStatus {
Expand Down Expand Up @@ -500,7 +500,7 @@ type CloudProjectSpecNotFound {
}

union CloudProjectSpecResult =
CloudProjectSpec
| CloudProjectSpec
| CloudProjectSpecNotFound
| CloudProjectUnauthorized

Expand Down
39 changes: 27 additions & 12 deletions system-tests/__snapshots__/web_security_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,47 @@ exports['e2e web security / when enabled / fails'] = `
1) web security
fails when clicking <a> to another origin:
CypressError: The command was expected to run against origin \`http://localhost:4466\` but the application is at origin \`https://www.foo.com:44665\`.
Timed out retrying after 4000ms
+ expected - actual
This commonly happens when you have either not navigated to the expected origin or have navigated away unexpectedly.
+'https://www.foo.com:44665/cross_origin'
Using \`cy.origin()\` to wrap the commands run on \`https://www.foo.com:44665\` will likely fix this issue.
\`cy.origin('https://www.foo.com:44665', () => {\`
\` <commands targeting https://www.foo.com:44665 go here>\`
\`})\`
https://on.cypress.io/cy-visit-succeeded-but-commands-fail
[stack trace lines]
2) web security
fails when submitted a form and being redirected to another origin:
CypressError: The command was expected to run against origin \`http://localhost:4466\` but the application is at origin \`https://www.foo.com:44665\`.
This commonly happens when you have either not navigated to the expected origin or have navigated away unexpectedly.
Timed out retrying after 4000ms
+ expected - actual
Using \`cy.origin()\` to wrap the commands run on \`https://www.foo.com:44665\` will likely fix this issue.
+'https://www.foo.com:44665/cross_origin'
\`cy.origin('https://www.foo.com:44665', () => {\`
\` <commands targeting https://www.foo.com:44665 go here>\`
\`})\`
https://on.cypress.io/cy-visit-succeeded-but-commands-fail
[stack trace lines]
3) web security
fails when using a javascript redirect to another origin:
CypressError: The command was expected to run against origin \`http://localhost:4466\` but the application is at origin \`https://www.foo.com:44665\`.
This commonly happens when you have either not navigated to the expected origin or have navigated away unexpectedly.
Using \`cy.origin()\` to wrap the commands run on \`https://www.foo.com:44665\` will likely fix this issue.
Timed out retrying after 4000ms
+ expected - actual
\`cy.origin('https://www.foo.com:44665', () => {\`
\` <commands targeting https://www.foo.com:44665 go here>\`
\`})\`
+'https://www.foo.com:44665/cross_origin'
https://on.cypress.io/cy-visit-succeeded-but-commands-fail
[stack trace lines]
4) web security
Expand Down

4 comments on commit 249cfde

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 249cfde Jan 13, 2025

Choose a reason for hiding this comment

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

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/14.0.0/linux-x64/develop-249cfde3e20343a918cb36e2dfaf4b930f978b19/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 249cfde Jan 13, 2025

Choose a reason for hiding this comment

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

Circle has built the linux arm64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/14.0.0/linux-arm64/develop-249cfde3e20343a918cb36e2dfaf4b930f978b19/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 249cfde Jan 13, 2025

Choose a reason for hiding this comment

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

Circle has built the darwin arm64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/14.0.0/darwin-arm64/develop-249cfde3e20343a918cb36e2dfaf4b930f978b19/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 249cfde Jan 13, 2025

Choose a reason for hiding this comment

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

Circle has built the darwin x64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/14.0.0/darwin-x64/develop-249cfde3e20343a918cb36e2dfaf4b930f978b19/cypress.tgz

Please sign in to comment.