Mocha and Chai test never starts when running an Express app - javascript

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.

Related

Karma startup and teardown config

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();

How to test with Jest after connecting to MongoDB?

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();
})
});

How to write integration test with Jest and Express?

I am trying to write integration tests with a third party microservice (Assume it is call Service). When a request is sent to Service, it will fire a webhook. What I am trying to do is to test it the webhook parsed correctly.
import express from "express";
import bodyParser from "body-parser";
import { handleHook} from "./hook";
export const app = express();
app.use(bodyParser.json(), handleHook);
describe("integration", () => {
test("hook", async () => {
const mock = jest.fn();
app.post("/", (req, res) => {
mock(req);
res.send("");
});
const p = new Promise<Server>(resolve => {
const server = app.listen(3000, () => {
resolve(server);
});
});
const server = await p;
await upload();
jest.useFakeTimers();
setTimeout(() => {
server.close();
}, 15000);
jest.runAllTimers();
expect(mock).toHaveBeenCalledTimes(4);
});
});
However, I got two problems. First, I got
Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with --detectOpenHandles to troubleshoot this issue
but using --detectOpenHandles does not show how to troubleshoot this issue.
Second, because the webhook is fire asynchronously, how can I ensure to catch all of them or wait for a period of time to timeout.

Auth middleware not calling stub - NodeJS, sinon

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

child.kill() does not kill the running process

I have this block of code:
const childProcess = require("child_process");
let child;
before(function(done) {
// 'npm start' starts an express server.
child = childProcess.exec(["npm start"]);
done();
});
// My tests run here
after(function() {
child.kill();
});
The node.exe process never stops running. I can see it running when if I log running processes.
This is what happens in the server file when the npm start command runs :
const app = express();
app.listen(process.env.PORT || app.get("port"), function() {
console.log("HTTP listening on *:" + app.get("port"));
});
I m using mocha.js to run my tests

Categories