implemented code coverage
This commit is contained in:
parent
d004a01b69
commit
0ea28fa50a
@ -10,7 +10,7 @@
|
|||||||
"start": "tsc && node dist/index.js || exit 1",
|
"start": "tsc && node dist/index.js || exit 1",
|
||||||
"dev": "nodemon -e ts,yaml --exec \"npm run start\"",
|
"dev": "nodemon -e ts,yaml --exec \"npm run start\"",
|
||||||
"loadDev": "node dist/test/loadDev.js",
|
"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": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
|
25
src/db.ts
25
src/db.ts
@ -42,15 +42,18 @@ export default class db {
|
|||||||
});
|
});
|
||||||
mongoose.connection.on('error', console.error.bind(console, 'connection error:'));
|
mongoose.connection.on('error', console.error.bind(console, 'connection error:'));
|
||||||
mongoose.connection.on('disconnected', () => { // reset state on disconnect
|
mongoose.connection.on('disconnected', () => { // reset state on disconnect
|
||||||
console.info('Database disconnected');
|
if (process.env.NODE_ENV !== 'test') { // Do not interfere with testing
|
||||||
this.state.db = 0;
|
console.info('Database disconnected');
|
||||||
done();
|
this.state.db = 0;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
process.on('SIGINT', () => { // close connection when app is terminated
|
process.on('SIGINT', () => { // close connection when app is terminated
|
||||||
mongoose.connection.close(() => {
|
if (!this.state.db) { // database still connected
|
||||||
console.info('Mongoose default connection disconnected through app termination');
|
mongoose.connection.close(() => {
|
||||||
process.exit(0);
|
console.info('Mongoose default connection disconnected through app termination');
|
||||||
});
|
process.exit(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
mongoose.connection.once('open', () => {
|
mongoose.connection.once('open', () => {
|
||||||
mongoose.set('useFindAndModify', false);
|
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 () {
|
static getState () {
|
||||||
return this.state;
|
return this.state;
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import db from './db';
|
|||||||
// TODO: add multiple samples at once
|
// TODO: add multiple samples at once
|
||||||
// TODO: coverage
|
// TODO: coverage
|
||||||
// TODO: think about the display of deleted/new samples and validation in data and UI
|
// 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
|
// tell if server is running in debug or production environment
|
||||||
console.info(process.env.NODE_ENV === 'production' ? '===== PRODUCTION =====' : process.env.NODE_ENV === 'test' ? '' :'===== DEVELOPMENT =====');
|
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));
|
before(done => TestHelper.before(done));
|
||||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||||
afterEach(done => TestHelper.afterEach(server, done));
|
afterEach(done => TestHelper.afterEach(server, done));
|
||||||
|
after(done => TestHelper.after(done));
|
||||||
|
|
||||||
describe('GET /materials', () => {
|
describe('GET /materials', () => {
|
||||||
it('returns all materials', done => {
|
it('returns all materials', done => {
|
||||||
@ -146,7 +147,6 @@ describe('/material', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects requests from a write user', done => {
|
it('rejects requests from a write user', done => {
|
||||||
|
@ -5,14 +5,17 @@ import globals from '../globals';
|
|||||||
|
|
||||||
// TODO: restore measurements for m/a
|
// TODO: restore measurements for m/a
|
||||||
|
|
||||||
|
// TODO: coverage!!!
|
||||||
|
|
||||||
|
|
||||||
describe('/measurement', () => {
|
describe('/measurement', () => {
|
||||||
let server;
|
let server;
|
||||||
before(done => TestHelper.before(done));
|
before(done => TestHelper.before(done));
|
||||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||||
afterEach(done => TestHelper.afterEach(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 => {
|
it('returns the right measurement', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'get',
|
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;
|
const data = await MeasurementModel.findById(req.params.id).lean().exec().catch(err => {next(err);}) as any;
|
||||||
if (data instanceof Error) return;
|
if (data instanceof Error) return;
|
||||||
if (!data) {
|
if (!data) {
|
||||||
res.status(404).json({status: 'Not found'});
|
return res.status(404).json({status: 'Not found'});
|
||||||
}
|
}
|
||||||
|
|
||||||
// add properties needed for sampleIdCheck
|
// 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;
|
if (!await templateCheck(measurement, 'change', res, next)) return;
|
||||||
await MeasurementModel.findByIdAndUpdate(req.params.id, measurement, {new: true}).lean().exec((err, data) => {
|
await MeasurementModel.findByIdAndUpdate(req.params.id, measurement, {new: true}).lean().exec((err, data) => {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
console.log(data);
|
|
||||||
res.json(MeasurementValidate.output(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) => {
|
MeasurementModel.findById(req.params.id).lean().exec(async (err, data) => {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
if (!data) {
|
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;
|
if (!await sampleIdCheck(data, req, res, next)) return;
|
||||||
await MeasurementModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted}).lean().exec(err => {
|
await MeasurementModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted}).lean().exec(err => {
|
||||||
if (err) return next(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;
|
measurement.status = 0;
|
||||||
await new MeasurementModel(measurement).save((err, data) => {
|
await new MeasurementModel(measurement).save((err, data) => {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
console.log(data);
|
|
||||||
res.json(MeasurementValidate.output(data.toObject()));
|
res.json(MeasurementValidate.output(data.toObject()));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import TestHelper from "../test/helper";
|
import TestHelper from "../test/helper";
|
||||||
|
import db from '../db';
|
||||||
|
|
||||||
|
|
||||||
describe('/', () => {
|
describe('/', () => {
|
||||||
@ -6,6 +7,7 @@ describe('/', () => {
|
|||||||
before(done => TestHelper.before(done));
|
before(done => TestHelper.before(done));
|
||||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||||
afterEach(done => TestHelper.afterEach(server, done));
|
afterEach(done => TestHelper.afterEach(server, done));
|
||||||
|
after(done => TestHelper.after(done));
|
||||||
|
|
||||||
describe('GET /', () => {
|
describe('GET /', () => {
|
||||||
it('returns the root message', done => {
|
it('returns the root message', done => {
|
||||||
@ -40,7 +42,15 @@ describe('/', () => {
|
|||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/authorized',
|
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
|
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));
|
before(done => TestHelper.before(done));
|
||||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||||
afterEach(done => TestHelper.afterEach(server, done));
|
afterEach(done => TestHelper.afterEach(server, done));
|
||||||
|
after(done => TestHelper.after(done));
|
||||||
|
|
||||||
describe('GET /samples', () => {
|
describe('GET /samples', () => {
|
||||||
it('returns all samples', done => {
|
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, {
|
TestHelper.request(server, done, {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/sample/400000000000000000000005',
|
url: '/sample/400000000000000000000005',
|
||||||
|
@ -13,6 +13,7 @@ describe('/template', () => {
|
|||||||
before(done => TestHelper.before(done));
|
before(done => TestHelper.before(done));
|
||||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||||
afterEach(done => TestHelper.afterEach(server, done));
|
afterEach(done => TestHelper.afterEach(server, done));
|
||||||
|
after(done => TestHelper.after(done));
|
||||||
|
|
||||||
describe('/template/condition', () => {
|
describe('/template/condition', () => {
|
||||||
describe('GET /template/conditions', () => {
|
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;
|
const templateData = await model(req).findById(req.params.id).lean().exec().catch(err => {next(err);}) as any;
|
||||||
if (templateData instanceof Error) return;
|
if (templateData instanceof Error) return;
|
||||||
if (!templateData) {
|
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
|
if (!_.isEqual(_.pick(templateData, _.keys(template)), template)) { // data was changed
|
||||||
|
@ -9,6 +9,7 @@ describe('/user', () => {
|
|||||||
before(done => TestHelper.before(done));
|
before(done => TestHelper.before(done));
|
||||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||||
afterEach(done => TestHelper.afterEach(server, done));
|
afterEach(done => TestHelper.afterEach(server, done));
|
||||||
|
after(done => TestHelper.after(done));
|
||||||
|
|
||||||
describe('GET /users', () => {
|
describe('GET /users', () => {
|
||||||
it('returns all users', done => {
|
it('returns all users', done => {
|
||||||
|
@ -39,6 +39,10 @@ export default class TestHelper {
|
|||||||
server.close(done);
|
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}
|
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);
|
let st = supertest(server);
|
||||||
if (options.hasOwnProperty('auth') && options.auth.hasOwnProperty('key')) { // resolve API key
|
if (options.hasOwnProperty('auth') && options.auth.hasOwnProperty('key')) { // resolve API key
|
||||||
@ -58,6 +62,9 @@ export default class TestHelper {
|
|||||||
st = st.delete(options.url)
|
st = st.delete(options.url)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (options.hasOwnProperty('reqType')) { // request body
|
||||||
|
st = st.type(options.reqType);
|
||||||
|
}
|
||||||
if (options.hasOwnProperty('req')) { // request body
|
if (options.hasOwnProperty('req')) { // request body
|
||||||
st = st.send(options.req);
|
st = st.send(options.req);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user