Skip to content
This repository has been archived by the owner on May 24, 2021. It is now read-only.

Commit

Permalink
feat: add Cypress.currentTest.retries support
Browse files Browse the repository at this point in the history
  • Loading branch information
kuceb committed Feb 15, 2019
1 parent f65b9ba commit b3a85be
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 24 deletions.
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,20 @@ require('cypress-plugin-retries')

### Usage

Use the environment variable `CYPRESS_RETRIES` to set the retry number:
**[Preferred]** On a per-test or per-hook basis, set the retry number:
> Note: this plugin **adds Cypress.currentTest** and you should only use it if you're using this plugin.
```js
Cypress.currentTest.retries(2)
```
**or** Use the environment variable `CYPRESS_RETRIES` to set the retry number for **all spec files**:
```bash
CYPRESS_RETRIES=2 npm run cypress
```
**or** Use `Cypress.env('RETRIES')` in your spec file:
**or** Use `Cypress.env('RETRIES')` in your spec file to set the retry number for **all tests**:
```js
Cypress.env('RETRIES', 2)
```
**or** Use `mocha`'s `this.retries(n)` inside of a test:
**or [undersirable]** Use `mocha`'s `this.retries(n)` inside of a test:
> Note: **must use `function()` notation, not arrows `()=>{}`**
```js
it('test', function() {
Expand Down
4 changes: 3 additions & 1 deletion cypress.json
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
{}
{
"projectId": "3e57fb"
}
118 changes: 107 additions & 11 deletions cypress/integration/spec.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,46 @@
/// <reference types="cypress"/>

Cypress.config('defaultCommandTimeout', 100)
const retryNum = 4
Cypress.env('RETRIES', retryNum)
Cypress.env('NO_FAIL', false)
Cypress.env('RETRIES', 0)

const _ = Cypress._

describe('Cypress.currentTest', () => {
let error
let curtest
try{
curtest = Cypress.currentTest
} catch(e) {
error = e
}
let lastId

it('throws error outside spec', function() {
expect(error).ok.property('message').contains('currentTest')
expect(this._runnable).eq(Cypress.currentTest)
curtest = Cypress.currentTest
expect(lastId).eq(this._runnable.id)
})

beforeEach(() => {
lastId = Cypress.currentTest.id
})
// Cypress.log({message:'set'})
it('gets correct runnable', () => {
expect(lastId).eq(Cypress.currentTest.id)
})
})

describe('deeply nested', () => {
const pushHook = name => {
console.log(`%c${name}`, 'color:blue')
// console.log(`%c${name}`, 'color:blue')
expect(name).ok
hooks.push(name)
}
let hooks = []
let foo = 0

const failUntil = num => {
if (Cypress.env('NO_FAIL')) {
return
}
if (num === true) {
expect(false).ok
}
Expand All @@ -28,12 +51,11 @@ describe('deeply nested', () => {

cy.on('fail', err => {
hooks.push('FAIL')
// debugger
throw err
})

Cypress.env('RETRIES', 4)
beforeEach(() => {
Cypress.currentTest.retries(4)
pushHook('BE 0')
foo++
})
Expand Down Expand Up @@ -129,8 +151,6 @@ describe('deeply nested', () => {

describe('async', () => {
it('pass using done', function(done) {
Cypress.env('RETRIES', 4)

cy.on('fail', err => {
done()
})
Expand All @@ -140,6 +160,7 @@ describe('async', () => {

describe('fail 10 times', function() {
this.retries(10)

let foo = 0
beforeEach(() => {
foo++
Expand All @@ -150,3 +171,78 @@ describe('fail 10 times', function() {
expect(this._runnable.currentRetry()).eq(10)
})
})

describe('retries set via Cypress.currentTest.retries', () => {
let logs = []

beforeEach(() => {
Cypress.env('RETRIES', 0)
if (!Cypress.currentTest._currentRetry) {
logs = []
}
cy.on('log:added', (attr, log) => {
logs.push(attr)
})
Cypress.currentTest.retries(1)
})

it('can set retries in hooks', () => {
expect(logs.length).eq(1)
})

it('prefers test retries over env var', () => {
Cypress.currentTest.retries(2)

expect(logs.length, 'log length').eq(2)
cy.log('foo')
})
})

describe('after all hook', () => {
describe('after hook fails test', () => {
let didFail = false

describe('should fail in after hook', () => {
it('fails but caught', () => {
expect(true).ok
})
after(() => {
cy.on('fail', err => {
didFail = true
// Cypress.log({message: didFail})
// throw err
})
expect(false).ok
})
})
describe('verify prev fail', () => {
it('did fail', () => {
expect(didFail).ok
})
})
})
describe('after hook lets test fail', () => {
let didFail = false
let didRunAfterHook = false
describe('should fail in after hook', () => {
it('fails but caught', () => {
cy.on('fail', err => {
didFail = true
// Cypress.log({message: didFail})
// throw err
})
expect(false).ok
})
after(() => {
didRunAfterHook = true
expect(true).ok
})
})
describe('verify prev fail', () => {
it('did fail', () => {
expect(didFail).ok
expect(didRunAfterHook).ok
})
})
})
})
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"description": "Cypress plugin allowing tests to retry a configurable amount of times",
"main": "src",
"scripts": {
"test-e2e": "node test.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
Expand Down
11 changes: 11 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// <reference types="cypress" />

namespace Cypress {
interface Cypress {
/**
* Gets the current test. Added by cypress-plugin-retries
*/
currentTest: Mocha.ISuiteCallbackContext
}
}

24 changes: 22 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const _ = Cypress._
let logs = []

const getDefaultRetries = () => {
Expand Down Expand Up @@ -46,8 +47,8 @@ Cypress.runner.onRunnableRun = function(runnableRun, runnable, args) {
const next = args[0]

if (isAfterAllHook) {
test.err = null
if (test.state !== 'failed') {
test.err = null
test.state = 'passed'
}
}
Expand Down Expand Up @@ -96,6 +97,12 @@ Cypress.runner.onRunnableRun = function(runnableRun, runnable, args) {
return _onRunnableRun.apply(this, [runnableRun, runnable, args])
}

const pluginError = (message) => {throw new Error(`[cypress-plugin-retries]: ${message}`)}

// Cypress.Commands.add('retries', (n) => {

// })

addGlobalStyle(/*css*/ `
.command-state-retry {
color: orange
Expand Down Expand Up @@ -170,4 +177,17 @@ function addGlobalStyle(css) {

const debug = function() {
// console.log.apply(this, arguments)
}
}

Object.defineProperty(Cypress, 'currentTest', {
get: function(){
const r = cy.state('runnable')
if (!r) {
const err = new Error()
err.message = 'Cypress.currentTest cannot be accessed outside a test or hook (it, before, after, beforeEach, afterEach)'
throw err
}
return r && r.ctx.currentTest || r
}
})

8 changes: 1 addition & 7 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
const cypress = require('cypress')

cypress.run({
reporter: 'junit',
browser: 'electron',
config: {
// baseUrl: 'http://localhost:8080',
chromeWebSecurity: false,
},
spec: 'cypress/integration/spec.js',
}).then(res => {
console.log(res)
})

0 comments on commit b3a85be

Please sign in to comment.