mirror of
https://github.com/cypress-io/cypress.git
synced 2026-01-25 16:39:04 -06:00
fix: make sure scrollTo, window, document, title, go, reload, location, hash, and url commands can communicate with the AUT (#30858)
This commit is contained in:
@@ -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:**
|
||||
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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 })
|
||||
@@ -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 })
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
})
|
||||
},
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -89,6 +89,9 @@ 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 })
|
||||
|
||||
@@ -96,6 +99,8 @@ export default (Commands, Cypress, cy, state) => {
|
||||
})
|
||||
|
||||
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,
|
||||
@@ -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,
|
||||
|
||||
@@ -333,7 +333,7 @@ type CloudProjectNotFound {
|
||||
}
|
||||
|
||||
union CloudProjectResult =
|
||||
CloudProject
|
||||
| CloudProject
|
||||
| CloudProjectNotFound
|
||||
| CloudProjectUnauthorized
|
||||
|
||||
@@ -456,7 +456,7 @@ type CloudProjectSpec implements Node {
|
||||
}
|
||||
|
||||
union CloudProjectSpecFlakyResult =
|
||||
CloudFeatureNotEnabled
|
||||
| CloudFeatureNotEnabled
|
||||
| CloudProjectSpecFlakyStatus
|
||||
|
||||
type CloudProjectSpecFlakyStatus {
|
||||
@@ -500,7 +500,7 @@ type CloudProjectSpecNotFound {
|
||||
}
|
||||
|
||||
union CloudProjectSpecResult =
|
||||
CloudProjectSpec
|
||||
| CloudProjectSpec
|
||||
| CloudProjectSpecNotFound
|
||||
| CloudProjectUnauthorized
|
||||
|
||||
|
||||
@@ -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\`.
|
||||
|
||||
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]
|
||||
|
||||
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\`.
|
||||
|
||||
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]
|
||||
|
||||
4) web security
|
||||
|
||||
Reference in New Issue
Block a user