1
votes

I'm new in e2e testing with Cypress and I have a question.

I wrote a test and I want not to use Cypress wait() command in it.

it('Should modify checkbox state', () => {
        login();
        cy.visit(TabsSettings.SIZE_FORMATS).then(() => {
            cy.xpath('(//div[@data-qa="sizeFormats"]//*[4]//*//*[1]//*//*//*)[1]', { timeout: 10000 }).click().then(() => {
                expect(
                    cy.xpath('(//input[@type="checkbox"])[1]')
                        .then(checkbox => checkbox).should('be.checked')
                );
            });
            cy.get('span').contains('Change').click().then(() => {
                cy.get('li').contains('Disable').click().then({ timeout: 5000 }, () => {
                    cy.wait(500);
                    cy.xpath('(//div[@data-qa="sizeFormats"]//*[4]//*//*[1]//*//*//*)[1]').click().then(() => {
                        expect(
                            cy.xpath('(//input[@type="checkbox"])[1]')
                                .then(checkbox => checkbox[0]).should('be.checked')
                        );
                    });
                    cy.xpath('(//div[@data-qa="sizeFormats"]//*[4]//*//*[1]//*//*//*)[18]').click().then(() => {
                        expect(
                            cy.xpath('(//input[@type="checkbox"])[2]')
                                .then(checkbox => checkbox[3]).should('not.checked')
                        );
                    });
                });
                cy.xpath('//span[contains(text(), "Disable Selected")]').click().then(() => {
                    cy.get('li').contains('Enable').click().then(() => {
                        expect(
                            cy.get('input[type=checkbox]')
                                .then(checkbox => checkbox).should('not.checked')
                        );
                    });
                });
                cy.get('input[type=checkbox]').then(el => el[0].click()).then(() => {
                    expect(
                        cy.get('input[type=checkbox]')
                            .then(checkbox => checkbox).should('be.checked')
                    );
                }).then(() => {
                    cy.xpath('//i').then(x => x[1].click());
                    cy.get('input[type=checkbox]').should('not.checked');
                });
                cy.get('div[data-main-select=true]').then(list => list[1].click()).then(() => {
                    cy.xpath('(//li[contains(text(), "50")])[1]').click().then(() => {
                        cy.get('input[type=checkbox]').should(checkboxes => {
                            expect(checkboxes).to.have.length(51);
                        });
                    });
                });
                cy.xpath('(//div[@data-qa="sizeFormats"]//*[4]//*//*[1]//*//*//*)[1]').click().then(() => {
                    cy.wait(150);
                    expect(
                        cy.get('input[type=checkbox]')
                            .then(checkbox => checkbox).should('be.checked')
                    );
                });
            });
        });
    });

My problem is that if I not use that cy.wait(500) command, the test fails. I googled a lot but I cannot find an answer for my problem. The project is an React project, using Hooks. What may be caused the problem is that my component renders multiple times after that click() event. The page does not reload, but the main component rerenders several times. If this is the problem, how can I wait for finishing all renderings, and just after that continue the test, without using the wait function ?

2
This looks complicated. Let me digest all the code and I will get back to you.Maccurt
To get rid of a cy.wait() you generally need to make sure the command chain is using Cypress' automatic retry. The .then(() => preceding the wait is breaking that , so maybe you can solve it by substituting .should(() => - if I understand correctly, should will retry the code within.Richard Matsen
Also, xpath syntax is quite noisy, I would try to replace cy.xpath() with cy.get() where possible. See the caveats on the source pageRichard Matsen

2 Answers

1
votes

You shouldn't need to use wait with time, but sometimes you may need to wait for a certain request to finish. I find it's the case with some AJAX requests. You can get it to wait for a specific request to finish using route definitions:

cy.server()
cy.route('activities/*', 'fixture:activities').as('getActivities')
cy.route('messages/*', 'fixture:messages').as('getMessages')

// visit the dashboard, which should make requests that match
// the two routes above
cy.visit('http://localhost:8888/dashboard')

// pass an array of Route Aliases that forces Cypress to wait
// until it sees a response for each request that matches
// each of these aliases
cy.wait(['@getActivities', '@getMessages'])

// these commands will not run until the wait command resolves above
cy.get('h1').should('contain', 'Dashboard')

Read more here: https://docs.cypress.io/guides/guides/network-requests.html#Waiting

1
votes

Looking at it a bit further, you seem to be using a promise-style syntax unnecessarily.

Because Cypress has automatic retry on (most) commands, you can just call the commands sequentially without awaiting the result with .then(... constructs.

As an example, your code might be revised to something like this,

it('Should modify checkbox state', () => {
  login();
  cy.visit(TabsSettings.SIZE_FORMATS);
  cy.xpath('(//div[@data-qa="sizeFormats"]//*[4]//*//*[1]//*//*//*)[1]', {timeout: 10000 }).click();

  // cy.xpath('(//input[@type="checkbox"])[1]').then(checkbox => checkbox).should('be.checked')
  cy.get('input[@type="checkbox"]).eq(0).should('be.checked');  // NB eq() has zero-based indexing.

  cy.get('span').contains('Change').click();
  cy.get('li').contains('Disable').click();
  // OR if you have to wait for the Disable button/link to appear, use this
  cy.contains('li', 'Disable').click();

  cy.xpath('(//div[@data-qa="sizeFormats"]//*[4]//*//*[1]//*//*//*)[1]').click();
  cy.get('input[@type="checkbox"]).eq(0).should('be.checked');
  ...

I'm not familiar with xpath syntax, so the translation is a guess, but it seems Cypress' commands are a little more readable, have a flatter layout, PLUS you get auto-retry built in, which removes the need to wait for specific periods.

If you want to add to your question a pseudocode translation of the xpath expressions, I'll give you the equivalent Cypress commands.