Cypress automating tool: Difference between revisions

From A Technological Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
 
Line 15: Line 15:
<li><p>[https://nodejs.org/ <u>Install node</u>]. In our case we should have it as a docker image</p></li>
<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>
<li><p>generating package.json</p>
<syntaxhighlight>npm init</syntaxhighlight></li>
<syntaxhighlight lang="bash">npm init</syntaxhighlight></li>
<li><p>install cypress</p>
<li><p>install cypress</p>
<syntaxhighlight>npm install cypress --save-dev
<syntaxhighlight lang="bash">npm install cypress --save-dev
./node_modules/.bin/cypress install</syntaxhighlight></li>
./node_modules/.bin/cypress install</syntaxhighlight></li>
<li><p>open Cypress GUI</p>
<li><p>open Cypress GUI</p>
<syntaxhighlight>node_modules/.bin/cypress open</syntaxhighlight></li>
<syntaxhighlight lang="bash">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>Select E2E Testing, it will create cypress folder and cypress.config.js</p></li>
<li><p>On browser, select Specs and Create Examples</p>
<li><p>On browser, select Specs and Create Examples</p>
Line 27: Line 27:
</li>
</li>
<li><p>run tests from CLI</p>
<li><p>run tests from CLI</p>
<syntaxhighlight>node_modules/.bin/cypress run
<syntaxhighlight lang="bash">node_modules/.bin/cypress run
--spec e2e/my_tests/smoke_tests.cy.js
--spec e2e/my_tests/smoke_tests.cy.js
--config-file cypress.config.js
--config-file cypress.config.js
Line 45: Line 45:
* create hello_world.cy.js file with:
* create hello_world.cy.js file with:


<syntaxhighlight>// defines test suite
<syntaxhighlight lang="TypeScript">// defines test suite
describe('Smoke Tests', {optional_config_keys: value}, () =&gt; {
describe('Smoke Tests', {optional_config_keys: value}, () => {
     // defines test case/s
     // defines test case/s
     it('Sample test', () =&gt; {
     it('Sample test', () => {
         // logs a message
         // logs a message
         cy.debug('Console message');
         cy.debug('Console message');
Line 56: Line 56:
== suites and test configurations ==
== suites and test configurations ==


<syntaxhighlight>describe(
<syntaxhighlight lang="TypeScript">describe(
     'Tests Suite',
     'Tests Suite',
     {
     {
Line 66: Line 66:
         }
         }
     },
     },
     () =&gt; {
     () => {
         cy.log(cy.config(viewportWidth));
         cy.log(cy.config(viewportWidth));
         cy.log(cy.env(DEMO));
         cy.log(cy.env(DEMO));
Line 81: Line 81:
=== Browser commands ===
=== Browser commands ===


<syntaxhighlight>cy.visit(url); // Load a page</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.visit(url); // Load a page</syntaxhighlight>
<syntaxhighlight>cy.reload(); // refresh page</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.reload(); // refresh page</syntaxhighlight>
<syntaxhighlight>cy.go(&quot;back/forward&quot;); // clicks browser button</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.go("back/forward"); // clicks browser button</syntaxhighlight>
<syntaxhighlight>cy.url() | .window() | .title(); // prints this info</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.url() | .window() | .title(); // prints this info</syntaxhighlight>
<span id="elements-selector"></span>
<span id="elements-selector"></span>
=== elements selector ===
=== elements selector ===


&quot;CSS and Path Checker&quot; and &quot;Relative Xpath&quot; browser extension is a good help
"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
<syntaxhighlight lang="TypeScript">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>
[...].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 lang="TypeScript">cy.contains(); // element contains a literal Text (regular expressions allowed)</syntaxhighlight>
<syntaxhighlight>cy.first() | last | next | prev | parents | children | siblings | find</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.first() | last | next | prev | parents | children | siblings | find</syntaxhighlight>
<span id="elements-actions"></span>
<span id="elements-actions"></span>
=== elements actions ===
=== elements actions ===


<syntaxhighlight>cy.type(); // fill a field
<syntaxhighlight lang="TypeScript">cy.type(); // fill a field
// with {} we can specify a key. Example .type({enter});</syntaxhighlight>
// with {} we can specify a key. Example .type({enter});</syntaxhighlight>
<syntaxhighlight>cy.clear(); // removes text</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.clear(); // removes text</syntaxhighlight>
<syntaxhighlight>cy.click() | dblclick | rightclick; // triggers mouse click on element
<syntaxhighlight lang="TypeScript">cy.click() | dblclick | rightclick; // triggers mouse click on element
// we can pass {force: true} if element is not visible
// we can pass {force: true} if element is not visible
// can call it with coordinates: .click(x,y)</syntaxhighlight>
// can call it with coordinates: .click(x,y)</syntaxhighlight>
<syntaxhighlight>cy.check() | uncheck; // un/checks a radio/checkbox</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.check() | uncheck; // un/checks a radio/checkbox</syntaxhighlight>
<syntaxhighlight>cy.focus() | blur | submit | hover | select</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.focus() | blur | submit | hover | select</syntaxhighlight>
<syntaxhighlight>cy.trigger(event); // trigger any DOM event</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.trigger(event); // trigger any DOM event</syntaxhighlight>
=== assertions ===
=== assertions ===


<syntaxhighlight>cy.should(status, value);</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.should(status, value);</syntaxhighlight>
statuses:
statuses:


Line 115: Line 115:
* equal functions can also be passed, check https://docs.cypress.io/api/commands/should example:
* equal functions can also be passed, check https://docs.cypress.io/api/commands/should example:


<syntaxhighlight>cy.get('#header a') // yields the element
<syntaxhighlight lang="TypeScript">cy.get('#header a') // yields the element
   .should('have.attr', 'href') // yields the &quot;href&quot; attribute
   .should('have.attr', 'href') // yields the "href" attribute
   .and('equal', '/users')  </syntaxhighlight>
   .and('equal', '/users')  </syntaxhighlight>
=== hooks ===
=== hooks ===


<syntaxhighlight>before(() =&gt; {}); // runs once before all tests</syntaxhighlight>
<syntaxhighlight lang="TypeScript">before(() => {}); // runs once before all tests</syntaxhighlight>
<syntaxhighlight>beforeEach(() =&gt; {}); // runs before every test </syntaxhighlight>
<syntaxhighlight lang="TypeScript">beforeEach(() => {}); // runs before every test </syntaxhighlight>
<syntaxhighlight>afterEach(() =&gt; {}); // runs after each test </syntaxhighlight>
<syntaxhighlight lang="TypeScript">afterEach(() => {}); // runs after each test </syntaxhighlight>
<syntaxhighlight>after(() =&gt; {}); // runs once all tests are done</syntaxhighlight>
<syntaxhighlight lang="TypeScript">after(() => {}); // runs once all tests are done</syntaxhighlight>
If they are inside a block (describe()), it only applies to them
If they are inside a block (describe()), it only applies to them


Line 129: Line 129:
=== Exceptions ===
=== Exceptions ===


<syntaxhighlight>Cypress.on('uncaught:exception', (err, runnable) =&gt; { return false });</syntaxhighlight>
<syntaxhighlight lang="TypeScript">Cypress.on('uncaught:exception', (err, runnable) => { return false });</syntaxhighlight>
=== utilities ===
=== utilities ===


<syntaxhighlight>cy.wait(ms); // sleep</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.wait(ms); // sleep</syntaxhighlight>
<syntaxhighlight>cy.pause(); // stops the test</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.pause(); // stops the test</syntaxhighlight>
<syntaxhighlight>cy.screenshot(); // takes screenshot</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.screenshot(); // takes screenshot</syntaxhighlight>
<syntaxhighlight>cy.log(); // print message</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.log(); // print message</syntaxhighlight>
<syntaxhighlight>cy.debug(); // print to browser console</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.debug(); // print to browser console</syntaxhighlight>
<syntaxhighlight>cy.fixture(file); .as(alias); // loads a fixture
<syntaxhighlight lang="TypeScript">cy.fixture(file); .as(alias); // loads a fixture
import user from './fixtures/file.json'; // another way
import user from './fixtures/file.json'; // another way
// example
// example
cy.fixture('user').then((userFixture) =&gt; {
cy.fixture('user').then((userFixture) => {
   expect(user, 'the same data').to.deep.equal(userFixture)
   expect(user, 'the same data').to.deep.equal(userFixture)
}) </syntaxhighlight>
}) </syntaxhighlight>
<syntaxhighlight>[...].then(); // work with yeilded subject  </syntaxhighlight>
<syntaxhighlight lang="TypeScript">[...].then(); // work with yeilded subject  </syntaxhighlight>
<syntaxhighlight>// hide XHR requests: on /cypress/support/e2e.js add:
<syntaxhighlight lang="TypeScript">// hide XHR requests: on /cypress/support/e2e.js add:
// Hide fetch/XHR requests
// Hide fetch/XHR requests
const app = window.top;
const app = window.top;
Line 155: Line 155:
   app.document.head.appendChild(style);
   app.document.head.appendChild(style);
}</syntaxhighlight>
}</syntaxhighlight>
<syntaxhighlight>it.only(); // runs only this test of the suite</syntaxhighlight>
<syntaxhighlight lang="TypeScript">it.only(); // runs only this test of the suite</syntaxhighlight>
<syntaxhighlight>cy.wrap(); // yield (passes) to cypress an object
<syntaxhighlight lang="TypeScript">cy.wrap(); // yield (passes) to cypress an object


cy.wrap({ name: 'Jane Lane' });
cy.wrap({ name: 'Jane Lane' });
const getName = () =&gt; {return 'Jane Lane'}; cy.wrap({ name: getName }).invoke('name').should('eq', 'Jane Lane');</syntaxhighlight>
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
<syntaxhighlight lang="TypeScript">cy.invoke(); // invokes a function (JS, jquery...) on the element


cy.get('.input').invoke('val').should('eq', 'foo'); // Invoke the 'val' function
cy.get('.input').invoke('val').should('eq', 'foo'); // Invoke the 'val' function
cy.get('.modal').invoke('show'); // Invoke the jQuery 'show' function
cy.get('.modal').invoke('show'); // Invoke the jQuery 'show' function
cy.get('a.external').invoke('removeAttr', 'href'); // removes href attribute from &quot;a.external&quot; elements
cy.get('a.external').invoke('removeAttr', 'href'); // removes href attribute from "a.external" elements
cy.get('input').invoke('attr', 'id', 'new-id'); // changes &quot;id&quot; input attribute
cy.get('input').invoke('attr', 'id', 'new-id'); // changes "id" input attribute
cy.wrap({ animate: fn }).invoke('animate'); // Invoke the 'animate' function</syntaxhighlight>
cy.wrap({ animate: fn }).invoke('animate'); // Invoke the 'animate' function</syntaxhighlight>
<span id="global-variables"></span>
<span id="global-variables"></span>
Line 172: Line 172:
They can be defined in /cypress.env.json. To access it from the servers use:
They can be defined in /cypress.env.json. To access it from the servers use:


<syntaxhighlight>Cypress.env(&quot;FIRST_JSON_LEVEL&quot;).SUBVARIABLE1.SUBVARIABLE2.SUBVARIABLEN</syntaxhighlight><span id="plugins"></span>
<syntaxhighlight lang="TypeScript">Cypress.env("FIRST_JSON_LEVEL").SUBVARIABLE1.SUBVARIABLE2.SUBVARIABLEN</syntaxhighlight><span id="plugins"></span>
== Plugins ==
== Plugins ==


get them on https://www.npmjs.com install it with:
get them on https://www.npmjs.com install it with:


<syntaxhighlight>npm install -D plugin-name</syntaxhighlight>
<syntaxhighlight lang="bash">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:
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>
<syntaxhighlight lang="TypeScript">require('plugin-name');</syntaxhighlight>
Example with https://www.npmjs.com/package/cypress-plugin-tab
Example with https://www.npmjs.com/package/cypress-plugin-tab


<syntaxhighlight>npm install -D </syntaxhighlight>
<syntaxhighlight lang="bash">npm install -D </syntaxhighlight>
<syntaxhighlight>require('cypress-plugin-tab');</syntaxhighlight>
<syntaxhighlight lang="TypeScript">require('cypress-plugin-tab');</syntaxhighlight>
<syntaxhighlight>cy.get('#inputFirstname').type('myName').tab().type('lastName');</syntaxhighlight>
<syntaxhighlight lang="TypeScript">cy.get('#inputFirstname').type('myName').tab().type('lastName');</syntaxhighlight>
Util plugins:
Util plugins:



Latest revision as of 13:11, 22 October 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 page
cy.reload(); // refresh page
cy.go("back/forward"); // clicks browser button
cy.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 text
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)
cy.check() | uncheck; // un/checks a radio/checkbox
cy.focus() | blur | submit | hover | select
cy.trigger(event); // trigger any DOM event

assertions

cy.should(status, value);

statuses:

cy.get('#header a') // yields the element
  .should('have.attr', 'href') // yields the "href" attribute
  .and('equal', '/users')

hooks

before(() => {}); // runs once before all tests
beforeEach(() => {}); // runs before every test
afterEach(() => {}); // runs after each test
after(() => {}); // runs once all tests are done

If they are inside a block (describe()), it only applies to them

Exceptions

Cypress.on('uncaught:exception', (err, runnable) => { return false });

utilities

cy.wait(ms); // sleep
cy.pause(); // stops the test
cy.screenshot(); // takes screenshot
cy.log(); // print message
cy.debug(); // print to browser console
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)
})
[...].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 suite
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');
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-name

in 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 -D
require('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