|
| 1 | +--- |
| 2 | +title: Cross Origin Testing |
| 3 | +--- |
| 4 | + |
| 5 | +<Alert type="info"> |
| 6 | + |
| 7 | +<strong class="alert-header"> Note </strong> |
| 8 | + |
| 9 | +As of Cypress [v12.0.0](https://on.cypress.io/changelog#12-0-0), Cypress has the |
| 10 | +capability to visit multiple origins in a single test via the |
| 11 | +[cy.origin()](https://on.cypress.io/origin) command! |
| 12 | + |
| 13 | +</Alert> |
| 14 | + |
| 15 | +Cypress limits each test to visiting domains that share the same superdomain. If |
| 16 | +a navigation occurs that does not meet the same superdomain rule, the |
| 17 | +[`cy.origin()`](/api/commands/origin) command must be used to execute Cypress |
| 18 | +commands inside the newly navigated origin. |
| 19 | + |
| 20 | +But what is same superdomain? It is actually very similar to that of same |
| 21 | +origin! Two URLs have the same origin if the protocol, port (if specified), and |
| 22 | +host match. Cypress automatically handles hosts of the same superdomain by |
| 23 | +injecting the |
| 24 | +[`document.domain`](https://developer.mozilla.org/en-US/docs/Web/API/Document/domain) |
| 25 | +property into the visited `text/html` pages. This is why navigations without the |
| 26 | +use of the [`cy.origin()`](/api/commands/origin) command are solely scope to the |
| 27 | +same superdomain. |
| 28 | + |
| 29 | +We understand this is a bit complicated to understand, so we have built a nifty |
| 30 | +chart to help clarify the differences! |
| 31 | + |
| 32 | +### Parts of a URL |
| 33 | + |
| 34 | +``` |
| 35 | +┌───────────────────────────────────────────────────────────────────────────────────────┐ |
| 36 | +│ href │ |
| 37 | +├──────────┬──┬─────────────────────────────────────┬───────────────────────────┬───────┤ |
| 38 | +│ protocol │ │ host │ path │ hash │ |
| 39 | +│ │ ├──────────────────────────────┬──────┼──────────┬────────────────┤ │ |
| 40 | +│ │ │ hostname │ port │ pathname │ search │ │ |
| 41 | +| | ├───────────┬──────────────────┤ │ │ │ │ |
| 42 | +│ │ │ subdomain │ superdomain (sd) │ │ │ │ │ |
| 43 | +| | ├───────────┼─────────┬────────┤ │ ├─┬──────────────┤ │ |
| 44 | +│ │ │ │ domain │ TLD │ │ │ │ query │ │ |
| 45 | +│ │ │ │ │ │ │ │ │ │ │ |
| 46 | +" https: // sub . example . com : 8080 /p/a/t/h ? query=string #hash " |
| 47 | +│ │ │ │ │ |
| 48 | +│ origin │ | │ │ |
| 49 | +├─────────────┬───────────┬─────────────────────────┤ │ │ │ |
| 50 | +│ (sd) origin │ │ (sd) origin │ │ │ │ |
| 51 | +└─────────────┴───────────┴─────────────────────────┴──────────┴────────────────┴───────┘ |
| 52 | +``` |
| 53 | + |
| 54 | +Given the URLs below, all have the same superdomain compared to |
| 55 | +`https://www.cypress.io`. |
| 56 | + |
| 57 | +- `https://cypress.io` |
| 58 | +- `https://docs.cypress.io` |
| 59 | +- `https://example.cypress.io/commands/querying` |
| 60 | + |
| 61 | +The URLs below, however, will have different superdomains/origins compared to |
| 62 | +`https://www.cypress.io`. |
| 63 | + |
| 64 | +- `http://www.cypress.io` (Different protocol) |
| 65 | +- `https://docs.cypress.io:81` (Different port) |
| 66 | +- `https://www.auth0.com/` (Different host of different superdomain) |
| 67 | + |
| 68 | +The `http://localhost` URLs differ if their ports are different. For example, |
| 69 | +the `http://localhost:3000` URL is considered to be a different origin from the |
| 70 | +`http://localhost:8080` URL. |
| 71 | + |
| 72 | +The rules are: |
| 73 | + |
| 74 | +- <Icon name="exclamation-triangle" color="red"></Icon> You **cannot** |
| 75 | + [visit](/api/commands/visit) two domains of different superdomains in the same |
| 76 | + test and continue to interact with the page without the use of the |
| 77 | + [`cy.origin()`](/api/commands/origin) command. |
| 78 | +- <Icon name="check-circle" color="green"></Icon> You **can** |
| 79 | + [visit](/api/commands/visit) two or more domains of different origin in |
| 80 | + **different** tests without needing [`cy.origin()`](/api/commands/origin). |
| 81 | + |
| 82 | +For practical purposes, this means the following: |
| 83 | + |
| 84 | +```javascript |
| 85 | +// This test will run without error |
| 86 | +it('navigates', () => { |
| 87 | + cy.visit('https://www.cypress.io') |
| 88 | + cy.visit('https://docs.cypress.io') |
| 89 | + cy.get('selector') // yup all good |
| 90 | +}) |
| 91 | +``` |
| 92 | + |
| 93 | +```javascript |
| 94 | +// this will error because stackoverflow.com doesn't match the cypress.io superdomain |
| 95 | +it('navigates', () => { |
| 96 | + cy.visit('https://www.cypress.io') |
| 97 | + cy.visit('https://stackoverflow.com') |
| 98 | + cy.get('selector') |
| 99 | +}) |
| 100 | +``` |
| 101 | + |
| 102 | +To fix the above cross-origin error, use `cy.origin()` to indicate which origin |
| 103 | +the sequential command should run against: |
| 104 | + |
| 105 | +```javascript |
| 106 | +it('navigates', () => { |
| 107 | + cy.visit('https://www.cypress.io') |
| 108 | + cy.visit('https://stackoverflow.com') |
| 109 | + cy.origin('https://stackoverflow.com', () => { |
| 110 | + cy.get('selector') // yup all good |
| 111 | + }) |
| 112 | +}) |
| 113 | +``` |
| 114 | + |
| 115 | +```javascript |
| 116 | +it('navigates', () => { |
| 117 | + cy.visit('https://www.cypress.io') |
| 118 | +}) |
| 119 | + |
| 120 | +// split visiting different origin in another test |
| 121 | +it('navigates to new origin', () => { |
| 122 | + cy.visit('https://stackoverflow.com') |
| 123 | + cy.get('selector') // yup all good |
| 124 | +}) |
| 125 | +``` |
| 126 | + |
| 127 | +This limitation exists because Cypress switches to the domain under each |
| 128 | +specific test when it runs. For more information on this, please see our Web |
| 129 | +Security page regarding |
| 130 | +[Different superdomain per test requires cy.origin command](/guides/guides/web-security#Different-superdomain-per-test-requires-cy-origin-command). |
| 131 | + |
| 132 | +#### Other workarounds |
| 133 | + |
| 134 | +There are other ways of testing the interaction between two superdomains. The |
| 135 | +browser has a natural security barrier called `origin policy` this means that |
| 136 | +state like `localStorage`, `cookies`, `service workers` and many other APIs are |
| 137 | +not shared between them anyways. Cypress does offer APIs around `localStorage`, |
| 138 | +`sessionStorage`, and `cookies` that are not limited to this restriction. |
| 139 | + |
| 140 | +As a best practice, you should not visit or interact with a 3rd party service |
| 141 | +not under your control. However, there are exceptions! If your organization uses |
| 142 | +Single Sign On (SSO) or OAuth then you might involve a 3rd party service other |
| 143 | +than your superdomain, which can be safely tested with |
| 144 | +[`cy.origin()`](/api/commands/origin). |
| 145 | + |
| 146 | +We've written several other guides specifically about handling this situation. |
| 147 | + |
| 148 | +- [Best Practices: Visiting external sites](/guides/references/best-practices#Visiting-external-sites) |
| 149 | +- [Web Security: Common Workarounds](/guides/guides/web-security#Common-Workarounds) |
| 150 | +- [Recipes: Logging In - Single Sign On](/examples/examples/recipes#Logging-In) |
| 151 | +- [Guides: Amazon Cognito Authentication](/guides/end-to-end-testing/amazon-cognito-authentication) |
| 152 | +- [Guides: Okta Authentication](/guides/end-to-end-testing/okta-authentication) |
0 commit comments