Skip to content

Commit

Permalink
feat: add cross origin testing guide
Browse files Browse the repository at this point in the history
  • Loading branch information
AtofStryker committed Dec 1, 2022
1 parent b725472 commit b3c5c6d
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 179 deletions.
4 changes: 4 additions & 0 deletions content/_data/sidebar.json
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,10 @@
"title": "Cross Browser Testing",
"slug": "cross-browser-testing"
},
{
"title": "Cross Origin Testing",
"slug": "cross-origin-testing"
},
{
"title": "Web Security",
"slug": "web-security"
Expand Down
148 changes: 148 additions & 0 deletions content/guides/guides/cross-origin-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
---
title: Cross Origin Testing
---

<Alert type="info">

<strong class="alert-header"> Note </strong>

As of Cypress [v12.0.0](https://on.cypress.io/changelog#12-0-0), Cypress has the
capability to visit multiple origins in a single test via the
[cy.origin()](https://on.cypress.io/origin) command!

</Alert>

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`](/api/commands/origin) command must be used to execute assertions
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 are the same for both. Cypress automatically handles hosts of the same
superdomain by injecting the
[`document.domain`](https://developer.mozilla.org/en-US/docs/Web/API/Document/domain)
property into the visited `text/html` pages. This is why navigations without the
use of the [`cy.origin()`](/api/commands/origin) command are solely scope to the
same superdomain.

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:

- <Icon name="exclamation-triangle" color="red"></Icon> 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.
- <Icon name="check-circle" color="green"></Icon> You **can**
[visit](/api/commands/visit) two or more domains of different origin in
**different** tests without needing [`cy.origin`](/api/commands/origin).

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 │ │ │ │
└─────────────┴───────────┴─────────────────────────┴──────────┴────────────────┴───────┘
```

For practical purposes, this means the following:

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

```javascript
it('navigates', () => {
cy.visit('https://www.cypress.io')
cy.visit('https://stackoverflow.com')
cy.get('selector') // this will error w/o cy.origin wrap
})
```

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

```javascript
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](/guides/guides/web-security#Different-superdomain-per-test-requires-cy-origin-command).

#### Other workarounds

There are other ways of testing the interaction between 2 superdomains. Because
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`](/api/commands/origin).

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

- [Best Practices: Visiting external sites](/guides/references/best-practices#Visiting-external-sites)
- [Web Security: Common Workarounds](/guides/guides/web-security#Common-Workarounds)
- [Recipes: Logging In - Single Sign On](/examples/examples/recipes#Logging-In)
- [Guides: Amazon Cognito Authentication](/guides/end-to-end-testing/amazon-cognito-authentication)
- [Guides: Okta Authentication](/guides/end-to-end-testing/okta-authentication)
42 changes: 3 additions & 39 deletions content/guides/guides/web-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,45 +79,9 @@ This is because the commands that were expected to run on the second domain are
actually being run on the first domain.

Without `cy.origin`, you can visit different superdomains in _different_ tests,
but not in the _same_ test.

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

```javascript
it('navigates', () => {
cy.visit('https://www.cypress.io')
cy.visit('https://stackoverflow.com')
cy.get('selector') // this will error w/o cy.origin wrap
})
```

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

```javascript
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
})
```
but not in the _same_ test. Please read our
[Cross Origin Testing Guide](/guides/guides/cross-origin-testing) for more
information.

Although Cypress tries to enforce this limitation, it is possible for your
application to bypass Cypress's ability to detect this.
Expand Down
144 changes: 4 additions & 140 deletions content/guides/references/trade-offs.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ to have. In a sense they prevent you from writing bad, slow, or flaky tests.
- There will never be support for [multiple browser tabs](#Multiple-tabs).
- You cannot use Cypress to drive
[two browsers at the same time](#Multiple-browsers-open-at-the-same-time).
- Each test is bound to a [single superdomain](#Navigation-Rules). Cross-origin
navigation inside tests can be enabled by using the
[`cy.origin`](/api/commands/origin) command.
- Each test is bound to a single superdomain. Cross-origin navigation inside
tests can be enabled by using the [`cy.origin`](/api/commands/origin) command.
Please read our
[Cross Origin Testing Guide](/guides/guides/cross-origin-testing).

#### Temporary trade-offs:

Expand Down Expand Up @@ -269,140 +270,3 @@ app.listen(8081, () => {})
This avoids ever needing a second open browser, but still gives you an
end-to-end test that provides 100% confidence that the two clients can
communicate with each other.

### Navigation Rules

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`](/api/commands/origin) command must be used to execute assertions
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 are the same for both. Cypress automatically handles hosts of the same
superdomain by injecting the
[`document.domain`](https://developer.mozilla.org/en-US/docs/Web/API/Document/domain)
property into the visited `text/html` pages. This is why navigations without the
use of the [`cy.origin`](/api/commands/origin) command are solely scope to the
same superdomain.

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:

- <Icon name="exclamation-triangle" color="red"></Icon> 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.
- <Icon name="check-circle" color="green"></Icon> You **can**
[visit](/api/commands/visit) two or more domains of different origin in
**different** tests without needing [`cy.origin`](/api/commands/origin).

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 │ │ │ │
└─────────────┴───────────┴─────────────────────────┴──────────┴────────────────┴───────┘
```

For practical purposes, this means the following:

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

```javascript
it('navigates', () => {
cy.visit('https://www.cypress.io')
cy.visit('https://stackoverflow.com')
cy.get('selector') // this will error w/o cy.origin wrap
})
```

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

```javascript
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](/guides/guides/web-security#Different-superdomain-per-test-requires-cy-origin-command).

#### Other workarounds

There are other ways of testing the interaction between 2 superdomains. Because
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`](/api/commands/origin).

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

- [Best Practices: Visiting external sites](/guides/references/best-practices#Visiting-external-sites)
- [Web Security: Common Workarounds](/guides/guides/web-security#Common-Workarounds)
- [Recipes: Logging In - Single Sign On](/examples/examples/recipes#Logging-In)
- [Guides: Amazon Cognito Authentication](/guides/end-to-end-testing/amazon-cognito-authentication)
- [Guides: Okta Authentication](/guides/end-to-end-testing/okta-authentication)

0 comments on commit b3c5c6d

Please sign in to comment.