问题
We have an application interacting with an (Node.js) HTTP server. To test the API calls, we have created a test HTTP server, which is working fine with the application. All the calls we make work as expected from the application.
Recently, we have been spending time trying to automate the testing of these API calls. One strategy we came up with was to:
- start the test HTTP server automatically;
- make calls to it;
- close the test HTTP server after the test.
Here is how our first test is written so far:
var serverHandler = require('../../server/serverHandler.js');
describe('Test the test server', function() {
beforeEach(async () => {
serverHandler.start(500, 'index.js'); // index.js: the HTTP test server.
// 500: 500 ms of latency to mimic a slow response.
result = await serverHandler.isRunning();
expect(result).toEqual(true);
});
afterEach(async () => {
serverHandler.kill();
result = await serverHandler.isRunning();
expect(result).toEqual(false);
});
test('Server is killed', async () => {
// We could have more complex test logic here...
serverHandler.kill();
try {
result = await serverHandler.isRunning();
expect(result).toEqual(false);
} catch (error) {
expect(error).toEqual({
error: 'server is running',
});
}
});
});
Where the serverHandler
is as follow:
const spawn = require('child_process').spawn;
const isReachable = require('is-reachable');
var child = null;
exports.start = (latency, path) => {
child = spawn('node', [path, latency]);
};
exports.kill = () => {
child.kill();
};
exports.isRunning = async () => {
return await isReachable('http://localhost:8080');
};
As you can see, so far we are only trying to make steps 1 and 3 work, before adding anymore test logic. Sadly, it does not. When I run this test, I get the following output:
● Test the test server › Server is killed
expect(received).toEqual(expected) // deep equality
Expected: true
Received: false
14 |
15 | result = await serverHandler.isRunning();
> 16 | expect(result).toEqual(true);
| ^
17 | });
18 |
19 | afterEach(async () => {
at toEqual (__tests__/integration/serverIntegrationExample.test.js:16:20)
at tryCatch (node_modules/regenerator-runtime/runtime.js:45:40)
at Generator.invoke [as _invoke] (node_modules/regenerator-runtime/runtime.js:271:22)
at Generator.prototype.(anonymous function) [as next] (node_modules/regenerator-runtime/runtime.js:97:21)
at tryCatch (node_modules/regenerator-runtime/runtime.js:45:40)
at invoke (node_modules/regenerator-runtime/runtime.js:135:20)
at node_modules/regenerator-runtime/runtime.js:145:13
at tryCallOne (node_modules/promise/lib/core.js:37:12)
at node_modules/promise/lib/core.js:123:15
at flush (node_modules/asap/raw.js:50:29)
It looks like the server is never actually started. I know the test server is working well because all calls succeed in the application. I have found various sources speaking of similar problems, but most of them seem to be either dead ends, or make use of non-portable OS features, which is unacceptable for us (I am getting this output from Ubuntu).
What is(are) the problem(s) in this code and how can I achieve this? Also note, this is my first Node.js project, so any constructive advice on the code would be greatly appreciated.
EDIT
Here is the code for index.js
:
const Express = require('express');
const multer = require('multer');
const bodyParser = require('body-parser');
const fs = require('fs');
const labelListMock = require('./mockData');
const uploadDirectory = './images';
const app = Express();
app.use(bodyParser.json());
const Storage = multer.diskStorage({
destination(req, file, callback) {
callback(null, uploadDirectory);
},
filename(req, file, callback) {
callback(null, `${file.fieldname}_${Date.now()}_${file.originalname}`);
},
});
const upload = multer({storage: Storage});
app.get('/', (req, res) => {
res.status(200).send('You can post to /DispatchData.');
});
var latency = process.argv[2];
if (isNaN(latency)) {
latency = 0;
}
app.use(function(req, res, next) {
setTimeout(next, latency);
});
app.get('/RetrieveTypes', (req, res) => {
res.status(200).json(labelListMock);
});
app.post(
'/DispatchData',
checkUploadPath,
upload.single('photo'),
(req, res, next) => {
console.log('file', req.file);
console.log('body', req.body);
res.status(200).json({
message: 'success!',
fileName: req.file.originalname,
category: 'buildAILabel',
});
},
);
module.exports = app.listen(8080, () => {
console.log(
'Mock server running on http://localhost:8080 (or http:://10.0.2.2:8080 if using an emulator.)',
);
});
function checkUploadPath(req, res, next) {
fs.exists(uploadDirectory, function(exists) {
if (exists) {
next();
} else {
fs.mkdir(uploadDirectory, function(err) {
if (err) {
console.log('Error in folder creation');
next();
}
next();
});
}
});
}
来源:https://stackoverflow.com/questions/58423661/how-to-to-run-close-an-http-server-as-child-process