It happens frequently that automation testing requires to be performed in multiple origins, i.e. when the base configured url is being replaced by another one during test execution.
Good examples are log in/sign up forms via social networks which invoke opening a pop-up window with a domain different from the base url, or third-party payment services which provide website owner with the mechanism of purchasing subscriptions.
describe('template spec', () => {
it('navigates', () => {
const url = Cypress.config('baseUrl');
cy.visit(url);
cy.visit('www.instagram.com');
//This will get a cross-origin error
cy.contains('Allow essential and optional cookies').click();
});
});
const { defineConfig } = require('cypress');
module.exports = defineConfig({
e2e: {
baseUrl: 'https://www.blender.org/',
specPattern: 'cypress/e2e/**',
},
});
In the following case if test attempts to get access to a new domain, Cypress will throw a cross-origin error:
As of Cypress v12.0.0, Cypress officially provides its users with the opportunity to run multiple domains in one test with cy.origin() and manage pop-up windows.
cy.origin(url, callbackFn)
cy.origin(url, options, callbackFn)
url:
This can be any string of valid link or pre-defined global variable (e.g. from cypress.config.js)
It overrides the baseUrl
configured in global configuration while inside the callback. So cy.visit()
and cy.request()
will use this URL as a prefix, not the configured baseUrl
.
options:
This is an optional argument which can be passed to cy.origin()
function as a simple Javascript object and deserialized in the new origin. These can be: username, password for logging, payments details and so on.
callbackFn:
This is a regular function which will be executed in the new origin. All elements located on the page of initial origin will not be accessible for Cypress within this callback.
baseUrl
is set to ‘https://www.blender.org/’
which means that originally all the tests will visit this particular link.
To avoid repeating call cy.visit(baseUrl)
, let’s move this code to beforeEach
hook:
beforeEach(() => {
const url = Cypress.config('baseUrl');
cy.visit(url) // Or url can be hardcoded if needed
})
This code will run before each test scenario.
At the bottom of the home page https://www.blender.org/ there is a link to Blender’s official Instagram page.
Based on described introduction above, let’s use cy.origin() to switch from Blender home page to their Instagram account and validate cookies acceptance message.
describe('template spec', () => {
it('passes', () => {
cy.window().then((win) => {
cy.stub(win, 'open').as('Open');
});
//Essential only if beforeEach hook is not set
const url = Cypress.config('baseUrl');
cy.visit(url);
//
cy.window().scrollTo('bottom');
var instaUrlString;
cy.get('.social-icons__instagram')
.invoke('attr', 'href')
.then(($instaUrl) => {
instaUrlString = $instaUrl.toString();
const updatedInstaUrl = instaUrlString.replace(
'instagram.com',
'www.instagram.com'
);
cy.origin(
updatedInstaUrl,
{ args: updatedInstaUrl },
(updatedInstaUrl) => {
cy.visit(updatedInstaUrl);
cy.contains('Allow essential and optional cookies').click();
}
);
});
cy.visit(url);
});
});
Well done! We’ve got expected behavior: Cypress visits Blender’s home page, then scrolls page to the bottom, gets href
property from Instagram link and then, converting it to an appropriate link starting from ‘www‘, passes it to cy.origin().
Callback function demonstrates that the further assertions are applied to the new origin.
What is more, opening a new origin window is stubbed by using cy.stub()
function which makes it possible to get rid of unnecessary opened windows.
The same code is applicable for BDD (Behavior-driven development) testing with the only difference that the code from inside of it()
script should be defined within a definite step:
When('I change the origin of my test configuration', () => {
cy.window().then((win) => {
cy.stub(win, 'open').as('Open');
});
//Essential only if beforeEach hook is not set
const url = Cypress.config('baseUrl');
cy.visit(url);
//
cy.window().scrollTo('bottom');
var instaUrlString;
cy.get('.social-icons__instagram')
.invoke('attr', 'href')
.then(($instaUrl) => {
instaUrlString = $instaUrl.toString();
const updatedInstaUrl = instaUrlString.replace(
'instagram.com',
'www.instagram.com'
);
cy.origin(
updatedInstaUrl,
{ args: updatedInstaUrl },
(updatedInstaUrl) => {
cy.visit(updatedInstaUrl);
cy.contains('Allow essential and optional cookies').click();
}
);
});
cy.visit(url);
});
Feature file:
Feature: Cross-origin test
Scenario: As a user, I can use different origins in one test
When I change the origin of my test configuration
And I visit Base url
Here is the link to project illustrating multi-domain testing with Cypress: https://github.com/vamelchenia/multi-domain-cypress