Skip to content

Commit

Permalink
feat: provide the ability to modify retries count from plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
eGavr committed Jul 4, 2017
1 parent cbe6bd5 commit fc1a372
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 10 deletions.
25 changes: 17 additions & 8 deletions lib/runner/mocha-runner/retry-mocha-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ module.exports = class RetryMochaRunner extends EventEmitter {
super();

this._mocha = mocha;
this._retriesLeft = config.retry;
this._config = config;
this._retriesPerformed = 0;

this._handleFailEvent(mocha, RunnerEvents.TEST_FAIL);
this._handleErrorEvent(mocha, RunnerEvents.ERROR);
Expand All @@ -24,7 +25,7 @@ module.exports = class RetryMochaRunner extends EventEmitter {
}

_handleFail(event, failed) {
if (!this._retriesLeft) {
if (!this._hasRetriesLeft()) {
this.emit(event, failed);
return;
}
Expand All @@ -46,24 +47,32 @@ module.exports = class RetryMochaRunner extends EventEmitter {
}

_emitRetry(failed) {
this._shouldRetry = true;
this.emit(RunnerEvents.RETRY, _.extend(failed, {retriesLeft: this._retriesLeft - 1}));
}

run() {
this._shouldRetry = false;

return this._mocha.run()
.then((stats) => Boolean(stats.failed) && this._retry());
.then(() => this._retry());
}

_retry() {
if (this._hasRetriesLeft()) {
--this._retriesLeft;

this._mocha.reinit();
return this.run();
if (!this._shouldRetry) {
return;
}

++this._retriesPerformed;
this._mocha.reinit();
return this.run();
}

_hasRetriesLeft() {
return this._retriesLeft > 0;
}

get _retriesLeft() {
return this._config.retry - this._retriesPerformed;
}
};
96 changes: 94 additions & 2 deletions test/lib/runner/mocha-runner/retry-mocha-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ describe('mocha-runner/retry-mocha-runner', () => {
beforeEach(() => mochaAdapter = createMochaAdapter());
afterEach(() => sandbox.restore());

describe('constructor', () => {
it('should provide the ability to mutate the passed config', () => {
const config = {retry: 1};
const retryMochaRunner = createRetryMochaRunner(config);

mochaAdapter.run.callsFake(emitEvent(RunnerEvents.TEST_FAIL, createTestStub()));

config.retry = 0;

return retryMochaRunner.run()
.then(() => assert.calledOnce(mochaAdapter.run));
});
});

describe('run', () => {
describe('on test fail', () => {
it('should emit "TEST_FAIL" event if no retries were set', () => {
Expand All @@ -49,6 +63,36 @@ describe('mocha-runner/retry-mocha-runner', () => {
.then(() => assert.calledOnceWith(onTestFail, test));
});

it('should not retry if no retries were set', () => {
const retryMochaRunner = createRetryMochaRunner({retry: 0});

mochaAdapter.run.callsFake(emitEvent(RunnerEvents.TEST_FAIL, createTestStub()));

return retryMochaRunner.run()
.then(() => assert.calledOnce(mochaAdapter.run));
});

it('should emit "TEST_FAIL" event if retries count is below zero', () => {
const retryMochaRunner = createRetryMochaRunner({retry: -1});
const onTestFail = sinon.spy().named('onTestFail');
const test = createTestStub();

mochaAdapter.run.callsFake(emitEvent(RunnerEvents.TEST_FAIL, test));
retryMochaRunner.on(RunnerEvents.TEST_FAIL, onTestFail);

return retryMochaRunner.run()
.then(() => assert.calledOnceWith(onTestFail, test));
});

it('should not retry if retries count is below zero', () => {
const retryMochaRunner = createRetryMochaRunner({retry: -1});

mochaAdapter.run.callsFake(emitEvent(RunnerEvents.TEST_FAIL));

return retryMochaRunner.run()
.then(() => assert.calledOnce(mochaAdapter.run));
});

it('should emit "RETRY" event if retries were set', () => {
const retryMochaRunner = createRetryMochaRunner({retry: 1});
const onTestRetry = sinon.spy().named('onTestRetry');
Expand Down Expand Up @@ -128,6 +172,15 @@ describe('mocha-runner/retry-mocha-runner', () => {
.then(() => assert.calledOnceWith(onErr, 'err'));
});

it('should not retry if no runnable passed', () => {
const retryMochaRunner = createRetryMochaRunner({retry: 1});

mochaAdapter.run.callsFake(emitEvent(RunnerEvents.ERROR, 'err'));

return retryMochaRunner.run()
.then(() => assert.calledOnce(mochaAdapter.run));
});

it('should emit "ERROR" event if a failed runnable does not have a parent', () => {
const retryMochaRunner = createRetryMochaRunner({retry: 1});
const onErr = sinon.spy().named('onErr');
Expand All @@ -140,6 +193,15 @@ describe('mocha-runner/retry-mocha-runner', () => {
.then(() => assert.calledOnceWith(onErr, 'err', runnable));
});

it('should not retry if a failed runnable does not have a parent', () => {
const retryMochaRunner = createRetryMochaRunner({retry: 1});

mochaAdapter.run.callsFake(emitEvent(RunnerEvents.ERROR, 'err', createRunnableStub()));

return retryMochaRunner.run()
.then(() => assert.calledOnce(mochaAdapter.run));
});

it('should emit "ERROR" event if no retries were set', () => {
const retryMochaRunner = createRetryMochaRunner({retry: 0});
const onErr = sinon.spy().named('onErr');
Expand All @@ -152,6 +214,36 @@ describe('mocha-runner/retry-mocha-runner', () => {
.then(() => assert.calledOnceWith(onErr, 'err', runnable));
});

it('should not retry if no retries were set', () => {
const retryMochaRunner = createRetryMochaRunner({retry: 0});

mochaAdapter.run.callsFake(emitEvent(RunnerEvents.ERROR, 'err', createTestStub({})));

return retryMochaRunner.run()
.then(() => assert.calledOnce(mochaAdapter.run));
});

it('should emit "ERROR" event if retries count is below zero', () => {
const retryMochaRunner = createRetryMochaRunner({retry: -1});
const onErr = sinon.spy().named('onErr');
const runnable = createTestStub({});

mochaAdapter.run.callsFake(emitEvent(RunnerEvents.ERROR, 'err', runnable));
retryMochaRunner.on(RunnerEvents.ERROR, onErr);

return retryMochaRunner.run()
.then(() => assert.calledOnceWith(onErr, 'err', runnable));
});

it('should not retry if retries count is below zero', () => {
const retryMochaRunner = createRetryMochaRunner({retry: -1});

mochaAdapter.run.callsFake(emitEvent(RunnerEvents.ERROR, 'err', createTestStub({})));

return retryMochaRunner.run()
.then(() => assert.calledOnce(mochaAdapter.run));
});

it('should emit "RETRY" event if retries were set', () => {
const retryMochaRunner = createRetryMochaRunner({retry: 1});
const onRetry = sinon.spy().named('onRetry');
Expand Down Expand Up @@ -202,7 +294,7 @@ describe('mocha-runner/retry-mocha-runner', () => {
it('should submit for retry a failed mocha', () => {
const retryMochaRunner = createRetryMochaRunner({retry: 1});

mochaAdapter.run.callsFake(emitEvent(RunnerEvents.ERROR));
mochaAdapter.run.callsFake(emitEvent(RunnerEvents.ERROR, 'err', createRunnableStub({})));

return retryMochaRunner.run()
.then(() => assert.calledTwice(mochaAdapter.run));
Expand All @@ -211,7 +303,7 @@ describe('mocha-runner/retry-mocha-runner', () => {
it('should reinit mocha before a retry', () => {
const retryMochaRunner = createRetryMochaRunner({retry: 1});

mochaAdapter.run.callsFake(emitEvent(RunnerEvents.ERROR));
mochaAdapter.run.callsFake(emitEvent(RunnerEvents.ERROR, 'err', createRunnableStub({})));

return retryMochaRunner.run()
.then(() => assert.callOrder(mochaAdapter.reinit, mochaAdapter.run));
Expand Down

0 comments on commit fc1a372

Please sign in to comment.