implemented code coverage
This commit is contained in:
parent
d004a01b69
commit
0ea28fa50a
@ -10,7 +10,7 @@
|
||||
"start": "tsc && node dist/index.js || exit 1",
|
||||
"dev": "nodemon -e ts,yaml --exec \"npm run start\"",
|
||||
"loadDev": "node dist/test/loadDev.js",
|
||||
"coverage": "nyc --reporter=html --reporter=tex mocha dist/**/**.spec.js"
|
||||
"coverage": "tsc && nyc --reporter=html --reporter=text mocha dist/**/**.spec.js --timeout 5000"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
|
13
src/db.ts
13
src/db.ts
@ -42,15 +42,18 @@ export default class db {
|
||||
});
|
||||
mongoose.connection.on('error', console.error.bind(console, 'connection error:'));
|
||||
mongoose.connection.on('disconnected', () => { // reset state on disconnect
|
||||
if (process.env.NODE_ENV !== 'test') { // Do not interfere with testing
|
||||
console.info('Database disconnected');
|
||||
this.state.db = 0;
|
||||
done();
|
||||
}
|
||||
});
|
||||
process.on('SIGINT', () => { // close connection when app is terminated
|
||||
if (!this.state.db) { // database still connected
|
||||
mongoose.connection.close(() => {
|
||||
console.info('Mongoose default connection disconnected through app termination');
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
});
|
||||
mongoose.connection.once('open', () => {
|
||||
mongoose.set('useFindAndModify', false);
|
||||
@ -60,6 +63,14 @@ export default class db {
|
||||
});
|
||||
}
|
||||
|
||||
static disconnect (done) {
|
||||
mongoose.connection.close(() => {
|
||||
console.info(process.env.NODE_ENV === 'test' ? '' : `Disconnected from database`);
|
||||
this.state.db = 0;
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
static getState () {
|
||||
return this.state;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import db from './db';
|
||||
// TODO: add multiple samples at once
|
||||
// TODO: coverage
|
||||
// TODO: think about the display of deleted/new samples and validation in data and UI
|
||||
// TODO: improve error coverage
|
||||
|
||||
// tell if server is running in debug or production environment
|
||||
console.info(process.env.NODE_ENV === 'production' ? '===== PRODUCTION =====' : process.env.NODE_ENV === 'test' ? '' :'===== DEVELOPMENT =====');
|
||||
|
@ -12,6 +12,7 @@ describe('/material', () => {
|
||||
before(done => TestHelper.before(done));
|
||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||
afterEach(done => TestHelper.afterEach(server, done));
|
||||
after(done => TestHelper.after(done));
|
||||
|
||||
describe('GET /materials', () => {
|
||||
it('returns all materials', done => {
|
||||
@ -146,7 +147,6 @@ describe('/material', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('rejects requests from a write user', done => {
|
||||
|
@ -5,14 +5,17 @@ import globals from '../globals';
|
||||
|
||||
// TODO: restore measurements for m/a
|
||||
|
||||
// TODO: coverage!!!
|
||||
|
||||
|
||||
describe('/measurement', () => {
|
||||
let server;
|
||||
before(done => TestHelper.before(done));
|
||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||
afterEach(done => TestHelper.afterEach(server, done));
|
||||
after(done => TestHelper.after(done));
|
||||
|
||||
describe('GET /mesurement/{id}', () => {
|
||||
describe('GET /measurement/{id}', () => {
|
||||
it('returns the right measurement', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'get',
|
||||
|
@ -36,7 +36,7 @@ router.put('/measurement/' + IdValidate.parameter(), async (req, res, next) => {
|
||||
const data = await MeasurementModel.findById(req.params.id).lean().exec().catch(err => {next(err);}) as any;
|
||||
if (data instanceof Error) return;
|
||||
if (!data) {
|
||||
res.status(404).json({status: 'Not found'});
|
||||
return res.status(404).json({status: 'Not found'});
|
||||
}
|
||||
|
||||
// add properties needed for sampleIdCheck
|
||||
@ -55,7 +55,6 @@ router.put('/measurement/' + IdValidate.parameter(), async (req, res, next) => {
|
||||
if (!await templateCheck(measurement, 'change', res, next)) return;
|
||||
await MeasurementModel.findByIdAndUpdate(req.params.id, measurement, {new: true}).lean().exec((err, data) => {
|
||||
if (err) return next(err);
|
||||
console.log(data);
|
||||
res.json(MeasurementValidate.output(data));
|
||||
});
|
||||
});
|
||||
@ -66,12 +65,12 @@ router.delete('/measurement/' + IdValidate.parameter(), (req, res, next) => {
|
||||
MeasurementModel.findById(req.params.id).lean().exec(async (err, data) => {
|
||||
if (err) return next(err);
|
||||
if (!data) {
|
||||
res.status(404).json({status: 'Not found'});
|
||||
return res.status(404).json({status: 'Not found'});
|
||||
}
|
||||
if (!await sampleIdCheck(data, req, res, next)) return;
|
||||
await MeasurementModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted}).lean().exec(err => {
|
||||
if (err) return next(err);
|
||||
res.json({status: 'OK'});
|
||||
return res.json({status: 'OK'});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -89,7 +88,6 @@ router.post('/measurement/new', async (req, res, next) => {
|
||||
measurement.status = 0;
|
||||
await new MeasurementModel(measurement).save((err, data) => {
|
||||
if (err) return next(err);
|
||||
console.log(data);
|
||||
res.json(MeasurementValidate.output(data.toObject()));
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,5 @@
|
||||
import TestHelper from "../test/helper";
|
||||
import db from '../db';
|
||||
|
||||
|
||||
describe('/', () => {
|
||||
@ -6,6 +7,7 @@ describe('/', () => {
|
||||
before(done => TestHelper.before(done));
|
||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||
afterEach(done => TestHelper.afterEach(server, done));
|
||||
after(done => TestHelper.after(done));
|
||||
|
||||
describe('GET /', () => {
|
||||
it('returns the root message', done => {
|
||||
@ -40,7 +42,15 @@ describe('/', () => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'get',
|
||||
url: '/authorized',
|
||||
auth: {name: 'admin', pass: 'Abc123!!'},
|
||||
auth: {basic: {name: 'admin', pass: 'Abc123!!'}},
|
||||
httpStatus: 401
|
||||
});
|
||||
});
|
||||
it('does not work with incorrect username', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'get',
|
||||
url: '/authorized',
|
||||
auth: {basic: {name: 'adminxx', pass: 'Abc123!!'}},
|
||||
httpStatus: 401
|
||||
});
|
||||
});
|
||||
@ -66,4 +76,32 @@ describe('/', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('An invalid JSON body', () => {
|
||||
it('is rejected', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'post',
|
||||
url: '/',
|
||||
httpStatus: 400,
|
||||
reqType: 'json',
|
||||
req: '{"xxx"}',
|
||||
res: {status: 'Invalid JSON body'}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('A not connected database', () => {
|
||||
it('resolves to an 500 error', done => {
|
||||
db.disconnect(() => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'get',
|
||||
url: '/',
|
||||
httpStatus: 500
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// describe('API') // TODO not in production
|
||||
});
|
@ -19,6 +19,7 @@ describe('/sample', () => {
|
||||
before(done => TestHelper.before(done));
|
||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||
afterEach(done => TestHelper.afterEach(server, done));
|
||||
after(done => TestHelper.after(done));
|
||||
|
||||
describe('GET /samples', () => {
|
||||
it('returns all samples', done => {
|
||||
@ -197,7 +198,7 @@ describe('/sample', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a deleted sample for a maintain/admin user', done => { // TODO: make tests work
|
||||
it('returns a deleted sample for a maintain/admin user', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'get',
|
||||
url: '/sample/400000000000000000000005',
|
||||
|
@ -13,6 +13,7 @@ describe('/template', () => {
|
||||
before(done => TestHelper.before(done));
|
||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||
afterEach(done => TestHelper.afterEach(server, done));
|
||||
after(done => TestHelper.after(done));
|
||||
|
||||
describe('/template/condition', () => {
|
||||
describe('GET /template/conditions', () => {
|
||||
|
@ -44,7 +44,7 @@ router.put('/template/:collection(measurement|condition)/' + IdValidate.paramete
|
||||
const templateData = await model(req).findById(req.params.id).lean().exec().catch(err => {next(err);}) as any;
|
||||
if (templateData instanceof Error) return;
|
||||
if (!templateData) {
|
||||
res.status(404).json({status: 'Not found'});
|
||||
return res.status(404).json({status: 'Not found'});
|
||||
}
|
||||
|
||||
if (!_.isEqual(_.pick(templateData, _.keys(template)), template)) { // data was changed
|
||||
|
@ -9,6 +9,7 @@ describe('/user', () => {
|
||||
before(done => TestHelper.before(done));
|
||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||
afterEach(done => TestHelper.afterEach(server, done));
|
||||
after(done => TestHelper.after(done));
|
||||
|
||||
describe('GET /users', () => {
|
||||
it('returns all users', done => {
|
||||
|
@ -39,6 +39,10 @@ export default class TestHelper {
|
||||
server.close(done);
|
||||
}
|
||||
|
||||
static after(done) {
|
||||
db.disconnect(done);
|
||||
}
|
||||
|
||||
static request (server, done, options) { // options in form: {method, url, auth: {key/basic: 'name' or 'key'/{name, pass}}, httpStatus, req, res}
|
||||
let st = supertest(server);
|
||||
if (options.hasOwnProperty('auth') && options.auth.hasOwnProperty('key')) { // resolve API key
|
||||
@ -58,6 +62,9 @@ export default class TestHelper {
|
||||
st = st.delete(options.url)
|
||||
break;
|
||||
}
|
||||
if (options.hasOwnProperty('reqType')) { // request body
|
||||
st = st.type(options.reqType);
|
||||
}
|
||||
if (options.hasOwnProperty('req')) { // request body
|
||||
st = st.send(options.req);
|
||||
}
|
||||
|
Reference in New Issue
Block a user