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

Prevent Cypress from resolving stubs with cy.route #4163

Closed
toddgallimore opened this issue May 8, 2019 · 5 comments · Fixed by #4176
Closed

Prevent Cypress from resolving stubs with cy.route #4163

toddgallimore opened this issue May 8, 2019 · 5 comments · Fixed by #4176
Assignees

Comments

@toddgallimore
Copy link

toddgallimore commented May 8, 2019

Feature Request

I'd like to be able to test loading states easier, by deciding myself when requests are resolved.

Current behaviour:

I can't currently find a way to prevent a cy.route from resolving. It seems closely related to this issue, although that is very old and has been closed with comments to say it's been included, but I can't find any docs for it.

I have looked everywhere and also asked questions in the Gitter forum.

I'd like to be able to prevent cy.route from resolving, until I tell it, so I can test the loading the state.

Desired behavior:

Something like this:

beforeEach(() => {
  cy.server();
  cy.route({
    url,
    method,
    status,
    response,
    resolve: false // tell Cypress that I'll resolve it myself when I'm ready
  }).as('namedRequest');
});

it('I should be able to test a loading state here (while request is still loading)', () => {
  cy.get(spinner).should('be.visible');
  expect(something).toEqual(somethingElse);
});

it('I should be able to resolve it here', () => {
  cy.get('@namedRequest').resolve(response); // tell Cypress I'm now ready and want it to be resolved (success)
  cy.get(spinner).should('not.exist');
  expect(something).toEqual(somethingElse);
});

it('I should be able to reject it here', () => {
  cy.get('@namedRequest').reject(error); // tell Cypress I'm now ready and want it to be rejected (failed request)
  cy.get(spinner).should('not.exist');
  expect(something).toEqual(somethingElse);
});

It does feel like Cypress should already be able to handle this (because it's awesome). But I can't find any docs for it and I'm struggling to find help elsewhere.

Versions

Cypress ^3.2.0
Node 10.15.3
Chrome 74

@flotwig
Copy link
Contributor

flotwig commented May 8, 2019

Hey @toddgallimore, controlling responses in this manner is something we're planning on adding as part of #687.

@toddgallimore
Copy link
Author

toddgallimore commented May 9, 2019

Hey @toddgallimore, controlling responses in this manner is something we're planning on adding as part of #687.

Excellent. It's on the roadmap. Keep up the good work!

Is there anything you can suggest for the time being?

I found a way by stubbing window.fetch, but it will stub EVERY single call to window.fetch so I'm not able to stub multiple requests with different responses. My solution was something like the below.

(I'll leave this here for other people's reference, or for someone smarter than me to improve on this and get closer to the requirements).

export default function deferrer() {
  const deferred = {};
  deferred.promise = new Promise((resolve, reject) => {
    deferred.resolve = resolve;
    deferred.reject = reject;
  });
  return deferred;
}

export default function FetchStub(cy, windw) {
  this.deferred = deferrer();
  this.stub = cy.stub(windw, 'fetch')
    .returns(this.deferred.promise);

  this.resolve = function (response) {
    this.deferred.resolve({
      text: () => JSON.stringify(response),
      json: () => response,
      ok: true
    });
  };
  this.reject = function (error) {
    this.deferred.reject({
      text: () => JSON.stringify(error),
      json: () => error,
      ok: false
    });
  };
}

which you can then use like this:

let stubFetch;

beforeEach(() => {
  cy.visit(url, {
    onBeforeLoad(windw) {
      stubFetch = new FetchStub(cy, windw);
    }
  });
});

it('should do something', () => {
  stubFetch.resolve({ ...someResponse });
  expect(something).toEqual(somethingElse);
});

it('should do else', () => {
  stubFetch.reject({ ...someError });
  expect(something).toEqual(somethingElse);
});

@cypress-bot cypress-bot bot added the stage: proposal 💡 No work has been done of this issue label May 24, 2019
@michal-ciechan
Copy link

michal-ciechan commented Aug 3, 2019

I would suggest an api such as

it('should show loader while loading then show content', () => {
  // Stub out the normal route with a Promise Completion Source
  cy.route("GET", "/some/url").defer().as("someUrlPromise")
  // or
  cy.routeDeferred("GET", "/some/url").as("someUrlPromise"); // could be just cy.route
  
  // Check loading state
  cy.get("loader").should("exist");

  // Complete request
  // this could be cy.getRoute(), or just cy.route("@xxx")
  cy.get("@someUrlPromise").resolve({ 
        status: xxx,
        headers: {},
        body: "@someUrlPromiseResponseBodyFixture"
  })

  // Check Loaded State
  cy.get("loader").should("not.exist");
});

Anyhow, just my 2 cents. It's a pain to need to add random wait times (2-5 seconds) in order to have non flakey tests, as they quickly add up!

@cypress-bot cypress-bot bot added stage: needs review The PR code is done & tested, needs review and removed stage: proposal 💡 No work has been done of this issue labels Jun 24, 2020
@cypress-bot cypress-bot bot added stage: work in progress stage: needs review The PR code is done & tested, needs review and removed stage: needs review The PR code is done & tested, needs review stage: work in progress labels Aug 25, 2020
@cypress-bot cypress-bot bot added stage: pending release and removed stage: needs review The PR code is done & tested, needs review labels Aug 31, 2020
@cypress-bot
Copy link
Contributor

cypress-bot bot commented Sep 1, 2020

Released in 5.1.0.

This comment thread has been locked. If you are still experiencing this issue after upgrading to
Cypress v5.1.0, please open a new issue.

@cypress-bot cypress-bot bot locked as resolved and limited conversation to collaborators Sep 1, 2020
@jennifer-shehane
Copy link
Member

The features requested in this issue are now possible as part of cy.route2().

cy.route2() is currently experimental and requires being enabled by passing "experimentalNetworkStubbing": true through your Cypress configuration. This will eventually be merged in as part of our standard API.

Please see the cy.route2() docs for full details: https://on.cypress.io/route2

If you encounter any issues or unexpected behavior while using cy.route2() we encourage you to open a new issue so that we can work out all the issues before public release. Thanks!

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

Successfully merging a pull request may close this issue.

4 participants