{"_id":"57fe8b9efe877f1700b867ab","user":"568fffce769f210d0013258f","__v":1,"category":{"_id":"5696c1168560a60d00e2c1d6","__v":9,"pages":["5696c11aaa12bc0d0050332c","5696c11aaa12bc0d0050332d","5696c11a8400d52d00dd5631","5696c11a59a6692d003fad06","56a007d14583912300b5efcf","56a007d166c8420d00d7fc7c","56a6824e683cfb0d00dc586f","56b383fe3ccec63700a7ac1c","56b3a7de0e4c450d00699d22"],"project":"568fde81b700ce0d002f4b43","version":"56954a94fe18811700c9bfda","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2016-01-13T21:26:46.069Z","from_sync":false,"order":5,"slug":"references","title":"References"},"parentDoc":null,"version":{"_id":"56954a94fe18811700c9bfda","project":"568fde81b700ce0d002f4b43","__v":6,"createdAt":"2016-01-12T18:48:52.007Z","releaseDate":"2016-01-12T18:48:52.007Z","categories":["56954a95fe18811700c9bfdb","56954a95fe18811700c9bfdc","56954a95fe18811700c9bfdd","56954a95fe18811700c9bfde","56954a95fe18811700c9bfdf","56954a95fe18811700c9bfe0","56954a95fe18811700c9bfe1","56954a95fe18811700c9bfe2","56954a95fe18811700c9bfe3","56954a95fe18811700c9bfe4","5695649fdcaf0d1700cb8721","5696c1168560a60d00e2c1d6","56a7a32e79395317007c1ad6","5898fc3eec49fb0f004c2663","589cc675ea37da23004e05e1"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"foo","version_clean":"0.0.0","version":"0.0"},"project":"568fde81b700ce0d002f4b43","updates":["59392eca0073e80027c8ab6c"],"next":{"pages":[],"description":""},"createdAt":"2016-10-12T19:14:38.447Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"auth":"required","params":[],"url":""},"isReference":false,"order":4,"body":"# Contents\n\n- :fa-angle-right: [Overview](#section-overview)\n- :fa-angle-right: [Limitations](#section-limitations)\n  - [One Superdomain per Test](#section-one-superdomain-per-test)\n  - [Cross Origin Iframes](#section-cross-origin-iframes)\n  - [Insecure Content](#section-insecure-content)\n- :fa-angle-right: [Common Workarounds](#section-common-workarounds)\n  - [External Navigation](#section-external-navigation)\n  - [Form Submission Redirects](#section-form-submission-redirects)\n  - [JavaScript Redirects](#section-javascript-redirects)\n- :fa-angle-right: [Disabling Web Security](#section-disabling-web-security)\n\n***\n\n# Overview\n\nBrowsers 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 `<iframes>` when their origin policies do not match.\n\nBecause Cypress' internal architecture is different from that of Selenium, Cypress must be able to directly communicate with your remote application at all times. Unfortunately, browsers naturally try to prevent how Cypress works.\n\nTo 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 your application without needing to modify any application code - and we are *mostly* able to do this.\n\n**Examples of what Cypress does under the hood:**\n\n  - Injects [`document.domain`](https://developer.mozilla.org/en-US/docs/Web/API/Document/domain) into `text/html` pages.\n  - Proxies all `HTTP`/`HTTPS` traffic.\n  - Changes the hosted url to match that of the application under test.\n  - Uses the browser's internal APIs for network level traffic.\n\nWhen Cypress first loads, the internal Cypress web application is hosted on a random port: something like `http://localhost:65874/__/`.\n\nAfter the first [`cy.visit`](https://on.cypress.io/api/visit) is issued in a test, Cypress automatically 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.\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"How is HTTPS supported?\",\n  \"body\": \"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.\"\n}\n[/block]\n\n***\n\n# Limitations\n\nIt'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.\n\n## One Superdomain per Test\n\nBecause Cypress changes its own host URL to match that of your applications, it requires that your application remain on the same superdomain for the entirety of a single test.\n\nIf you attempt to visit two different superdomains, Cypress will error. Visiting subdomains works fine, but two different superdomains does not. You can visit different superdomains in *different* tests, just not the *same* test.\n\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy\\n  .visit(\\\"https://www.cypress.io\\\")\\n  .visit(\\\"https://docs.cypress.io\\\") // yup all good\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy\\n  .visit(\\\"https://apple.com\\\")\\n  .visit(\\\"https://google.com\\\")      // bad, this will immediately error\\n\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nAlthough Cypress tries to enforce this limitation, it is possible for your application to bypass Cypress's ability to detect this.\n\n**Examples of test cases that will error due to superdomain limitations:**\n\n1. [`cy.click`](https://on.cypress.io/api/click) an `<a>` with an `href` to a different superdomain.\n2. [`cy.submit`](https://on.cypress.io/api/submit) a `<form>` that causes your webserver to redirect to you a different superdomain.\n3. Issue a JavaScript redirect in your application, such as `window.location.href = '...'`, to a different superdomain.\n\nIn each of these situations, Cypress will lose the ability to automate your application and will immediately error.\n\nRead on to learn about [working around these common problems](#section-common-workarounds) or even [disabling web security](#section-disabling-web-security) altogether.\n\n***\n\n## Cross Origin Iframes\n\nIf your site embeds an `<iframe>` that is a cross-origin frame, Cypress will not be able to automate or communicate with this `<iframe>`.\n\n**Examples of uses for cross-origin iframes:**\n\n- Embedding a `Vimeo` or `Youtube` video.\n- Displaying a credit card form from `Stripe` or `Braintree`.\n- Displaying an embedded login form from `Auth0`.\n\nIt's actually *possible* for Cypress to accomodate these situations the same way Selenium does, but you will never have **native** access to these iframes from inside of Cypress.\n\nAs a workaround, you may be able to use [`window.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) to directly communicate with these iframes and control them (if the 3rd party iframe supports it).\n\nOther than that, you'll have to wait for us to implement API's to support this (check our [open issue](https://github.com/cypress-io/cypress/issues/136)), or you can [disable web security](#section-disabling-web-security).\n\n***\n\n## Insecure Content\n\nBecause of the way Cypress is designed, if you are testing an `HTTPS` site, Cypress will error anytime you attempt to navigate back to an `HTTP` site. This behavior helps highlight a *pretty serious* security problem with your application.\n\n**Example of accessing insecure content:**\n\n*Test code*\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy.visit(\\\"https://app.corp.com\\\")\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nIn the application code, you set `cookies` and store a session on the browser.\n\nNow let's imagine you have a single `insecure` link (or JavaScript redirect) in your application code.\n\n*Application code*\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"<html>\\n  <a href=\\\"http://app.corp.com/page2\\\">Page 2</a>\\n</html>\\n\",\n            \"language\": \"html\"\n        }\n    ]\n}\n[/block]\n\nCypress will immediately fail with the following test code:\n\n*Test code*\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy\\n  .visit(\\\"https://app.corp.com\\\")\\n  .get(\\\"a\\\").click()               // will immediately fail\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nBrowsers refuse to display insecure content on a secure page. Because Cypress initially changed its URL to match `https://app.corp.com` when the browser followed the `href` to `http://app.corp.com/page2`, the browser will refuse to display the contents.\n\nNow you may be thinking...'this sounds like a problem with Cypress because when I work with my application outside of Cypress it works just fine'.\n\nHowever, the truth is, Cypress is exposing a **security vulnerability** in your application, and you *want* it to fail in Cypress.\n\n`cookies` that do not have their `secure` flag set to `true` will be sent as clear text to the insecure URL. This leaves your application vulnerable to session hijacking.\n\nThis security vulnerability exists **even if** your webserver forces a `301 redirect` back to the `HTTPS` site. The original `HTTP` request was still made once, exposing insecure session information.\n\n**The Solution**\n\nSimply update your `HTML` or `JavaScript` code to not navigate to an insecure `HTTP` page and instead only use `HTTPS`. Additionally make sure that cookies have their `secure` flag set to `true`.\n\nIf you're in a situation where you don't control the code, or otherwise cannot work around this, you can bypass this restriction in Cypress by [disabling web security](#section-dislabing-web-security).\n\n***\n\n# Common Workarounds\n\nLet's investigate how you might encounter `cross origin` errors in your test code and break down how to work around them in Cypress.\n\n## External Navigation\n\nThe most common situation where you might encounter this error is when you click on an `<a>` that navigates to another superdomain.\n\n**Application code that is served at `localhost:8080`**\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"<html>\\n  <a href=\\\"https://google.com\\\">Google</a>\\n</html>\\n\",\n            \"language\": \"html\"\n        }\n    ]\n}\n[/block]\n\n**Test code**\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy\\n  .visit(\\\"http://localhost:8080\\\") // where your webserver + HTML is hosted\\n  .get(\\\"a\\\").click()               // browser attempts to load google.com, Cypress errors\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nThere is essentially never any reason to visit a site that you don't control in your tests. It's prone to error and slow.\n\nInstead, all you need to test is that the `href` property is correct!\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"// this is much easier to do and will run considerably faster\\ncy\\n  .visit(\\\"http://localhost:8080\\\")\\n  .get(\\\"a\\\").should(\\\"have.attr\\\", \\\"href\\\", \\\"https://google.com\\\") // no page load!\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nOkay but let's say you're worried about `google.com` serving up the right HTML content. How would you test that? Easy! Just make a [`cy.request`](https://on.cypress.io/api/request) directly to it. [`cy.request`](https://on.cypress.io/api/request) is **NOT bound to CORS or same-origin policy**.\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy\\n  .visit(\\\"http://localhost:8080\\\")\\n  .get(\\\"a\\\").then(function($a) {\\n    // pull off the fully qualified href from the <a>\\n    var url = $a.prop(\\\"href\\\")\\n\\n    // make a cy.request to it\\n    cy.request(url).its(\\\"body\\\").should(\\\"include\\\", \\\"</html>\\\")\\n  })\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nStill not satisfied? Do you really want to click through to another application? Okay then read about [disabling web security](#section-disabling-web-security).\n\n***\n\n## Form Submission Redirects\n\nWhen you submit a regular HTML form, the browser will follow this `HTTP(s) request`.\n\n**Application code that is served at `localhost:8080`**\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"<html>\\n  <form method=\\\"POST\\\" action=\\\"/submit\\\">\\n    <input type=\\\"text\\\" name=\\\"email\\\" />\\n    <input type=\\\"submit\\\" value=\\\"Submit\\\" />\\n  </form>\\n</html>\\n\",\n            \"language\": \"html\"\n        }\n    ]\n}\n[/block]\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy\\n  .visit(\\\"http://localhost:8080\\\")\\n  .get(\\\"form\\\").submit()           // submit the form!\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nIf your backend server handling the `/submit` route does a `30x` redirect to a different superdomain, you will get a `cross origin` error.\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"// imagine this is some node / express code\\n// on your localhost:8080 server\\n\\napp.post(\\\"/submit\\\", function(req, res) {\\n  // redirect the browser to google.com\\n  res.redirect(\\\"https://google.com\\\")\\n})\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nA commone use case for this is `Single sign-on (SSO)`. In that situation you may `POST` to a different server and are redirected elsewhere (typically with the session token in the URL).\n\nIf that's the case, don't worry - you can work around it with [`cy.request`](https://on.cypress.io/api/request). [`cy.request`](https://on.cypress.io/api/request) is special because it is **NOT bound to CORS or same-origin policy**.\n\nIn fact we can likely bypass the initial visit altogether and just `POST` directly to your `SSO` server.\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"cy\\n  .request(\\\"POST\\\", \\\"https://sso.corp.com/auth\\\", {username: \\\"foo\\\", password: \\\"bar\\\"})\\n  .then(function(response) {\\n    // pull out the location redirect\\n    var loc = response.headers[\\\"Location\\\"]\\n\\n    // parse out the token from the url (assuming its in there)\\n    var token = parseOutMyToken(loc)\\n\\n    // do something with the token that your web application expects\\n    // likely the same behavior as what your SSO does under the hood\\n    // assuming it handles query string tokens like this\\n    cy.visit(\\\"http://localhost:8080?token=\\\" + token)\\n\\n    // if you don't need to work with the token you can sometimes\\n    // just visit the location header directly\\n    cy.visit(loc)\\n  })\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nNot working for you? Don't know how to set your token? If you still need to be able to be redirected to your SSO server you can read about [disabling web security](#section-disabling-web-security).\n\n***\n\n## JavaScript Redirects\n\nWhen we say *JavaScript Redirects* we are talking about any kind of code that does something like this:\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"window.location.href = \\\"http://some.superdomain.com\\\"\\n\",\n            \"language\": \"javascript\"\n        }\n    ]\n}\n[/block]\n\nThis is probably the hardest situation to test because it's usually happening due to another cause. You will need to figure out why your JavaScript code is redirecting. Perhaps you're not logged in, and you need to handle that setup elsewhere? Perhaps you're using a `Single sign-on (SSO)` server and you just need to read the previous section about working around that?\n\nIf you can't figure out why your JavaScript code is redirecting you to a different superdomain then you might want to just read about [disabling web security](#section-disabling-websecurity).\n\n***\n\n# Disabling Web Security\n\nSo if you cannot work around any of the issues using the suggested workarounds above, you may want to disable web security.\n\nOne last thing to consider here is that every once in a while we discover bugs in Cypress that lead to `cross origin` errors that can otherwise be fixed. If you think you're experiencing a bug, [come into gitter](https://gitter.im/cypress-io/cypress) or [open an issue](https://github.com/cypress-io/cypress/issues/new).\n\nTo start, you will need to understand that **not all browsers expose a way to turn off web security**. Some do, some don't. If you rely on disabling web security, you will not be able to run tests on browsers that do not support this feature.\n\nStill here? That's cool, let's disable web security!\n\n**Set `chromeWebSecurity` to `false` in `cypress.json` and we'll take care of the rest.**\n\n[block:code]\n{\n    \"codes\": [\n        {\n            \"code\": \"{\\n  chromeWebSecurity: false\\n}\\n\",\n            \"language\": \"json\"\n        }\n    ]\n}\n[/block]\n\nThe browser will now display insecure content, you can now navigate to any superdomain without cross origin errors, and you can access cross origin iframes that are embedded in your application.\n\nOne thing you may notice though is that Cypress still enforces visiting a single superdomain with [`cy.visit`](https://on.cypress.io/api/visit). This is an artificial limitation (and one that can be removed). You should [open an issue](https://github.com/cypress-io/cypress/issues/new) and tell us what you're trying to do!","excerpt":"How Cypress handles same-origin policy","slug":"web-security","type":"basic","title":"Web Security"}

Web Security

How Cypress handles same-origin policy

# Contents - :fa-angle-right: [Overview](#section-overview) - :fa-angle-right: [Limitations](#section-limitations) - [One Superdomain per Test](#section-one-superdomain-per-test) - [Cross Origin Iframes](#section-cross-origin-iframes) - [Insecure Content](#section-insecure-content) - :fa-angle-right: [Common Workarounds](#section-common-workarounds) - [External Navigation](#section-external-navigation) - [Form Submission Redirects](#section-form-submission-redirects) - [JavaScript Redirects](#section-javascript-redirects) - :fa-angle-right: [Disabling Web Security](#section-disabling-web-security) *** # Overview 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 `<iframes>` when their origin policies do not match. Because Cypress' internal architecture is different from that of Selenium, Cypress must be able to directly communicate with your remote application at all times. Unfortunately, browsers naturally try to prevent how Cypress works. 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 your application without needing to modify any application 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`](https://on.cypress.io/api/visit) is issued in a test, Cypress automatically 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. [block:callout] { "type": "info", "title": "How is HTTPS supported?", "body": "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." } [/block] *** # 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. ## One Superdomain per Test Because Cypress changes its own host URL to match that of your applications, it requires that your application remain on the same superdomain for the entirety of a single test. If you attempt to visit two different superdomains, Cypress will error. Visiting subdomains works fine, but two different superdomains does not. You can visit different superdomains in *different* tests, just not the *same* test. [block:code] { "codes": [ { "code": "cy\n .visit(\"https://www.cypress.io\")\n .visit(\"https://docs.cypress.io\") // yup all good\n", "language": "javascript" } ] } [/block] [block:code] { "codes": [ { "code": "cy\n .visit(\"https://apple.com\")\n .visit(\"https://google.com\") // bad, this will immediately error\n\n", "language": "javascript" } ] } [/block] 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 due to superdomain limitations:** 1. [`cy.click`](https://on.cypress.io/api/click) an `<a>` with an `href` to a different superdomain. 2. [`cy.submit`](https://on.cypress.io/api/submit) a `<form>` that causes your webserver to redirect to you a different superdomain. 3. Issue a JavaScript redirect in your application, such as `window.location.href = '...'`, to a different superdomain. In each of these situations, Cypress will lose the ability to automate your application and will immediately error. Read on to learn about [working around these common problems](#section-common-workarounds) or even [disabling web security](#section-disabling-web-security) altogether. *** ## Cross Origin Iframes If your site embeds an `<iframe>` that is a cross-origin frame, Cypress will not be able to automate or communicate with this `<iframe>`. **Examples of uses for cross-origin iframes:** - Embedding a `Vimeo` or `Youtube` video. - Displaying a credit card form from `Stripe` or `Braintree`. - Displaying an embedded login form from `Auth0`. It's actually *possible* for Cypress to accomodate these situations the same way Selenium does, but you will never have **native** access to these iframes from inside of Cypress. As a workaround, you may be able to use [`window.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) to directly communicate with these iframes and control them (if the 3rd party iframe supports it). Other than that, you'll have to wait for us to implement API's to support this (check our [open issue](https://github.com/cypress-io/cypress/issues/136)), or you can [disable web security](#section-disabling-web-security). *** ## Insecure Content Because of the way Cypress is designed, if you are testing an `HTTPS` site, Cypress will error anytime you attempt to navigate back to an `HTTP` site. This behavior helps highlight a *pretty serious* security problem with your application. **Example of accessing insecure content:** *Test code* [block:code] { "codes": [ { "code": "cy.visit(\"https://app.corp.com\")\n", "language": "javascript" } ] } [/block] In the application code, you set `cookies` and store a session on the browser. Now let's imagine you have a single `insecure` link (or JavaScript redirect) in your application code. *Application code* [block:code] { "codes": [ { "code": "<html>\n <a href=\"http://app.corp.com/page2\">Page 2</a>\n</html>\n", "language": "html" } ] } [/block] Cypress will immediately fail with the following test code: *Test code* [block:code] { "codes": [ { "code": "cy\n .visit(\"https://app.corp.com\")\n .get(\"a\").click() // will immediately fail\n", "language": "javascript" } ] } [/block] Browsers refuse to display insecure content on a secure page. Because Cypress initially changed its URL to match `https://app.corp.com` when the browser followed the `href` to `http://app.corp.com/page2`, the browser will refuse to display the contents. Now you may be thinking...'this sounds like a problem with Cypress because when I work with my application outside of Cypress it works just fine'. However, the truth is, Cypress is exposing a **security vulnerability** in your application, and you *want* it to fail in Cypress. `cookies` that do not have their `secure` flag set to `true` will be sent as clear text to the insecure URL. This leaves your application vulnerable to session hijacking. This security vulnerability exists **even if** your webserver forces a `301 redirect` back to the `HTTPS` site. The original `HTTP` request was still made once, exposing insecure session information. **The Solution** Simply update your `HTML` or `JavaScript` code to not navigate to an insecure `HTTP` page and instead only use `HTTPS`. Additionally make sure that cookies have their `secure` flag set to `true`. If you're in a situation where you don't control the code, or otherwise cannot work around this, you can bypass this restriction in Cypress by [disabling web security](#section-dislabing-web-security). *** # Common Workarounds Let's investigate how you might encounter `cross origin` errors in your test code and break down how to work around them in Cypress. ## External Navigation The most common situation where you might encounter this error is when you click on an `<a>` that navigates to another superdomain. **Application code that is served at `localhost:8080`** [block:code] { "codes": [ { "code": "<html>\n <a href=\"https://google.com\">Google</a>\n</html>\n", "language": "html" } ] } [/block] **Test code** [block:code] { "codes": [ { "code": "cy\n .visit(\"http://localhost:8080\") // where your webserver + HTML is hosted\n .get(\"a\").click() // browser attempts to load google.com, Cypress errors\n", "language": "javascript" } ] } [/block] There is essentially never any reason to visit a site that you don't control in your tests. It's prone to error and slow. Instead, all you need to test is that the `href` property is correct! [block:code] { "codes": [ { "code": "// this is much easier to do and will run considerably faster\ncy\n .visit(\"http://localhost:8080\")\n .get(\"a\").should(\"have.attr\", \"href\", \"https://google.com\") // no page load!\n", "language": "javascript" } ] } [/block] Okay but let's say you're worried about `google.com` serving up the right HTML content. How would you test that? Easy! Just make a [`cy.request`](https://on.cypress.io/api/request) directly to it. [`cy.request`](https://on.cypress.io/api/request) is **NOT bound to CORS or same-origin policy**. [block:code] { "codes": [ { "code": "cy\n .visit(\"http://localhost:8080\")\n .get(\"a\").then(function($a) {\n // pull off the fully qualified href from the <a>\n var url = $a.prop(\"href\")\n\n // make a cy.request to it\n cy.request(url).its(\"body\").should(\"include\", \"</html>\")\n })\n", "language": "javascript" } ] } [/block] Still not satisfied? Do you really want to click through to another application? Okay then read about [disabling web security](#section-disabling-web-security). *** ## Form Submission Redirects When you submit a regular HTML form, the browser will follow this `HTTP(s) request`. **Application code that is served at `localhost:8080`** [block:code] { "codes": [ { "code": "<html>\n <form method=\"POST\" action=\"/submit\">\n <input type=\"text\" name=\"email\" />\n <input type=\"submit\" value=\"Submit\" />\n </form>\n</html>\n", "language": "html" } ] } [/block] [block:code] { "codes": [ { "code": "cy\n .visit(\"http://localhost:8080\")\n .get(\"form\").submit() // submit the form!\n", "language": "javascript" } ] } [/block] If your backend server handling the `/submit` route does a `30x` redirect to a different superdomain, you will get a `cross origin` error. [block:code] { "codes": [ { "code": "// imagine this is some node / express code\n// on your localhost:8080 server\n\napp.post(\"/submit\", function(req, res) {\n // redirect the browser to google.com\n res.redirect(\"https://google.com\")\n})\n", "language": "javascript" } ] } [/block] A commone use case for this is `Single sign-on (SSO)`. In that situation you may `POST` to a different server and are redirected elsewhere (typically with the session token in the URL). If that's the case, don't worry - you can work around it with [`cy.request`](https://on.cypress.io/api/request). [`cy.request`](https://on.cypress.io/api/request) is special because it is **NOT bound to CORS or same-origin policy**. In fact we can likely bypass the initial visit altogether and just `POST` directly to your `SSO` server. [block:code] { "codes": [ { "code": "cy\n .request(\"POST\", \"https://sso.corp.com/auth\", {username: \"foo\", password: \"bar\"})\n .then(function(response) {\n // pull out the location redirect\n var loc = response.headers[\"Location\"]\n\n // parse out the token from the url (assuming its in there)\n var token = parseOutMyToken(loc)\n\n // do something with the token that your web application expects\n // likely the same behavior as what your SSO does under the hood\n // assuming it handles query string tokens like this\n cy.visit(\"http://localhost:8080?token=\" + token)\n\n // if you don't need to work with the token you can sometimes\n // just visit the location header directly\n cy.visit(loc)\n })\n", "language": "javascript" } ] } [/block] Not working for you? Don't know how to set your token? If you still need to be able to be redirected to your SSO server you can read about [disabling web security](#section-disabling-web-security). *** ## JavaScript Redirects When we say *JavaScript Redirects* we are talking about any kind of code that does something like this: [block:code] { "codes": [ { "code": "window.location.href = \"http://some.superdomain.com\"\n", "language": "javascript" } ] } [/block] This is probably the hardest situation to test because it's usually happening due to another cause. You will need to figure out why your JavaScript code is redirecting. Perhaps you're not logged in, and you need to handle that setup elsewhere? Perhaps you're using a `Single sign-on (SSO)` server and you just need to read the previous section about working around that? If you can't figure out why your JavaScript code is redirecting you to a different superdomain then you might want to just read about [disabling web security](#section-disabling-websecurity). *** # Disabling Web Security So if you cannot work around any of the issues using the suggested workarounds above, you may want to disable web security. One last thing to consider here is that every once in a while we discover bugs in Cypress that lead to `cross origin` errors that can otherwise be fixed. If you think you're experiencing a bug, [come into gitter](https://gitter.im/cypress-io/cypress) or [open an issue](https://github.com/cypress-io/cypress/issues/new). To start, you will need to understand that **not all browsers expose a way to turn off web security**. Some do, some don't. If you rely on disabling web security, you will not be able to run tests on browsers that do not support this feature. Still here? That's cool, let's disable web security! **Set `chromeWebSecurity` to `false` in `cypress.json` and we'll take care of the rest.** [block:code] { "codes": [ { "code": "{\n chromeWebSecurity: false\n}\n", "language": "json" } ] } [/block] The browser will now display insecure content, you can now navigate to any superdomain without cross origin errors, and you can access cross origin iframes that are embedded in your application. One thing you may notice though is that Cypress still enforces visiting a single superdomain with [`cy.visit`](https://on.cypress.io/api/visit). This is an artificial limitation (and one that can be removed). You should [open an issue](https://github.com/cypress-io/cypress/issues/new) and tell us what you're trying to do!