Skip to content

Commit 09b006d

Browse files
committed
fix: make sure scrollTo, window, document, title, go, reload, location, hash, and url commands can communicate with the AUT
1 parent 2f01310 commit 09b006d

File tree

10 files changed

+160
-32
lines changed

10 files changed

+160
-32
lines changed

cli/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ in this [GitHub issue](https://github.com/cypress-io/cypress/issues/30447). Addr
5656
- 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).
5757
- The CSS pseudo-class `:dir()` is now supported when testing in Electron. Addresses [#29766](https://github.com/cypress-io/cypress/issues/29766).
5858
- 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).
59+
- `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).
5960

6061
**Misc:**
6162

packages/driver/cypress/e2e/e2e/origin/commands/actions.cy.ts

+95-9
Original file line numberDiff line numberDiff line change
@@ -190,23 +190,109 @@ context('cy.origin actions', { browser: '!webkit' }, () => {
190190

191191
context('cross-origin AUT errors', () => {
192192
// We only need to check .get here because the other commands are chained off of it.
193+
// the exceptions are window(), document(), title(), url(), hash(), location(), go(), reload(), and scrollTo()
194+
const assertOriginFailure = (err: Error, done: () => void) => {
195+
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\`.`)
196+
expect(err.message).to.include(`This commonly happens when you have either not navigated to the expected origin or have navigated away unexpectedly.`)
197+
expect(err.message).to.include(`Using \`cy.origin()\` to wrap the commands run on \`http://www.foobar.com:3500\` will likely fix this issue.`)
198+
expect(err.message).to.include(`cy.origin('http://www.foobar.com:3500', () => {\`\n\` <commands targeting http://www.foobar.com:3500 go here>\`\n\`})`)
199+
200+
// make sure that the secondary origin failures do NOT show up as spec failures or AUT failures
201+
expect(err.message).not.to.include(`The following error originated from your test code, not from Cypress`)
202+
expect(err.message).not.to.include(`The following error originated from your application code, not from Cypress`)
203+
done()
204+
}
205+
193206
it('.get()', { defaultCommandTimeout: 50 }, (done) => {
194207
cy.on('fail', (err) => {
195208
expect(err.message).to.include(`Timed out retrying after 50ms:`)
196-
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\`.`)
197-
expect(err.message).to.include(`This commonly happens when you have either not navigated to the expected origin or have navigated away unexpectedly.`)
198-
expect(err.message).to.include(`Using \`cy.origin()\` to wrap the commands run on \`http://www.foobar.com:3500\` will likely fix this issue.`)
199-
expect(err.message).to.include(`cy.origin('http://www.foobar.com:3500', () => {\`\n\` <commands targeting http://www.foobar.com:3500 go here>\`\n\`})`)
200-
201-
// make sure that the secondary origin failures do NOT show up as spec failures or AUT failures
202-
expect(err.message).not.to.include(`The following error originated from your test code, not from Cypress`)
203-
expect(err.message).not.to.include(`The following error originated from your application code, not from Cypress`)
204-
done()
209+
assertOriginFailure(err, done)
205210
})
206211

207212
cy.get('a[data-cy="dom-link"]').click()
208213
cy.get('#button')
209214
})
215+
216+
it('.window()', (done) => {
217+
cy.on('fail', (err) => {
218+
assertOriginFailure(err, done)
219+
})
220+
221+
cy.get('a[data-cy="dom-link"]').click()
222+
cy.window()
223+
})
224+
225+
it('.document()', (done) => {
226+
cy.on('fail', (err) => {
227+
assertOriginFailure(err, done)
228+
})
229+
230+
cy.get('a[data-cy="dom-link"]').click()
231+
cy.document()
232+
})
233+
234+
it('.title()', (done) => {
235+
cy.on('fail', (err) => {
236+
assertOriginFailure(err, done)
237+
})
238+
239+
cy.get('a[data-cy="dom-link"]').click()
240+
cy.title()
241+
})
242+
243+
it('.url()', (done) => {
244+
cy.on('fail', (err) => {
245+
assertOriginFailure(err, done)
246+
})
247+
248+
cy.get('a[data-cy="dom-link"]').click()
249+
cy.url()
250+
})
251+
252+
it('.hash()', (done) => {
253+
cy.on('fail', (err) => {
254+
assertOriginFailure(err, done)
255+
})
256+
257+
cy.get('a[data-cy="dom-link"]').click()
258+
cy.hash()
259+
})
260+
261+
it('.location()', (done) => {
262+
cy.on('fail', (err) => {
263+
assertOriginFailure(err, done)
264+
})
265+
266+
cy.get('a[data-cy="dom-link"]').click()
267+
cy.location()
268+
})
269+
270+
it('.go()', (done) => {
271+
cy.on('fail', (err) => {
272+
assertOriginFailure(err, done)
273+
})
274+
275+
cy.get('a[data-cy="dom-link"]').click()
276+
cy.go('back')
277+
})
278+
279+
it('.reload()', (done) => {
280+
cy.on('fail', (err) => {
281+
assertOriginFailure(err, done)
282+
})
283+
284+
cy.get('a[data-cy="dom-link"]').click()
285+
cy.reload()
286+
})
287+
288+
it('.scrollTo()', (done) => {
289+
cy.on('fail', (err) => {
290+
assertOriginFailure(err, done)
291+
})
292+
293+
cy.get('a[data-cy="dom-link"]').click()
294+
cy.scrollTo('bottom')
295+
})
210296
})
211297

212298
context('#consoleProps', () => {

packages/driver/cypress/e2e/e2e/origin/commands/viewport.cy.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,10 @@ context('cy.origin viewport', { browser: '!webkit' }, () => {
154154

155155
cy.window().its('innerHeight').should('eq', 480)
156156
cy.window().its('innerWidth').should('eq', 320)
157-
})
158157

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

163163
cy.origin('http://www.idp.com:3500', () => {

packages/driver/cypress/e2e/e2e/origin/navigation.cy.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,11 @@ describe('event timing', { browser: '!webkit' }, () => {
192192

193193
cy.origin('http://www.foobar.com:3500', () => {
194194
cy.log('inside cy.origin foobar')
195-
})
196-
197-
// 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
198-
cy.window().then((win) => {
199-
win.location.href = 'http://www.idp.com:3500/fixtures/primary-origin.html'
195+
// Updating href is one of the few allowed commands. See https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#location
196+
// However, not everything on the window is accessible. Therefore, we force window() to only run on the same origin as the AUT context
197+
cy.window().then((win) => {
198+
win.location.href = 'http://www.idp.com:3500/fixtures/primary-origin.html'
199+
})
200200
})
201201

202202
cy.origin('http://www.idp.com:3500', () => {

packages/driver/src/cy/commands/actions/scroll.ts

+3
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,9 @@ export default (Commands, Cypress, cy, state) => {
325325
const subjectChain = cy.subjectChain()
326326

327327
const ensureScrollability = () => {
328+
// Make sure the scroll command can communicate with the AUT
329+
Cypress.ensure.commandCanCommunicateWithAUT(cy)
330+
328331
try {
329332
subject = cy.getSubjectFromChain(subjectChain)
330333

packages/driver/src/cy/commands/location.ts

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import $errUtils from '../../cypress/error_utils'
44

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

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

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

2126
Cypress.log({ message: '', hidden: options.log === false, timeout: options.timeout })
@@ -26,6 +31,10 @@ export default (Commands, Cypress, cy) => {
2631
Commands.addQuery('location', function location (key, options: Partial<Cypress.Loggable & Cypress.Timeoutable> = {}) {
2732
// normalize arguments allowing key + options to be undefined
2833
// key can represent the options
34+
35+
// Make sure the location command can communicate with the AUT.
36+
// otherwise the command just yields 'null' and the reason may be unclear to the user.
37+
Cypress.ensure.commandCanCommunicateWithAUT(cy)
2938
if (_.isObject(key)) {
3039
options = key
3140
}

packages/driver/src/cy/commands/navigation.ts

+7
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,10 @@ export default (Commands, Cypress, cy, state, config) => {
616616
cleanup()
617617
}
618618

619+
// Make sure the reload command can communicate with the AUT.
620+
// if we failed for any other reason, we need to display the correct error to the user.
621+
Cypress.ensure.commandCanCommunicateWithAUT(cy)
622+
619623
return null
620624
})
621625
},
@@ -700,6 +704,9 @@ export default (Commands, Cypress, cy, state, config) => {
700704
cleanup()
701705
}
702706

707+
// Make sure the go command can communicate with the AUT.
708+
Cypress.ensure.commandCanCommunicateWithAUT(cy)
709+
703710
return null
704711
})
705712
}

packages/driver/src/cy/commands/window.ts

+7
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,18 @@ export default (Commands, Cypress, cy, state) => {
8989
}
9090

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

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

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

116121
Commands.addQuery('document', function documentFn (options: Partial<Cypress.Loggable & Cypress.Timeoutable> = {}) {
122+
// Make sure the document command can communicate with the AUT.
123+
Cypress.ensure.commandCanCommunicateWithAUT(cy)
117124
this.set('timeout', options.timeout)
118125
Cypress.log({
119126
hidden: options.log === false,

packages/graphql/schemas/cloud.graphql

+3-3
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ type CloudProjectNotFound {
333333
}
334334

335335
union CloudProjectResult =
336-
CloudProject
336+
| CloudProject
337337
| CloudProjectNotFound
338338
| CloudProjectUnauthorized
339339

@@ -456,7 +456,7 @@ type CloudProjectSpec implements Node {
456456
}
457457

458458
union CloudProjectSpecFlakyResult =
459-
CloudFeatureNotEnabled
459+
| CloudFeatureNotEnabled
460460
| CloudProjectSpecFlakyStatus
461461

462462
type CloudProjectSpecFlakyStatus {
@@ -500,7 +500,7 @@ type CloudProjectSpecNotFound {
500500
}
501501

502502
union CloudProjectSpecResult =
503-
CloudProjectSpec
503+
| CloudProjectSpec
504504
| CloudProjectSpecNotFound
505505
| CloudProjectUnauthorized
506506

system-tests/__snapshots__/web_security_spec.js

+27-12
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,47 @@ exports['e2e web security / when enabled / fails'] = `
3030
3131
1) web security
3232
fails when clicking <a> to another origin:
33+
CypressError: The command was expected to run against origin \`http://localhost:4466\` but the application is at origin \`https://www.foo.com:44665\`.
3334
34-
Timed out retrying after 4000ms
35-
+ expected - actual
35+
This commonly happens when you have either not navigated to the expected origin or have navigated away unexpectedly.
3636
37-
+'https://www.foo.com:44665/cross_origin'
38-
37+
Using \`cy.origin()\` to wrap the commands run on \`https://www.foo.com:44665\` will likely fix this issue.
38+
39+
\`cy.origin('https://www.foo.com:44665', () => {\`
40+
\` <commands targeting https://www.foo.com:44665 go here>\`
41+
\`})\`
42+
43+
https://on.cypress.io/cy-visit-succeeded-but-commands-fail
3944
[stack trace lines]
4045
4146
2) web security
4247
fails when submitted a form and being redirected to another origin:
48+
CypressError: The command was expected to run against origin \`http://localhost:4466\` but the application is at origin \`https://www.foo.com:44665\`.
49+
50+
This commonly happens when you have either not navigated to the expected origin or have navigated away unexpectedly.
4351
44-
Timed out retrying after 4000ms
45-
+ expected - actual
52+
Using \`cy.origin()\` to wrap the commands run on \`https://www.foo.com:44665\` will likely fix this issue.
4653
47-
+'https://www.foo.com:44665/cross_origin'
48-
54+
\`cy.origin('https://www.foo.com:44665', () => {\`
55+
\` <commands targeting https://www.foo.com:44665 go here>\`
56+
\`})\`
57+
58+
https://on.cypress.io/cy-visit-succeeded-but-commands-fail
4959
[stack trace lines]
5060
5161
3) web security
5262
fails when using a javascript redirect to another origin:
63+
CypressError: The command was expected to run against origin \`http://localhost:4466\` but the application is at origin \`https://www.foo.com:44665\`.
64+
65+
This commonly happens when you have either not navigated to the expected origin or have navigated away unexpectedly.
66+
67+
Using \`cy.origin()\` to wrap the commands run on \`https://www.foo.com:44665\` will likely fix this issue.
5368
54-
Timed out retrying after 4000ms
55-
+ expected - actual
69+
\`cy.origin('https://www.foo.com:44665', () => {\`
70+
\` <commands targeting https://www.foo.com:44665 go here>\`
71+
\`})\`
5672
57-
+'https://www.foo.com:44665/cross_origin'
58-
73+
https://on.cypress.io/cy-visit-succeeded-but-commands-fail
5974
[stack trace lines]
6075
6176
4) web security

0 commit comments

Comments
 (0)