Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async test moving on before finished #8

Open
bsell93 opened this issue May 8, 2020 · 2 comments
Open

Async test moving on before finished #8

bsell93 opened this issue May 8, 2020 · 2 comments

Comments

@bsell93
Copy link

bsell93 commented May 8, 2020

I'm using cypress-promise@1.0.2 and cypress@3.4.0 (I know a bit out of date) and I'm noticing that my async tests using cypress-promise are "completing" and moving on to the next test before all of the commands are finished in the test. This is happening in the UI of cypress (not cli)

Here is a test I have

const getNumbersFromElement = (element) => element.text().replace(/\D/g, '');
const getNumbers = async (cyName) =>
    +(await cy
        .getCy(cyName)
        .first()
        .then(($elementWithNumbers) => getNumbersFromElement($elementWithNumbers))
        .promisify());

const getFirstThingsNumbers = () => getNumbers('some-number');


const addAndRemoveThing = async (contains) => {
    cy.log(`Adding and removing thing containing: ${contains}`);
    cy.route('POST', '/api/thing.add').as('addThing');
    selectFirsThing();
    cy.clickCy('review-things');
    cy.url().should('contain', 'things');
    cy.contains(contains);
    cy.getCy('more-stuff')
        .its('length')
        .should('eq', 4);
    const someNumber = await getFirstThingsNumbers();
    const someOtherNumber = await getNumbers('some-element');
    const totalOfNumbers = await getNumbers('total-of-numbers');
    expect(Math.max(someNumber - someOtherNumber, 0)).to.equal(totalOfNumbers);
    const myTotal = await getNumbers('my-total');
    expect(myTotal).to.equal(totalOfNumbers);
    cy.contains('Submit Stuff');
    cy.clickCyContaining('remove-thing'); // <<<<<< Test gets this far and moves on to the next test
    cy.submit();
    cy.closeToastSuccess();
    cy.clickCy('go-do-stuff');
    cy.url().should('contain', 'stuff');
    waitForGetThings();
};

// Inside describe
it('should do stuff', async () => {
    cy.clickCy('thing');
    await addAndRemoveThing('stuff');
    cy.clickCy('other-thing');
    await addAndRemoveThing('otherStuff'); // <<<<<< In this call it moves on to the next test before finished
});

I have other tests (that I'm using promisify in) that are doing the same thing.

Edit: Confirmed that async/await was causing the issue. I removed all usages of it in this spec and am no longer seeing the issue where a test won't complete fully. It's possible there is a fix in a newer version or I am just using the promises wrong, but something is definitely not working right.

@flash42
Copy link

flash42 commented Feb 15, 2022

@NicholasBoll I've also tested your library but it seems that it has a major conceptual flow. Cypress doesn't know about test functions running asynchronously. If you have a test like this:

  it("should disable preview on unsaved changes",  async () => {
   /// My test
  });

the test will be successful immediately while Cypress will be running the queued commands. At least that is what I've experienced. What is your take on this?

@craig-o-curtis
Copy link

I'm using Cypress 12.3.0 + cypress-promise 1.1.0 and it is great for async API db setup - the only thing is I get annoying warnings

My setup:
/e2e/support/commands.ts

Cypress.Commands.add('callAPI', (method, params, options = {}) => {
	if (sessionId && loginInfo) {
		const data = {...};
		return cy
			.request({ method: 'POST', url: `${baseUrlAPI}/${method}`, body: data, ...options })
			.then(response => response.body.result);
	}
	throw new Error("Can't call API because you're not logged in");
});

/e2e/support/cypressApiUtils.ts

import promisify from 'cypress-promise';
...
export const asyncDeleteAllMatching = async (command: string, filter: string, refElemName = 'ref') => {
	const existingItems = await promisify(cy.callAPI(command, { filter }));
	const idGuys = Object.keys(existingItems)
		.filter(k => Array.isArray(existingItems[k]))
		.reduce((acc, k) => {
			const ids = existingItems[k].map(e => e[idElemName]);
			return [...acc, ...refs];
		}, []);

	if (objRefs.length > 0) {
		return await promisify(
			cy.callAPI('RemoveGuys', {
				idGuys,
				forceRemoval: true,
			})
		);
	}
	return new Cypress.Promise(resolve => resolve([]));
};

A cleaner method that calls before and after that I won't show,

And an example of a test using async niceness
someTest.cypress.ts

...
describe('do stuff', () => {
   before(async () => {
      // These guys are removed both in before and after if they exist
      await cleaner.asyncBeforeAndAfter( async () => {
         await asyncDeleteAllMatching('CreateGuys', [1,2,3])
      });
      // created for the test
      await createGuys([1,2,3]);
      await asyncVisit( '/path' ); // this is a promisify( cy.visit('/path') );
   })
});

This solved the problem of promise race conditions randomly not creating or deleting data.

The only minor annoyance now is the warnings:

image

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants