Adding Chai HTTP (https://www.chaijs.com/plugins/chai-http/) to a Node project tests.
Using the plugin (as in the documentation) is using:
var chai = require('chai')
, chaiHttp = require('chai-http');
chai.use(chaiHttp);
I'm wonder if I need to add chai.use(chaiHttp); in every test file I'm using chaiHttp? or can I setup chaiHttp once in one of the tests?
can it be in a common file?
From mocha v8.2.0, you can use https://mochajs.org/#global-fixtures.
global fixtures:
Are guaranteed to execute once and only once
You can use TEST FIXTURE DECISION-TREE WIZARD THING.
This flowchart will help you decide which of hooks, root hook plugins or global fixtures you should use.
After knowing this, here is an example:
a.test.js:
const chai = require('chai');
const { expect } = chai;
describe('a', () => {
it('should pass', () => {
expect(chai.request).to.be.a('function');
});
});
b.test.js:
const chai = require('chai');
const { expect } = chai;
describe('b', () => {
it('should pass', () => {
expect(chai.request).to.be.a('function');
});
});
fixtures.js:
var chai = require('chai'),
chaiHttp = require('chai-http');
exports.mochaGlobalSetup = function () {
chai.use(chaiHttp);
console.log('setup chaiHttp plugin');
};
Run the test suites and the result:
npx mocha --require fixtures.js ./**/*.test.js
setup chaiHttp plugin
a
✓ should pass
b
✓ should pass
2 passing (5ms)
Related
I am new to Node.js and Jest unit test cases. I have tried to call Jest for controller.js. It is working for one endpoint for another endpoint the controller is making a call to service.
I have not used the mock. Direct call from Jest I have tried. But 'request.on' has not been covered from Jest. I tried all combinations but no luck. I am adding the code details below.
Please let me know how to call 'request.on' from Jest or how to make calls to Service using mock.
controller.js
'use strict'
const service = require('./service/serviceClass');
const control = {
serve: (req, res) => {
service.serve(req, res);
},
}
module.exports = control;
serviceClass.js
require("dotenv").config();
const firebase = require('firebase-admin');
let fbMap = new Map();
function fbInit(){
let fbAdmin = firebase.initializeApp({
credential: firebase.credential.cert('service.json');
});
fbMap.set('fb', fbAdmin);
}
let serve = {
serve: (req, res, next) => {
fbInit();
const body = [];
req.on('data', (chunk) => body.push(chunk))
req.on('end', () => {
const reqString = Buffer.concat(body).toString();
var id = JSON.parse(reqString).firebaseId;
if(id !=== undefined){
var fire = fbMap.get('fb');
fire.auth().getUser(id).then((user)=>{
if(user != null){
console.log("email of the user:"+user.email);
}
)};
}
}
}
}
module.exports=serve;
It would be great if I get the help to either make 'mock' calls for service or how to make the code cover for 'request.on' from Jest.
I'm trying to test an Express API with Mocha and Chai.
My structure is as follows:
server.js
const express = require('express');
...
const loadCredentials = () => ({
...
})
const application = () => {
console.log('This is a log i should always see');
const app = express();
app.use('/api', authentication, authorization('#data/accounts'), router);
...
return app;
};
if (require.main === module) {
application.listen(443)
...
}
module.exports = { application };
test.js
const { application } = require('../server/src/server');
describe('Some async test', async () => {
it(, async () => {
console.log('I should really see this log!!');
server = application();
const res = await chai.request(server).get('/api');
...test stuff...
}
}
When I lerna run test (which runs mocha ./test.js --timeout 60000) the test never executes.
lerna notice cli v3.10.7
lerna info Executing command in 1 package: "yarn run test"
However, if I disable the call to application, the test starts (and fails because server is undefined).
I also tried refactoring application and passing an express() parameter to application(app) from the test, and I get the same behavior.
The test runs if I run it from WebStorm as an individual test.
Needless to say the server works when I yarn run it.
Any help would be appreciated.
When running Karma tests, I would like to start HTTP server to do some cross-origin network requests in tests. Is there a natural way to start the server before Karma tests start and close the server when Karma exits.
The solution is to use new karma.Server():
// #ts-check
const karma = require('karma');
const path = require('path');
const {createEchoServer} = require('./echo-server');
async function run() {
const configPath = path.join(__dirname, './karma.conf.js');
const karmaConfig = karma.config.parseConfig(configPath, {});
const echoServer = await createEchoServer();
const karmaServer = new karma.Server(karmaConfig, () => {
echoServer.close();
});
karmaServer.start();
}
run();
I'm trying to set up testing for various routes in my Express server that require connectivity to my MongoDB database.
I'm not sure how to structure the Jest file in order to allow for testing. In my normal index.js file, I'm importing the app, and running app.listen within the connect .then call, like this:
const connect = require("../dbs/mongodb/connect");
connect()
.then(_ => {
app.listen(process.env.PORT, _ => logger.info('this is running')
})
.catch(_ => logger.error('The app could not connect.');
I've tried running the same setup in my test.js files, but it's not working.
For example:
const connect = require("../dbs/mongodb/connect");
const request = require("supertest");
const runTests = () => {
describe("Test the home page", () => {
test("It should give a 200 response.", async () => {
let res = await request(app).get("/");
expect(res.statusCode).toBe(200);
});
});
};
connect()
.then(_ => app.listen(process.env.PORT))
.then(runTests)
.catch(err => {
console.error(`Could not connect to mongodb`, err);
});
How is it possible to wait for a connection to MongoDB before running my tests?
So, turns out there were a few changes that I had to make. Firstly, I had to load in my .env file before running the tests. I did this by creating a jest.config.js file in the root of my project:
module.exports = {
verbose: true,
setupFiles: ["dotenv/config"]
};
Then within the actual testing suite, I'm running beforeEach to connect to the MongoDB server.
const connect = require("../dbs/mongodb/connect");
const app = require("../app");
const request = require("supertest");
beforeEach(async() => {
await connect();
});
describe("This is the test", () => {
test("This should work", async done => {
let res = await request(app).get("/home");
expect(res.statusCode).toBe(200);
done();
})
});
Similar questions have been asked before & I have looked at & followed them but no luck:
Sinon stub being skipped as node express middleware
node express es6 sinon stubbing middleware not working
How to mock middleware in Express to skip authentication for unit test?
The general answer I get from these is that the module (app.js in my case) should be required AFTER the auth middleware method has been stubbed. I have done this, but still calls the original middleware:
src/app.js
const authentication = require('./authentication')
...
app.use(['/api/users', '/api/groups'], authentication.ensureAuthenticed])
module.exports = app
src/authentication.js
const { isValidAuth } = require('./lib')
exports.ensureAuthenticated = (req, res, next) => {
...
}
__helpers__/supertest.js
// This file just calls endpoints with supertest but this is the only file
// that includes 'app'
const app = require('../../src/app')
module.exports = {
post: {
...
},
get: {
...
},
put: {
...
},
delete: {
...
}
}
users.spec.js
const authentication = require('../../src/authentication')
const authenticationStubs = require('../__stubs__/authentication')
let supertest
let ensureAuthStub
describe('Users', () => {
before(() => {
ensureAuthStub = sinon.stub(authentication, 'ensureAuthenticated').callsFake(authenticationStubs.ensureAuthenticated)
supertest = require('../__helpers__/supertest')
})
// tests
after(() => {
ensureAuthStub.restore()
})
})
__stubs__/authentication.js
exports.ensureAuthenticated = (req, res, next) => {
...
}
In users.spec.js, I load in supertest.js (which loads in src/app.js) AFTER the method has been mocked so I am not sure why the original is still being invoked.
I have also attempted to manually clear the cache before mocking but still does not work.
I think the solution would be using Rewire instead (or with) Supertest.
Rewire lets you to mock top level components of a module. Though you would need to mock middleware before passing to Supertest.
Turns out it was something to do with having supertest.js require app.js. I now have users.spec.js require the app and pass it it into supertest methods as a param. It now works. Still unsure why though