Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait for an own function (which returns a promise) before tests are executed

I'm new to cypress and am trying to figure out how things work.

I have my own function (which calls a test controller server to reset the database). It returns a promise which completes when the DB have been successfully resetted.

function resetDatabase(){
  // returns a promise for my REST api call.
}

My goal is to be able to execute it before all tests.

describe('Account test suite', function () {

  // how can I call resetDb here and wait for the result
  // before the tests below are invoked?

  it('can log in', function () {
        cy.visit(Cypress.config().testServerUrl + '/Account/Login/')

        cy.get('[name="UserName"]').type("admin");
        cy.get('[name="Password"]').type("123456");
        cy.get('#login-button').click();
  });

  // .. and more test

})

How can I do that in cypress?

Update

I've tried

  before(() => {
    return resetDb(Cypress.config().apiServerUrl);
  });

But then I get an warning saying:

Cypress detected that you returned a promise in a test, but also invoked one or more cy commands inside of that promise

I'm not invoking cy in resetDb().

like image 981
jgauffin Avatar asked Sep 03 '18 17:09

jgauffin


2 Answers

Cypress have promises (Cypress.Promise), but they are not real promises, more like duck typing. In fact, Cypress isn't 100% compatible with real promises, they might, or might not, work.

Think of Cypress.Promise as a Task or an Action. They are executed sequentially with all other cypress commands.

To get your function into the Cypress pipeline you can use custom commands. The documentation doesn't state it, but you can return a Cypress.Promise from them.

Cypress.Commands.add('resetDb', function () {
  var apiServerUrl = Cypress.config().apiServerUrl;
  return new Cypress.Promise((resolve, reject) => {
    httpRequest('PUT', apiServerUrl + "/api/test/reset/")
      .then(function (data) {
        resolve();
      })
      .catch(function (err) {
        reject(err);
      });
  });
});

That command can then be executed from the test itself, or as in my case from before().

describe('Account', function () {
  before(() => {
    cy.resetDb();
  });

  it('can login', function () {
    // test code
  });

})
like image 173
jgauffin Avatar answered Sep 22 '22 15:09

jgauffin


You can use cy.wrap( promise ), although there might still be a bug where it never times out (haven't tested).

Otherwise, you can use cy.then() (which is undocumented, can break in the future, and I'm def not doing any favors by promoting internal APIs):

cy.then(() => {
    return myAsyncFunction();
});

You can use both of these commands at the top-level of spec like you'd use any command and it'll be enqueued into cypress command queue and executed in order.

But unlike cy.wrap (IIRC), cy.then() supports passing a callback, which means you can execute your async function at the time of the cy command being executed, not at the start of the spec (because expressions passed to cy commands evaluate immediately) --- that's what I'm doing in the example above.

like image 25
dwelle Avatar answered Sep 18 '22 15:09

dwelle