diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index 5291f6488358..3c9a8c1657ed 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -420,6 +420,11 @@ declare namespace Cypress { titlePath: string[] } + /** + * Information about current test retry + */ + currentRetry: number + /** * Information about the browser currently running the tests */ diff --git a/packages/driver/cypress/e2e/cypress/cypress.cy.js b/packages/driver/cypress/e2e/cypress/cypress.cy.js index e498308e7f54..dfa9e945e3f5 100644 --- a/packages/driver/cypress/e2e/cypress/cypress.cy.js +++ b/packages/driver/cypress/e2e/cypress/cypress.cy.js @@ -86,6 +86,96 @@ describe('driver/src/cypress/index', () => { }) }) + context('.currentRetry', () => { + describe('test is not retried', () => { + before(() => { + expect(Cypress.currentRetry).to.eq(0) + }) + + beforeEach(() => { + expect(Cypress.currentRetry).to.eq(0) + }) + + afterEach(() => { + expect(Cypress.currentRetry).to.eq(0) + }) + + after(() => { + expect(Cypress.currentRetry).to.eq(0) + }) + + it('correctly returns currentRetry', () => { + expect(Cypress.currentRetry).to.eq(0) + }) + }) + + describe('test is retried due to beforeEach hook failure', { retries: 1 }, () => { + before(() => { + expect(Cypress.currentRetry).to.be.oneOf([0, 1]) + }) + + beforeEach(() => { + expect(Cypress.currentRetry).to.eq(1) + }) + + it('correctly returns currentRetry', () => { + expect(Cypress.currentRetry).to.eq(1) + }) + + afterEach(() => { + expect(Cypress.currentRetry).to.eq(1) + }) + + after(() => { + expect(Cypress.currentRetry).to.eq(1) + }) + }) + + describe('test is retried due to test failure', { retries: 1 }, () => { + before(() => { + expect(Cypress.currentRetry).to.be.oneOf([0, 1]) + }) + + beforeEach(() => { + expect(Cypress.currentRetry).to.be.oneOf([0, 1]) + }) + + it('correctly returns currentRetry', () => { + expect(Cypress.currentRetry).to.eq(1) + }) + + afterEach(() => { + expect(Cypress.currentRetry).to.eq(1) + }) + + after(() => { + expect(Cypress.currentRetry).to.eq(1) + }) + }) + + describe('test is retried due to afterEach hook failure', { retries: 1 }, () => { + before(() => { + expect(Cypress.currentRetry).to.be.oneOf([0, 1]) + }) + + beforeEach(() => { + expect(Cypress.currentRetry).to.be.oneOf([0, 1]) + }) + + it('correctly returns currentRetry', () => { + expect(Cypress.currentRetry).to.be.oneOf([0, 1]) + }) + + afterEach(() => { + expect(Cypress.currentRetry).to.eq(1) + }) + + after(() => { + expect(Cypress.currentRetry).to.eq(1) + }) + }) + }) + context('.isCy', () => { it('returns true on cy, cy chainable', () => { expect(Cypress.isCy(cy)).to.be.true @@ -104,7 +194,7 @@ describe('driver/src/cypress/index', () => { }) }) - context('.Log', () => { + context('.log', () => { it('throws when passing non-object to Cypress.log()', () => { const fn = () => { Cypress.log('My Log') diff --git a/packages/driver/src/cypress.ts b/packages/driver/src/cypress.ts index beb6c763061e..1dfee6488b4e 100644 --- a/packages/driver/src/cypress.ts +++ b/packages/driver/src/cypress.ts @@ -787,6 +787,12 @@ class $Cypress { } } + get currentRetry (): number { + const ctx = this.cy.state('runnable').ctx + + return ctx?.currentTest?._currentRetry || ctx?.test?._currentRetry + } + static create (config: Record) { const cypress = new $Cypress()