Reputation: 1879
Blocked by a Cypress custom command not executing properly within a spec's after hook when a test failed. Experimented with the following minimal spec examples.
Context
Testing two Cypress custom commands:
cy.cmdLogin()
: Standard username password authenticationcy.cmdLogout()
: cy.get('logout_button').click()
Spec #1, cy.cmdLogout()
in after hook does work
Very simple Cypress tests spec, test cy.cmdLogin()
with after hook with cy.cmdLogout()
, works perfectly:
context('SPEC Login', () => {
after('AFTER Logout', () => {
if (this.successLogin) {
cy.cmdLogout().then(() => {
cy.log('Logout Success');
});
}
});
it('TEST Login', () => {
cy.cmdLogin().then(() => {
cy.log('Login Success');
this.successLogin = true;
});
});
});
Spec #2, cy.cmdLogout()
in after hook does not work
Modified Cypress tests spec, test cy.cmdLogin()
with after hook with cy.cmdLogout()
, now added a test that forced failure expect(false).to.be.a('boolean').to.be.true;
. The after hook cy.cmdLogout()
is called and fails:
Verified that Cypress could handle cy.get('logout_button')
without failure.
Yet, extending with .click()
, cy.get('logout_button').click()
, Cypress would throw an error: Can not perform click()
on undefined
.
context('SPEC Login', () => {
after('AFTER Logout', () => {
if (this.successLogin) {
cy.cmdLogout().then(() => {
cy.log('Logout Success');
});
}
});
it('TEST Login', () => {
cy.cmdLogin().then(() => {
cy.log('Login Success');
this.successLogin = true;
});
});
it('TEST Fail', () => {
expect(false).to.be.a('boolean').to.be.true;
});
});
Spec #3, removed after hook, cy.cmdLogout()
moved to another test does work
Modified Cypress tests spec again and removed after hook, test cy.cmdLogin()
, test forced failure, and now test cy.cmdLogout()
. This works perfectly:
context('SPEC Login', () => {
it('TEST Login', () => {
cy.cmdLogin().then(() => {
cy.log('Login Success');
this.successLogin = true;
});
});
it('TEST Fail', () => {
expect(false).to.be.a('boolean').to.be.true;
});
it('TEST Logout', () => {
if (this.successLogin) {
cy.cmdLogout().then(()=> {
cy.task('log', 'Logout Success');
});
}
});
});
Insight as to why Cypress is finicky with spec's after hook would be very much appreciated
Upvotes: 2
Views: 620
Reputation: 31944
The short answer (for the general situation) is change after()
hook to before()
hook, but in your case that wouldn't work because this.successLogin
will always be undefined inside a before
.
You would need to create a cy.isLoggedIn()
command or call cy.cmdLogout()
unconditionally.
To get after()
the logic working on a fail, use
after('AFTER Logout', () => {
cy.cmdLogout()
});
Cypress.on('fail', (error, runnable) => {
cy.cmdLogout()
throw error
})
which is equivalent to this in plain javascript
try {
some-code-that-might-error()
cy.cmdLogout() // does not run if error occurs
} catch (error) {
cy.cmdLogout() // do the logout in error situation
}
Upvotes: 1