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
You can skip tests by placing an x in front of the describe or it block, or placing a .skip
after it.
xit('should work', function (done) {});
describe.skip('features', function() {});
You can also run a single test by placing a .only
on the test. for instance
describe('feature 1', function() {});
describe.only('feature 2', function() {});
describe('feature 3', function() {});
Only the feature 2 block would run in this case.
There doesn't appear to be a way to programmatically skip tests, but you could just do some sort of check in a beforeEach
statement and only run the test if the flag was set.
beforeEach(function(){
if (wrongEnvironment){
runTest = false
}
}
describe('feature', function(){
if(runTest){
it('should work', function(){
// Test would not run or show up if runTest was false,
}
}
}
It depends how you want to programmatically skip the test. If the conditions for skipping can be determined before any test code is run, then you can just call it
or it.skip
as needed, based on a condition. For instance, this will skip some tests if the environment variable ONE
is set to any value:
var conditions = {
"condition one": process.env["ONE"] !== undefined
// There could be more conditions in this table...
};
describe("conditions that can be determined ahead of time", function () {
function skip_if(condition, name, callback) {
var fn = conditions[condition] ? it.skip: it;
fn(name, callback);
};
skip_if("condition one", "test one", function () {
throw new Error("skipped!");
});
// async.
skip_if("condition one", "test one (async)", function (done) {
throw new Error("skipped!");
});
skip_if("condition two", "test two", function () {
console.log("test two!");
});
});
If the conditions you want to check can only be determined at test time, it is a bit more complicated. If you do not want to access anything not strictly speaking part of the testing API, then you could do this:
describe("conditions that can be determined at test time", function () {
var conditions = {};
function skip_if(condition, name, callback) {
if (callback.length) {
it(name, function (done) {
if (conditions[condition])
done();
else
callback(done);
});
}
else {
it(name, function () {
if (conditions[condition])
return;
callback();
});
}
};
before(function () {
conditions["condition one"] = true;
});
skip_if("condition one", "test one", function () {
throw new Error("skipped!");
});
// async.
skip_if("condition one", "test one (async)", function (done) {
throw new Error("skipped!");
});
skip_if("condition two", "test two", function () {
console.log("test two!");
});
});
Whereas my first example was marking the tests as formally skipped (aka "pending"), the method I've just shown will just avoid performing the actual test but the tests won't be marked as formally skipped. They will be marked as passed. If you absolutely want to have them skipped I don't know of any way short of accessing parts that are not properly speaking part of the testing API:
describe("conditions that can be determined at test time", function () {
var condition_to_test = {}; // A map from condition names to tests.
function skip_if(condition, name, callback) {
var test = it(name, callback);
if (!condition_to_test[condition])
condition_to_test[condition] = [];
condition_to_test[condition].push(test);
};
before(function () {
condition_to_test["condition one"].forEach(function (test) {
test.pending = true; // Skip the test by marking it pending!
});
});
skip_if("condition one", "test one", function () {
throw new Error("skipped!");
});
// async.
skip_if("condition one", "test one (async)", function (done) {
throw new Error("skipped!");
});
skip_if("condition two", "test two", function () {
console.log("test two!");
});
});
Say I wanted to skip my parametrized test if my test description contained the string "foo", I would do this:
// Skip parametrized test if description contains the string "foo"
(test.description.indexOf("foo") === -1 ? it : it.skip)("should test something", function (done) {
// Code here
});
// Parametrized tests
describe("testFoo", function () {
test({
description: "foo" // This will skip
});
test({
description: "bar" // This will be tested
});
});
In your case, I believe that if you wanted to check environment variables, you could use NodeJS's:
process.env.ENV_VARIABLE
For example (Warning: I haven't tested this bit of code!), maybe something like this:
(process.env.NODE_ENV.indexOf("prod") === -1 ? it : it.skip)("should...", function(done) {
// Code here
});
Where you can set ENV_VARIABLE to be whatever you are keying off of, and using that value, skip or run the test. (FYI the documentation for the NodeJS' process.env is here: https://nodejs.org/api/process.html#process_process_env)
I won't take complete credit for the first part of this solution, I found and tested the answer and it worked perfectly to skip tests based on a simple condition through this resource: https://github.com/mochajs/mocha/issues/591
Hope this helps! :)
This answer does work for ES6.
Instead of:
describe('your describe block', () => {
You want:
(condition ? describe : describe.skip)('your describe block', () => {
This conditionally skips all tests in the describe block IF the condition is false.
Or, instead of:
it('your it block', () => {
You want:
(condition ? it : it.skip)('your it block', () => {
This conditionally skips one test IF the condition is false.
As @danielstjules answered here there is a way to skip test. @author of this topic has copied answer from github.com mochajs discussion, but there is no info in what version of mocha it available.
I'm using grunt-mocha-test module for integrating mocha test functionality in my project. Jumping to last (for now) version - 0.12.7 bring me mocha version 2.4.5 with implementation of this.skip().
So, in my package.json
"devDependencies": {
"grunt-mocha-test": "^0.12.7",
...
And then
npm install
And it make me happy with this hook:
describe('Feature', function() {
before(function () {
if (!Config.isFeaturePresent) {
console.log('Feature not configured for that env, skipping...');
this.skip();
}
});
...
it('should return correct response on AB', function (done) {
if (!Config.isABPresent) {
return this.skip();
}
...
Please don't. A test that doesn't work consistently across environments should be acknowledged as such by your build infrastructure. And it can be very disorienting when the CI builds have a different number of tests run than local.
Also it screws up repeatability. If different tests run on the server and local I can have tests failing in dev and passing in CI or vice versa. There's no forcing function and I have no way to quickly and accurately correct a failed build.
If you must turn off tests between environments, instead of conditionally running tests, tag your tests and use a filter to eliminate tests that don't work in certain build targets. That way everybody knows what's going on and it tempers their expectations. It also lets everybody know that there's inconsistency in the test framework, and someone might have a solution that gets them running properly again. If you just mute the test they might not even know there's a problem.