Cypress cross-origin testing

Cypress cross-origin testing

How to handle multiple origins/domains in a single test.

One of the things that are not that easy to understand is how cy.origin works. How to test with Cypress a flow that implies multiple domains. I have a small Romanian QA Community in discord where we debate various topics, and one of them is the use of cy.origin from Cypress.

What exactly is the most common errors encountered in Cypress when dealing with multiple domains:

cy.origin() requires the first argument to be a different domain than top
When redirected to third party payment website Cypress does not find elements

or

The test scenario includes navigating to a different domain but my Cypress cy.get does not find any elements


Handling multiple origins/domains in Cypress tests can be a bit tricky, but let's break it down in a simpler way. Unlike Selenium-based frameworks that use a separate driver to interact with the browser, in Cypress framework everything works without the "middle-man". When you run a test in Cypress, your web app is rendered inside a browser, and Cypress operates within that browser.

Now, imagine your test scenario involves navigating from one domain to another, like from martioli.com to github.com. Since Cypress runs inside the browser, you might encounter Cross-Origin Resource Sharing (CORS) issues. To overcome this, Cypress uses a clever trick under the hood. It creates an iframe within the initial origin (martioli.com) when you load a different origin/domain (github.com).

To understand this concept better, think of it as a smaller square (github.com) inside a bigger square (martioli.com).

Now, let's take a look at some code examples to illustrate this further. In the following example, we visit martioli.com, assert something, and then click on the GitHub icon, which redirects us to github.com:

But once you try at line 7 to get an element from the new page, the test will fail

Cypress will actually help you out here on how to fix this, but lets try to understand what it says.

The first argument of cy.origin is the new origin. Whether you end up on a specific subdomain or endpoint of github.com, the origin remains the same (github.com). Inside the cy.origin callback function, you can perform tasks like fetching elements, typing, and making assertions, but only related to the new domain/origin.

In some cases, you might return to the initial origin from the nested origin. You can handle this by continuing your test outside of the cy.origin block. Here's an example:

You now continue from line 12.


But what if you get redirected again within github.com? Well, it follows the same logic—a square inside a square, nested.
I will try to explain with this drawing below

I think this is a bit more clear, no?

What downsides cy.origin has? Here are a few I have encountered:

  1. Inside the cy.origin code block you can pass only serialized data.

What do I mean? See on the picture above json data. In order for code to run inside the cy.origin block you either hardcode it or transfer it inside as json like data.

Not everybody writes their tests with the selectors hardcoded in the test as a string, that is not a good practice. So, they write the selectors separately in a file (or part of POM structure), and then import that into the initial test. Find here an example of how I take care of my selectors in my cypress framework.
OK, then how this transfer is done?

You first need to put a second argument, an object with property args that has value(s) of what you want to be passed in. See below an example. I have also updated my code to include imported selectors.

Lets briefly walk thru line 11.

First argument is the origin

Second one is an object that has a property called args (its important for you to name it args) and that property has a value of GITHUB . As you can see at the top of the code snippet that GITHUB is a variable that contains our selectors from the github page

Then third argument is the call back function. I put GITHUB again (you can name it anything else it does not matter but I keep the same name to be easy readable)

Why should I care that data is passed from one origin to another serialized? Because if your selectors or anything else you want to transfer, may contain a function, then you will get a very hard to trace-back error. So, remember, the selectors you pass in for cy.origin should be serializable, in other words able to be converted to json format.

2. Also if the new origin has an iframe itself then this helper method provided by Cypress will only work if you declare it inside the cy.origin block. This is also related to downside #1 where I mentioned that only serialized data makes it inside.


Hit the clap button if you found this useful. Or even buy me a coffee if you want to motivate me even more.

Which one is better? Selenium with POM or Cypress without POM
One of the best things about trying various frameworks and designs is that you have the possibility to directly see how it “feels” and have a better understanding of what suits best for your present or future projects. I have done the Different Angle Challenge and I have created the
Organize your Selectors in Automation Frameworks with Cypress
When it comes to software testing frameworks, selectors play a crucial role in making the code reusable, modular, and efficient. In the past, I used Object-Oriented Programming (OOP) and Page Object Model (POM) with Python and Selenium. Back then it made sense to keep selectors as part of each page