16

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().

jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • 1
    from what I know, there should be a `wait` method where you can directly wait for your api, but I may be wrong p.s. with the `wrap` method instead you should be able to wrap an ES6 promise and trasform it to a Cypress promise – quirimmo Sep 03 '18 at 17:32
  • @quirimmo Wait takes either a timeout or an `alias` from a previous command: https://docs.cypress.io/api/commands/wait.html#Syntax – jgauffin Sep 03 '18 at 17:33

2 Answers2

12

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
  });

})
jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • What is the method `httpRequest` , do you remember if it come from cypress, or a separate library -- maybe you defined it? Cypress has `cy.request(...)`. Also I wonder how your original `resetDb` function was different; (compare your original function that caused the error ("...but also invoked one or more cy commands inside of that promise"); vs the custom command you have here which does not have the error), is the only difference that it became a custom command, vs being a standalone function? – Nate Anderson Jan 20 '22 at 23:57
  • 1
    httpRequest: it was a function that I coded myself. I changed the resetDb to be able to specify the HTTP server address in cypress configuration file, instead of hardcoding it. – jgauffin Jan 22 '22 at 12:05
2

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.

dwelle
  • 6,894
  • 2
  • 46
  • 70