Cypress automating tool: Difference between revisions
imported>Unknown user No edit summary |
imported>Unknown user No edit summary |
||
| Line 1: | Line 1: | ||
Cypress is an end-to-end testing framework designed for modern web applications for enhancing the efficiency, reliability, and user experience of automated functional testing. Unlike traditional testing tools that operate outside the browser, Cypress runs directly inside it, enabling more consistent real-time interactions and observations. Key benefits for automated functional testing include: | |||
* '''Real-time Feedback''': Instantly see test results and debug directly in the browser. | |||
* '''Automatic Waiting''': Cypress auto-waits for elements, reducing flakiness. | |||
* '''Time Travel''': Snapshot the DOM at different stages to understand test progress. | |||
* '''Parallel Execution''': Speeds up test runs by distributing tests across machines. | |||
* '''Rich Ecosystem''': Comes with mocking, stubbing, and network interception capabilities. | |||
* '''Comprehensive Documentation''': Simplifies learning and adoption. | |||
* '''Cross-browser Testing''': Ensures app compatibility across different browsers. | |||
<span id="installing-cypress"></span> | |||
= Installing Cypress = | |||
<ul> | |||
<li><p>[https://nodejs.org/ <u>Install node</u>]. In our case we should have it as a docker image</p></li> | |||
<li><p>generating package.json</p> | |||
<syntaxhighlight>npm init</syntaxhighlight></li> | |||
<li><p>install cypress</p> | |||
<syntaxhighlight>npm install cypress --save-dev | |||
./node_modules/.bin/cypress install</syntaxhighlight></li> | |||
<li><p>open Cypress GUI</p> | |||
<syntaxhighlight>node_modules/.bin/cypress open</syntaxhighlight></li> | |||
<li><p>Select E2E Testing, it will create cypress folder and cypress.config.js</p></li> | |||
<li><p>On browser, select Specs and Create Examples</p> | |||
<ul> | |||
<li><p>click Advanced Examples - Actions for and example</p></li></ul> | |||
</li> | |||
<li><p>run tests from CLI</p> | |||
<syntaxhighlight>node_modules/.bin/cypress run | |||
--spec e2e/my_tests/smoke_tests.cy.js | |||
--config-file cypress.config.js | |||
--config video=true </syntaxhighlight></li></ul> | |||
Extra cypress configurations (--config): https://docs.cypress.io/guides/references/configuration | |||
To display browser during CLI run use --headed | |||
<span id="coding"></span> | |||
= Coding = | |||
<span id="hello-world"></span> | |||
== hello world == | |||
* Create a folder inside cypress/e2e for our context | |||
* create hello_world.cy.js file with: | |||
<syntaxhighlight>// defines test suite | |||
describe('Smoke Tests', {optional_config_keys: value}, () => { | |||
// defines test case/s | |||
it('Sample test', () => { | |||
// logs a message | |||
cy.debug('Console message'); | |||
}) | |||
})</syntaxhighlight> | |||
<span id="suites-and-test-configurations"></span> | |||
== suites and test configurations == | |||
<syntaxhighlight>describe( | |||
'Tests Suite', | |||
{ | |||
viewportWidth: 1024, | |||
viewportHeight: 700, | |||
env: { | |||
DEMO: true, | |||
API: 'http://localhost:9000', | |||
} | |||
}, | |||
() => { | |||
cy.log(cy.config(viewportWidth)); | |||
cy.log(cy.env(DEMO)); | |||
} | |||
)</syntaxhighlight> | |||
They can be accessed with cy.config(var) or cy.env(var) | |||
<span id="commands"></span> | |||
== Commands == | |||
Commands can be concatenated with . | |||
<span id="browser-commands"></span> | |||
=== Browser commands === | |||
<syntaxhighlight>cy.visit(url); // Load a page</syntaxhighlight> | |||
<syntaxhighlight>cy.reload(); // refresh page</syntaxhighlight> | |||
<syntaxhighlight>cy.go("back/forward"); // clicks browser button</syntaxhighlight> | |||
<syntaxhighlight>cy.url() | .window() | .title(); // prints this info</syntaxhighlight> | |||
<span id="elements-selector"></span> | |||
=== elements selector === | |||
"CSS and Path Checker" and "Relative Xpath" browser extension is a good help | |||
<syntaxhighlight>cy.get(); // gets an element. Use CSS selectors (#, ., [att=value], etc), Xpath | |||
[...].as(alias); // asign an alias to the selection and later use .get(@alias)</syntaxhighlight> | |||
<syntaxhighlight>cy.contains(); // element contains a literal Text (regular expressions allowed)</syntaxhighlight> | |||
<syntaxhighlight>cy.first() | last | next | prev | parents | children | siblings | find</syntaxhighlight> | |||
<span id="elements-actions"></span> | |||
=== elements actions === | |||
<syntaxhighlight>cy.type(); // fill a field | |||
// with {} we can specify a key. Example .type({enter});</syntaxhighlight> | |||
<syntaxhighlight>cy.clear(); // removes text</syntaxhighlight> | |||
<syntaxhighlight>cy.click() | dblclick | rightclick; // triggers mouse click on element | |||
// we can pass {force: true} if element is not visible | |||
// can call it with coordinates: .click(x,y)</syntaxhighlight> | |||
<syntaxhighlight>cy.check() | uncheck; // un/checks a radio/checkbox</syntaxhighlight> | |||
<syntaxhighlight>cy.focus() | blur | submit | hover | select</syntaxhighlight> | |||
<syntaxhighlight>cy.trigger(event); // trigger any DOM event</syntaxhighlight> | |||
=== assertions === | |||
<syntaxhighlight>cy.should(status, value);</syntaxhighlight> | |||
statuses: | |||
* [not.]have. : class, value, id, attr, css, focus | |||
* [not.]be. : empty, visible, disabled, selected | |||
* equal functions can also be passed, check https://docs.cypress.io/api/commands/should example: | |||
<syntaxhighlight>cy.get('#header a') // yields the element | |||
.should('have.attr', 'href') // yields the "href" attribute | |||
.and('equal', '/users') </syntaxhighlight> | |||
=== hooks === | |||
<syntaxhighlight>before(() => {}); // runs once before all tests</syntaxhighlight> | |||
<syntaxhighlight>beforeEach(() => {}); // runs before every test </syntaxhighlight> | |||
<syntaxhighlight>afterEach(() => {}); // runs after each test </syntaxhighlight> | |||
<syntaxhighlight>after(() => {}); // runs once all tests are done</syntaxhighlight> | |||
If they are inside a block (describe()), it only applies to them | |||
<span id="exceptions"></span> | |||
=== Exceptions === | |||
<syntaxhighlight>Cypress.on('uncaught:exception', (err, runnable) => { return false });</syntaxhighlight> | |||
=== utilities === | |||
<syntaxhighlight>cy.wait(ms); // sleep</syntaxhighlight> | |||
<syntaxhighlight>cy.pause(); // stops the test</syntaxhighlight> | |||
<syntaxhighlight>cy.screenshot(); // takes screenshot</syntaxhighlight> | |||
<syntaxhighlight>cy.log(); // print message</syntaxhighlight> | |||
<syntaxhighlight>cy.debug(); // print to browser console</syntaxhighlight> | |||
<syntaxhighlight>cy.fixture(file); .as(alias); // loads a fixture | |||
import user from './fixtures/file.json'; // another way | |||
// example | |||
cy.fixture('user').then((userFixture) => { | |||
expect(user, 'the same data').to.deep.equal(userFixture) | |||
}) </syntaxhighlight> | |||
<syntaxhighlight>[...].then(); // work with yeilded subject </syntaxhighlight> | |||
<syntaxhighlight>// hide XHR requests: on /cypress/support/e2e.js add: | |||
// Hide fetch/XHR requests | |||
const app = window.top; | |||
if (!app.document.head.querySelector('[data-hide-command-log-request]')) { | |||
const style = app.document.createElement('style'); | |||
style.innerHTML = | |||
'.command-name-request, .command-name-xhr { display: none }'; | |||
style.setAttribute('data-hide-command-log-request', ''); | |||
app.document.head.appendChild(style); | |||
}</syntaxhighlight> | |||
<syntaxhighlight>it.only(); // runs only this test of the suite</syntaxhighlight> | |||
<syntaxhighlight>cy.wrap(); // yield (passes) to cypress an object | |||
cy.wrap({ name: 'Jane Lane' }); | |||
const getName = () => {return 'Jane Lane'}; cy.wrap({ name: getName }).invoke('name').should('eq', 'Jane Lane');</syntaxhighlight> | |||
<syntaxhighlight>cy.invoke(); // invokes a function (JS, jquery...) on the element | |||
cy.get('.input').invoke('val').should('eq', 'foo'); // Invoke the 'val' function | |||
cy.get('.modal').invoke('show'); // Invoke the jQuery 'show' function | |||
cy.get('a.external').invoke('removeAttr', 'href'); // removes href attribute from "a.external" elements | |||
cy.get('input').invoke('attr', 'id', 'new-id'); // changes "id" input attribute | |||
cy.wrap({ animate: fn }).invoke('animate'); // Invoke the 'animate' function</syntaxhighlight> | |||
<span id="global-variables"></span> | |||
== Global variables == | |||
They can be defined in /cypress.env.json. To access it from the servers use: | |||
<syntaxhighlight>Cypress.env("FIRST_JSON_LEVEL").SUBVARIABLE1.SUBVARIABLE2.SUBVARIABLEN</syntaxhighlight> | |||
<span id="plugins"></span> | |||
== Plugins == | |||
get them on https://www.npmjs.com install it with: | |||
<syntaxhighlight>npm install -D plugin-name</syntaxhighlight> | |||
in the plugin information, it should say how to load it. It usually is adding on cypress/support/index.js: | |||
<syntaxhighlight>require('plugin-name');</syntaxhighlight> | |||
Example with https://www.npmjs.com/package/cypress-plugin-tab | |||
<syntaxhighlight>npm install -D </syntaxhighlight> | |||
<syntaxhighlight>require('cypress-plugin-tab');</syntaxhighlight> | |||
<syntaxhighlight>cy.get('#inputFirstname').type('myName').tab().type('lastName');</syntaxhighlight> | |||
Util plugins: | |||
* file-upload | |||
<span id="files-structure"></span> | |||
= Files structure = | |||
* '''/bin''': contains scripts to launch different type of tests | |||
* '''/cypress/e2e/.cy.js''': contains the actual tests | |||
* '''fixtures''': TBD | |||
* '''/support/custom_commands/''': custom folder where project commands will be placed | |||
* '''/support/commands.js''': commands and how cypress functions are named | |||
* '''/support/e2e.js''': framework configuration file. Here we will import all custom commands files. | |||
* '''/cypress.config.js''': default configurations for tests | |||
* '''/cypress.env.json''': global variables | |||
<!-- From bodyContent 1542992.mraw --> | <!-- From bodyContent 1542992.mraw --> | ||
Revision as of 11:33, 19 April 2025
Cypress is an end-to-end testing framework designed for modern web applications for enhancing the efficiency, reliability, and user experience of automated functional testing. Unlike traditional testing tools that operate outside the browser, Cypress runs directly inside it, enabling more consistent real-time interactions and observations. Key benefits for automated functional testing include:
- Real-time Feedback: Instantly see test results and debug directly in the browser.
- Automatic Waiting: Cypress auto-waits for elements, reducing flakiness.
- Time Travel: Snapshot the DOM at different stages to understand test progress.
- Parallel Execution: Speeds up test runs by distributing tests across machines.
- Rich Ecosystem: Comes with mocking, stubbing, and network interception capabilities.
- Comprehensive Documentation: Simplifies learning and adoption.
- Cross-browser Testing: Ensures app compatibility across different browsers.
Installing Cypress
Install node. In our case we should have it as a docker image
generating package.json
npm init
install cypress
npm install cypress --save-dev ./node_modules/.bin/cypress install
open Cypress GUI
node_modules/.bin/cypress open
Select E2E Testing, it will create cypress folder and cypress.config.js
On browser, select Specs and Create Examples
click Advanced Examples - Actions for and example
run tests from CLI
node_modules/.bin/cypress run --spec e2e/my_tests/smoke_tests.cy.js --config-file cypress.config.js --config video=true
Extra cypress configurations (--config): https://docs.cypress.io/guides/references/configuration
To display browser during CLI run use --headed
Coding
hello world
- Create a folder inside cypress/e2e for our context
- create hello_world.cy.js file with:
// defines test suite
describe('Smoke Tests', {optional_config_keys: value}, () => {
// defines test case/s
it('Sample test', () => {
// logs a message
cy.debug('Console message');
})
})
suites and test configurations
describe(
'Tests Suite',
{
viewportWidth: 1024,
viewportHeight: 700,
env: {
DEMO: true,
API: 'http://localhost:9000',
}
},
() => {
cy.log(cy.config(viewportWidth));
cy.log(cy.env(DEMO));
}
)They can be accessed with cy.config(var) or cy.env(var)
Commands
Commands can be concatenated with .
Browser commands
cy.visit(url); // Load a pagecy.reload(); // refresh pagecy.go("back/forward"); // clicks browser buttoncy.url() | .window() | .title(); // prints this info
elements selector
"CSS and Path Checker" and "Relative Xpath" browser extension is a good help
cy.get(); // gets an element. Use CSS selectors (#, ., [att=value], etc), Xpath
[...].as(alias); // asign an alias to the selection and later use .get(@alias)cy.contains(); // element contains a literal Text (regular expressions allowed)cy.first() | last | next | prev | parents | children | siblings | find
elements actions
cy.type(); // fill a field
// with {} we can specify a key. Example .type({enter});cy.clear(); // removes textcy.click() | dblclick | rightclick; // triggers mouse click on element
// we can pass {force: true} if element is not visible
// can call it with coordinates: .click(x,y)cy.check() | uncheck; // un/checks a radio/checkboxcy.focus() | blur | submit | hover | selectcy.trigger(event); // trigger any DOM eventassertions
cy.should(status, value);statuses:
- [not.]have. : class, value, id, attr, css, focus
- [not.]be. : empty, visible, disabled, selected
- equal functions can also be passed, check https://docs.cypress.io/api/commands/should example:
cy.get('#header a') // yields the element
.should('have.attr', 'href') // yields the "href" attribute
.and('equal', '/users')hooks
before(() => {}); // runs once before all testsbeforeEach(() => {}); // runs before every testafterEach(() => {}); // runs after each testafter(() => {}); // runs once all tests are doneIf they are inside a block (describe()), it only applies to them
Exceptions
Cypress.on('uncaught:exception', (err, runnable) => { return false });utilities
cy.wait(ms); // sleepcy.pause(); // stops the testcy.screenshot(); // takes screenshotcy.log(); // print messagecy.debug(); // print to browser consolecy.fixture(file); .as(alias); // loads a fixture
import user from './fixtures/file.json'; // another way
// example
cy.fixture('user').then((userFixture) => {
expect(user, 'the same data').to.deep.equal(userFixture)
})[...].then(); // work with yeilded subject// hide XHR requests: on /cypress/support/e2e.js add:
// Hide fetch/XHR requests
const app = window.top;
if (!app.document.head.querySelector('[data-hide-command-log-request]')) {
const style = app.document.createElement('style');
style.innerHTML =
'.command-name-request, .command-name-xhr { display: none }';
style.setAttribute('data-hide-command-log-request', '');
app.document.head.appendChild(style);
}it.only(); // runs only this test of the suitecy.wrap(); // yield (passes) to cypress an object
cy.wrap({ name: 'Jane Lane' });
const getName = () => {return 'Jane Lane'}; cy.wrap({ name: getName }).invoke('name').should('eq', 'Jane Lane');cy.invoke(); // invokes a function (JS, jquery...) on the element
cy.get('.input').invoke('val').should('eq', 'foo'); // Invoke the 'val' function
cy.get('.modal').invoke('show'); // Invoke the jQuery 'show' function
cy.get('a.external').invoke('removeAttr', 'href'); // removes href attribute from "a.external" elements
cy.get('input').invoke('attr', 'id', 'new-id'); // changes "id" input attribute
cy.wrap({ animate: fn }).invoke('animate'); // Invoke the 'animate' function
Global variables
They can be defined in /cypress.env.json. To access it from the servers use:
Cypress.env("FIRST_JSON_LEVEL").SUBVARIABLE1.SUBVARIABLE2.SUBVARIABLEN
Plugins
get them on https://www.npmjs.com install it with:
npm install -D plugin-namein the plugin information, it should say how to load it. It usually is adding on cypress/support/index.js:
require('plugin-name');Example with https://www.npmjs.com/package/cypress-plugin-tab
npm install -Drequire('cypress-plugin-tab');cy.get('#inputFirstname').type('myName').tab().type('lastName');Util plugins:
- file-upload
Files structure
- /bin: contains scripts to launch different type of tests
- /cypress/e2e/.cy.js: contains the actual tests
- fixtures: TBD
- /support/custom_commands/: custom folder where project commands will be placed
- /support/commands.js: commands and how cypress functions are named
- /support/e2e.js: framework configuration file. Here we will import all custom commands files.
- /cypress.config.js: default configurations for tests
- /cypress.env.json: global variables