Archived
2

implemented code coverage

This commit is contained in:
VLE2FE 2020-05-28 11:47:51 +02:00
parent d004a01b69
commit 0ea28fa50a
12 changed files with 79 additions and 18 deletions

View File

@ -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": "",

View File

@ -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
console.info('Database disconnected');
this.state.db = 0;
done();
if (process.env.NODE_ENV !== 'test') { // Do not interfere with testing
console.info('Database disconnected');
this.state.db = 0;
}
});
process.on('SIGINT', () => { // close connection when app is terminated
mongoose.connection.close(() => {
console.info('Mongoose default connection disconnected through app termination');
process.exit(0);
});
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;
}

View File

@ -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 =====');

View File

@ -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 => {

View File

@ -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',

View File

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

View File

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

View File

@ -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',

View File

@ -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', () => {

View File

@ -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

View File

@ -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 => {

View File

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