Best Practices

Assigning Return Values

Do not assign the return value of commands with const , let , or var in your spec.ts.

example.spec.ts
const button = cy.get('wm-button');

cy.visit('http://localhost:4200/');

// nope, fails
button.first().click();

Instead, use the *.command.ts files to declare all the selectors you need and call them in the spec.ts to execute the actions required.

example.command.ts
export const button = () => {
    return cy.get('wm-button');
};
example.spec.ts
import { button } from './example.command.ts';

describe('sample title', () => {
    ...
    it('sample title', () => {
        cy.visit('http://localhost:4200/')
        button().first().click();
    });
}  

Remembering that Cypress commands run asynchronously is important if you are attempting to mix Cypress commands with synchronous code. Synchronous code will execute immediately - not waiting for the Cypress commands above it to execute.

If you need more information about this, you can consult cypress documentation (Cypress Documentation).

Selecting Elements

A good practice to remove dependencies to CSS or JS changes is to use data-* attributes on the components we are going to test, so we can create a more direct selector with more context.

example.html
<wm-button 
    id="button1" 
    [model]="model.button1" 
    class="button1"
    tabindex="2"
    data-cy="load"
>
</wm-button>
example.command.ts
export const button1 = () => {
  return cy.get('[data-cy="load"]');
};

As you can see in the code above, you can create a data-cy attribute (line 6 of example.html) in the component you want to test from the sample and call the selector using it. This way, if you make changes to, for example, CSS classes, it won't be affected.

If you need more information about this, you can consult cypress documentation (Cypress Documentation).

For cases where we have to access third party components and we cannot add attributes, the order of selection would be as follows:

  1. Element ID

  2. Element tagname

  3. Element class

Avoid dependence on other tests

Each test has to be independent from the others, remember that they are not unit tests and if you need several actions to test something, all of them can be performed in the same test.

To make sure you have created an independent test just change the it to an it.only, if this test passes it means you have done a good job. Here is an example of using the it.only:

it.only('sample title', () => {
    cy.visit('http://localhost:4200/')
    button().first().click();
});

One behavior can lead to many actions, the important thing is not to confuse it with trying to test several behaviors.

If you need more information about this, you can consult cypress documentation (Cypress Documentation).

Fixture

The "fixture" command is responsible for loading a fixed set of data located in a file. It is a good practice to use this command instead of declaring local variables for values that I need to use constantly in tests. An example:

  1. In the fixture folder create a .json file where you can store your variables.

fixtures/example-fixture.json
{
    "globalVar" : "rgba(0, 0, 0, 0)"   
}   

2. Use the fixture command in your tests.

example.spec.ts
describe('sample title', ()=> {
    
    it('sample title 1', () => {
       button1().should('be.visible');
        
       button1().click();
       exampleComp1().should('be.exist');
        
       cy.fixture('example-fixture').should((data) => {
         expect(exampleComp1().invoke('css', 'background'))
            .to.be.equal(globalVar);
       });
     });
     
     it('sample title 2', () => {
        button2().should('be.visible');
        
        button2().click();
        exampleComp2().should('be.exist');
        
        cy.fixture('example-fixture').should((data) => {
         expect(exampleComp2().invoke('css', 'background'))
            .to.be.equal(globalVar);
       });
     });
}

Avoid doing things like this:

example.spec.ts
const globalVar = "rgba(0, 0, 0, 0)";

describe('sample title', ()=> {
    
    it('sample title 1', () => {
        button1().should('be.visible');
        
        button1().click();
        exampleComp1().should('be.exist');
        
        exampleComp1().should('have.css', 'background', globalVar);
     });
     
     it('sample title 2', () => {
        button2().should('be.visible');
        
        button2().click();
        exampleComp2().should('be.exist');
        
        expect(exampleComp2().invoke('css', 'background'))
            .to.be.equal(globalVar);
     });
}

Avoid declaring global variables in the spec.ts file or in the command.ts file, if you need to use one value in several tests use the fixture command.

If you need more information about this, you can consult cypress documentation (Cypress Documentation).

Last updated