Skip to content

Commit

Permalink
beforeAll hook: list skipped tests
Browse files Browse the repository at this point in the history
  • Loading branch information
juergba committed Apr 2, 2020
1 parent c5fc2be commit c04abcb
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 62 deletions.
7 changes: 7 additions & 0 deletions lib/reporters/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,13 @@ Base.prototype.epilogue = function() {
Base.consoleLog(fmt, stats.pending);
}

// skipped
if (stats.skipped) {
fmt = color('fail', ' %d skipped');

Base.consoleLog(fmt, stats.skipped);
}

// failures
if (stats.failures) {
fmt = color('fail', ' %d failing');
Expand Down
6 changes: 6 additions & 0 deletions lib/reporters/spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var EVENT_SUITE_END = constants.EVENT_SUITE_END;
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING;
var EVENT_TEST_SKIPPED = constants.EVENT_TEST_SKIPPED;
var inherits = require('../utils').inherits;
var color = Base.color;

Expand Down Expand Up @@ -88,6 +89,11 @@ function Spec(runner, options) {
Base.consoleLog(indent() + color('fail', ' %d) %s'), ++n, test.title);
});

runner.on(EVENT_TEST_SKIPPED, function(test) {
var fmt = indent() + color('fail', ' - %s');
Base.consoleLog(fmt, test.title);
});

runner.once(EVENT_RUN_END, self.epilogue.bind(self));
}

Expand Down
23 changes: 20 additions & 3 deletions lib/runnable.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,15 @@ Runnable.prototype.isPassed = function() {
return !this.isPending() && this.state === constants.STATE_PASSED;
};

/**
* Return `true` if this Runnable has been skipped.
* @return {boolean}
* @private
*/
Runnable.prototype.isSkipped = function() {
return this.skipped || (this.parent && this.parent.isSkipped());
};

/**
* Set or get number of retries.
*
Expand Down Expand Up @@ -360,7 +369,11 @@ Runnable.prototype.run = function(fn) {
};

try {
callFnAsync(this.fn);
if (this.isPending() || this.isSkipped()) {
done();
} else {
callFnAsync(this.fn);
}
} catch (err) {
// handles async runnables which actually run synchronously
emitted = true;
Expand All @@ -376,7 +389,7 @@ Runnable.prototype.run = function(fn) {

// sync or promise-returning
try {
if (this.isPending()) {
if (this.isPending() || this.isSkipped()) {
done();
} else {
callFn(this.fn);
Expand Down Expand Up @@ -481,7 +494,11 @@ var constants = utils.defineConstants(
/**
* Value of `state` prop when a `Runnable` has passed
*/
STATE_PASSED: 'passed'
STATE_PASSED: 'passed',
/**
* Value of `state` prop when a `Runnable` has been skipped by failing hook
*/
STATE_SKIPPED: 'skipped'
}
);

Expand Down
117 changes: 62 additions & 55 deletions lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ var HOOK_TYPE_BEFORE_ALL = Suite.constants.HOOK_TYPE_BEFORE_ALL;
var EVENT_ROOT_SUITE_RUN = Suite.constants.EVENT_ROOT_SUITE_RUN;
var STATE_FAILED = Runnable.constants.STATE_FAILED;
var STATE_PASSED = Runnable.constants.STATE_PASSED;
var STATE_SKIPPED = Runnable.constants.STATE_SKIPPED;
var dQuote = utils.dQuote;
var ngettext = utils.ngettext;
var sQuote = utils.sQuote;
var stackFilter = utils.stackTraceFilter();
var stringify = utils.stringify;
Expand Down Expand Up @@ -106,6 +106,10 @@ var constants = utils.defineConstants(
* Emitted when {@link Test} becomes pending
*/
EVENT_TEST_PENDING: 'pending',
/**
* Emitted when {@link Test} becomes skipped
*/
EVENT_TEST_SKIPPED: 'skipped',
/**
* Emitted when {@link Test} execution has failed, but will retry
*/
Expand All @@ -122,8 +126,7 @@ module.exports = Runner;
* @public
* @class
* @param {Suite} suite Root suite
* @param {boolean} [delay] Whether or not to delay execution of root suite
* until ready.
* @param {boolean} [delay] Whether to delay execution of root suite until ready.
*/
function Runner(suite, delay) {
var self = this;
Expand Down Expand Up @@ -271,12 +274,8 @@ Runner.prototype.checkGlobals = function(test) {
this._globals = this._globals.concat(leaks);

if (leaks.length) {
var format = ngettext(
leaks.length,
'global leak detected: %s',
'global leaks detected: %s'
);
var error = new Error(util.format(format, leaks.map(sQuote).join(', ')));
var msg = 'global leak(s) detected: %s';
var error = new Error(util.format(msg, leaks.map(sQuote).join(', ')));
this.fail(test, error);
}
};
Expand All @@ -287,9 +286,11 @@ Runner.prototype.checkGlobals = function(test) {
* @private
* @param {Test} test
* @param {Error} err
* @param {boolean} [force=false] - Whether to fail a pending test.
*/
Runner.prototype.fail = function(test, err) {
if (test.isPending()) {
Runner.prototype.fail = function(test, err, force) {
force = force === true;
if (test.isPending() && !force) {
return;
}

Expand Down Expand Up @@ -361,7 +362,7 @@ Runner.prototype.hook = function(name, fn) {
var hooks = suite.getHooks(name);
var self = this;

function next(i) {
function nextHook(i) {
var hook = hooks[i];
if (!hook) {
return fn();
Expand Down Expand Up @@ -419,18 +420,29 @@ Runner.prototype.hook = function(name, fn) {
return fn(errForbid);
}
} else if (err) {
self.failHook(hook, err);
// stop executing hooks, notify callee of hook err
return fn(err);
if (name === HOOK_TYPE_BEFORE_ALL) {
self.failHook(hook, err);
suite.tests.forEach(function(test) {
test.skipped = true;
});
suite.suites.forEach(function(suite) {
suite.skipped = true;
});
hooks = [];
} else {
self.failHook(hook, err);
// stop executing hooks, notify callee of hook err
return fn(err);
}
}
self.emit(constants.EVENT_HOOK_END, hook);
delete hook.ctx.currentTest;
next(++i);
nextHook(++i);
});
}

Runner.immediately(function() {
next(0);
nextHook(0);
});
};

Expand Down Expand Up @@ -587,7 +599,7 @@ Runner.prototype.runTests = function(suite, fn) {
}
}

function next(err, errSuite) {
function nextTest(err, errSuite) {
// if we bail after first err
if (self.failures && suite._bail) {
tests = [];
Expand Down Expand Up @@ -624,24 +636,29 @@ Runner.prototype.runTests = function(suite, fn) {
// test suite don't do any immediate recursive loops. Thus,
// allowing a JS runtime to breathe.
if (self._grep !== self._defaultGrep) {
Runner.immediately(next);
Runner.immediately(nextTest);
} else {
next();
nextTest();
}
return;
}

// skipped by failing hook
if (test.isSkipped()) {
test.state = STATE_SKIPPED;
self.emit(constants.EVENT_TEST_SKIPPED, test);
return nextTest();
}

// static skip, no hooks are executed
if (test.isPending()) {
if (self.forbidPending) {
test.isPending = alwaysFalse;
self.fail(test, new Error('Pending test forbidden'));
delete test.isPending;
self.fail(test, new Error('Pending test forbidden'), true);
} else {
self.emit(constants.EVENT_TEST_PENDING, test);
}
self.emit(constants.EVENT_TEST_END, test);
return next();
return nextTest();
}

// execute test and hook(s)
Expand All @@ -650,9 +667,7 @@ Runner.prototype.runTests = function(suite, fn) {
// conditional skip within beforeEach
if (test.isPending()) {
if (self.forbidPending) {
test.isPending = alwaysFalse;
self.fail(test, new Error('Pending test forbidden'));
delete test.isPending;
self.fail(test, new Error('Pending test forbidden'), true);
} else {
self.emit(constants.EVENT_TEST_PENDING, test);
}
Expand All @@ -662,7 +677,7 @@ Runner.prototype.runTests = function(suite, fn) {
self.suite = errSuite || self.suite;
return self.hookUp(HOOK_TYPE_AFTER_EACH, function(e, eSuite) {
self.suite = origSuite;
next(e, eSuite);
nextTest(e, eSuite);
});
}
if (err) {
Expand All @@ -674,14 +689,12 @@ Runner.prototype.runTests = function(suite, fn) {
// conditional skip within it
if (test.pending) {
if (self.forbidPending) {
test.isPending = alwaysFalse;
self.fail(test, new Error('Pending test forbidden'));
delete test.isPending;
self.fail(test, new Error('Pending test forbidden'), true);
} else {
self.emit(constants.EVENT_TEST_PENDING, test);
}
self.emit(constants.EVENT_TEST_END, test);
return self.hookUp(HOOK_TYPE_AFTER_EACH, next);
return self.hookUp(HOOK_TYPE_AFTER_EACH, nextTest);
} else if (err) {
var retry = test.currentRetry();
if (retry < test.retries()) {
Expand All @@ -693,31 +706,27 @@ Runner.prototype.runTests = function(suite, fn) {

// Early return + hook trigger so that it doesn't
// increment the count wrong
return self.hookUp(HOOK_TYPE_AFTER_EACH, next);
return self.hookUp(HOOK_TYPE_AFTER_EACH, nextTest);
} else {
self.fail(test, err);
}
self.emit(constants.EVENT_TEST_END, test);
return self.hookUp(HOOK_TYPE_AFTER_EACH, next);
return self.hookUp(HOOK_TYPE_AFTER_EACH, nextTest);
}

test.state = STATE_PASSED;
self.emit(constants.EVENT_TEST_PASS, test);
self.emit(constants.EVENT_TEST_END, test);
self.hookUp(HOOK_TYPE_AFTER_EACH, next);
self.hookUp(HOOK_TYPE_AFTER_EACH, nextTest);
});
});
}

this.next = next;
this.next = nextTest;
this.hookErr = hookErr;
next();
nextTest();
};

function alwaysFalse() {
return false;
}

/**
* Run the given `suite` and invoke the callback `fn()` when complete.
*
Expand All @@ -738,7 +747,7 @@ Runner.prototype.runSuite = function(suite, fn) {

this.emit(constants.EVENT_SUITE_BEGIN, (this.suite = suite));

function next(errSuite) {
function nextSuite(errSuite) {
if (errSuite) {
// current suite failed on a hook from errSuite
if (errSuite === suite) {
Expand All @@ -765,33 +774,33 @@ Runner.prototype.runSuite = function(suite, fn) {
// See comment in `this.runTests()` for more information.
if (self._grep !== self._defaultGrep) {
Runner.immediately(function() {
self.runSuite(curr, next);
self.runSuite(curr, nextSuite);
});
} else {
self.runSuite(curr, next);
self.runSuite(curr, nextSuite);
}
}

function done(errSuite) {
self.suite = suite;
self.nextSuite = next;
self.nextSuite = nextSuite;

// remove reference to test
delete self.test;

self.hook(HOOK_TYPE_AFTER_ALL, function() {
self.hook(HOOK_TYPE_AFTER_ALL, function cbHook() {
self.emit(constants.EVENT_SUITE_END, suite);
fn(errSuite);
});
}

this.nextSuite = next;
this.nextSuite = nextSuite;

this.hook(HOOK_TYPE_BEFORE_ALL, function(err) {
if (err) {
return done();
}
self.runTests(suite, next);
this.hook(HOOK_TYPE_BEFORE_ALL, function cbHook(/* err */) {
// if (err) {
// return done();
// }
self.runTests(suite, nextSuite);
});
};

Expand Down Expand Up @@ -850,9 +859,7 @@ Runner.prototype.uncaught = function(err) {
return;
} else if (runnable.isPending()) {
// report 'pending test' retrospectively as failed
runnable.isPending = alwaysFalse;
this.fail(runnable, err);
delete runnable.isPending;
this.fail(runnable, err, true);
return;
}

Expand Down
Loading

0 comments on commit c04abcb

Please sign in to comment.