My mocha tests are failing with:
MongoError: server XXXX sockets closed
I have a workaround how to fix them:
const https = require('https');
const server = https.createServer(..);
close() {
mongoose.disconnect(); // <-------- I will comment this line
this.server.close();
};
I would comment out the line mongoose.disconnect(); and my test suite starts working. I would like to clean up after my tests too. Each of my test files recreates server and starts from the scratch. It seems like the error appears because there needs to be some 'waiting' before the next test file executes.
How can I correct this error?
Solution - Captain Hook to the rescue!
If I understand correctly, you wish to startup and cleanup your server after the tests. You also have a series of repetitive tasks you need to do before and after each test.
Mocha has the perfect solution for you: Say hello to Mr. Hook!
Mocha hooks are functions that you can run both before all tests, after all tests, or before each test and after each test:
https://mochajs.org/#hooks
The documentation is pretty complete and I really do recommend it. I your case however, since you are dealing with databases, you probably will be dealing with async hooks.
Sounds complex? Don't worry!
This is how normal sync hooks work:
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
});
//tests
it("This is a test", () => {
assert.equal(1, 1);
});
});
async hooks only have one difference: they have a parameter done, which is called once your task is finished. Lets assume that we are setting up a DB that takes 1.5 seconds to setup. We want to do this before all the tests, and we only want to do it once.
Let's assume this is our listen function from our DB:
const listen = callback => {
setTimeout(callback, 1500);
};
So after 1.5 seconds, it calls the callback function signalizing it is ready for action.
Now lets see how we would make an async hook:
describe('hooks', function() {
let myDB;
before( done => {
myDB = newDB();
myDB(done);
});
//tests
});
And that's it! Hope it helps!
Related
I have a jest test file that looks like this:
import Client from "socket.io-client"
describe("my awesome project", () => {
let clientSocket;
beforeAll((done) => {
clientSocket = new Client(`http://localhost:3000`);
clientSocket.on("connect", done);
});
afterAll(() => {
clientSocket.close();
});
it("should work", (done) => {
clientSocket.on("redacted", (message) => {
expect(2 + 2).toBe(56);
//expect(message === "foobar").toEqual(true);
done();
});
clientSocket.emit("redacted", "world");
});
});
This is a POC and this currently the entire implementation.
The jest.config looks like this:
export default {
// Automatically clear mock calls, instances, contexts and results before every test
clearMocks: true,
// Indicates whether the coverage information should be collected while executing the test
collectCoverage: true,
// The directory where Jest should output its coverage files
coverageDirectory: "coverage",
// Indicates which provider should be used to instrument code for coverage
coverageProvider: "v8",
// A preset that is used as a base for Jest's configuration
preset: "ts-jest",
};
Which is just the file the --intit command generated.
The core of my problem is that any expect I use that results in a failed test, no matter how trivial takes an absurd amount of time to complete. I accidentally left it running as above overnight and it eventually completed in 14 hours.
But with a passing test Jest is absolutely fine and completes rapidly.expect(2 + 2).toBe(4); for example runs perfectly. On the failed tests I see the data come back from the socket as expected in the time expected. Its only when the expect is hit that it stalls out. So I don't believe the problem is in the socket setup or some sort of communication problem.
I've tried the config based solutions I've found to no effect - eg Jest - Simple tests are slow
This is being run on my local windows machine from a terminal I'm fully starting and stopping for each test on my IDE.
OK so now I see the problem, I needed a try catch.
Can't quite believe none of the examples or docs I looked at as much as hinted this is necessary to handle something so basic.
test("should work", (done) => {
clientSocket.on("redacted", (message: string) => {
try {
expect(2 + 2).toBe(56);
//expect(message === "foobar").toEqual(true);
done();
} catch (err) {
done(err)
}
});
clientSocket.emit("redacted", "world");
});
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 have problem with Mocha.
If i run this programmaticaly from Jake Mocha brakes down and don't show nothing more than some errors stuff like:
AssertionError: There is a code 200 in response
at Socket.<anonymous> (/home/X/Y/Z/test/test_Server.js:70:4)
at Socket.EventEmitter.emit (events.js:93:17)
at TCP.onread (net.js:418:51)
Runned from command line gives more expected results. That is:
19 passing (30ms)
7 failing
1) RTDB accepts connection with package and response with code 200 if correct package was send:
Uncaught AssertionError: There is a code 200 in response
at Socket.<anonymous> (/X/Y/Z/test/test_Server.js:70:4)
at Socket.EventEmitter.emit (events.js:93:17)
at TCP.onread (net.js:418:51)
2) XYZ should be able to store GHJ for IJS:
Error: expected f...
...
The problem is following code:
test('accepts connection with package and response with code 400 ' +
'if wrong package was send', function (done) {
console.log('client connecting to server');
var message = '';
var client = net.connect(8122, 'localhost', function () {
client.write('Hello');
client.end();
} );
client.setEncoding('utf8');
client.on('data', function (data) {
message += data;
} );
client.on('end', function (data) {
assert(message.indexOf('400') !== -1, 'There is a code 400 in response');
done();
});
client.on('error', function(e) {
throw new Error('Client error: ' + e);
});
});
If I do
assert(message.indexOf('400') !== -1, 'There is a code 400 in response');
just after
var message = '';
Mocha fails correctly (I mean displaying errors etc.), So this is fault of asynch assertion done on event. How can I correct that? Thats real problem Because this test is first, and I get no clue where to look for source of problem (If there is any). Should I somehow catch this assertion error and pass it to Mocha?
EDIT:
Answer to comment how is Jake running Mocha - just like that:
var Mocha = require('mocha');
...
task("test", [], function() {
// First, you need to instantiate a Mocha instance.
var mocha = new Mocha({
ui: 'tdd',
reporter: 'dot'
});
// Then, you need to use the method "addFile" on the mocha
// object for each file.
var dir = 'test';
fs.readdirSync(dir).filter(function(file){
// Only keep the .js files
return file.substr(-3) === '.js';
}).forEach(function(file){
// Use the method "addFile" to add the file to mocha
mocha.addFile(
path.join(dir, file)
);
});
// Now, you can run the tests.
mocha.run(function(failures){
if(failures){
fail("Mocha test failed");
} else {
complete();
}
});
}, {async: true});
I'm assuming since you say "programmatically" that your Jakefile issues require("mocha") and then creates a Mocha object on which it calls the run method.
If this is the case, then the reason it does not work is because Jake and Mocha are working at cross purposes. When Mocha executes a test, it traps unhandled exceptions. Schematically, (omitting details that are not important) it is something like:
try {
test.run();
}
catch (ex) {
recordFailure();
}
It is at the call to test.run that the test is executed. For tests that are purely synchronous, no problem. When a test is asynchronous, the asynchronous callback which is part of the test cannot execute inside the try... catch block Mocha establishes. The test will launch the asynchronous operation and return immediately. At some point in the future, the asynchronous operation calls the callback. When this happens, Mocha is not able to catch the exception in the asynchronous operation with a try... catch block. How does it catch such exceptions then? It listens to uncaughtException events.
Now, the problem when Mocha is run in the same execution context as Jake is that Jake also wants to trap uncaught exceptions. Jake sometimes has to launch asynchronous operations and wants to trap cases where these operations fail, so it listens to uncaughtException too. It installs its listener first. So when an asynchronous Mocha test fails with a exception, Jake's listener's is called, which cause Jake to immediately stop execution. Mocha never gets a chance to act.
I don't see a clear way to make both Jake and Mocha cooperate when run in the same execution context. There might be a way to fiddle with the handlers but I doubt that there is a robust way to make it work. (By "robust" I mean a way which will ensure that every single error is trapped and attributed to the correct source.) The vm module might help segregate their contexts while keeping them in the same OS process.
Based on this answer: https://stackoverflow.com/a/9132271/2024650
In few words: I remove listener on uncaughtException in Jake. This allow Mocha to handle this uncaughtExceptions. At the end I add back this listener.
This solves my answer for now:
task("test", [], function() {
var originalExeption = process.listeners('uncaughtException').pop();
//!!!in node 0.10.X you should also check if process.removeListener isn't necessary!!!
console.log(originalExeption);
// First, you need to instantiate a Mocha instance.
var mocha = new Mocha({
ui: 'tdd',
reporter: 'dot'
});
// Then, you need to use the method "addFile" on the mocha
// object for each file.
var dir = 'test';
fs.readdirSync(dir).filter(function(file){
// Only keep the .js files
return file.substr(-3) === '.js';
}).forEach(function(file){
// Use the method "addFile" to add the file to mocha
mocha.addFile(
path.join(dir, file)
);
});
// Now, you can run the tests.
mocha.run(function(failures){
if(failures){
fail("Mocha test failed");
} else {
complete();
}
process.listeners('uncaughtException').push(originalExeption);
});
}, {async: true});
it seems that you are testing a HTTP server by connecting with TCP to it, (correct if i'm wrong) if thats the case here, you should just drop your current test, and use appropriate module to test an HTTP server or REST API there are plenty modules like Superagent .
You should try call client.end() after you have received your first data event, this way it will call assert after first header is received.
if you want to continuously send and test requests, have all you assert in the data event and call correct assert each time it receives the header you want to test, just remember that you must call done() when its supposed to finish, and that it can't be delayed for a long period of time, the request must be one after another.
Other than that you can use async module if you want to test chained requests ( one request depends on another and another and so on..), in some case its useful to raise the mocha timeout to more than 10000 (10secs) to give the async part some time to complete.
I've got a node.js + express web server that I'm testing with Mocha. I start the web server within the test harness, and also connect to a mongodb to look for output:
describe("Api", function() {
before(function(done) {
// start server using function exported from another js file
// connect to mongo db
});
after(function(done) {
// shut down server
// close mongo connection
});
beforeEach(function(done) {
// empty mongo collection
});
describe("Events", function() {
it("Test1", ...);
it("Test2", ...);
it("Test3", ...);
it("Test4", ...);
it("Test5", ...);
});
});
If Mocha runs more than 4 tests at a time, it times out:
4 passing (2s)
1 failing
1) Api Test5:
Error: timeout of 2000ms exceeded
at null.<anonymous> (C:\Users\<username>\AppData\Roaming\npm\node_modules\moch\lib\runnable.js:165:14)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
If I skip any one of the 5 tests, it passes successfully. The same problem occurs if I reorder the tests (it's always the last one that times out). Splitting the tests into groups also doesn't change things.
From poking at it, the request for the final test is being sent to the web server (using http module), but it's not being received by express. Some of the tests make one request, some more than one. It doesn't affect the outcome which ones I skip. I haven't been able to replicate this behaviour outside mocha.
What on earth is going on?
With Mocha, if you declare a first argument to your (test) functions' callback (usually called done), you must call it, otherwise Mocha will wait until it's called (and eventually time out). If you're not going to need it in a test, don't declare it:
it('test1', function(done) {
..
// 'done' declared, so call it (eventually, usually when some async action is done)
done();
});
it('test2', function() {
// not an async test, not declaring 'done', obviously no need to call it
});
And since you're using http, try increasing http.globalAgent.maxSockets (which defaults to 5):
var http = require('http');
http.globalAgent.maxSockets = 100;
(I believe 0 turns it off completely but I haven't tried).