cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
46.59k stars 3.15k forks source link

Click and type events in after or afterEach hook don't work if one test fails #2831

Open StanFisher opened 5 years ago

StanFisher commented 5 years ago

Current behavior:

Any click event in the after block fails if one of the tests in an it block fails.

Desired behavior:

Click events in the after block should succeed even if there are tests that fail.

Steps to reproduce:

I forked the cypress-tiny-test repository and set up a reproducible example in the latest commit. https://github.com/StanFisher/cypress-test-tiny

Here's the commit containing the failing after block. https://github.com/StanFisher/cypress-test-tiny/commit/c185242f3fdd30715d16fc44e393e092c30c4d58

Notice that if the failing test is changed to succeed, then the two click events in the after block succeed.

Versions

Cypress 3.1.2 macOS Mojave 10.14.1 Chrome 70.0.3538.102

StanFisher commented 5 years ago

@jennifer-shehane Thanks for looking at this! Why was this labeled as a feature instead of a bug?

bahmutov commented 5 years ago

I marked it as a feature because once the test finishes, catching any possible errors is NOT something Mocha would do - because by then the test has finished. In Cypress the exception is there because the browser window still stays open after the test. If we closed the browser window immediately, the exception would never happen. So that's why I marked it as a feature

jennifer-shehane commented 5 years ago

I believed it was Mocha's implementation to not run after hooks on error of the test suite, but after further investigation, I see that Mocha does run after hooks on test failure. To quote the Mocha team on their hook execution:

  • If before hook fails, tests in a suite (where the hook is) and sub-suites are not executed. If after hook exists, it is called.
  • If beforeEach hook fails, remaining tests in that suite (where the hook is) or sub-suites are not executed. The remaining before hooks are also not executed. If afterEach hooks exist in that suite, or parent suites -- they get executed. The suite's after hooks are also executed.
  • If after hook fails, no additional hooks are called.
  • If afterEach hook fails, remaining tests in that suite (where the hook is) and sub-suites are not executed. The remaining after hooks (from parent suites) are executed. after hooks are executed 'up' starting from the suite of the last executed test, finishing with a suite where the hook is (inclusively).

After any hook error, the next sibling suite (relative to the suite with hook error) is executed.

This allows writing test hooks in a symmetrical manner:

  • before (each): allocate all resources for this and child test suites or tests
  • after (each): free all resources, allocated by before (each). Make sure, this will work correctly, even if some resource allocation failed -- it will still be called.

Based on this, I would qualify this as a bug in Cypress. We are upgrading Mocha to its latest version here https://github.com/cypress-io/cypress/issues/2528 I will see if the upgrade fixes this issue, if not, then it will require more investigation.

jennifer-shehane commented 5 years ago

I am unable to check this out in our v4 branch at the moment, but here is the reproducible code for the future. It's strange that the code in the after hook does run, but the click is not performed.

describe('page', () => {
  beforeEach(() => {
    cy.visit('https://www.cypress.io')
  })

  // ***** NOTE *****
  // The presence of this failing tests means that the clicks in the 'after' block don't work.
  // If this test is either removed or changed to be passing, then the 'after' block will work.
  it('fails', () => {
    cy.wrap(false).should('be.true')
  })

  after(() => {
    cy.get('#main-nav>li')
      .contains('Support').click()
    cy.url().should('contain', '/support/')
  })
})
immohsin commented 5 years ago

Any workaround for this one? After i run spec file, i want to cleanup few thing in case if anything fails.

toannguyen83 commented 5 years ago

I'm having the same issue. In the afterEach i need to perform cleanup after each test, undoing certain UI actions, but if the test failed, any action in afterEach doesn't work properly.

I have to do a weird workaround for now, having my clean up code in beforeEach, but, it won't perform clean up on the last test, so I need to also add a dummy test to the very end.

NareshGuduri commented 5 years ago

Is this fixed ?

jennifer-shehane commented 5 years ago

No this is not fixed. Issues will be closed when they are fixed.

cvasile001 commented 4 years ago

Hi Everyone. I am also experiencing this issue. Is there any update on this issue? Maybe a workaround? @jennifer-shehane

jennifer-shehane commented 4 years ago

My previous example for this bug no longer exhibits the error properly since the website under test has changed.

I tested this against the upcoming Cypress 4.0 release and verified that this is not fixed in that release.

To reproduce

spec.js

describe('page', () => {
  context('after click clicks', () => {
    it('passes', () => {
      cy.visit('https://example.cypress.io').then(() => {
        expect(false).to.be.false
      })
    })

    after(() => {
      cy.get('.home-list')
        .contains('Querying').click()
      cy.url().should('include', '/querying')
    })
  })

  context('after click does not click', () => {
    it('fails', () => {
      cy.visit('https://example.cypress.io').then(() => {
        expect(false).to.be.true
      })
    })

    after(() => {
      cy.get('.home-list')
        .contains('Querying').click()
      cy.url().should('include', '/querying')
    })
  })
})
Screen Shot 2020-01-29 at 3 33 03 PM
Brestachan commented 4 years ago

I hope this will be solved soon, or at least for someone to offer a workaround. I wrapped a lot of my tests with this, it seems to be super useful, except it doesn't work yet. :)

cvasile001 commented 4 years ago

@Brestachan you can add a dummy test that always passes before the next set of tests run. This will ensure that your after block click action is executed properly. Not the best workaround, but I found this helpful for tests that I know are failing with open bugs that might be a while before they work again.

stevenvachon commented 4 years ago

This is a duplicate of #1477, by the way.

jennifer-shehane commented 4 years ago

Type also causes this error:

describe('after hook no click', () => {
  beforeEach(() => {
    cy.visit('https://example.cypress.io')
  })

  // The presence of this failing tests means that the clicks in the 'after' block don't work.
  it('fails', () => {
    cy.wrap(false).should('be.true')
  })

  after(() => {
    cy.get('.nav')
      .contains('li', 'Utilities').click()
    cy.url().should('include', '/utilities')
  })
})

describe('afterEach hook no type', () => {
  beforeEach(() => {
    cy.visit('https://example.cypress.io')
  })

  // The presence of this failing tests means that the clicks in the 'after' block don't work.
  it('fails', () => {
    cy.wrap(false).should('be.true')
  })

  afterEach(() => {
    cy.get('.nav')
      .contains('Utilities').click()
    cy.url().should('include', '/utilities')
  })
})

describe('after hook no type', () => {
  beforeEach(() => {
    cy.visit('https://example.cypress.io/commands/actions')
  })

  // The presence of this failing tests means that the clicks in the 'after' block don't work.
  it('fails', () => {
    cy.wrap(false).should('be.true')
  })

  after(() => {
    cy.get('#email1').type('foo').should('have.value', 'foo')
  })
})

describe('afterEach hook no click', () => {
  beforeEach(() => {
    cy.visit('https://example.cypress.io/commands/actions')
  })

  // The presence of this failing tests means that the clicks in the 'after' block don't work.
  it('fails', () => {
    cy.wrap(false).should('be.true')
  })

  afterEach(() => {
    cy.get('#email1').type('foo').should('have.value', 'foo')
  })
})
stevenvachon commented 4 years ago

Is it possible to get this into a minor or patch release? I cannot use the dummy test idea because then cookies will have already been cleared.

TestLeafInc commented 4 years ago

This issue is blocking several tests of us for straight solution. Though we have overridden the mocha on cypress, Is there a deadline for this please?

wesam-mtour commented 3 years ago

use force type and force click in after or afterEach Hooks

szymon-niedrygas commented 3 years ago

use force type and force click in after or afterEach Hooks Unfortunately, also variables that are taken form external js file with const are not resolved

chrisdanna commented 3 years ago

Still an issue in version 7.7.0. Is it fixed in 8?

ma4ilda commented 2 years ago

Still an issue in 8.4.1 :(

Aishwarya-U-R commented 2 years ago

Is this not fixed yet? Really need an approach to run a few code even if tests fail! Blocking a whole suite of cases for us!

joselee commented 2 years ago

Having the same issue in afterAll() when a testcase fails! I'm using cypress version 8, and have been relying of afterAll() to perform cleanup after test execution.

kzahozhy commented 2 years ago

Still expirience this issue in version 9.7.0 Need the fix so badly, cause it blocks bunch of tests. In fact not only click or type is not working, but also no waiting for element is applied, all should checks are executed once and imediately.

DevrathsinghMusikaar commented 2 years ago

Facing same issue in version 10.3.1 The after hook don't work if one test fails. The after hook doesn't recognize the properties like find element in DOM and also not able to click Hope to see a fix soon. Thank you Cypress community image

JSoet commented 2 years ago

I'm not sure if I ran into the same issue, but I had a problem with a couple clicks not working in an afterEach (they seemed to work, cypress didn't say that they failed, but then the action in the UI didn't happen) and I added force: true and that resulted in them working.

shreejan-regmi01 commented 2 years ago

Problem still exists in v10.2.0

BathiyaL commented 1 year ago

As a temp solution I just add another it hook for data cleanup (not nice) Is there any workaround for this ?

kzahozhy commented 1 year ago

The only way for now is to add dummy test which will always be passed.

vbukin commented 1 year ago

why has not it fixed since 2018? Its really annoying bug ^( how to catch errors in a running test and delete the created data?

mishasgit commented 1 year ago

I still have the issue in 12.7 , but there is a workaround you can use .click({ force: true }) it worked for me

gabriel-syntax commented 1 year ago

Can we please get a fix for this?

Andor71 commented 1 year ago

Is this a joke, it passed like 4 years and haven't been fixed since ?

DenisBik commented 1 year ago

Hello! I encountered the same thing. If test fails - some of the components stop reacting to click() in afterEach hook. Even "force click" is not helping... Cypress V12.7. Are there any more suggestions? I have a lot of tests and they are all failing because of this issue...

yaobao1993 commented 1 year ago

I do encounter this issue too. After some investigation, here are some workarounds which works for me:

For click() API, Cypress.$(cssSelector).trigger('click') can be used;

For type() API, a custom function setInputValue() can work (for React);

const setInputValue = function (input: any, value: any) {
  const lastValue = input.value;
  input.value = value;
  const event: any = new Event('input', { bubbles: true });
  // Hack React 15
  event.simulated = true;
  // Hack React 16
  const tracker = input._valueTracker;
  if (tracker) {
    tracker.setValue(lastValue);
  }
  input.dispatchEvent(event);
};

And, cy.wait() works in this situation, so you can use it to wait if you have to.

Jonamarti commented 8 months ago

I understand using the after hook is discouraged ([https://docs.cypress.io/guides/references/best-practices#Using-after-or-afterEach-hooks]()) and we actually clean up right before each test run, but I find it quite frustrating having to launch the tests again and stop it 1 second later only for the app (DDBB) to have the initial state. Furthermore, I dont get why the code fails in the after hook even if discouraged, it's still a bug, right? Thanks!

darrenclose commented 7 months ago

5 years with no solution is quite a let down as this is causing a major issue in data cleanup for us. Our initial approach was to have it clean up on a blank test to start however if the previous set ran without issue then there would be no data to clean and thus fail the afterEach hook thus failing the rest of the run. So frustrating

goska-malaga commented 6 months ago

I actually cannot use force click as my after hook fails on loading a page and checking that intercepted call has status 200, it just doesn't wait as expected. I spent half a day thinking I must have made a mistake, but same code works if test pass and it actually looks like same rootcause. Considering that conditional actions are not a strength in Cypress I have hard time thinking how to clean up state before not to mention doing revolution to delete things from db (that could be a benefit but I am not sure we have ability to do that currently)

srclay commented 6 months ago

I've been having the same issue for days! Just stumbled across the workaround to add a test to the end of the run that will always pass. This solves the problem for the after all hook. I'm not using after each so can't comment on that. Needs to be fixed though!

abrugaro commented 2 months ago

This issue is still reproducible on Cypress 13.6.4