The documentation at the official Mocha site contains this example:
describe('User', function(){
describe('#save()', function(){
it('should save without error', function(done){
var user = new User('Luna');
user.save(function(err){
if (err) throw err;
done();
});
})
})
})
I want to know when I should nest my tests in the describe function and what the basic purpose of describe is. Can I compare the first argument passed to describe to comments in a programming language? Nothing is shown of describe in the output on the console. Is it only for readability purposes, or there is some other use for this function?
Is there anything wrong if I use it like this?
describe('User', function(){
describe('#save()', function(){
var user = new User('Luna');
user.save(function(err){
if (err) throw err;
done();
})
})
})
If I do it this way, the test still passes.
The it call identifies each individual tests but by itself it does not tell Mocha anything about how your test suite is structured. How you use the describe call is what gives structure to your test suite. Here are some of the things that using describe to structure your test suite does for you. Here's an example of a test suite, simplified for the purpose of discussion:
function Foo() {
}
describe("Foo", function () {
var foo;
beforeEach(function () {
foo = new Foo();
});
describe("#clone", function () {
beforeEach(function () {
// Some other hook
});
it("clones the object", function () {
});
});
describe("#equals", function () {
it("returns true when the object passed is the same", function () {
});
it("returns false, when...", function () {
});
});
afterEach(function () {
// Destroy the foo that was created.
// foo.destroy();
});
});
function Bar() {
}
describe("Bar", function () {
describe("#clone", function () {
it("clones the object", function () {
});
});
});
Imagine that Foo and Bar are full-fledged classes. Foo has clone and equals methods. Bar has clone. The structure I have above is one possible way to structure tests for these classes.
(The # notation is used by some systems (like for instance, jsdoc) to indicate an instance field. So when used with a method name, it indicates a method called on an instance of the class (rather than a class method, which is called on the class itself). The test suite would run just as well without the presence of #.)
Provide Banners
Some of Mocha's reporters show the names you give to describe in the reports they produce. For instance, the spec reporter (which you can use by running $ mocha -R spec), would report:
Foo
#clone
✓ clones the object
#equals
✓ returns true when the object passed is the same
✓ returns false, when...
Bar
#clone
✓ clones the object
4 passing (4ms)
Help Select Parts to Run
If you want to run only some of the tests, you can use the --grep option. So if you care only about the Bar class, you can do $ mocha -R spec --grep Bar, and get the output:
Bar
#clone
✓ clones the object
1 passing (4ms)
Or if you care only about the clone methods of all classes, then $ mocha -R spec --grep '\bclone\b' and get the output:
Foo
#clone
✓ clones the object
Bar
#clone
✓ clones the object
2 passing (5ms)
The value given to --grep is interpreted as a regex so when I pass \bclone\b I'm asking only for the word clone, and not things like clones or cloned.
Provide Hooks
In the example above the beforeEach and afterEach calls are hooks. Each hook affects the it calls that are inside the describe call which is the parent of the hook. The various hooks are:
beforeEach which runs before each individual it inside the describe call.
afterEach which runs after each individual it inside the describe call.
before which runs once before any of the individual it inside the describe call is run.
after which runs once after all the individual it inside the describe call are run.
These hooks can be used to acquire resources or create data structures needed for the tests and then release resources or destroy these structures (if needed) after the tests are done.
The snippet you show at the end of your question won't generate an error but it does not actually contain any test, because tests are defined by it.
It's hard to add to Louis' excellent answer. There are a couple of advantages of the describe block that he didn't mention which are the skip and only functions.
describe.skip(...) {
...
}
will skip this describe and all its nested describe and it functions while:
describe.only(...) {
...
}
will only execute that describe and its nested describe and it functions. The skip() and only() modifiers can also be applied to the it() functions.
To my knowledge, describe is really just there for humans... So we can see different areas of the app. You can nest describe n levels deep.
describe('user',function(){
describe('create',function(){}
});
Describe is just used for the sake of understanding the purpose of the tests , it is also used to logically group the tests . Lets say you are testing the database API's , all the database tests could come under the outer describe , so the outer describe logically groups all the database related . Lets say there are 10 database related API's to test , each of the inner describe functions defines what those tests are ....
The particular role of describe is to indicate which component is being tested and which method of that component is also being tested.
for example, lets say we have a User Prototype
var User = function() {
const self = this;
function setName(name) {
self.name = name
}
function getName(name) {
return self.name;
}
return{setName, getName};
}
module.exports = User;
And it needs to be tested, so a spec file is created for unit test
var assert = require('assert');
var User = require("../controllers/user.controller");
describe("User", function() {
describe('setName', function() {
it("should set the name on user", function() {
const pedro = new User();
name = "Pedro"
pedro.setName(name);
assert(pedro.getName(), name);
});
});
});
It is easy to see that the purpose of describe is indicating the component to be tested and the nested describe methods indicate which methods needs to be tested
Related
I try to call a lot of async functions in my mocha JS before hook but they are executed at last. Basically I am trying to execute repeated tests with different params from the constructor initialization.
I tried with only one function but it also execute at last.Tried to pass done() function to inner async function but it doesnt help either.
a.test.js and base.tests.js files :
describe('Test block', () => {
before((done) => {
const baseClass = new baseClass()
baseTests.applyTests(done)
});
describe('test',()=>{
....first which should be executed;
})
}
----------------------------------------------------------------
class baseClass {
constructor() {
init smth....
}
async applyTests(done) {
await Promise.All(
[
a(),
b(),
c()
]
done();
)
}
async a() {
return describe('TEST', () => {
it('TEST', (done) => {
chai.request(server)
.get(url)
.end((err, res) => {
asserts...
done();
});
});
}}
I expect to run first the async operations in the before hook and after that all other tests.
Keep in mind that describe and it blocks do not execute any tests; they add tests to the test list that Mocha will execute. Putting a describe block inside a function called from a before hook like this won't ever end up executing code like chai.request(... etc. (And even if it did, it would be totally broken: a before hook is run before each test, you don't want to do asserts there because it won't be linked to any particular unit test.)
I can't give more concrete advice because I'm not sure what you were trying to accomplish, but in general, your describe and it blocks should be top-level constructs and not put inside other code like this.
EDIT: Just to make the execution path here clear: your before hook runs, which calls applyTests, which calls a(), which executes a describe block and adds your unit test TEST to the test list, then it returns. It then begins running tests, including test and TEST.
EDIT: Ah, makes sense, let me suggest two patterns that are often used in unit tests.
Pattern 1: "Test Loop"
This pattern creates many similar-looking tests, using an array of input params to produce appropriate test descriptions and test bodies.
[
{ foo: "milk", bar: "smoothie" },
{ foo: "yogurt", bar: "fridge" },
{ foo: "whatever", bar: "container" }
].forEach(test => {
it("puts the " + test.foo + " in the " + test.bar, function () {
assert(subject.someMethod(foo) === bar);
});
});
Pattern 2: "Test Helper"
This pattern creates individual tests, but puts a common test body in a helper method so it can be reused.
function testSomeMethod(foo, bar) {
assert(subject(foo) == "bar");
}
it("puts the milk in the fridge", function () {
testSomeMethod("milk", "fridge");
});
it("puts the cereal in the pantry", function () {
testSomeMethod("cereal", "pantry");
});
Examples above are very simple, but either the test loop or the test helper pattern can be used to encapsulate a much more complicated series of steps (set up a request, look at some response headers / bodies, etc.).
Is there a way to set a particular test file as the first in mocha and then the rest of the test files can execute in any order.
One technique that can be used is to involve number in test filename such as
01-first-test.js
02-second-test.js
03-third-test.js
So by defining this, the test will be executed from first test until third test.
No. There is no guarantee your tests will run in any particular order. If you need to do some setup for tests inside of a given describe block, try using the before hook like so.
There is no direct way, but there is certainly a solution to this. Wrap your describe block in function and call function accordingly.
firstFile.js
function first(){
describe("first test ", function () {
it("should run first ", function () {
//your code
});
});
}
module.exports = {
first
}
secondFile.js
function second(){
describe("second test ", function () {
it("should run after first ", function () {
//your code
})
})
}
module.exports = {
second
}
Then create one main file and import modules.
main.spec.js
const firstThis = require('./first.js)
const secondSecond = require(./second.js)
firstThis.first();
secondSecond.second();
In this way you can use core javaScript features and play around with mocha as well.
This is the solution I have been using since long. would highly appreciate if anyone would come with better approach.
I'm trying to create mocha tests for my controllers using a config that has to be loaded async. Below is my code. However, when the mocha test is run, it doesn't run any tests, displaying 0 passing. The console.logs are never even called. I tried doing before(next => config.build().then(next)) inside of the describe, but even though the tests run, before is never called. Is there a way to have the config be loaded one time before any tests are run?
'use strict';
const common = require('./common');
const config = require('../config');
config
.build()
.then(test);
function test() {
console.log(1);
describe('Unit Testing', () => {
console.log(2);
require('./auth');
});
}
You should run Mocha with the --delay option, and then use run() once you are done building your test suite. Here is an example derived from the code you show in the question:
'use strict';
function test() {
console.log(1);
describe('Unit Testing', () => {
console.log(2);
it("test", () => {
console.log(3);
});
});
// You must use --delay for `run()` to be available to you.
run();
}
setTimeout(test, 1000);
I'm using setTimeout to simulate an asynchronous operation. Using --delay and run() allows you to build a suite that is the result of an asynchronous computation. Note, however, that the suite must be built in one shot. (You cannot have an asynchronous process inside describe that will make calls to it. This won't work.)
One thing you should definitely not do is what rob3c suggests: calling describe or it (or both) from inside a hook. This is a mistake that every now and then people make so it is worth addressing in details. The problem is that it is just not supported by Mocha, and therefore there are no established semantics associated with calling describe or it from inside a hook. Oh, it is possible to write simple examples that work as one might expect but:
When the suite becomes more complex, the suite's behavior no longer corresponds to anything sensible.
Since there are no semantics associated with this approach, newer Mocha releases may handle the erroneous usage differently and break your suite.
Consider this simple example:
const assert = require("assert");
const p = Promise.resolve(["foo", "bar", "baz"]);
describe("top", () => {
let flag;
before(() => {
flag = true;
return p.then((names) => {
describe("embedded", () => {
for (const name of names) {
it(name, () => {
assert(flag);
});
}
});
});
});
after(() => {
flag = false;
});
it("regular test", () => {
assert(flag);
});
});
When we run it, we get:
top
✓ regular test
embedded
1) foo
2) bar
3) baz
1 passing (32ms)
3 failing
// [stack traces omitted for brevity]
What's going on here? Shouldn't all the tests pass? We set flag to true in the before hook for the top describe. All tests we create in it should see flag as true, no? The clue is in the output above: when we create tests inside a hook, Mocha will put the tests somewhere but it may not be in a location that reflects the structure of the describe blocks in the code. What happens in this case is that Mocha just appends the tests created in the hook the the very end of the suite, outside the top describe, so the after hook runs before the dynamically created tests, and we get a counter-intuitive result.
Using --delay and run(), we can write a suite that behaves in a way concordant with intuition:
const assert = require("assert");
const p = Promise.resolve(["foo", "bar", "baz"]).then((names) => {
describe("top", () => {
let flag;
before(() => {
flag = true;
});
after(() => {
flag = false;
});
describe("embedded", () => {
for (const name of names) {
it(name, () => {
assert(flag);
});
}
});
it("regular test", () => {
assert(flag);
});
});
run();
});
Output:
top
✓ regular test
embedded
✓ foo
✓ bar
✓ baz
4 passing (19ms)
In modern environments, you can use top-level await to fetch your data up front. This is a documented approach for mocha: https://mochajs.org/#dynamically-generating-tests
Slightly adapting the example from the mocha docs to show the general idea:
function fetchData() {
return new Promise((resolve) => setTimeout(resolve, 5000, [1, 2, 3]));
}
// top-level await: Node >= v14.8.0 with ESM test file
const data = await fetchData();
describe("dynamic tests", function () {
data.forEach((value) => {
it(`can use async data: ${value}`, function () {
// do something with data here
});
});
});
This is nice as it is on a per-file basis, and doesn't involve you taking on management responsibility of the test runner as you do with --delay.
The problem with using the --delay command line flag and run() callback that #Louis mentioned in his accepted answer, is that run() is a single global hook that delays the root test suite. Therefore, you have to build them all at once (as he mentioned), which can make organizing tests a hassle (to say the least).
However, I prefer to avoid magic flags whenever possible, and I certainly don't want to have to manage my entire test suite in a single global run() callback. Fortunately, there's a way to dynamically create the tests on a per-file basis, and it doesn't require any special flags, either :-)
To dynamically create It() tests in any test source file using data obtained asynchronously, you can (ab)use the before() hook with a placeholder It() test to ensure mocha waits until before() is run. Here's the example from my answer to a related question, for convenience:
before(function () {
console.log('Let the abuse begin...');
return promiseFn().
then(function (testSuite) {
describe('here are some dynamic It() tests', function () {
testSuite.specs.forEach(function (spec) {
it(spec.description, function () {
var actualResult = runMyTest(spec);
assert.equal(actualResult, spec.expectedResult);
});
});
});
});
});
it('This is a required placeholder to allow before() to work', function () {
console.log('Mocha should not require this hack IMHO');
});
I want to compute some values before some tests. what is the best way to do that? To use "before" or call functions?
// Way 1
var expect = require('chai').expect;
describe("a test", function() {
var val1, val2;
before(function() {
val1 = computeVal1();
});
it("should return hi1", function() {
expect(val1).to.equal('hi1');
});
before(function() {
val2 = computeVal2();
});
it("should return hi2", function() {
expect(val2).to.equal('hi2');
});
});
Is the above way is better or the below way is better?
// Way 2
var expect = require('chai').expect;
describe("a test", function() {
var val1, val2;
val1 = computeVal1();
it("should return hi1", function() {
expect(val1).to.equal('hi1');
});
val2 = computeVal2();
it("should return hi2", function() {
expect(val2).to.equal('hi2');
});
});
It really makes no difference in this case because ultimately in the second example computeVal1() will run before the tests do. However, given this is exactly what the before / beforeEach hooks were designed for, I would be inclined to stay consistent with the framework and use them.
This is from the mocha documentation:
describe('hooks', function() {
before(function() {
// runs before all tests in this block
})
after(function(){
// runs after all tests in this block
})
beforeEach(function(){
// runs before each test in this block
})
afterEach(function(){
// runs after each test in this block
})
// test cases
})
So, there is not much difference in using before or calling functions directly under the describe. In your second example, val2's value won't be available to the first test, but in the first example, val2's value will be.
However, it is better practice IMO, to use beforeEach. This way state from one test does not affect another test.
Using the hooks (before and beforeEach) to initialize the data that your test uses is usually the best thing to do. Consider this:
In your 2nd snippet, if computeVal1 or computeVal2 fail, then Mocha won't run any test whatsoever. In the 1st snippet, Mocha may run some tests before it tries to call them and they fail. If you have many test files that Mocha loads, it may matter to you that Mocha runs as many test as it can before a failure occurs.
In your 2nd snippet, Mocha will almost always run computeVal1 and computeVal2 even if they are not needed. If they are computationally costly, you'll pay this cost every time. If you run mocha --grep=foo so that it does not select any of your tests, both functions will be called.
In your first snippet, Mocha will run them only if they are needed. If you run mocha --grep=foo, Mocha won't call your functions.
In your 2nd snippet, even using describe.skip for your describe call won't make Mocha skip calling the functions.
I'm trying to unit test a CouchDB design doc (written using couchapp.js), example:
var ddoc = {
_id: '_design/example',
views: {
example: {
map: function(doc) {
emit(doc.owner.id, contact);
}
}
}
}
module.exports = contacts
I can then require this file into a mocha test very easily.
The problem is CouchDB exposes a few global functions that the map functions use ("emit" function above) which are unavailable outside of CouchDB (i.e. in these unit tests).
I attempted to declare a global function in each test, for example:
var ddoc = require('../example.js')
describe('views', function() {
describe('example', function() {
it('should return the id and same doc', function() {
var doc = {
owner: {
id: 'a123456789'
}
}
// Globally-scoped mocks of unavailable couchdb 'emit' function
emit = function(id, doc) {
assert.equal(contact.owner.id, id);
assert.equal(contact, doc);
}
ddoc.views.example.map(doc);
})
})
})
But Mocha fails with complaints of global leak.
All of this together started to "smells wrong", so wondering if there's better/simpler approach via any libraries, even outside of Mocha?
Basically I'd like to make mock implementations available per test which I can call asserts from.
Any ideas?
I'd use sinon to stub and spy the tests. http://sinonjs.org/ and https://github.com/domenic/sinon-chai
Globals are well, undesirable but hard to eliminate. I'm doing some jQuery related testing right now and have to use --globals window,document,navigator,jQuery,$ at the end of my mocha command line so... yeah.
You aren't testing CouchDb's emit, so you should stub it since a) you assume that it works and b) you know what it will return
global.emit = sinon.stub().returns(42);
// run your tests etc
// assert that the emit was called
This part of the sinon docs might be helpful:
it("makes a GET request for todo items", function () {
sinon.stub(jQuery, "ajax");
getTodos(42, sinon.spy());
assert(jQuery.ajax.calledWithMatch({ url: "/todo/42/items" }));
});
Hope that helps.