I have a code where certain tests will always fail in CI environment. I would like to disable them based on an environment condition.
How to programmatically skip a
I use runtime skipping from Mocha for the same scenario as you're describing. It is the copy paste from the docs:
it('should only test in the correct environment', function() {
if (/* check test environment */) return this.skip();
// make assertions
});
As you can see, it skips the test based on environment. My own condition is if(process.env.NODE_ENV === 'continuous-integration')
.
It can be used to either statically to disable a test or entire suite, or dynamically skip it at runtime.
Here's an example runtime usage:
it('should only test in the correct environment', function() {
if (/* check test environment */) {
// make assertions
} else {
this.skip();
}
});
You can use my package mocha-assume to skip tests programmatically, but only from outside the tests. You use it like this:
assuming(myAssumption).it("does someting nice", () => {});
Mocha-assume will only run your test when myAssumption
is true
, otherwise it will skip it (using it.skip
) with a nice message.
Here's a more detailed example:
describe("My Unit", () => {
/* ...Tests that verify someAssuption is always true... */
describe("when [someAssumption] holds...", () => {
let someAssumption;
beforeAll(() => {
someAssumption = /* ...calculate assumption... */
});
assuming(someAssumption).it("Does something cool", () => {
/* ...test something cool... */
});
});
});
Using it this way, you can avoid cascading failures. Say the test "Does something cool"
would always fail when someAssumption does not hold - But this assumption was already tested above (in Tests that verify someAssuption is always true"
).
So the test failure does not give you any new information. In fact, it is even a false-positive: The test did not fail because "something cool" did not work, but because a precondition for the test was not satisfied. with mocha-assume
you can often avoid such false positives.
This is not really using mocha's features, rather tweaking it to get the behaviour I wanted.
I wanted to skip any subsequent 'it's' in my protractor mocha tests and one 'it' failed. This was because once one step of a journey test failed it was almost certain the rest would fail, and may take a long time and hog the build server if they are using browser waits for elements to appear on a page etc.
When just running standard mocha tests (not protractor) this can be achieved with global beforeEach and afterEach hooks by attaching a 'skipSubsequent' flag to the test's parent (describe) like this:
beforeEach(function() {
if(this.currentTest.parent.skipSubsequent) {
this.skip();
}
});
afterEach(function() {
if (this.currentTest.state === 'failed') {
this.currentTest.parent.skipSubsequent = 'true'
}
})
When attempting this with protractor and mocha it the scope of 'this' has changed and the code above does not work. You end up with an error message like 'error calling done()' and protractor halts.
Instead I ended up with the code below. Not the prettiest, but it ends up replacing the implementation of remaining test functions with a this.skip(). This will probably stop working if/when the internals of mocha change with later versions.
It was figured out through some trial and error by debugging and inspecting mocha's internals...helps make browser test suites complete sooner when the tests fail though.
beforeEach(function() {
var parentSpec = this.currentTest.parent;
if (!parentSpec.testcount) {
parentSpec.testCount = parentSpec.tests.length;
parentSpec.currentTestIndex = 0;
} else {
parentSpec.currentTestIndex = parentSpec.currentTestIndex + 1;
}
if (parentSpec.skipSubsequent) {
parentSpec.skipSubsequent = false;
var length = parentSpec.tests.length;
var currentIndex = parentSpec.currentTestIndex;
for (var i = currentIndex + 1; i < length; i++) {
parentSpec.tests[i].fn = function() {
this.skip();
};
}
}
});
afterEach(function() {
if (this.currentTest.state === 'failed') {
this.currentTest.parent.skipSubsequent = 'true'
}
});
mocha test/ --grep <pattern>
https://mochajs.org/
describe.skip
or it.skip
describe('Array', function() {
it.skip('#indexOf', function() {
// ...
});
});
describe.only
or it.only
describe('Array', function() {
it.only('#indexOf', function() {
// ...
});
});
More info at https://mochajs.org/#inclusive-tests