Bad practices

Tests with a single assertion

You're not writing unit tests, don't be afraid to have a lot of asserts in an integration test

Cypress runs a series of asynchronous lifecycle events that reset state between tests and restarting tests is much slower than adding more asserts.

example.spec.ts
it('Verify the control exists', () => {
    c1TrueDBGrid().should('be.exist');
});
example.spec.ts
it('Verify the control exists and is visible', () => {
    c1TrueDBGrid().should('be.exist');
    c1TrueDBGrid().should('be.visible');
});

Avoid doing this type of test.

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

Note, this does not mean that you should not use this type of assertions, you can run them to verify that the environment you need to test is correct in the "Arrange" section, you can see more about this here.

Unnecessary Waiting

In Cypress, it is almost never necessary to use cy.wait() for an arbitrary amount of time. If you find yourself doing this, there is probably a much simpler way. Usually a better implementation to avoid waits and implement stable tests is to make assertions (using should) based on the expected state of the control to validate.

example.spec.ts
 //Correct usage
 it('sample title', () => {
    button().should('be.exist');
    button().should('be.visible');
    
    button().click();
    
    gridCell(0,0).should('be.exist');
    gridCell(0,0).should('be.visible');
    gridCell(0,0).dblclick();
    
    gridCellEditable(0,0).should('be.exist');
    gridCellEditable(0,0).should('be.visible');
  });
  
  //Bad usage
  it('sample title', () => {
    button().should('be.exist');
    button().should('be.visible');
    
    button().click();
    cy.wait(1000);
    gridCell(0,0).dblclick();
    
    gridCellEditable(0,0).should('be.exist');
    gridCellEditable(0,0).should('be.visible');
  });

Forcing

The use of { force: true } should not normally be used to interact with components as it tends to omit checks that may not be representing the behavior you want to simulate or make some test unstable. An example would be to force click on a component that is not enabled and this check is omitted so the test would not be simulating real behavior.

These actions are not performed if you use forcing:

  • Scroll the element into view.

  • Ensure it is visible.

  • Ensure it is not disabled.

  • Ensure it is not detached.

  • Ensure it is not readonly.

  • Ensure it is not animating.

  • Ensure it is not covered.

  • Fire the event at a descendent.

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

This does not mean that it is bad practice to use it, only that you have to ask yourself if you are making good use of it and are not omitting necessary checks in the test.

Using .then() in callbacks

Use should instead of then because cypress retries any assertion that is inside a should assertion. If then is used, it is validated only once. This avoids test instability because it takes into account the rendering time of the sample components. An Example:

example.spec.ts
it('sample title', () => {
    controls.getButtonById(4).click({ force: true });
    controls.getLabelById(7).invoke('text').should((text) => {
        expect(text).to.deep.equal('4');
    });
});

Avoid doing things like this:

example.spec.ts
it('sample title', () => {
    controls.getButtonById(4).click({ force: true });
    controls.getLabelById(7).invoke('text').then((text) => {
        expect(text).to.deep.equal('4');
    });
});

Selectors using > for direct child nodes

Avoid using direct child selector (">") to refer controls or components on the UI, try to use whitespaces.

example.commands.ts
//Correct usage
export const gridMode = () => {
  return cy.get('wm-c1flexgrid wm-c1flexgrid-default');
}

//Bad usage
export const gridMode = () => {
  return cy.get('wm-c1flexgrid > wm-c1flexgrid-default');
}

Last updated