```
"One thing you may notice though is that Cypress still enforces
visiting a single superdomain with cy.visit().
This is an artificial limitation (and one that can be removed).
You should open an issue and tell us what you’re trying to do!"
I was trying to get a quick script to press an update button on 500 of our domains.
```
Maybe you could document a way for us to remove this limit without having to open an issue to have the core functioning of the app changed ? Maybe allow passing an argument when running the app.
Yeah, it can be done. Quick question - is there any reason you need a browser to load up 500 different domains and click a button?
Wouldn't it be much much easier to just use cy.request
or another programatic means to accomplish this?
For instance, what does clicking the button do? Send an HTTP request is my guess. So instead of using the UI, just send the HTTP request directly using cy.request
. Same result, 100x faster, and no domain issues.
Any additional information about your use case would be helpful.
Just jumping in to say that I have a use-case where I need to load several sites in the same test (not 500, 2 will do for a test).
I'm testing a browser extension that will show a modal (via a content script) on several sites that you can whitelist in its settings. The extension uses a global timer (via its background tab) to synchronise the extension's behaviour across different sites/tabs/link clicks/refreshes (it persists a countdown as you browse those various whitelisted sites, among other things). Because of this restriction, I can't test that the synchronisation works when the sites I visit are on different domains.
I can't just make a cy.request
because I need Chrome to load the page, then load the extension's contentscript on it, then assert that the contentscript shows the modal and that its content is coherent with the cross-tab synchronisation I expect to happen.
Wouldn't it be much much easier to just use cy.request or another programatic means to accomplish this?
To me the issue is that it is _more_ work to simulate the requests than it is to have Cypress fill in a form.
That and it deviates too far from the User flow that my users would be experiencing.
This is an applicable issue for my organization's test code. We recently implemented OKTA, which requires you to go to a super domain to authenticate then route to the super domain that is going to be tested. When I use "cy.visit()" after authenticating, all authentication data will be wiped out and Cypress will attempt to authenticate the same exact way again, causing either a sid or cross domain error. Due to this issue, we are about to drop Cypress all together and move back to Selenium.
@alovato88 if you switched to using cy.request
to programmatically log in to receive your token, everything would just work. We have multiple recipes showcasing this.
@MaxwellGBrown we've been down this rabbit hole many times with many different user feedback and the answer is always the same - you can test your login page in isolation away from the main app once, and then use cy.request
to programmatically use it afterwards. You get the benefit of "really testing it like a user" and then once that is done you get no further benefit.
Just visit the OTHER domain in the test and log in. You could even stub the network request if you wanted to prevent the 3rd party server from redirecting you. Once you do that, then use cy.request
to programmatically receive the token and then START with the token in hand visiting your real app. Just set the token directly in cookies or localstorage and your app will "start" logged in.
There are many other issues in here in which I've commented providing different approaches and work arounds you all may find useful.
Our best practices cover this pretty in depth, and I've even given a talk about this subject and provide real world examples of how to approach this problem.
@ejoubaud You can do this in Cypress - simply visit the domains in different tests, not the same test. As long as you don't visit two different super domains in one test it will all just work. Visit one super domain, test your extension, and then in a separate test visit a different one and test your extension in there.
@brian-mann Where can I find any of these showcased recipes?
I think I have a good use case for this. We're migrating from a monolithic Ruby on Rails app, to micro-services on the back-ends and user-type differentiated front-ends. Our new front-ends are React SPAs, and one of them is way too big to replace at once, so for some app routes we just display the original page within an iframe whereas for others we're using React components to render those routes.
At present I can't write tests that exercise new and old at the same time. I'm presently working around this by putting every test in its own file, but this is far from ideal.
We also require this functionality to test a third party integration
I would love to be able to visit multiple domains. My use case is testing the integration between a front end site and a backend admin. There are certainly ways around not visiting multiple domains, however locally they are only running on different ports (3000, and 3001). There certainly are work arounds:
cy.request
. I could do this however I'd be making requests to the backend api to seed users and make changes. If the API shape changes now my integration suite changes as does my application code. It seems like a strange coupling that I'd rather not haveThis is an absolute blocker for my current client. They have built a solution that integrates several SaaS systems including Salesforce, and need to be able to test side-effects in integrated systems. For example, that registering in the Web front-end causes a lead to be created in Salesforce.
We too will have to abandon Cypress for Selenium, despite _significant_ enthusiasm for Cypress, if this use case can't be addressed.
_Update:_ maybe not ... we are able to subsequently test state on the SaaS system in a second context, and reset it in a third. Something of a hack though.
w8ing this too.
This limitation is a blocker for us as well.
I thought I might be able to overcome this limitation by being a bit creative. I tried the following solutions without success:
Workaround attempt 1 - Use a custom proxy to remove security headers
For starters I set chromeWebSecurity
to false
.
This didn't help me because the external application I wanted to use sent back an x-frame-options
header. I found out that Cypress does remove these for the Application Under Test (AUT), but not for external applications.
To solve this I created a proxy which would remove these headers, and passed this proxy to Cypress using environment variables:
const fs = require('fs');
const hoxy = require('hoxy');
const hostname = 'localhost';
const port = process.argv[2];
createProxy(hostname, port);
console.log(`Started proxy on ${hostname}:${port}`);
function createProxy(hostname, port) {
const proxy = hoxy
.createServer({
certAuthority: {
key: fs.readFileSync(`${__dirname}/ca/selfsigned-ca.key.pem`),
cert: fs.readFileSync(`${__dirname}/ca/selfsigned-ca.crt.pem`)
}
})
.listen(port, hostname);
proxy.intercept({ phase: 'response' }, removeSecurityHeaders);
}
function removeSecurityHeaders(request, response) {
console.log(request.fullUrl());
delete response.headers['x-frame-options'];
}
Passing it to Cypress: HTTPS_PROXY=http://localhost:8080 HTTP_PROXY=http://localhost:8080 https_proxy=http://localhost:8080 http_proxy=http://localhost:8080 cypress open
.
Requests where passing through my proxy, but it still didn't work. After a while I found out that only the requests for the AUT where passing though the proxy.
Later I also found out that Cypress uses a proxy itself, so combining this with a custom proxy probably wouldn't work well.
Workaround attempt 2 - Load Chrome extension to remove security headers
My second attempt was to load a Chrome extension which would remove those nasty headers.
I added chrome-ext-downloader to my package.json
so it would download the extension.
{
"scripts": {
"download-extension": "ced gleekbfjekiniecknbkamfmkohkpodhe extensions/ignore-x-frame-headers"
},
"dependencies": {
"chrome-ext-downloader": "^1.0.4",
}
}
And loaded the extension via plugins/index.js
const path = require('path');
module.exports = (on, config) => {
on('before:browser:launch', (browser = {}, args) => {
console.log(config, browser, args);
if (browser.name === 'chrome') {
const ignoreXFrameHeadersExtension = path.join(__dirname, '../extensions/ignore-x-frame-headers');
args.push(args.push(`--load-extension=${ignoreXFrameHeadersExtension}`));
}
return args;
});
};
With this the external page did load. However, Cypress didn't work on that page. Apparently Cypress uses the proxy to inject itself into the page.
Conclusion
With the current version of Cypress it seems to be impossible to get it to work with multiple super domains. Creativity doesn't seem to help.
To solve this, it should be solved in Cypress itself.
Now let's discuss this.
I would say there are definitely e2e test use cases that require this.
Granted, in some cases one can use cy.request
to achieve the same result as actually interacting with the extra domain.
When you are testing a SPA, you can either go with the cy.request
solution, or just mock the whole backend.
Things are different when you want to test the integration between different applications. If testing such integrations is the main focus of your tests, you need support for multiple super domains. Often such integrations include more complicated flows such as: application1
=> third party application1
=> application2
=> third party application 2
=> application1
.
Now one can argue that Cypress just isn't meant for use cases like this. Especially if there is a technical limitation which is nearly impossible to overcome.
What I am currently missing in this discussion is an explanation on what this technical limitation is. Why does Cypress currently support only one super domain? What would be needed to support multiple? Would implementing that make Cypress a lot more complex? Or would it be, just a lot of work?
Related:
Here's a hacky workaround:
Cypress.Commands.add('forceVisit', url => {
cy.get('body').then(body$ => {
const appWindow = body$[0].ownerDocument.defaultView;
const appIframe = appWindow.parent.document.querySelector('iframe');
// We return a promise here because we don't want to
// continue from this command until the new page is
// loaded.
return new Promise(resolve => {
appIframe.onload = () => resolve();
appWindow.location = url;
});
});
});
Hi @suchipi this looked like a promising workaround! But unfortunately the x-frame-options issue still remains for us...
Refused to display 'https://*****' in a frame because it set 'X-Frame-Options' to 'deny'.
Tested this with hope it will work, it is already an improvement sa it seems to load the page in the promise but then:
Refused to display 'https://**'' in a frame because it set 'X-Frame-Options' to 'sameorigin'.
Will watch this post for updates.
Let me present the use-case I need to visit 2 domains for, to bring in my 2 cents on this issue.
localhost:8000
), where people from our staff need to validate identity of users;localhost:8001
), where our users can digitally sign a contract once they were authentified.This is the TL;DR version of our onboarding workflow. It is very collaborative between our users and our back-office, and it doesn't make sense to test one without the other.
Programming this via cy.request
would cost much more in terms of maintenance than what we're doing now ie creating multiple specs called something-a
, something-b
, that are supposed to run one after another. Every step requiring to switch what app is being used needs a new subspec.
Maybe things running on localhost
with different port numbers could be considered the same domain to make most developers from this thread happy? (ie we get out of the "3rd party" argument)
For the record, we tried to use subdomains to address this. It worked fine on developers' environment but it turned out to be very difficult to build in a CI pipeline, in terms of complexity and pipeline time.
I have this in my cypress.json
{
"baseUrl": "https://my-website.com",
"chromeWebSecurity": false
}
but I'm still getting this error:
CypressError: Cypress detected a cross origin error happened on page load:
Blocked a frame with origin "https://my-website.com" from accessing a cross-origin frame.
Before the page load, you were bound to the origin policy:
A cross origin error happens when your application navigates to a new superdomain which does not match the origin policy above.
This typically happens in one of three ways:
Cypress does not allow you to change superdomains within a single test.
You may need to restructure some of your test code to avoid this problem.
Alternatively you can also disable Chrome Web Security which will turn off this restriction by setting { chromeWebSecurity: false } in your 'cypress.json' file.
https://on.cypress.io/cross-origin-violation
Any ideas as to why explicitly disabling chromeWebSecurity doesn't work?
Is there a reason cypress suggests changing this config property but it doesn't work?
My current workaround is to have separate tests visit the different domains. It works because during dev I have a dummy server keeping up with requests made from the different origins.
describe("Do stuff on one site then visit another and check it worked", () => {
it("Can open the first site and do some things", () => {
cy.visit("localhost:8080");
// do stuff that sends data to a dev server running on another port on localhost
});
it("Can see the results in the other place", () => {
cy.visit("localhost:8888");
// validate my things went good
});
});
Test names and descriptions are vague on purpose.
It's not best practices since my tests have to be run sequentially and depend on the previous, but it's helped me test my workflow better.
Is there any plans to fix this issue soon, as the way our login process works in our UI it's impossible to test e2e properly using Cypress without this fix. It seems a real shame as otherwise all our devs and testers really like it.
Hello!
I hope you are having a beautiful day!
As a paying customers, we hope that it will be fixed soon. We really need this.
I too am an advocate for this feature. In the mean time how do I use cy.request for dynamic urls?
Our app creates workflows i.e. /workflow/3479 <-- This number is dynamic. Upon form submission, it adds /task/968 <-- This stays the same as long as the same workflow type is selected and created from. The end url we have is something like /workflow/3467/task/968. We have limited testing server dedication, so it takes 3 minutes for the form to be submitted, and it sucks being hit with a CORS error. I disabled web security and the app just crashes with no message for the console. It just says "chrome-error://chromewebdata/" in the runner. I think this is due to our internal SSO, and I will try to implement what was mentinoned in the sso recipe. The problem for me is I'm not as technical as I would like to be, and it will take me a long time just to implement this, if I can at all. That said, for me personally or perhaps people who aren't that technical as well, it would be cool to just move on to the next domain and continue with my test. Currently, I've spent more hours than I care to trying to get around this. Also I would like to see a real e2e test. I really like cypress more than selenium. We are currently using TestCafe, which at first glance seems to be more complicated than testing should be. I'm trying real hard to push our organization to go full on cypress because by far it is the coolest tool I've seen, but having something like this implemented would definitely give the extra push to adopt Cypress.
Edit: Also we have an additional refresh token that updates itself every 2 minutes, so I'm not sure if even setting the token in the redirect as shown in the recipe will work.
🙏
cypress 3.2.0
Windows 10
Chrome 73
I felt the same way until I actually spent a dozen hours trying to figure
out our Auth0 architecture. Trust me: put in the time now to figure this
out and you will profit in the future.
On Wed, Apr 10, 2019, 4:06 PM nchaudry notifications@github.com wrote:
I too am an advocate for this feature. In the mean time how do I use
cy.request for dynamic urls?
Our app creates workflows i.e. /workflow/3479 <-- This number is dynamic.
Upon form submission, it adds /task/968 <-- This stays the same as long as
the same workflow type is selected and created from. The end url we have is
something like /workflow/3467/task/968. We have limited testing server
dedication, so it takes 3minutes for the form to be submitted, and it sucks
being hit with a CORS error. I disabled web security and the app just
crashes with no message for the console. It just says
"chrome-error://chromewebdata/" in the runner. I think this is due to our
internal SSO, and I will try to implement what was mentinoed in the sso
recipe
https://github.com/cypress-io/cypress-example-recipes/tree/master/examples/logging-in__single-sign-on.
The problem for me is I'm not as technical as I would like to be, and it
will take me a long time just to implement this, if I can at all. That
said, for me personally or perhaps people who aren't that technical as
well, it would be cool to just move on to the next domain and continue with
my test. Currently, I've spent more hours than I care to trying to get
around this. Also I would like to see a real e2e test.cypress 3.2.0
Windows 10
Chrome 73—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/cypress-io/cypress/issues/944#issuecomment-481865482,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AIeL6o2Hbtgw2xexUAYmKeHiAhiAszLmks5vflJigaJpZM4Ql_rR
.
Here's a hacky workaround:
Cypress.Commands.add('forceVisit', url => { cy.get('body').then(body$ => { const appWindow = body$[0].ownerDocument.defaultView; const appIframe = appWindow.parent.document.querySelector('iframe'); // We return a promise here because we don't want to // continue from this command until the new page is // loaded. return new Promise(resolve => { appIframe.onload = () => resolve(); appWindow.location = url; }); }); });
How do you get the xhr request appear. What I wish to do is the following
cy.wait("@aliasVisitWebPage").then(
xhr => {
const token = xhr.responseBody;
cy.log(token);
}
);
I also have a good use case for that:
We want to make sure that if a user visits a different page and the user spends more than x
seconds to come back to our web site, so when the user comes back, we should log out that user for security reasons.
cy.login().then(() => {
cy.visit('main-page');
cy.hash().should('eq', '#/main-page');
});
cy.log('Visit google website');
cy.visit('https://www.google.com');
cy.wait(15000);
cy.go('back');
cy.log('User should be logged out');
cy.hash().should('not.eq', '#/main-page');
I'm new to Cypress and evaluating it for possible use. I'm also new to Javascript. So, I need to login to a site which has internal redirect to SSO URL. I had a security but issue but now have
"chromeWebSecurity": false
i cypress.json. I can pas the security but during run after login see a blank page. So, my test fails badly. Please, suggest how to overcome that?
Thanks
Jeff
do we have any update about a solution for it? Currently, this issue is also blocking me to use cypress for some tests that I would like to do... because I have a form that I submit and takes me to a different domain, so I can't simply navigate to this different url...
and using chromeWebSecurity:false causes other issues in my applications, so it is not an option...
I also had issues with multiple domains that I could not work around (dependency on a 3rd party at this time). It's required (and desired) for our end to end tests. I spent some time getting this to work by examining the browser interactions via devtools then replicating with successive cy.request
calls. It's not pretty but sharing in case it helps someone else. Cypress is a great tool and I appreciate the active community around it
cy.get('a')
.contains('rabbit hole')
.get('a')
.invoke('attr', 'href')
.then((href) => {
cy.request(href)
.then ((resp) => {
// need to work with the last redirect
const postLoginUrl = resp.redirects.pop().split(': ')[1];
// scrape idsrv.xsrf for form post
const idsrv = resp.body.match(/idsrv\.xsrf\"\;\,\"\;value\"\;\:\"\;(.*?)\"\;/)[1];
const postLoginUrlOptions = {
method: 'POST',
url: postLoginUrl,
form: true,
body: {
"username": username,
"password": password,
"idsrv.xsrf": idsrv
}
}
cy.request(postLoginUrlOptions)
.then ((postResp) => {
const postShareUri = postResp.body.match(/consentUrl\"\;\:\"\;(.*?)\"\;\,\"\;/)[1];
const scopes = postShareUri.match(/scope\=(.*?)\%20(.*?)\%20/);
const postShareUrlHostMatch = postResp.redirects.pop().match(/\d+\: (.*?)\:\/\/(.*?)\//);
const postShareUrl = `${postShareUrlHostMatch[1]}://${postShareUrlHostMatch[2]}${postShareUri}`.replace(/\&/g,'&');
const postShareUrlOptions = {
method: 'POST',
url: postShareUrl,
form: true,
body: {
"idsrv.xsrf": idsrv,
"scopes": scopes[1],
"scopes": scopes[2],
"RememberConsent": "false",
"button": "yes"
}
}
// cheesy check that things are on track
cy.request(postShareUrlOptions)
.then ((postShareResp) => {
expect(postShareResp.redirects.length).to.equal(3);
});
const logoutUrl = `${postShareUrlHostMatch[1]}://${postShareUrlHostMatch[2]}/logout`;
const logoutOptions = {
method: 'POST',
url: logoutUrl,
form: true,
body: {
"idsrv.xsrf": idsrv,
}
}
cy.request(logoutOptions)
.then ((logoutResp) => {
expect(logoutResp.body).to.have.string("You are now logged out");
});
});
})
});
I think that Cypress simply doesn't know how to fix the issue or doesn't care about the above issue with multiple domain redirects
I really love this tool. unfortunately, this is a huge blocker when doing SSO authentication which requires the user to navigate to a different domain and come back. chromeWebSecurity doesn't help, so not sure how to solve this situation... though, this seems feasible with other tools for E2E automation
Get the token from your SSO provider using cy.request(), you should never
have to leave your domain for this.
On Wed, Jun 19, 2019 at 3:16 PM Francesco Paolo Vitullo <
[email protected]> wrote:
I really love this tool. unfortunately, this is a huge blocker when doing
SSO authentication which requires the user to navigate to a different
domain and come back. chromeWebSecurity doesn't help, so not sure how to
solve this situation... though, this seems feasible with other tools for
E2E automation—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/cypress-io/cypress/issues/944?email_source=notifications&email_token=ACDYX2XNMCKDQBZXETKQK4TP3KHZPA5CNFSM4EEX7LI2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYDE67Y#issuecomment-503730047,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ACDYX2UETL3Z2ONJQATLW6DP3KHZPANCNFSM4EEX7LIQ
.
My app uses OAuth for a lot of stuff and this is a huge blocker.
This is causing me a lot of grief right now. Programmatically authenticating can get quite complicated. Not everyone has ideal setups.
Here's a perfect use case for needing access to multiple "superdomains", for which using cy.request()
simply won't work:
Our web site, https://shop.nordstrom.com has a search form in the header. Certain search terms result in a 302 redirect to our subsidiary companies' web sites. Searching for
rack
redirects to https://www.nordstromrack.comtrunk club
redirects to https://www.trunkclub.comWe are liking Cypress (a lot!), but it does seem odd that there is seemingly no workaround for this problem.
Further... The fact that there's no useful error given seems odd. All I get instead of the expected redirect, I wind up at chrome-error://chromewebdata/ with no explanation whatsoever.
Hello Cypress Team- Will there be a fix anytime soon on this? . It is long pending from November 2017!!!
Hey! The docs say that disabling web security will allow navigating from a http site to a https site, but this results in chrome-error://chromewebdata/
in practice. It would be very useful for this functionality to actually be in place
I have a similar problem to everyone above, but maybe a different wrinkle.
We have an authentication app that's shared by several apps in our enterprise, and it's on different subdomains in the same superdomain (i.e., login at https://login.mycompany.com
, then redirects back to my app at https://app.mycompany.com
).
However, when I'm running my tests against locally hosted versions of those apps (i.e. login at http://localhost:5555
, app at http://localhost:7777
), I get the "You may only visit a single unique domain per test" error because of the different localhost ports. BTW, this only happens when I run in Electron (headless or in the runner). It's fine when I run Chrome, as i have chromeWebSecurity
turned off.
I know it's better to use request to login, and I do that for all of my other tests -- this case is my one smoke test that makes sure the login integration works correctly.
@jrnail23
this case is my one smoke test that makes sure the login integration works correctly.
Wouldn't whatever you're doing through cy.request in your other tests already cover this integration? If your login service isn't working, then it will fail those tests.
@Joelasaur that's kinda beside the point. The other tests don't cover the redirect from the login service.
I can imagine this must also come up if you're testing a paypal payment flow, using one of their testing services.
Hello Cypress Team- Can we at least know if this issue will be fixed at all? This will help us in making a decision on wether to use Cypress or not.
Really would love to get an update about whether or not this is going to be fixed. This is basically the only roadblock to my team switching from protractor to cypress.
I am in the same situation as @Raiune stated above. We federate our identity (e.g. login) our to Azure Active Directory, upon successful authentication, it redirects back our app, with the necessary tokens. After this point, cypress will work very (incredibly) well, but the federated authentication, which requires multiple superdomain support is a show stopper for us.
In the same boat, we use Firebase for verification and we can't navigate to the Firebase link. Can't just use cy.request()
either, since the verification page needs to be loaded and some code on the page executed. All the workarounds I've found, like "chromeWebSecurity": false
don't work either.
Surprised this issue is outstanding for so long, such a small thing but such a big impact. We're wanting to move over from Puppeteer, but we can't while this is blocking us. Can't even write a simple signup test.
I agree with the crowd here. Provided workaround is not a real solution. End to end tests should not have any kind of hacking in between. I want my test to behave exactly as it would be human.
Human would not stub requests, copy tokens and change my API to force being logged in using third-party auth.
For everyone who find this issue blocking further progress in writing tests: jest-puppeteer seems to be a viable replacement for cypress with similar easy-to-use ratio.
+1000
With now many applications running with auth0 and many others, this actually becomes a very big blocker. Indeed I understand why it does not work and how the inner workings of cypress does not allow this, yet is still there and a blocker.
Perhaps a chrome plug-in? Or a hack in chromium?
To add to the chorus, we have invested time and resource in Cypress before discovering this blocker. Testing across super-domains isn't unusual in modern application testing - a concept Cypress claims to excel in.
Really looking forward to an update on this issue, for us it would be a great shame to have to switch everything back to Webdriver.
Also a blocker for my company. We're considering moving from TestCafe to Cypress, but this issue is impacting us.
@rodrigotolledo due to this issue, we are thinking of going the opposite - from Cypress to TestCafe. What are your reasons for not using TestCafe?
Hello Everyone,
I am new to Cypress, was excited to try to this after hearing lot of buzz from friends. Also spent lots of time in figuring out why my tests unable to connect to federated site from another host for an authentication purposes. Now, i understand this is a known blocked from couple of years.
Can someone explain me whether the hacker below posted by other user works?
Cypress.Commands.add('forceVisit', url => {
cy.get('body').then(body$ => {
const appWindow = body$[0].ownerDocument.defaultView;
const appIframe = appWindow.parent.document.querySelector('iframe');
// We return a promise here because we don't want to
// continue from this command until the new page is
// loaded.
return new Promise(resolve => {
appIframe.onload = () => resolve();
appWindow.location = url;
});
});
});
@MalleswariV yes this has been working for me reliably. I use it like so: cy.forceVisit(myurl)
.
@thedgbrt thanks for your quick response..but where you add this workaround? in the same spec you are visiting two different super domains?
yes, or inside cypress/support/commands.js
, it will then be available in all your test files.
when i add it throws me an error saying cy.forceVisit is not a function.
@MalleswariV You would need to share more details about your setup to help us figure out why that is, but this is not a support forum. You should ask on stack overflow. You can tag me there if you want.
as much as I would love it, sadly not all 3rd party authentication allows for programmatic access to get tokens.
This is a huge problem for me 😢
Finally, I can give a helping hand to all of you who wants to visit any other domain inside Cypress test.
_My first try was to run a Cypress test from inside of another Cypress test:_
cy.exec("npx cypress run --spec path/to/test.js --headed")
.then((result) => {
console.log(result)
})
_Although it was working (running a second Cypress instance running the second test), it was very slow and did not keep the session data (cookies etc.)._
MY SECOND TRY ALLOWS ME TO VISIT UNLIMITED NUMBER OF DOMAINS!:
First, you need to add Puppeteer to your project:
npm install puppeteer
Then you can use it like this:
Parent test:
blahblahblah
cy.exec("node path\\to\\file.js --headed", {timeout: 180000})
.then((result) => {
console.log(result.stdout)
})
blahblahblah
Child test:
const puppeteer = require('puppeteer');
puppeteer.launch({headless: false, userDataDir: "./user_data"}).then(async browser => {
const page = await browser.newPage();
await page.goto('https://www.google.com');
await page.waitFor('some_element');
const message = await page.evaluate(() => document.querySelector('some_element').innerText)
console.log(message)
await browser.close();
});
Important notes:
https://github.com/cypress-io/cypress/issues/789
console.log(message)
is used in child test to send data to STDOUT. It is then captured by result.stdout
in parent test. You can also use STDERR to output the data (console.error
instead of cypress.log in child test and result.stderr
in parent test)
Please keep in mind that when you run cy.exec(), your CWD (Current Working Directory) is the root of your Cypress repository, so in order to run any tests you need to use the relative path, like cypress\\integration\\mytest.js
You can shorten the code to get the text from the element:
https://github.com/GoogleChrome/puppeteer/issues/3260#issuecomment-422081505
Instead of
await page.evaluate(() => document.querySelector('#my-sweet-id').innerText)
await page.evaluate(() => document.querySelector('#my-sweet-id').innerHTML)
You can use page.$eval:
await page.$eval('#my-sweet-id', e => e.innerText);
await page.$eval('#my-sweet-id', e => e.innerHTML);
ENJOY!
If you have any questions, just ask :) It is working perfectly for me and overcome the issue with visiting more than one superdomain in one test.
@wojciechsabaj the idea of running puppeteer inside cypress made me laugh (ironic, right?), but this is a pretty good workaround!
@wojciechsabaj,
Did you try this with an sso implementation, where the login redirects to more than on super domain and finally comes to the main website?
@wojciechsabaj Thanks for this workaround, much appreciated but Cypress really should fix this. Running Puppeteer inside Cypress is not a viable solution to run at scale.
@jrnail23 Thanks! I fully experienced how frustrating it is when you have your framework almost ready and then BAM! - you find an issue like this. I _can_ imagine the motivation behind keeping testing in the boundaries of one superdomain but there are some situations when you do not want/need/have time or knowledge to build a second testing system just to mimick the server's actions using requests. In my case I needed to visit a separate page that was loading a bunch of client-side scripts, this is why I started with running a nested Cypress test and ended with a wrapper for Puppeteer. I was not able to use simple requests without simulating a lot of work that was done by scripts that can be executed by a properly working browser.
@ankeshdave I took a quick look at SSO mechanisms and my answer is: using my method, you can return anything you want from the child test. SSO mechanisms give you a token that needs to be used when making subsequent requests. You should be able to extract the token (or better, return the value via STDOUT of the child test to result.stdout of the parent test) and then insert the token into the proper place. It might be interesting to cooperate with SSO using my method. I am fully aware that not each SSO is under your control, so if you are successful with implementing my solution in your code, please share it with us and I can try to prepare a more general solution to SSO usage in Cypress.
@you1anna, please be aware that this issue was marked with "production board" tag a few days ago, so I hope that creators of Cypress took this issue seriously and will put some effort to make it easier for us to create tests in Cypress.
Guys, we need it
This issue makes Cypres useless for anybody willing to test web application which needs to move between domains (especially for auth)
I need this feature to navigate between two applications we own. We need to test that our administrative application changes to settings update our public facing application. These applications run on different ports locally. It looks like we'll have to go back to codecept, because this is not going to work for us. This is sad because I was really excited about using cypress. It feels like this limitation is imposed needlessly.
I need this feature to navigate between two applications we own. We need to test that our administrative application changes to settings update our public facing application. These applications run on different ports locally. It looks like we'll have to go back to codecept, because this is not going to work for us. This is sad because I was really excited about using cypress. It feels like this limitation is imposed needlessly.
I am facing a similar issue, not able to navigate between the applications running on different port
Anyone know what the tag "Product Board" means here? This appears to be the only issue with that tag
Not that I'm actively contributing the the solution with PRs or hacks/workarounds, but:
I'll be adding my "+1".
Considered using this for a growing client and sadly it's a non-starter as we are the SSO that would need to be tested against/across 100s of sites (client site -> our SSO -> client site, etc, etc).
A shame really, Cypress is so featureful and promising.
We really need this feature. Like everyone else here, Our app uses central Auth, and visiting the local url will take you to central Auth, where you can login and it will redirect you back to the original url. It's a common pattern and it's not trivial to login through an endpoint. Spent a lot of time setting up cypress for my job but can't demo anything because of this issue.
@rotexhawk as a workaround you can use puppeteer to get the auth credentials and inject them to your app. I can provide an example how to implement it if you want...
@pkuczynski thanks but I already tried that.
Cypress.Commands.add("login", () => {
cy.getCookie("automation").then(cookie => {
if (!cookie) {
cy.exec("node ../costar-suite/cypress/helpers/login.js --headed", { timeout: 180000 }).then(res => {
const cookies = JSON.parse(res.stdout);
cy.log(cookies);
for (let cookie of cookies) {
cy.setCookie(cookie.name, cookie.value, omit(["name", "value", cookie]));
}
});
}
});
});
before(function() {
cy.login();
});
Login.js
const puppeteer = require("puppeteer");
puppeteer
.launch({
args: ["--ignore-certificate-errors", "--enable-features=NetworkService"],
})
.then(async browser => {
const page = await browser.newPage();
await page.goto("http://localhost.com:4000/");
await page.waitForSelector(".login-form-component");
await page.type("#username", "username");
await page.type("#password", "pass");
await page.waitForSelector("#loginButton");
await page.click("#loginButton");
await page.waitForSelector(".navigation-container li a");
const cookies = await page.cookies();
console.log(JSON.stringify(cookies));
await browser.close();
});
And I guess this was not working? Its not the best way to pass over data via stdout. I was using cy.task()
@pkuczynski yeah ^ that's not working. I was just trying to test things and thanks for the tip on cy.task()
.
Your welcome, let me know if you still have issues...
I've been struggling with this for a while, so here is my current implementation with great thanks to the tips of using puppeteer and cy.task()
. Our app uses OAuth2 for all authentication, also the first-party apps. So I had to navigate to a page on a different port (login-server) to login a user. That is now handled by the cypress task through puppeteer. Puppeteer logs in, then gets the entire user model (just the token could also work in your case) and returns that to the task. The task again returns that. I made a cypress custom command to start the task, get the user model, set it in localstorage, and then my tests can run.
plugins/index.ts
module.exports = (on, config) => {
on('task', {
login({ username, password }) {
return (async () => {
const browser = await puppeteer.launch({ ignoreHTTPSErrors: true });
const page = await browser.newPage();
await page.goto('https://my-app.test:4200', { // The app redirects to the login-page
waitUntil: 'networkidle2' // Wait until login-page has been reached
});
await page.type('#email', username); // Insert username in form
await page.type('#password', password); // Insert password
await page.click('button[type="submit"]'); // Click login button
await page.waitForNavigation({ waitUntil: 'networkidle2' }); // Wait until redirected back to the app
const user = await page.evaluate(() => { // Get the user-model from localStorage
return localStorage.getItem('user');
});
await browser.close(); // Close puppeteer
return user; // Return the user-model to Cypress
})();
}
});
Then in support/index.ts
(or a different file which is imported in support/index.ts
)
Cypress.Commands.add('login', (username, password) => {
cy.task('login', {username: username, password: password}).then(user => {
window.localStorage.setItem('user', user);
});
});
And finally in my test whatever-test.spec.ts
describe('Whatever test', () => {
it('should login and do some stuff', () => {
cy.login('[email protected]', 'SomeSecretPassword');
});
});
Hopefully this will help somebody who is facing the same problem. If you can't get it working feel free to send me a message, I might help you if I can find the time ;-).
Yeah, it can be done. Quick question - is there any reason you need a _browser_ to load up 500 different domains and click a button?
Wouldn't it be much much easier to just use
cy.request
or another programatic means to accomplish this?For instance, what does clicking the button do? Send an HTTP request is my guess. So instead of using the UI, just send the HTTP request directly using
cy.request
. Same result, 100x faster, and no domain issues.Any additional information about your use case would be helpful.
I am already very well aware of the best practices which says we should be logging in programmatically via API requests and not thru the UI. This works well in simple straight-forward apps like kitchen-sinks, todos, apples and oranges etc. But enterprise-grade applications are a bit more complex than getting a token by just doing a single cy.request() to a /apples/oranges/giveMeUserToken
endpoint. Just to give an overview of the complexity, our dev teams are distributed across multiple countries/timezones and there are about 7 different multifactor authentication calls where tokens are passed between the headers and parameters of these APIs to retrieve the final session-cookie. Each subsequent call depends on the authenticity of the token from the previous call. Not to mention these tokens get changed periodically for security purposes. These are all owned by different co-located security teams who are beyond a feature team's reach. To get the token you will have to ping 7 different teams in the middle of the night for the secrets which will only be valid for a week or so. Hence, logging in via API is out of question here.
Wanting a real full walkthrough of our registration and login process (using firebase auth) I used the following method to forcefully open another domain / url in the cypress browser. Inspired by the snippet from @suchipi:
Cypress.Commands.add('forceWindow', url => {
cy.get('body').then(body$ => {
let newWindow = open(url)
return new Promise(resolve => {
setTimeout(x => {
newWindow.close()
resolve()
}, 2000)
})
});
});
This works with any domain but I didn't test using cy on the other domain/window, as we only need to open this window so the cypress browser is logged in (cy.request() didn't work):
cy.forceWindow(loginLink).then(x => {
cy.reload()
})
Improvements welcome.
Our application uses Identity server for authentication so we do need to be able to redirect from superdomain to handle authentication and back to the domain where we started. We have separated the tests in one test doing the login action an another that performs the navigation and validation. Before this separation was working because the session cookie was persisted and could be used for the validation test case but it looks like this has been changed lately. Suggestions are welcome
One more update on this one: what I did is preserve the sessions cookie's with a cookies whitelist on the navigation and validation test test. This work-around works, still it would be nice to be able to navigate between IDS and the rest of the application.
My company is building an Oauth service and we have several domains. We need to be able to redirect from one to another and don't have yet the ability to login programatically. In fact, we want to test our OAuth login process like a real user and we can't because Cypress doesn't allow us to visit different domains.
It is really painful and we refuse to "hack" this with iframe / puppeteer or some other solution, it's too dirty and we can't include that in our codebase (even if these are cool solutions 😄).
What i don't understand is: You notice users that you have good practices, and it's a good thing, but here, Cypress just say "NO!" to what we want to do and, because of that, it is totally useless for some cases that we want to test.
I even tried to use {chromeWebSecurity: false}
but, even if this worked once with an old Chrome version, it doesn't anymore.
is there any available solution, with cypress, to do what i want?
EDIT: After a long talk with the team we agreed to change our process because we thought about Cypress's way of doing thing and decided to get rid of our socials network OAuth strategies tests.
We will test this differently. We "hacked" the problem of having multiple apps on different domains on our side by registering all of them on the same domain in a review environment (login form, email / sms services and third party app that want to use our solution)
After 2 months of struggling with this meaningless feature/issue(read blocker), we have finally decided to throw Cypress outta the window and adopt Puppeteer as our E2E test automation.
Writing tests with Puppeteer is not as good an experience compared to Cypress. But tests execution is surprisingly exponentially faster + you got the luxury to test in multiple browsers + runs faster in CI pipeline cause of much smaller docker image ....and guess what !!! you can actually route your app thru 100 different domains to get the session cookie that you needed...without someone telling you that its not a "best practice" and locking u into a single domain
After 2 months of struggling with this meaningless feature/issue(read blocker), we have finally decided to throw Cypress outta the window and adopt Puppeteer as our E2E test automation.
Writing tests with Puppeteer is not as good an experience compared to Cypress. But tests execution is surprisingly exponentially faster + you got the luxury to test in multiple browsers + runs faster in CI pipeline cause of much smaller docker image ....and guess what !!! you can actually route your app thru 100 different domains to get the session cookie that you needed...without someone telling you that its not a "best practice" and locking u into a single domain
we reached the same decision and combined Puppeteer with Jest.
@jennifer-shehane I've wanted to ask... What is the position of the cypress team about this issue?
Is there any possibility to make it flexible, or as a design choice it will continue as it is?
It seems like a true block to a lot of people. Its very frustrating to have to abandon cypress when you realize that you don't have any options or simple workarounds to such scenarios. And these scenarios are not that even uncommon! If you use OIDC authentication on an identity server, you're already done for... Cypress is not viable in these scenarios unless you're up to do some crazy workarounds
We ended up using puppeteer in a cypress task, which is kind of not the point of it, but for now this dirty workaround helps us to continue to use cypress.io.
I was tired to wait because when looking at the code you will understand that it will never change.
If you want another solution, I recommend CodeceptJS.
Wrong thread Mr. Mikael. This is a non-selenium community. CodeceptJs is just another wrapper over Selenium.
Not really, it is also for Puppeteer and it works fine with Browserless.
"chromeWebSecurity": false,
doesn't work on the newest chrome versions.
I switch between different subdomains (HTTPS and HTTP) but with the same domain, and I still got this:
ypressError: cy.visit() failed because you are attempting to visit a second unique domain.
You may only visit a single unique domain per test.
Different subdomains are okay, but unique domains are not.
The previous domain you visited was: 'https://yyy.domain.io'
You're attempting to visit this new domain: 'http://xxx.domain.io'
You may need to restructure some of your code to prevent this from happening.
https://on.cypress.io/cannot-visit-second-unique-domain
"chromeWebSecurity": false, doesn't work on the newest chrome versions.
I have the same problem. It was working fine a few days ago. Any solutions for this? Thanks!
I managed it by using the same domain and the same protocol (https for both).
I managed it by using the same domain and the same protocol (https for both).
Oh, I can't do the same because we use SSO hosted in another domain
Adding my "+1" here, we do use SSO hosted in another domain as well. Is there any update from the cypress team about this issue? If not, we will have to pass this awesome tool.
Well this should add in cypress asap, because now we do end to end testing and mostly we have different auth intergration like sing up Login (gmail, facebook,twitter etc) so this should allow and this is the functionality we need almost every end to end testing
It would be helpful to be able to write Cypress tests in which an application visits different domains. This is a normal thing for many redirect flows (e.g. auth, payments, etc.) and it would be nice to be able to fully test these flows without having to create brittle workarounds for the individual pieces.
It is very frustrating to have so many limitations like this in cypress, this is a blocker in my use case and I will have to switch back to webdriverIO
It's a shame that no one will even speak to this issue as its plaguing so many people that are either using the product or want to use the product. I have an entire test suite that uses Cypress for one of our software products, but for our other product we can't use it due to multiple superdomain redirects upon login. I have tried many different things to get Cypress to work with it but to no avail. Have to continue using Protractor, but I'd much rather be using Cypress.
I think everyone would appreciate a comment one way or another from the Cypress team as to whether this issue is even on your radar.
"chromeWebSecurity": false
is still not working
Any updates on that?
The Cypress team still intends to address this issue as it is within our scope of work and roadmap for our product. The work required to fix this is very large and inter-connected to other issues involving Cypress's core functionality.
This issue is still in the 'proposal' stage, which means no work has been done on this issue as of today, so we do not have an estimate on when this will be delivered.
Heh, my first day with Cypress and this happens... :/
Heh, my first day with Cypress and this happens... :/
Haha, you are lucky. Imagine people spending 3-6 months building up the entire test-suite of 100+ tests and then realize midway that they can't proceed any further because of this bug :)
@abhidp Yea, this is unacceptable.
It shouldn't come as a surprise to the Cypress team right? Probably Chrome-beta versions shown that this problem will eventually come.
@jennifer-shehane are you following chrome-beta changes to prevent this kind of breaking changes?
I managed to get it working by loading an extension that force-allows cross-origin sites:
I used this extension: https://github.com/vitvad/Access-Control-Allow-Origin
module.exports = (on, config) => {
on("before:browser:launch", (browser, launchOptions) => {
if (browser.name === "chrome") {
launchOptions.args.push(
"--load-extension=cypress/extensions/Access-Control-Allow-Origin-master"
);
return launchOptions;
}
});
};
Now your multidomain tests should go through fine. Extension needs no manual configuration.
lack of this block my work...
Here's a hacky workaround:
Cypress.Commands.add('forceVisit', url => { cy.get('body').then(body$ => { const appWindow = body$[0].ownerDocument.defaultView; const appIframe = appWindow.parent.document.querySelector('iframe'); // We return a promise here because we don't want to // continue from this command until the new page is // loaded. return new Promise(resolve => { appIframe.onload = () => resolve(); appWindow.location = url; }); }); });
Not working for me, after pass url to cy.forceVisit(), nothing happend ;/
- you configure the extension
Im not really understand step 4, can you explain?
@kamil-rogowski-gc I've updated the post with guide
@kamil-rogowski-gc I've updated the post with guide
Ok thanks but I cant see this extension. Will work this solution on CI? As I can see you do something in browser manually
@kamil-rogowski-gc I've reupdated the guide. Now it works out of the box. I used a different extension this time, that works for all domains out of the box. Let me know if it works
@Vioner I attempted the steps in your post above and the spec still failed trying to access a different domain, the error returned was the usual error about accessing a 2nd superdomain. Was there anything else you had to do to configure this to get it working?
Sorry guys, but I may have misinformed you.
I just reinstalled everything, did clean tests without the extension, no custom changes and it's kind of random. I guess it depends on the Cypress proxy and "timing" - when things happen and in what order.
Regardless of method used to start tests, they sometimes all go through fine, sometimes first succeeds and rest fails due to cross origin crap, and sometimes all tests fail...
All in all, this is a serious issue on Cypress' side and no workaround seems to be working - just like 2 years ago.
Sorry guys, but I may have misinformed you.
I just reinstalled everything, did clean tests without the extension, no custom changes and it's kind of random. I guess it depends on the Cypress proxy and "timing" - when things happen and in what order.
Regardless of method used to start tests, they sometimes all go through fine, sometimes first succeeds and rest fails due to cross origin crap, and sometimes all tests fail...All in all, this is a serious issue on Cypress' side and no workaround seems to be working - just like 2 years ago.
Yeah, I was surprised that someone found the solution to this age old problem on their first day with Cypress. I was excited to try out ur solution, but .... disappointment, just like 2 years ago :(
Running into the same issue as you all are. Very interested as to whether Cypress will come up with a solution.
In my case, I need to wait on requests from a set of my app's APIs
So, my app is running as http://localhost:8089
, and waiting on requests like https://dev-service.domain.com
. The XHR requests are not showing up in the left hand pane either
But, when I run the tests against the dev server https://dev-app.domain.com
, the waits work and I can see the XHR requests in the left hand pane. Is this also a side effect of that?
The big issue is that "chromeWebSecurity": false
is no longer working in chrome - and we have many use cases for needing to do this which is critical :(
I just want the https and http versions of the same site to work properly. But am blocked because of this policy.
I tried the solution with forceVisit and disable chrome security, but still doesn't seem to work. I think that tha main problem is with chrome security, because now I get the error:
chrome-error://chromewebdata/ istead of cross-origin. :/
In our application a button click leads to another domain, where the redirect url in our case is dynamically generated and each time unique because of Okta implementation. Cypress gave me the error described in the other comments mentioned above of the cross origins error. With the tips and tricks in the Cypress documentation (https://docs.cypress.io/guides/guides/web-security.html#Same-superdomain-per-test) I found a hacky workaround for our test case.
By splitting the part of getting the redirect url in the before and continue the rest of my test case in the test itself, I can use the redirect url in my visit there. This way I still have a test case who is close to the user experience and which is across multiple domains.
describe('Login', () => {
let testUrl: string | null;
before((tileIndex: number) => {
cy.clearCookies();
cy.visit('/');
cy.login();
cy.get('data-test')
.eq(tileIndex)
.click()
.then(xhr => {
testUrl = (Cypress.$(xhr))[0].children[0].getAttribute('href');
});
});
it('Single sign-on is succesfull', () => {
cy.visit(`${testUrl}`);
cy.get('data-test').click();
});
});
Hope it helps someone!
Any update on this feature?
+1
cy.login('[email protected]', 'SomeSecretPassword');
The 'task' event has not been registered in the plugins file. You must register it before using cy.task()
@jennifer-shehane I see lots of comments on people needing this. Wanted to echo a real world usage and need for this for openid connect session management.
Due to the policy to prevent two origins in a test we are unable to test any of our authentication as an integration test using cypress.
We have a single page app that is a fully reliant party for an Oauth provider that is internal to our system. It is hosted on a separate subdomain. To login initially we redirect to the auth site. While on the client when a user must reprove that they are them we display a modal that is an iframe so that the proper cookies are set from the Oauth provider on that login.
We have the exact case as @Austio and would love to see some resolution to this issue.
+1
I really wish this was out of the box as well.
I had to authenticate with auth0 and go through our app which would trigger the problem in this issue. I read the auth0 e2e cypress article on how to setup that auth. with cy.request() but they were using grant_type: password
which was something I did not wanted to include in my app.
I wanted to test the login page as well, so, to bypass this limitation, I used Puppeteer do login and get the cookies created:
const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] }); // Needed to run inside docker
const page = await browser.newPage();
await page.goto(URL);
await page.type('#username', USERNAME);
await page.type('#password', PASSWORD);
await page.click('.ulp-button');
const auth0Cookies = await page.cookies();
browser.close();
and then running cypress with:
await cypress.run({
config: { video: false, env: { auth0Cookies } }
})
and in the spec file:
Cypress.env('auth0Cookies').forEach(({ name, value, domain, expires, httpOnly, path, secure }) => {
cy.setCookie(name, value, {
domain,
expiry: expires,
httpOnly,
path,
secure,
});
});
cy.visit(URL)
And therefore, because the cookies are already set, auth0 login page does not show up and I can go straight to the app page and no two super domains, but still have managed to test the login and the app page
Hope this helps someone :)
This is especially relevant in light of "chromeWebSecurity": false not working.
Even if that was working it should give you an idea how many people are actually setting it to false... which is the main answer to this issue.
--edit removed link to different issue
Real world scenario that requires this support:
A1 = web app 1
A2 = web app 2 (different domain)
1) Log into A1 to submit claim
2) Submit claim in A1
3) Switch to A2 to approve claim
4) Approve claim in A2
5) Switch to A1 to view approved claim
6) Validate approved claim details in A1
I really wish this was out of the box as well.
I had to authenticate with auth0 and go through our app which would trigger the problem in this issue. I read the auth0 e2e cypress article on how to setup that auth. with cy.request() but they were usinggrant_type: password
which was something I did not wanted to include in my app.I wanted to test the login page as well, so, to bypass this limitation, I used Puppeteer do login and get the cookies created:
const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] }); // Needed to run inside docker const page = await browser.newPage(); await page.goto(URL); await page.type('#username', USERNAME); await page.type('#password', PASSWORD); await page.click('.ulp-button'); const auth0Cookies = await page.cookies(); browser.close();
and then running cypress with:
await cypress.run({ config: { video: false, env: { auth0Cookies } } })
and in the spec file:
Cypress.env('auth0Cookies').forEach(({ name, value, domain, expires, httpOnly, path, secure }) => { cy.setCookie(name, value, { domain, expiry: expires, httpOnly, path, secure, }); }); cy.visit(URL)
And therefore, because the cookies are already set, auth0 login page does not show up and I can go straight to the app page and no two super domains, but still have managed to test the login and the app page
Hope this helps someone :)
Most certainly did ❤️ Thanks so much.
Wanting a real full walkthrough of our registration and login process (using firebase auth) I used the following method to forcefully open another domain / url in the cypress browser. Inspired by the snippet from @suchipi:
Cypress.Commands.add('forceWindow', url => { cy.get('body').then(body$ => { let newWindow = open(url) return new Promise(resolve => { setTimeout(x => { newWindow.close() resolve() }, 2000) }) }); });
This works with any domain but I didn't test using cy on the other domain/window, as we only need to open this window so the cypress browser is logged in (cy.request() didn't work):
cy.forceWindow(loginLink).then(x => { cy.reload() })
Improvements welcome.
This worked for me. I was trying to click on a button inside an email in Mailosaur to verify account creation on our site. (I create an account on our UI. And the email verification needs to be done in Mailosaur account. I find the email got sent and have to click on the verify email button to verify) I already had the url from cy.request. But I had no idea how to click on the button due to the fact that it goes to a different domain. I used this piece of code and it works great. This was a big help.
Thank you @wingsuitist
I would really appreciate if you can explain this a bit from the 2nd line,
cy.get('body').then(body$ => {
let newWindow = open(url) return new Promise(resolve => { setTimeout(x => { newWindow.close() resolve() }, 2000) })
I don't really understand why there is no easy workaround for people who really need this feature. I like opinionated frameworks, but there are legit reasons to visit (for us at least 2)ports in a single test and no, cy.request
is not always the proper way to solve this and disabling chromeWebSecurity
does not help here. This issue has been open for 2 1/2 years, it has 126 comments and I'm just wondering why it's still open, because it doesn't feel like the maintainers are willing to at least offer a somewhat decent workaround.
Thanks to @suchipi for providing a workaround that luckily works for us <3
Ps. Thanks to everyone working on this great tool <3 Coming from years of Capybara (which is not a bad tool per se), I really love Cypress for everything it offers!
It's really suprising to see it's not considered as a bug. At the home page it states End-2-End testing.
My perception of End-2-End testing is covering a complete business flow. Not just testing the front-end of a single application.
I really hope i will be made possible to do the following steps in a single test:
cy.visit('https://company-application-a.nl')...
verify a create function at the front-end application
cy.visit('https://company-application-b.nl')...
verify a read function at the back-office application
If someone has a workaround for the time being that would be great. I tried all other solutions above but can't seem get the desired result.
I do think Cypress has great potential! So keep up the good work.
We too, depend on multiple systems at different domains to be tested as a whole, which is currently impossible because of this artificial restriction.
I'm not opposed being opinionated and trying to make a case for separating different systems in different tests, but the real world is not perfect.
If there could be a way to at least disable this restriction for those of us who have systems in place that can't be changed over night (or in the next year even), then that would help us all out.
Cypress gets to keep their opinions on how and what to test, out of the box, and advocate their thoughts on it. And for those people who might agree, but do not have the luxury to follow that lead: we could work around it.
Thanks for considering it, it would be an amazingly welcome change and one that will probably help me to continue using Cypress instead of having to switch over to yet another tool.
Will cypress team take this on priority at least now. This is the only tool in market does this. Our application totally depend on Facebook login as we deal with group data Analytics. With out logging in Facebook there is not way we automate. I cannot login to Facebook using cypress and we also have landing page on a different repo which works on redirection. I cannot separate the test cases and it is not considered as end to end. Just because of this reason we have moved to playwright. I am not sure when they will realise.
Our team is currently working on crafting a better experience around testing authentication, which is a large use case covered in this issue. We know that many people are dissatisfied with the current approach of testing authentication programmatically and we want to address those concerns.
There are multiple phases to addressing the core of the issues with testing authentication that we'll be rolling out piece by piece. We do read everyones comments and use them to evaluate how to approach the work ahead of us.
@jennifer-shehane Thank you for your hint about working on it. Please don't just focus on Authentication, by building some OAuth mock or anything like this. I guess there may be many use cases no one things of now, like payment gateways. There are so many other situations where you need cross-domain testing without restrictions. For example, we build a web archive browser that uses web workers and some domain magic to make the website think it's actually from its original source, while it is loaded from a WARC archive streaming from the server. Our current workaround consists of separate puppeteer scripts run outside of cypress.io. I understand the urge to stick to a holy architecture of how things should be done, but sometimes there just has to be the "ok, I know what I'm doing, please ignore this - button". Or maybe I'm getting the whole issue wrong? If so I'm humbled and sorry for using up this character Space.
I agree with @wingsuitist
You simply can't do e2e testing with Cypress and any sort of payment provider which is, as you can imagine, crucial for a lot of businesses.
A very simple example is using PayPal as a payment option, there's no way you can do e2e testing with an integration like that currently.
This is really a downer, apparently we cannot test CAS login (https://apereo.github.io/cas/6.1.x/index.html) with current implementation of Cypress.
I really wish this was out of the box as well.
I had to authenticate with auth0 and go through our app which would trigger the problem in this issue. I read the auth0 e2e cypress article on how to setup that auth. with cy.request() but they were usinggrant_type: password
which was something I did not wanted to include in my app.I wanted to test the login page as well, so, to bypass this limitation, I used Puppeteer do login and get the cookies created:
const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] }); // Needed to run inside docker const page = await browser.newPage(); await page.goto(URL); await page.type('#username', USERNAME); await page.type('#password', PASSWORD); await page.click('.ulp-button'); const auth0Cookies = await page.cookies(); browser.close();
and then running cypress with:
await cypress.run({ config: { video: false, env: { auth0Cookies } } })
and in the spec file:
Cypress.env('auth0Cookies').forEach(({ name, value, domain, expires, httpOnly, path, secure }) => { cy.setCookie(name, value, { domain, expiry: expires, httpOnly, path, secure, }); }); cy.visit(URL)
And therefore, because the cookies are already set, auth0 login page does not show up and I can go straight to the app page and no two super domains, but still have managed to test the login and the app page
Hope this helps someone :)
This could work, will give it a try, thanks 👍
New to Cypress and this thread. Was just trying out Cypress for my app and got blocked at the very first step. For starters, app is hosted at app_name.azurewebsites.net
and IDP page is hosted at app_name-idp.azurewebsites.net
. The workflow involves redirecting to the idp and then redirecting back to the app. Are these not treated as the same superdomain? i.e azurewebsites.net
? I am getting an error on redirecting back from IDP to the app as it's asking for basic auth credentials again and cy.visit('/')
returns error saying it's a new domain!
We have the same issue - we use worldpay as a payment provider which opens in a new window. Its a dynamic URL and once payment is submitted user gets sent back to their completed cart on the original URL. I have tried so many workarounds to no avail
I am facing the similar issues. I want to validate the third party FAQ URL (another super-domain) which is in the footer of the web application and check certain content of that page. I am able to use cy.request , but can't validate/perform other operation. We have similar use cases across the application. I have tried every recipe from https://github.com/cypress-io/cypress-example-recipes/tree/master/examples/testing-dom__tab-handling-links , But not getting any workaround to resolve this
Recently ran into this issue while trying to get our Cypress tests running locally. The platform we are testing uses UI pages from two different projects, and we regularly navigate between projects in user flows. It only presents a problem when we're running against local and get an error trying to visit the two different localhost ports
One solution I found was setting one project's localhost port as the baseUrl, and overwriting the visit function to intercept any calls to your other port. It's hacky, but gets around the issue
Cypress.Commands.overwrite(
'visit',
(
originalFn,
url,
options
) => {
if(url.includes('localhost:12000')) {
cy.window().then(win => {
return win.open(url, '_self');
});
}
else { return originalFn(url, options); }
});
Recently ran into this issue while trying to get our Cypress tests running locally. The platform we are testing uses UI pages from two different projects, and we regularly navigate between projects in user flows. It only presents a problem when we're running against local and get an error trying to visit the two different localhost ports
One solution I found was setting one project's localhost port as the baseUrl, and overwriting the visit function to intercept any calls to your other port. It's hacky, but gets around the issue
Cypress.Commands.overwrite( 'visit', ( originalFn, url, options ) => { if(url.includes('localhost:12000')) { cy.window().then(win => { return win.open(url, '_self'); }); } else { return originalFn(url, options); } });
worked for me, thanks :1st_place_medal:
I am also facing the same issue where cypress not allowing redirect to external applications. As part of my testing , I need to navigate to different applications from my application ( lets say Bank websites based on selection) and share the transaction details. It is getting redirected back after a few navigation in external website. While going to third party website, there are many details passed over through multiple API calls , so it cannot be done with cy.request. I have tried every recipe from cypress documentation, but nothing worked out.
Is there any solution to tackle this third party redirects?
Hello, I feel with all those comments above. There are clearly enough supports to at least make this a user options for advanced users to bypass. @jennifer-shehane could you please acknowledge @wingsuitist comment as this is not purely an auth issue and maybe let us know if there is any plan regarding this?
@jennifer-shehane and the other great people on the cypress team,
I'm going to hop on aboard this already long comment train and push for this as well. My use case is validating that a node-red server + ui (served on a different port than the main app) can be interacted with and that those interactions will change the behavior of the main app.
I second what @djpasch said above:
My perception of End-2-End testing is covering a complete business flow. Not just testing the front-end of a single application.
Couldn't agree more
Thanks!
I really need this too. There's no way to test modern web apps without this. They all use Oauth 2.0 with PKCE on the client and authorization server-side, so there's no way you can fixture this. In some scenarios you probably can but realistically you can never do this. It's just error prone and not worth it.
So yes, we need this!
We have two scenarios that need two domains in one test. First, the already mentioned Oauth case but we also need to test an end-to-end scenario, not just a one simple site test. Corporate users of our website create 'activities' using a UI in one domain (Domain A) and, once published, the activities are available to applicants to apply for. The applicants login to a quite different domain (Domain B), search for the activities and apply for those of interest. A view of applicants for each activity is then available back in Domain A to the creators. We want to test the whole round trip. After advocating for Cypress it is proving a bit embarrassing that such a scenario is not possible.
Seems like use cases for multiple domains are piling up, I want to add one more common scenario to that.
We have two applications, first one is client-facing and second is a backoffice management-kind-of website.
We wanted to test full scenario which goes like this:
Using API instead of web crawling seems to miss the point here a little bit, we want to test end user expierience (great for regression testing after new release)
Also its needed for online payments, e.g making e2e purchase via paypal which includes redirects ofc and its not allowed atm
I wonder why it is still not implemented after 3 years of discussion? This is a deal-breaker when choosing between testing frameworks.
I know cypress THINKS it's got all scenarios covered with documentation, but as anyone can see after going through this topic this is simply not true.
I can't visit a local file which I created after I've been my staging application, because I get cross origin error.
Our team is currently working on crafting a better experience around testing authentication, which is a large use case covered in this issue. We know that many people are dissatisfied with the current approach of testing authentication programmatically and we want to address those concerns.
There are multiple phases to addressing the core of the issues with testing authentication that we'll be rolling out piece by piece. We do read everyone's comments and use them to evaluate how to approach the work ahead of us.
Thank you @jennifer-shehane, that is indeed our use case, is there an update/timeline on this?
Would it be possible to point to the issue/branch where this is being reviewed, maybe we can get some help on the feature development and fast-forward the release :)
I also have a use case. Two companies joined hands in The Netherlands 10 years ago. Due to multiple issues, both being very strong brands, they have two different domains (A.nl) and (B.nl). Authentication for both is handled on a service that runs on domain A.nl. So if a user wants to login to B.nl, their authentication is handled by A.nl, hence a visit to B.nl first takes you to A.nl which is now set as the superdomain. I now cannot navigate to and hence automate any test case fo domain B.nl.
I will have to use protractor now !!!! 🤦 🤦
Before you ask why protractor, the UI for B.nl is in angular and existing E2E tests are all in protractor / typeScript
I would love to see this implemented, until then we are stuck with selenium. Here's the use-case:
Our team develops a client side SDK which our customers integrate on their own site. We also have a dashboard where our customers can log in, configure their integration and view activity.
We need the ability to run tests which visit our dashboard and play with some settings, then switch to an example customer site which uses our SDK where we perform some actions, then switch back to the dashboard to check that the actions have been logged correctly.
@StickyCube A lot of people have requested this feature for over 3 years now and it seems that Cypress isn't the right tool for the job in some cases until this is implemented. I agree that it will be a good addition to Cypress the decision to not implement is very opinionated which is wrong IMO. The reasoning is to test each layer separately. So in your example, it will be suggested that you utilise cy.request
to visit your dashboard as a first step to set up the settings like you want, then again using cypress requests to set up the state of your client site using the SDK and as a last step you then visit your dashboard in a browser to check that everything is logged as expected.
I know it is a very opinionated way of telling someone how to test but that seems to be the crux of the issue here. I think this should be implemented and people should be able to decide whether they want to utilise APIs to drive tests faster or not. Pushing for best practices is great but I think users of the tool should be able to decide how they use the tool rather than forcing them to do so.
I redirect users to a payment processor at the end of a checkout.
I want my cypress tests to follow my process up through that (it'll be their sandbox instance). I want to check they're always forwarded to the right URL, and that the price / description matches with what they'd see there, as part of my CI.
Same here. Our flow goes through payment process which happens on our payment provider domain but the page is designed and maintained by us. We show a lot of additional purchase related information there and it's important for us to check how it looks and how it works. After payment users are redirected to the page that shows them what happens next with their purchase with additional options to choose.
As a result we have 3 different domains and mocking/ignoring any one of them does not look like end2end testing to us because we cannot be sure that we provide smooth and reliable flow for our customers.
This is the only blocker we have while having full paid version.
Just to make sure I understand this, cuz I am facing some issues and this is possibly because of this scenario.
I faced the CORS problem before, when setting my baseUrl to something like "localhost:4000" and the api (auth and everything else) was at "localhost:3000". By just setting "chromeWebSecurity":false in cypress.json that would work
Now I am working on a project where I have my app and the api running on two different docker containers exposed locally in localhost with different porst... While I was running Cypress locally, I would have the exact same scanerio (both on localhost but different port).
Now I am trying to run Cypress dockerized, and for that I had to set my baseUrl to "http://webapp" and the apiBaseUrl at "http://api" (those are the app and api url's exposed by docker for each container through the docker network created for them)
Result? I can authenticate to the app because I call the auth api with a request, and fill in the localStorage with the token received... but when the app makes a request to the api to fetch data to fill in a grid for example, nothing comes back.
Would this be the scenario mentioned in this thread @jennifer-shehane ?
Thanks
Are there ANY plans for cypress to allow it?
My company went in such a direction that we may eventually give up on cypress because of this.
@Jacek-fstack Did you try the workaround provided here? https://github.com/cypress-io/cypress/issues/944#issuecomment-444312914 We've been using it since we started migrating to Cypress a couple months ago and it has been working fine.
@rubiii hey, thanks for pinging, but nope, still getting chromerror and test stops
nice workaround:
Cypress.Commands.add('forceVisit', url => {
cy.window().then(win => {
return win.open(url, '_self');
});
});
@dudziakm I tried this, and it didn't work
I understand why Cypress team might consider this an anti-pattern, etc. BUT there are legitimate cases where this is useful.
In my case I am working on a web extension that works for a 3rd party website. So I have neither control over the website or the login flow for that website. So in order to test the extension, I MUST be able to hook into the login flow mid-way of a running test.
It's been 3 years. I am SURE cypress team is not going to work on it. Otherwise, it would be done already. This is a dead end.
You should open an issue and tell us what you’re trying to do!
I'm trying to use Cypress as an end-to-end testing framework. I'd like Cypress to go to backend, do stuff there, then go to frontend and check if stuff works. And of course I'd like to do it in the same test.
@Leksat Haha that's an awesome comment. You just bashed Cypress :D Cypress - the end-to-end testing framework which can't end-to-end test! :+1:
Well it would be cool if the team came back with an official response to this. If this is a technical issue I'm sure the community could help out.
So far it seems that Cypress team thinks this an anti-pattern. But as demonstrated by many people here, and as any experienced developer knows, there are always going to be cases that need adhoc solutions. And in a testing framework you expect flexibility depending on what you're testing.
I switched to Playwright. It does this all. But I've just started, so can't tell which one is better.
@Pithikos it's on the roadmap as work in progress now at least :) https://docs.cypress.io/guides/references/roadmap.html#Upcoming-features
Most helpful comment
Here's a hacky workaround: