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

Cypress hangs up when using done within a before hook after cy.request #1075

Closed
vrockai opened this issue Dec 15, 2017 · 10 comments · Fixed by #5097
Closed

Cypress hangs up when using done within a before hook after cy.request #1075

vrockai opened this issue Dec 15, 2017 · 10 comments · Fixed by #5097

Comments

@vrockai
Copy link

vrockai commented Dec 15, 2017

Current behavior:

When using a done callback within a then method of a cy.request in a before hook, tests won't wait for elements to appear on page (page load/redirect) and the whole test-suite will hang-up (it never finishes).

image

When not using the done function in the hook, everything works as expected = the cy.get('button') waits for the page to load.

Desired behavior:

The test behavior should be independent of the usage of the done function inside the before hook.

How to reproduce:

Try running my simple test code with a page that take a while to load.

Test code:

describe('A test with done function chained with a request', function () {
  before(function (done) {
    cy.request('/')
      .then(function () {
        done();
      });
  });

  it('should never get into a never-ending loop', function () {
    cy.login() // Our custom login method
    cy.visit('/');

    // Cypress doesn't wait for this elements
    cy.get('button')
    // Click does throw an error, but the test won't terminate and will never timeout
      .click();
  });
});
  • Operating System: Ubuntu 17.10
  • Cypress Version: 1.2.0
  • Browser Version: Google Chrome 63.0.3239.84 (Official Build) (64-bit)
@brian-mann
Copy link
Member

Yeah this should certainly work - I cannot see any reason why it wouldn't. We'll look into it.

Curious - why do you need to yield done in the before hook? You rarely, if ever need to use done in Cypress since we automatically wait for all enqueued commands to finish. It may be necessary in your expanded use case, but curious what it is and why it's necessary.

The handful of times done is necessary is during events that you bind documented here: https://docs.cypress.io/api/events/catalog-of-events.html#

@vrockai
Copy link
Author

vrockai commented Dec 15, 2017

I'm glad you asked, because that's actually related to another problem I have, but I wanted to investigate further before filing a proper issue.

I'm writing an E2E test, where I need to "seed" our platform with data and I do it in the before hook. That requires running a long async function (basically a cy.request), where I wanted to use polling for checking if everything is ready before running any tests. Actual polling is straightforward, you even have an example for that in the docs, but I wasn't able to poll an endpoint in intervals - like make a request every 10 seconds. It wasn't working with setTimeout nor with Cypress._.delay. My conclusion so far is, that any cy.request called within a setTimeout won't happen. While it wasn't a blocker for me to poll without any pause between calls, I went for it, but it left me with this done function dangling in the before hook and that's how I discovered this bug.

Please let me know if this should work or I am just missing a concept or two. I definitely need to read the whole doc again, after using Cypress for a few weeks now.

Thanks!

@jennifer-shehane jennifer-shehane added the stage: needs investigating Someone from Cypress needs to look at this label Dec 15, 2017
@brian-mann
Copy link
Member

@vrockai I believe you can accomplish this with Cypress.Promise.delay(...) which is a promisified setTimeout... use this in conjuction with a recursive cy.request.

function req () {
  cy.request(...).then((resp) => {
     return Cypress.Promise.delay(100).then(req)
   })
}

req()

@dabizlja
Copy link

@brian-mann For example if i have function without setTimeout in it but it needs to wait sometimes 10sec, sometimes more or less to load, what is solution. I wanna have some function where i will not need to type exactly the time after which my page will be loaded i just wanna tell to cypress do this when the page is loaded?

Thanks.

@Graham42
Copy link
Contributor

Graham42 commented Jan 30, 2018

I also was having this problem but solved it by returning a "Promise" instead of using the done callback.
Does it work if you change your code to the below?

before(function() {
  return cy.request("/");
});

@dabizlja
Copy link

Thank you for answer, but i think the cy.visit('some_page') will always wait until the whole page is loaded and this is simple solution which solving my problem!:)
Cheers!

@jennifer-shehane
Copy link
Member

The code for this is done, but this has yet to be released. We'll update this issue and reference the changelog when it's released.

@cypress-bot
Copy link
Contributor

cypress-bot bot commented Oct 23, 2019

Released in 3.5.0.

@tsteuwer
Copy link

tsteuwer commented Dec 31, 2019

This issue is still happening in 3.6.1. I want to visit a URL once since we have a very legacy backend that takes forever to load. But before does not wait for cy.visit() to completely load and angular (js) to bootstrap completely. It works if I put it in a beforeEach.

Example (pseduo code)

const { mockSocket } = require('../../support/mock-socket');

describe('Test My Page', () => {
	before(() => {
		cy.visit('/my/page', {
			onBeforeLoad(win) {
				mockSocket(win);
			}
		});
	});

	it('it should correctly load the page', () => {
		cy.url().should('include', '/my/page');
	});

	it('should do something else', () => {
		cy.get('#ts-1-header').should(...);
	});
});

I've been able to get this to work by using the following (although I feel incredibly dirty doing this and we have to wait the extra 10 seconds even if the page has loaded already):

const { mockSocket } = require('../../support/mock-socket');

describe('Test My Page', () => {
	before((done) => {
		return cy.visit('/my/page', {
			timeout: 30000,
			onBeforeLoad(win) {
				mockSocket(win);
			}
		}).then({ timeout: 30000 }, () => {
			return Cypress.Promise.delay(10000).then(done);
		});
	});

	it('it should correctly load the page', () => {
		cy.url().should('include', '/my/page');
	});

	it('should do something else', () => {
		cy.get('#ts-1-header').should(...);
	});
});

@jennifer-shehane
Copy link
Member

This issue will be closed to further comment as the exact issue here was resolved and tested.

@tsteuwer If you're experiencing a bug similar to this in Cypress, please open a new issue with a fully reproducible example that we can run. There may be a specific edge case with the issue that we need more detail to fix.

@cypress-io cypress-io locked as resolved and limited conversation to collaborators Jan 2, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
6 participants