Skip to main content

Cross Origin Testing

info
Note

As of Cypress v12.0.0, Cypress has the capability to visit multiple origins in a single test via the cy.origin() command!

Cypress limits each test to visiting domains that share the same superdomain. If a navigation occurs that does not meet the same superdomain rule, the cy.origin() command must be used to execute Cypress commands inside the newly navigated origin.

But what is same superdomain? It is actually very similar to that of same origin! Two URLs have the same origin if the protocol, port (if specified), and host match. Cypress automatically handles hosts of the same superdomain by injecting the document.domain property into the visited text/html pages. This is why navigations without the use of the cy.origin() command are solely scope to the same superdomain.

caution
Disabling document.domain Injection

In some cases, document.domain injection may cause issues. As of Cypress v12.4.0, disabling document.domain injection is available with the experimentalSkipDomainInjection option. Please read about this experiment for more information

We understand this is a bit complicated to understand, so we have built a nifty chart to help clarify the differences!

Parts of a URL

┌───────────────────────────────────────────────────────────────────────────────────────┐
│ href │
├──────────┬──┬─────────────────────────────────────┬───────────────────────────┬───────┤
│ protocol │ │ host │ path │ hash │
│ │ ├──────────────────────────────┬──────┼──────────┬────────────────┤ │
│ │ │ hostname │ port │ pathname │ search │ │
| | ├───────────┬──────────────────┤ │ │ │ │
│ │ │ subdomain │ superdomain (sd) │ │ │ │ │
| | ├───────────┼─────────┬────────┤ │ ├─┬──────────────┤ │
│ │ │ │ domain │ TLD │ │ │ │ query │ │
│ │ │ │ │ │ │ │ │ │ │
" https: // sub . example . com : 8080 /p/a/t/h ? query=string #hash "
│ │ │ │ │
│ origin │ | │ │
├─────────────┬───────────┬─────────────────────────┤ │ │ │
│ (sd) origin │ │ (sd) origin │ │ │ │
└─────────────┴───────────┴─────────────────────────┴──────────┴────────────────┴───────┘

Given the URLs below, all have the same superdomain compared to https://www.cypress.io.

  • https://cypress.io
  • https://docs.cypress.io
  • https://example.cypress.io/commands/querying

The URLs below, however, will have different superdomains/origins compared to https://www.cypress.io.

  • http://www.cypress.io (Different protocol)
  • https://docs.cypress.io:81 (Different port)
  • https://www.auth0.com/ (Different host of different superdomain)

The http://localhost URLs differ if their ports are different. For example, the http://localhost:3000 URL is considered to be a different origin from the http://localhost:8080 URL.

The rules are:

  • You **cannot** [visit](/api/commands/visit) two domains of different superdomains in the same test and continue to interact with the page without the use of the [`cy.origin()`](/api/commands/origin) command.
  • You **can** [visit](/api/commands/visit) two or more domains of different origin in **different** tests without needing [`cy.origin()`](/api/commands/origin).

For practical purposes, this means the following:

// This test will run without error
it('navigates', () => {
cy.visit('https://www.cypress.io')
cy.visit('https://docs.cypress.io')
cy.get('selector') // yup all good
})
// this will error because stackoverflow.com doesn't match the cypress.io superdomain
it('navigates', () => {
cy.visit('https://www.cypress.io')
cy.visit('https://stackoverflow.com')
cy.get('selector')
})

To fix the above cross-origin error, use cy.origin() to indicate which origin the sequential command should run against:

it('navigates', () => {
cy.visit('https://www.cypress.io')
cy.visit('https://stackoverflow.com')
cy.origin('https://stackoverflow.com', () => {
cy.get('selector') // yup all good
})
})
it('navigates', () => {
cy.visit('https://www.cypress.io')
})

// split visiting different origin in another test
it('navigates to new origin', () => {
cy.visit('https://stackoverflow.com')
cy.get('selector') // yup all good
})

This limitation exists because Cypress switches to the domain under each specific test when it runs. For more information on this, please see our Web Security page regarding Different superdomain per test requires cy.origin command.

Other workarounds

There are other ways of testing the interaction between two superdomains. The browser has a natural security barrier called origin policy this means that state like localStorage, cookies, service workers and many other APIs are not shared between them anyways. Cypress does offer APIs around localStorage, sessionStorage, and cookies that are not limited to this restriction.

As a best practice, you should not visit or interact with a 3rd party service not under your control. However, there are exceptions! If your organization uses Single Sign On (SSO) or OAuth then you might involve a 3rd party service other than your superdomain, which can be safely tested with cy.origin().

We've written several other guides specifically about handling this situation.