diff --git a/assets/img/guides/references/cy-visit-subsequent-commands-timed-out.png b/assets/img/guides/references/cy-visit-subsequent-commands-timed-out.png new file mode 100644 index 0000000000..122f4c496f Binary files /dev/null and b/assets/img/guides/references/cy-visit-subsequent-commands-timed-out.png differ diff --git a/content/_data/sidebar.json b/content/_data/sidebar.json index a42e602aaa..5972cb3d09 100644 --- a/content/_data/sidebar.json +++ b/content/_data/sidebar.json @@ -320,6 +320,14 @@ { "title": "Cross Browser Testing", "slug": "cross-browser-testing" + }, + { + "title": "Cross Origin Testing", + "slug": "cross-origin-testing" + }, + { + "title": "Web Security", + "slug": "web-security" } ] }, diff --git a/content/api/commands/origin.md b/content/api/commands/origin.md index 9265053963..741723c151 100644 --- a/content/api/commands/origin.md +++ b/content/api/commands/origin.md @@ -22,7 +22,10 @@ patterns commonly found in framebusting. When using the `cy.origin()` command, the third party code may also need to be modified for framebusting techniques. This can be enabled by setting the [`experimentalModifyObstructiveThirdPartyCode`](/guides/references/experiments) -flag to `true` in the Cypress configuration. +flag to `true` in the Cypress configuration. More information about this +experimental flag can be found on our +[Web Security](/guides/guides/web-security#Modifying-Obstructive-Third-Party-Code) +page. diff --git a/content/faq/questions/using-cypress-faq.md b/content/faq/questions/using-cypress-faq.md index d08b9db4eb..bc3126ade5 100644 --- a/content/faq/questions/using-cypress-faq.md +++ b/content/faq/questions/using-cypress-faq.md @@ -919,6 +919,8 @@ application under test runs in any way, so you can safely ignore this warning. The network traffic between Cypress and the backend server still happens via HTTPS. +See also the [Web Security](/guides/guides/web-security) guide. + ## Is there an option to run Cypress in CI with Developer Tools open? We want to track network and console issues. No. There is not currently a way to run Cypress in `cypress run` with Developer diff --git a/content/guides/end-to-end-testing/okta-authentication.md b/content/guides/end-to-end-testing/okta-authentication.md index 006a71323d..f3d7f679d1 100644 --- a/content/guides/end-to-end-testing/okta-authentication.md +++ b/content/guides/end-to-end-testing/okta-authentication.md @@ -12,7 +12,9 @@ e2eSpecific: true - Programmatically authenticate with [Okta](https://okta.com) via a custom Cypress command - Adapting your [Okta](https://okta.com) application for programmatic - authentication during testing + authentication during testing + + diff --git a/content/guides/guides/cross-browser-testing.md b/content/guides/guides/cross-browser-testing.md index f25a0398cc..b0f946b5a1 100644 --- a/content/guides/guides/cross-browser-testing.md +++ b/content/guides/guides/cross-browser-testing.md @@ -14,7 +14,7 @@ browser engine), and Firefox. Web Security Tests that require the -[`chromeWebSecurity` configuration option to be disabled](/guides/references/configuration#Browser) +[`chromeWebSecurity` configuration option to be disabled](/guides/guides/web-security#Disabling-Web-Security) may experience issues in non-Chromium based browsers. diff --git a/content/guides/guides/cross-origin-testing.md b/content/guides/guides/cross-origin-testing.md new file mode 100644 index 0000000000..40bc5f4bc0 --- /dev/null +++ b/content/guides/guides/cross-origin-testing.md @@ -0,0 +1,152 @@ +--- +title: Cross Origin Testing +--- + + + + Note + +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! + + + +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 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`](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. + +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: + +```javascript +// 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 +}) +``` + +```javascript +// 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: + +```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 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()`](/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) diff --git a/content/guides/guides/web-security.md b/content/guides/guides/web-security.md new file mode 100644 index 0000000000..1e5a203ec1 --- /dev/null +++ b/content/guides/guides/web-security.md @@ -0,0 +1,485 @@ +--- +title: Web Security +e2eSpecific: true +--- + +Browsers adhere to a strict +[same-origin policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy). +This means that browsers restrict access between `` when their origin +policies do not match. + +Because Cypress works from within the browser, Cypress must be able to directly +communicate with your remote application at all times. Unfortunately, browsers +naturally try to prevent Cypress from doing this. + +To get around these restrictions, Cypress implements some strategies involving +JavaScript code, the browser's internal APIs, and network proxying to _play by +the rules_ of same-origin policy. It is our goal to fully automate the +application under test without you needing to modify your application's code - +and we are _mostly_ able to do this. + +#### Examples of what Cypress does under the hood: + +- Injects + [`document.domain`](https://developer.mozilla.org/en-US/docs/Web/API/Document/domain) + into `text/html` pages. +- Proxies all HTTP / HTTPS traffic. +- Changes the hosted URL to match that of the application under test. +- Uses the browser's internal APIs for network level traffic. + +When Cypress first loads, the internal Cypress web application is hosted on a +random port: something like `http://localhost:65874/__/`. + +After the first [`cy.visit()`](/api/commands/visit) command is issued in a test, +Cypress changes its URL to match the origin of your remote application, thereby +solving the first major hurdle of same-origin policy. Your application's code +executes the same as it does outside of Cypress, and everything works as +expected. + + + +How is HTTPS supported? + +Cypress does some pretty interesting things under the hood to make testing HTTPS +sites work. Cypress enables you to control and stub at the network level. +Therefore, Cypress must assign and manage browser certificates to be able to +modify the traffic in real time. + +You'll notice Chrome display a warning that the 'SSL certificate does not +match'. This is normal and correct. Under the hood we act as our own CA +authority and issue certificates dynamically in order to intercept requests +otherwise impossible to access. We only do this for the superdomain currently +under test, and bypass other traffic. That's why if you open a tab in Cypress to +another host, the certificates match as expected. + +Note, that Cypress allows you to optionally specify CA / client certificate +information for use with HTTPS sites. See +[Configuring client certificates](/guides/references/client-certificates). If +the remote server requests a client certificate for a configured URL, Cypress +will supply it. + + + +## Limitations + +It's important to note that although we do our **very best** to ensure your +application works normally inside of Cypress, there _are_ some limitations you +need to be aware of. + +### Different superdomain per test requires `cy.origin` command + +Cypress changes its own host URL to match that of your applications. With the +exception of `cy.origin`, Cypress requires that the URLs navigated to have the +same superdomain for the entirety of a single test. + +If you attempt to visit two different superdomains, the `cy.origin` command must +be used to wrap Cypress commands of the second visited domain. Otherwise, +Cypress commands will timeout after the navigation and will eventually error. +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. 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. + +#### Examples of test cases that will error without the use of `cy.origin` + +1. [`.click()`](/api/commands/click) an `` with an `href` to a different + superdomain with subsequent Cypress commands being run. +2. [`.submit()`](/api/commands/submit) a `
` that causes your web server to + redirect to you a different superdomain where additional Cypress commands are + run. +3. Issue a JavaScript redirect in your application, such as + `window.location.href = '...'`, to a different superdomain where additional + Cypress commands are run. + +In each of these situations, Cypress will lose the ability to automate your +application and will error via command timeout unless the `cy.origin` command is +used. + +Read on to learn about +[working around these common problems](/guides/guides/web-security#Common-Workarounds). + +### Cross-origin iframes + +If your site embeds an `