How to manipulate results of Mocha test in Node.js? - javascript

I have a simple Mocha file:
const assert = require('assert');
describe('Array', function () {
describe('#indexOf()', function () {
it('should return -1 when the value is not present', function () {
assert.equal([1, 2, 3].indexOf(4), -1);
});
});
});
I'm looking to run the test above inside Node.js and get access to the test results for further manipulation.
I know it's possible to import Mocha and run tests, like this:
const Mocha = require('mocha');
const test = new Mocha();
test.addFile('./assert.js');
test.run();
But, I'd like a way of getting the result of assert.equal and the corresponding descriptions, perhaps via the then() method. Any ideas? Could Sinon.JS help?
The end goal is to display these tests in the browser, using an API endpoint.

You can use the instance of test and look for events for each test execution.
for example:
const Mocha = require('mocha');
const test = new Mocha();
test.addFile('./assert.js');
let runner = test.run();
runner.on('pass', (e) => {
passed.push({
title: e.title,
speed: e.speed,
duration: e.duration,
file: e.file
});
});
runner.on('fail', (e) => {
failed.push({
title: e.title,
err: error,
file: e.file
});
});

Related

Import a file after the Jest environment has been torn down

I'm making a simple API with Express and I'm trying to add tests with Jest but when I try to run the tests it displays the next error:
ReferenceError: You are trying to `import` a file after the Jest environment has been torn down.
at BufferList.Readable (node_modules/readable-stream/lib/_stream_readable.js:179:22)
at BufferList.Duplex (node_modules/readable-stream/lib/_stream_duplex.js:67:12)
at new BufferList (node_modules/bl/bl.js:33:16)
at new MessageStream (node_modules/mongodb/lib/cmap/message_stream.js:35:21)
at new Connection (node_modules/mongodb/lib/cmap/connection.js:52:28)
/home/jonathangomz/Documents/Node/Express/Devotionals/node_modules/readable-stream/lib/_stream_readable.js:111
var isDuplex = stream instanceof Duplex;
^
TypeError: Right-hand side of 'instanceof' is not callable
I'm not sure to trust the result if right after jest break (or something like that):
My test is:
const app = require("../app");
const request = require("supertest");
describe("Testing root router", () => {
test("Should test that true === true", async () => {
jest.useFakeTimers();
const response = await request(app).get("/");
expect(response.status).toBe(200);
});
});
My jest configuration on package.json:
"jest": {
"testEnvironment": "node",
"coveragePathIgnorePatterns": [
"/node_modules/"
]
}
Notes:
I read about jest.useFakeTimers() but It's not working and I'm not sure if I'm using in the wrong way. I also tried adding it to the beforeEach method but nothing.
In my case, I had to add the package to transformIgnorePatterns in the jest config.
Add jest.useFakeTimers('modern') before the asynchronous call. Add jest.runAllTimers() after the asynchronous call. This will fast-forward timers for you.
const app = require("../app")
const request = require("supertest")
describe("Testing root router", () => {
test("Should test that true === true", async () => {
//Before asynchronous call
jest.useFakeTimers("modern")
const response = await request(app).get("/")
//After asynchronous call
jest.runAllTimers()
expect(response.status).toBe(200)
})
})
Try adding --testTimeout=10000 flag when calling jest, it works for me.
Information based on Testing NodeJs/Express API with Jest and Supertest
--testTimeout flag - This increases the default timeout of Jest which is 5000ms. This is important since the test runner needs to refresh the database before running the test
By adding jest.useFakeTimers() just after all your import.
What about making your test async ?
const app = require("../app");
const request = require("supertest");
describe("Testing root router",async () => {
test("Should test that true === true", async () => {
jest.useFakeTimers();
const response = await request(app).get("/");
expect(response.status).toBe(200);
});
});

Jest cleaning up of Express server settings

I'm playing around with a side practice software, and I'm trying to learn how to use Jest for testing. But I get an error when it should clean up the testing suite, I suspect because of async code.
When I run the Jest CLI with --runInBand, it works great, but I want to understand and fix so it will work without the flag.
\
Example of one of the test files
const {Genre} = require('../../../models/genre');
const {mongoose} = require('../../../app');
const request = require('supertest');
let server;
describe('testing GET for genres', function() {
beforeEach( function() {
server = require('../../../app').server;
});
afterEach(async function() {
await Genre.deleteMany({});
await mongoose.connection.close();
server.close();
});
it('should create a genre',async function() {
let genre = {
name: "abcde"
};
const result = await request(server).post('/api/genres').send(genre);
return expect(result).toBeDefined();
}) ;
});
Example of the other one:
const {User} = require('../../../models/user');
const request = require('supertest');
const {mongoose} = require('../../../app');
let server;
describe('testing POST for users', function() {
beforeEach(function() {
server = require('../../../app').server;
});
afterEach(async function() {
await User.deleteMany({});
await mongoose.connection.close();
server.close();
});
it('should create a user',async function() {
let user = {
email: "testing123#gmail.com",
password: "Yoyoyoy"
};
const result = await request(server).post('/api/users').send(user);
expect(result.status).toBe(200);
expect(result.body).toHaveProperty("email", "testing123#gmail.com");
expect(result.body).toHaveProperty("isAdmin", false);
}) ;
});
And when I run npm test, On of the 2 tests fail, and I get the error that the server is already running and also the error that I tried to do stuff/log after jest was shut down. Cleary this is a sync issue, can anyone help me to understand why, and how to control this?

Unit Test library is called from wrapper library

I am building a wrapper around a javascript library in pinojs.
I'm wondering how I can write a unit test to verify the info function within pino was actually called.
Here's a code snippet
const { logger } = require(`../../../lib/index`);
describe(`when logger is configured with pino-pretty`, () => {
beforeEach(() => {
myAppLogger = logger({
prettyPrint: true
});
});
it(`then pino info method is called on pino instance`, () => {
const pinoSpy = sinon.spy(pino, 'info');
myAppLogger.info('info message');
expect(pinoSpy).to.have.been.called;
expect(pinoSpy).to.not.throw();
});
});
Where myAppLogger is just an instance of pino
pino(options, stream).child(props);

How to clear a module mock between tests in same test suite in Jest?

I've mocked some nodejs modules (one of them, for example, is fs). I have them in a __mocks__ folder (same level als node_modules) folder and the module mocking works. However, whichever "between test clearing" option I use, the next test is not "sandboxed". What is going wrong here?
A very simplified example of the mocked fs module is:
// __mocks__/fs.js
module.exports = {
existsSync: jest.fn()
.mockReturnValueOnce(1)
.mockReturnValueOnce(2)
.mockReturnValueOnce(3)
}
I'm simply expecting that in every test, whenever init() is called (see below), existsSync starts again at value 1: the first value of jest.fn().mockReturnValue(). In the testfile I have the following structure:
// init.test.js
const init = require("../init");
const { existsSync } = require("fs");
jest.mock("fs");
describe("initializes script", () => {
afterEach(() => {
// see below!
});
test("it checks for a package.json in current directory", () => {
init();
});
test("it stops script if there's a package.json in dir", () => {
init(); // should be run in clean environment!
});
}
And once again very simplified, the init.js file
const { existsSync } = require("fs");
console.log("value of mocked response : ", existsSync())
I'm getting the following results for existsSync() after the first and second run ofinit() respectively when I run in afterEach():
jest.resetModules() : 1, 2
existsSync.mockReset(): 1, undefined
existsSync.mockClear(): 1, 2
existsSync.mockRestore(): 1, undefined
Somebody know what I'am doing wrong? How do I clear module mock between tests in the same suite? I'll glady clarify if necessary. Thanks!
Reset the modules and require them again for each test:
describe("initializes script", () => {
afterEach(() => {
jest.resetModules()
});
beforeEach(() => {
jest.mock("fs");
})
test("it checks for a package.json in current directory", () => {
const init = require("../init");
init();
});
test("it stops script if there's a package.json in dir", () => {
const init = require("../init");
init();
});
}
I had problems with the solution above. I managed to solve the issue with the next snippet.
afterEach(() => {
Object.keys(mockedModule).forEach(method => mockedModule[method].mockReset())
})
I would prefer to have a native method doing this though. Something like mockedModule.mockReset().
For local variables, the scope of declaration is important.
const mockFunc1 = jest.fn() // possibly bad mock reset/clear between tests
describe('useGetMetaData', () => {
const mockFunc2 = jest.fn() // good mock reset/clear between tests
afterEach(() => {/* reset/clear mocks */})
test.todo('implement tests here')
})

Hooking a custom mocha reporter

I am new to javascript and mocha. I have been looking at how to create a third party reporter. I saw some samples at https://github.com/mochajs/mocha/wiki/Third-party-reporters
I created one that meets my needs and was able to install it and use it. But, the requirement is to not install the reporter. It can either be a different file or be part of the same js file.
Can anyone please tell me how to hook the reporter with the js file?
Here is my test js file
const mochasteps = require('mocha-steps')
var Mocha = require('mocha');
var report = require('./report')
var mochainstance = new Mocha({reporter: report});
console.log(mochainstance._reporter)
before(() => console.log('before'))
after(() => console.log('after'))
describe('Array', () => {
step('should start empty', done => {
var arr = [];
if (arr.length == 1) return done()
done(new Error('array length not 0'))
});
});
describe('Test', () => {
step('some Test', done => {
done();
});
});
Here is my test report.js file that does the reporting.
var mocha = require('mocha');
module.exports = report;
function report(runner) {
mocha.reporters.Base.call(this, runner);
runner.on('pass', function(test){
console.log('[pass]%s', test.title);
});
runner.on('fail', function(test, err){
console.log('[fail]%s(%s)', test.title, err.message);
});
runner.on('end', function(){
process.exit(0);
});
}
Thanks,
r1j1m1n1
You need to pass the path to the custom reporter when running the tests. In your example, assuming test.js and report.js are in the same folder, it would be as follows:
mocha test.js -R 'report.js'
This will run the test.js tests with report.js as the reporter without having to install the reporter.

Categories

Resources