- Assume working on windows
- Install node.js
- Install git and git bash
- Install VS code
- git, npm knowledges
- Create Cypress-automation-framework folder
- Open VS code on this folder
- Open git bash terminal on VS code
- run
npm init
- follow the steps and initialize the fields as you want. For instance:
- follow the steps and initialize the fields as you want. For instance:
- run
{
"name": "cypress-automation-framework",
"version": "1.0.0",
"description": "Cypress Automation Framework",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Nicolas Parisse",
"license": "ISC"
}
- Install cypress:
npm install --save-dev [email protected]
- Create .gitignore file and remove node_modules
- Open cypress for the first time through git bash:
./node_modules/.bin/cypress open
- Select E2E Testing
- Choose Chrome browser
- Select Scaffold example specs
cypress folder must be generated in your cypress-automation-framework folder - Open cypress again and here are the sample tests!
Mocha comes with two function describe()
and it()
. It uses those function to regroup the tests.
describe()
takes two arguments: the name of the test and the function to apply the test. It is basically used to regroup the test.
it()
function must define each individual test inside the describe block and also take two argument: the name of the this individual test should do and the function with all the action to perform it.
This extension will fasten your code writting with usefull autocomplete feature:
Just to get wonderfull icons like below:
You can get et selector directly from cypress after running a test:
- Select a step in step body to display the iframe window you are testing
- Click on the target icon
- Click on the inspect icon
- Select the expected element in the iframe window
- Get the selector
Chrome dev tools has a feature in itself which propose to get css selectors of elements from the html file.
- Open dev tools (press F12 on chrome tab)
- Select elements tab
- Click on the inspect icon
- Select the expected element
- Right-click on the expected element > copy > css selector
It is way recommended to create a specific attribute on the elements during the development. For instance data-cy
. It will avoid any issue when a feature changes the css elements or its position in the html page.
You can check this topic to be convinced.
Ranorex Selocity can be usefull to find the simpliest css selector. It can also be used to find element through xpath.
The assertions on Cypress are handled through the chai library.
Chai has several interfaces that allow the developer to choose the most comfortable. The chain-capable BDD styles provide an expressive language & readable style, while the TDD assert style provides a more classical feel.
You can visit the chai website for more details.
In case of invalid assertion, cypress presents the reason why it did not workd and also point out specifically where the invalid assertion is located in the code.
- Go to your git bash terminal
- Run this command:
./node_modules/.bin/cypress run
- the tests start to run:
This window provides the configuration of the test environment such as the web browser where the tests are running, the cypress version, etc... - the test result for one test:
- the tests end:
The above command executes the tests headlessly, you won't see them running. You can modify this behaviour by adding the--headed
option:./node_modules/.bin/cypress run --headed
All the options available are listed on cypress website documentation here
- the tests start to run:
Cypress framework is asynchone. So when some script instruction are added in a test while not being from the cy framework it leads to some unexpected behaviour.
For instance in the below code:
describe("Test Contact Us form via Automation Test Store", () => {
it.only("Should be able to submit a successful submission via contact us form", () => {
cy.visit("https://automationteststore.com/");
cy.xpath('//a[contains(@href, "contact") and starts-with(text(), "Con")]').click();
cy.get('#ContactUsFrm_first_name').type("Jean");
cy.get('#ContactUsFrm_email').type("[email protected]");
cy.get('#ContactUsFrm_email').should('have.attr', 'name', 'email')
cy.get('#ContactUsFrm_enquiry').type("Do you provide international shipping?");
cy.get('button[title="Submit"]').click();
cy.get('.mb40 > :nth-child(3)').should('have.text', "Your enquiry has been successfully sent to the store owner!")
console.log("Test has been completed!")
})
})
The console.log instruction will most likely happen before all the cy instructions.
As Console.log can't be used, you must use Cypress log command:
cy.log("Test has been completed!")
It is actually possible to handle non cypress command by using promises:
describe('Inspect Automation Test Store items using chain of commands', () => {
it('Click on the first item using item text', () => {
cy.visit("https://automationteststore.com/")
cy.get('.prdocutname').contains('Skinsheen Bronzer Stick').click().then(function(itemHeaderText){
console.log('Selected the following item: ' + itemHeaderText.text())
})
})
})
In the above code sample, the console.log command is handled correctly as it is inserted in the callback function of then method.
Variables should never used to perform cy commands as the order of action can't be certain. Instance of a bad practice:
const makeupLink = cy.get("a[href*='product/category&path=']").contains('Makeup')
const skincareLink = cy.get("a[href*='product/category&path=']").contains('Skincare')
skincareLink.click()
makeupLink.click()
A variable should not be used to perform cy commands, when it is used it should only to get information. It must also be used through a promise to ensure the element is still accessible. For instance:
cy.get('h1 .maintext').then(($headerText) => {
const headerText = $headerText.text()
cy.log("Found header text: " + headerText)
expect(headerText).is.eq('Makeup')
})
Invoke cypress method will invoke the JQuery method given as parameter:
cy.get('.modal').invoke('show')
BeforeEach function in cypress is performed before any individual test inside a describe function. In this BeforeEach function, you can define aliases which will then be accessible in each individual tests:
beforeEach(() => {
cy.visit("https://automationteststore.com/")
cy.get("a[href*='product/category&path=']").contains('Hair Care').click()
cy.get("#grid").click()
cy.get(".thumbnails.grid .thumbnail").as("productThumbnailGrid")
})
it('Validate product thumbnail count', () => {
cy.get('@productThumbnailGrid').should('have.length', 4)
})
Aliases are not necessarly inserted in BeforeEach function.
Cypress prevent access to a page from a different domain in a single test. it is not possible to visit site of different domains. For instance, both test codes won't work:
describe("Cypress web security", () => {
it("Validate visiting two different domains", () => {
cy.visit("https://www.webdriveruniversity.com/")
cy.visit("https://automationteststore.com/")
});
it.only("validate visiting two different domains via user action", () => {
cy.visit("https://www.webdriveruniversity.com/")
cy.get("#automation-test-store").invoke("removeAttr", "target").click() // click on a button which redirect to https://automationteststore.com/
cy.contains('#ContactUsFrm', 'Contact Us Form').find('#field_11').should('contain', 'First name')
});
})
To prevent a button opening a new tab when clicking on it:
cy.get("#contact-us").invoke('removeAttr', 'target').click()
When a button direct to a new page, we might want to go back to the previous page as would do the previous button of the browser:
cy.go('back')
cy.go('forward')
reload with cache: cy.reload()
reload without cache: cy.reload(true)
For further details upon events see the Cypress documentation is here.
Cypress automatically accept alert event. It still possible to handle them. For instance, we can assert it contains a certain string:
cy.on('window:alert', (str) => {
expect(str).to.equal('I am an alert box!')
})
it("Validate Js confirm box works when clicking cancel", () => {
cy.visit("https://www.webdriveruniversity.com")
cy.get("#popup-alerts").invoke('removeAttr', 'target').click()
cy.get("#button4").click()
cy.on('window:confirm', (str) => {
return false; // Cancel the confirm box
})
cy.get("#confirm-alert-text").contains('You pressed Cancel!')
});
The Cypress log would result as below:
By default, Cypress does not handle iframes.
For instance, you can't select any element in an iframe from Cypress window:
Cypress would only provide you the access to the iframe element.
In order to bypass this, it is possible to use a promise to handle the content of the iframe, grab the body of the iframe and wrap it in the cy.wrap method to perform cy press commands on it:
cy.get('#frame').then($iframe => {
const body = $iframe.contents().find('body')
cy.wrap(body).as('iframe')
})
This bypass will work as Cypress will then be able to use the iframe's body as a usual html element. Still, the snapshot won't display the content of the iframe while performing action on it. So when a test fail on an iframe it can't be handled easily.
Below, the 'blank' image while the test still passed:
the issue can be found on github here and seem not to be taken seriously by Cypress.
cy.get('[type="checkbox"]').check() // Check checkbox element
cy.get('[type="radio"]').first().check() // Check first radio element
below checkboxes:
<form>
<input type="checkbox" id="subscribe" value="subscribe" />
<label for="subscribe">Subscribe to newsletter?</label>
<input type="checkbox" id="acceptTerms" value="accept" />
<label for="acceptTerms">Accept terms and conditions.</label>
</form>
Can be checked by value as below:
cy.get('form input').check(['subscribe', 'accept'])
cy.get('#radio-buttons-selected-disabled input[type="radio"][value="cabbage"]').should('be.disabled')
They can be selected through their value or their visible content through the same method. Let take this html element for instance:
<select class="dropdown-menu-lists" id="dropdowm-menu-1">
<option value="java">JAVA</option>
<option value="c#">C#</option>
<option value="valuepython">Python</option>
<option value="sql">SQL</option>
</select>
cy.get('#dropdowm-menu-1').select('valuepython')
cy.get('#dropdowm-menu-1').select('Python')
cy.get('#dropdowm-menu-2').select('java').should('have.value', 'testng')
- insert a in the field
- select Avacado
it('selects the Avacado option', () => {
cy.get('#myInput').type('A')
cy.get('#myInputautocomplete-list > div').each(($el) => {
if($el.text() === 'Avacado') {
cy.wrap($el).click() // or use directly jquery => $el.trigger('click')
}
})
cy.get('#submit-button').click()
});
the cypress documentation on mouse events is here
cy.get('#actions').scrollIntoView()
cy.get('#idElement').dblclick()
cy.get('#idElement').click()
Sometimes, an element switches from display: none
to display: block
only according to css pseudo class of another element.
For instance:
html:
<div class=toBeHovered>
<div class=hiddenByDefault>
Hello !
</div>
</div>
css:
.hiddenByDefault {
display: none;
}
toBeHovered:hover .hiddenByDefault {
display: block;
}
In this case, the usual cy.trigger('mouseover')
won't work as it is not a real mouseover but a trigger of the js mouseover event.
Thanks to Chrome Devtools Protocol you can fix it for any chromium-based browser by installing a cypress plugin:
npm install cypress-real-events
it won't work for firefox test !
Then import it on the e2e.js file:
import "cypress-real-events";
this feature should be used the less possible as not a built-in cypress solution, there won't be snashots on the cypress UI. In the image below you can see the assertion is validated while the snapshot does not display the element:
Another workaround is to force the action even if the element is hidden:
cy.get(HiddenElement).click({force:true})
it is possible to traverse the DOM elements:
- children()
- closest()
- eq()
- filter()
- find()
- first()
- last()
- nextAll()
- nextUntil()
- not()
- parent()
- parents()
- prev()
- prevAll()
- prevUntil()
- siblings()
As Cypress is asynchronous, loops must be prohibited as any cypress command inside might not be executed in the expected order.
function goToYearsPanel() {
goToMonthsPanel()
cy.get('@monthsPanelHeader').click()
cy.get('@yearsPanel').should('be.visible').then(() => {
do
{
IsCorrectYearPanel = true
cy.get('@yearsPanel').first().then($year => {
if(futureYear < Number($year.text()))
{
cy.log("Selecting previous years panel: first year " + $year.text() + " > " + futureYear)
IsCorrectYearPanel = false
selectPreviousYearsPanel()
}
})
cy.get('@yearsPanel').last().then($year => {
if(futureYear > Number($year.text()))
{
cy.log("Selecting next years panel: last year " + $year.text() + " < " + futureYear)
IsCorrectYearPanel = false
selectNextYearsPanel()
}
})
} while (!IsCorrectYearPanel);
})
}
The above code won't work as expected. IsCorrectYearPanel would be check true and so go out of the loop before it is set false in one of the then()
promise.
The use of recursive functions must be chosen instead:
function goToYearsPanel() {
goToMonthsPanel()
cy.get('@monthsPanelHeader').click()
cy.get('@yearsPanel').should('be.visible').then(() => {
BrowseToCorrectYearsPanel()
})
}
function BrowseToCorrectYearsPanel()
{
cy.get('@yearsPanel').first().then($year => {
if(futureYear < Number($year.text()))
{
cy.log("Selecting previous years panel: first year " + $year.text() + " > " + futureYear)
selectPreviousYearsPanel()
BrowseToCorrectYearsPanel()
}
})
cy.get('@yearsPanel').last().then($year => {
if(futureYear > Number($year.text()))
{
cy.log("Selecting next years panel: last year " + $year.text() + " < " + futureYear)
selectNextYearsPanel()
BrowseToCorrectYearsPanel()
}
})
}
<form>
<h2>Please choose a file to upload:</h2>
<input type="file" id="myFile" name="filename">
<input type="submit" id="submit-button" onclick="fileSubmitted()">
</form>
it("uploads a file", () => {
cy.get("#myFile").selectFile('cypress/fixtures/laptop.png')
cy.get("#submit-button").click()
//modify the alert event triggered on upload to validate the upload
cy.on('window:alert', (str) => {
expect(str).to.equal('Your file has now been uploaded!')
})
});
- before(): runs once before all tests in the block
- beforeEach(): runs before each test in the block
- afterEach(): runs after each test in the block
- after(): runs once after all tests in the block
In the below cypress hooks test, two individual tests are running with all above hooks defined with some logs:
describe('hooks', () => {
before(() => {
cy.log('runs once before all tests in the block')
});
after(() => {
cy.log('runs once after all tests in the block')
});
beforeEach(() => {
cy.log('runs before each test in the block')
});
afterEach(() => {
cy.log('runs after each test in the block')
});
it('Exemple test 1', () => {
cy.log('Exemple test 1')
});
it('Exemple test 2', () => {
cy.log('Exemple test 2')
});
});
It results as expected in the cypress log panel:
Cypress can play with external data through the fixtures()
method. This can be used to split the test process and the data which drives the test.
For instance, when testing the submission of a form with multiple input from the user. It is better to split the user inputs to the process consisting in typing all the inputs and submit the form.
it("Should be able to submit a successful submission via contact us form", () => {
cy.get('[name="first_name"]').type("Jean")
cy.get('[name="last_name"]').type("Valjean")
cy.get('[name="email"]').type("[email protected]")
cy.get('textarea.feedback-input').type("I am a character from Les Miserables")
cy.get('[type="submit"]').click()
cy.get('h1').should('have.text','Thank You for your Message!')
});
Let create a file in cypress/fixtures folder called example.json:
{
"name": "Jean",
"last_name": "Valjean",
"email": "[email protected]",
"description": "I am a character from Les Miserables"
}
before(() => {
cy.fixture('example').then(function(data){
globalThis.data = data
})
});
it("Should be able to submit a successful submission via contact us form", () => {
cy.get('[name="first_name"]').type(data.name)
cy.get('[name="last_name"]').type(data.last_name)
cy.get('[name="email"]').type(data.email)
cy.get('textarea.feedback-input').type(data.description)
cy.get('[type="submit"]').click()
cy.get('h1').should('have.text',data.messageValidation)
});
Now, the data are seperated from the process. It can be updated without changing the test.
As you might noticed: the data is added through the
before()
hook. It is then added for all theit()
individual test of adescribe()
global test. As you might noticed: the extension of example.json file wasn't provided nor the fullpath. By default, cypress look into its cypress/fixtures folder. The extension file can be ommited as long as it follows the cypress fixture file's extension expected order.
It is recommended to split the data in as many file as there are tests, but also split them according to their meaning. In the below example, two json files were created:
- To store user input
- To store message returned by the application used to validate the test
The fixtures' reference can be simplified through aliases:
beforeEach(() => {
cy.fixture('userDetails').as('user')
cy.fixture('enquiryValidation').as('enquiryValidation')
cy.fixture('log').as('log')
});
And then called from those aliases:
it.only("Should be able to submit a successful submission via contact us form", () => {
cy.get('@user').then((user) => {
cy.get('#ContactUsFrm_first_name').type(user.first_name);
cy.get('#ContactUsFrm_email').type(user.email);
cy.get('#ContactUsFrm_enquiry').type(user.enquiry);
})
cy.get('#ContactUsFrm_email').should('have.attr', 'name', 'email')
cy.get('button[title="Submit"]').click();
cy.get('@enquiryValidation').then((expect) => {
cy.get('.mb40 > :nth-child(3)').should('have.text', expect.enquiryValidated)
})
cy.get('@log').then((log) => {
cy.log(log.itComplete)
})
})
fixtures were added in the
beforeEach()
hook instead ofbefore()
. An alias gets removed after the end of eachit()
test !
Cypress allows to custom ower own cypress command or even overwrite existing ones. These custom or overwritten commands are usually setup in the cypress/support/command.js file. Any custom commands can be added in another js file as long as this file is imported in cypress/support/e2e.js file.
Cypress.Commands.add('login', (email, pw) => {})
cy.login('email', 'password')
Cypress.Commands.overwrite('visit', (orig, url, options) => {})
Custom commands should not be used everywhere. Any custom command is available all over the automated tests. It is prefered to use page object modelling to restrict the use of method to a specific page.
It consists in isolating the tests from the pages/routes. This way you make a dissociation between a test and a page/route. Therefore, a test can handle more than a page/route and a page/route can be used in multiple tests without repeating the code.
Let consider the previous login custom command can only be used in a login page. Then it is prefered to create a cypress/support/pageObjects/yourWebsite/loginPage.js file:
class loginPage_PO {
login(email, pw) {
//do your cypress commands to login
}
}
export default loginPage_PO;
_PO for PageObject
Then in your test file you can import the file and use the class:
import loginPage_PO from "../../support/pageObjects/yourWebsite/loginPage";
Describe("how login page should behave", () => {
it("should be able to login", () => {
const loginPage_PO = new loginPage_PO()
loginPage_PO.login('emails','pwd')
})
})
Any required data for a PO to work must be initialized during the construction of the object. It prevents a test to call this class and forget to initialize its datas. For instance in the test:
import My_PO from "../../support/pageObjects/website_domain/my_PO";
/// <reference types="cypress" />
describe("what the test do", () => {
// define at the root of the test to be available amongst all hooks.
let my_PO
before(() => {
my_PO = new My_PO(); // initialized here to be able to apply cypress command in the constructor
});
beforeEach(function () {
my_PO.AccessHomePage();
my_PO.ClickOnLink();
})
it("must validate a specific test", () => {
my_PO.applyMethod();
});
});
in the PO class:
class My_PO {
constructor() {
this.setProductNames();
}
setProductNames() {
// initialize data from cypress/fixtures/products.json file
cy.fixture("products").then((data) => {
this.products = data;
});
}
applyMethod() {
this.products.productName.forEach(function (element) {
// do something
})
}
}
export default My_PO;
Cypress' configurations are stored in cypress.config.js.
You can see the current configuration setup directly from Settings menu. Also, clicking on the edit button (see below image) would redirect you to the cypress.config.js
see cypress documentation for more details upon configuration.
cy.visit(Cypress.env('webdriveruniversityBaseUrl', { timeout: 60000 }));
Describe('my test', () => {
Cypress.config('defaultCommandTimeout', 20000)
it('do something', () => {
//something to do
})
})
You can force a pause after a specific cypress command and even inside the same instruction:
cy.title().pause().should('include', 'something'')
When adding a pause inside the same isntruction, it allows to go to the next cypress command in the instruction without continuing the hole test:
usefull to debug a test !
Used to wait for an actions or a certain time.
cy.wait(3000) // wait 3000ms
cy.wait('@getProfile') // wait for alias to be available
It is not recommended to add wait as it can explode the time for all the test's run.
As a synchronous command, it must be declared in the then() promise to ensure it applies at the expected location in the test workflow. For instance:
cy.get("cssSelector").each(($el) => {
//do something
}).then(() => {
debugger // will pause in the debugger dev tool once each selected elements are treated.
})
See the configuration's details here
Videos and screenshots are made only when executing cypress with the cypress run
command line.
The report indicate where the screenshot of the failed test is stored:
It is also possible to take a screenshot at a specific moment from cypress command:
cy.screenshot("screenshot title")
when no title given, it is made up from
describe()
andit()
names.
Screenshots and videos folders can be removed before the run of cypress through a configuration key: trashAssetsBeforeRuns: true
.
To validate multiplaform use cases, it is necessary to test different size (smartphone, tablet, surface, laptop screen, desktop screen, etc...).
Details on how to configure the cy.viewport()
command here.
For instance:
cy.viewport(1024, 768)
cy.viewport('iphone-6')
default value is 1000px width per 660px height.
The viewport size is displayed on the cypress interface:
In cypress.config.js:
e2e: {
viewportHeight: 1080,
viewportWidth: 1920
}
When the cypress interface can't display the 1:1 size it shows a zoom out snapshot of the website:
Cypress clears all the cookies when it starts to run. Still, it might be requeste on a specif test amongst all the test run to clear it. The localStorage is also cleared before each test. more details:
When running the tests, a specific test, recording on cypress cloud or jus topening cypress interface we had to apply one of the below command lines:
./node_modules/cypress/bin/cypress open
./node_modules/cypress/bin/cypress run --spec cypress/e2e/webdriver-uni/checkboxes.test.js
./node_modules/cypress/bin/cypress run --spec cypress/e2e/webdriver-uni/checkboxes.test.js
./node_modules/cypress/bin/cypress run --spec cypress/e2e/webdriver-uni/checkboxes.test.js --record --key
with npx, it just simplify them:
npx cypress open
npx cypress run --spec cypress/e2e/webdriver-uni/checkboxes.test.js
npx cypress run --spec cypress/e2e/webdriver-uni/checkboxes.test.js --record --key
npm install npx
In package.json file, it is possible to setup scripts to apply directives such as:
"scripts": {
"triggerAllTests-headless": "npx cypress run",
"triggerAllTests-headed": "npx cypress run --headed"
}
Which can then be executed by running them on npm command line:
npm run triggerAllTests-headless
npm install --save-dev cypress-multi-reporters mocha-junit-reporter
for more details, see the report page on cypress here to setup the reporte. It will provides xml file for each test which can then be used in CI pipelines. For instance of what these xml file can contain:
<?xml version="1.0" encoding="UTF-8"?>
<testsuites name="Mocha Tests" time="2.578" tests="2" failures="0">
<testsuite name="Root Suite" timestamp="2024-03-01T16:29:11" tests="0" file="cypress\e2e\webdriver-uni\data-tables.test.js" time="0.000" failures="0">
</testsuite>
<testsuite name="handling data via webdriveruni" timestamp="2024-03-01T16:29:11" tests="2" time="2.563" failures="0">
<testcase name="handling data via webdriveruni calculates and asserts the total age of all users" time="0.729" classname="calculates and asserts the total age of all users">
</testcase>
<testcase name="handling data via webdriveruni asserts the age of a user in the table" time="0.274" classname="asserts the age of a user in the table">
</testcase>
</testsuite>
</testsuites>
to merge the xml files:
npx junit-merge -d cypress/results/junit -o cypress/results/junit/results.xml
Same thing but it reports in json file and can generate automaticallly a html file from them.
To install the plugin:
npm install --save-dev mochawesome mochawesome-merge mochawesome-report-generator
reported-config.json file:
{
"reporterEnabled": "spec, cypress-multi-reporters",
"mochaJunitReporterReporterOptions": {
"mochaFile": "cypress/results/junit/results-[hash].xml"
},
"reporterOptions": {
"reporterEnabled": "mochawesome",
"mochawesomeReporterOptions": {
"reportDir": "cypress/results/mochawesome",
"quite": true,
"overwrite": false,
"html": false,
"json": true
}
}
}
cypress.config.js:
e2e: {
reporter: 'cypress-multi-reporters',
reporterOptions: {
configFile: 'reporter-config.json',
}
}
Then executing the npx cypress run
will also generate the json files to the directory given in reported-config.json file
to merge the json generated and generate the html report:
npx mochawesome-merge cypress/results/mochawesome/*.json > mochawesome.json && npx marge mochawesome.json
The html report is generated at mochawesome-report/assets/mochawesome.html and look like this:
const fs = require('fs-extra');
const path = require('path');
function getConfigurationByFile(file) {
const pathToConfigFile = path.resolve('config', `${file}.json`)
if(!fs.existsSync(pathToConfigFile)) {
console.log('No custom config file found.' + pathToConfigFile)
return {}
}
return fs.readJson(pathToConfigFile)
}
module.exports = defineConfig({
projectId: "wztwmc",
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
const file = config.env.configFile || ''
return getConfigurationByFile(file)
}
}
})
const pathToConfigFile = path.resolve('config',
${file}.json)
path to the config folder storing a list of config file such as:
- dev.json
- staging.json
- security.json
- prod.json
config.env.configFile
: key set up as argument when running cypress app.
For instance config/staging.json:
{
"baseUrl": "https://www.automationteststore.com/",
"env": {
"name": "Joe Blogs"
}
}
Any value setup in this file would overwrite the existing one setup in cypress.config.js
npx cypress open --env configFile=staging
The above command will look for the config/staging.json file.
Any custom variables must be setup in the env section of the cypress.config.js file.
Access the custom configuration values:
Cypress.env.name
Any key setup in an environment config file such as config/staging.json can be retrieved through this command.
In configuration file:
{
retries:{
runMode: 0,
openMode: 1
}
}
when running test from
cypress run
command it won't rety failed test. But it wil retry once throughcypress open
.
On cypress interface, the retries are displayed as below:
In any test file, the configuration can be edited:
it("should do something", {
retries: {
runMode: 2,
openMode: 2
}
}, () => {}
)
If any kind of test should run only on some browser. It can be configured individually as done for the retry configuration:
it("should do something", {
retries: {
runMode: 2,
openMode: 2
},
browser: ['chrome', 'firefox']
}, () => {}
)
It would be displayed as below in Cypress interface:
In a more global aspect, any kind of configuration key can be setup on an individual test
it()
ordescribe()
.
Also, inside a test, you can check the browser to apply a different behaviour:
it("should do something", () => {
if(Cypress.isBrowser('chrome'))
{
//apply chrome behaviour
}
})