w3resource

Delayed root suite pending tests, exclusive tests and inclusive tests


Delayed root suite

There cases when you need to perform asynchronous operations before any suites are run, in such case you may want to delay the root suite. You should run mocha with the -delay flag. This attaches to the global context, a special callback function, run().

setTimeout(function() {
  // do some setup

  describe('my suite', function() {
    // ...
  });

  run();
}, 5000);

Pending tests

A pending test is a test that does not have a callback. Consider the test below:

describe('Array', function() {
  describe('#indexOf()', function() {
    // pending test is below
    it('has to return -1 when the value is not present');
  });
});

The pending tests will be included in the test results, and will be marked as pending. A pending test will not be considered a failed test.

Exclusive tests

The exclusively feature enables you to run only the specified suite or test-case by appending .only to the function. An example of executing only a particular suite is shown below:

describe('Array', function() {
  describe.only('#indexOf()', function() {
    // ...
  });
});

It should be noted that all the nested suites will be executed.

An example of executing an individual test case is shown below:

describe('Array', function() {
  describe('#indexOf()', function() {
    it.only('has to return -1 unless present', function() {
      // ...
    });

    it('has to return the index when present', function() {
      // ...
    });
  });
});

In versions before v3.0.0, .only() used string matching to decide the tests to execute; this is no longer in use. In v3.0.0 and above, we can use .only multiple times to define a subset of test to run:

describe('Array', function() {
  describe('#indexOf()', function() {
    it.only('has to return -1 unless present', function() {
      // this test will be run
    });

    it.only('has to return the index when present', function() {
      // this test will also be run
    });

    it('has  to return -1 if called with a non-Array context', function() {
      // this test will not be run
    });
  });
});

You can also choose multiple suites:

describe('Array', function() {
  describe.only('#indexOf()', function() {
    it('has to return -1 unless present', function() {
      // this test runs
    });

    it('has to return the index when present', function() {
      // this test will equally be run
    });
  });

  describe.only('#concat()', function() {
    it('has to return a new Array', function() {
      // this test will run as well
    });
  });

  describe('#slice()', function() {
    it('has to return a new Array', function() {
      // this test won?t run
    });
  });
});

However, tests will have precedence:

describe('Array', function() {
  describe.only('#indexOf()', function() {
    it.only('has to return -1 unless present', function() {
      // this test runs
    });

    it('has to return the index when present', function() {
      // this test won?t run
    });
  });
});

It should be noted that if Hooks are present they will still be executed.

Inclusive tests

The inclusive feature is the inverse of the .only(). When you append .skip(), you can tell Mocha to ignore test case(s). Anything that is skipped is marked as pending, and will be reported as pending. Below is an example of skipping an individual test:

describe('Array', function() {
  describe('#indexOf()', function() {
    it.skip('has to return -1 unless present', function() {
      // this test won?t be run
    });

    it('has to return the index when present', function() {
      // this test is run
    });
  });
});

You can equally put .skip() on an entire suite. This is equivalent to appending .skip() on onto all the tests that are in the suite. The hooks in the suite will also be skipped.

describe('Array', function() {
  describe.skip('#indexOf()', function() {
    it('has to return -1 unless present', function() {
      // this test wont? be run
    });
  });
});

It should be noted that codes in skipped suites, that you place outside of hooks or tests will still be executed, as mocha still invokes the suite function to build up the suite structure for visualization.

The best practice is to use .skip() instead of commenting tests out.

You can also skip at runtime using this.skip(). In situations where a test needs an environment or configuration you cannot detected beforehand, it is appropriate to use a runtime skip. Here is an example:

it('has to only test in the correct environment', function() {
  if (/* check test environment */) {
    // make assertions
  } else {
    this.skip();
  }
});

The test above will be reported as pending. It is equally important to note that calling this.skip() will effectively abort the test.

The best practice is not to execute further instructions in a test or hook after calling this.skip(), so as to avoid confusion.

In contrast consider the following code:

it('only has to test in the correct environment', function() {
  if (/* check test environment */) {
    // then make assertions
  } else {
    // do nothing
  }
});

This test will be reported as pending because it does nothing.

It is a good practice to not do nothing, a test either use this.skip() or make an assertion.

If you want to skip multiple tests in this manner, you should use this.skip() in a ?before all? hook:

before(function() {
  if (/* check test environment */) {
    // setup code
  } else {
    this.skip();
  }
});

This skips all it,beforeEach/afterEach, and describe blocks within the suite. before/after hooks will be skipped unless they are defined at the same level as the hook that contains this.skip().

describe('outer', function() {
  before(function() {
    this.skip();
  });

  after(function() {
    // this will be executed
  });

  describe('inner', function() {
    before(function() {
      // this will be skipped
    });

    after(function() {
      // this will be skipped
    });
  });
});

When you skip a test within an "after all" hook, it will throw an exception in a future version of Mocha, since it is deprecated. You should use a return statement or other means to abort hook execution instead.