implemented code coverage
This commit is contained in:
		| @@ -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": "", | ||||||
|   | |||||||
							
								
								
									
										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('error', console.error.bind(console, 'connection error:')); | ||||||
|     mongoose.connection.on('disconnected', () => {  // reset state on disconnect |     mongoose.connection.on('disconnected', () => {  // reset state on disconnect | ||||||
|  |       if (process.env.NODE_ENV !== 'test') {  // Do not interfere with testing | ||||||
|         console.info('Database disconnected'); |         console.info('Database disconnected'); | ||||||
|         this.state.db = 0; |         this.state.db = 0; | ||||||
|       done(); |       } | ||||||
|     }); |     }); | ||||||
|     process.on('SIGINT', () => {  // close connection when app is terminated |     process.on('SIGINT', () => {  // close connection when app is terminated | ||||||
|  |       if (!this.state.db) {  // database still connected | ||||||
|         mongoose.connection.close(() => { |         mongoose.connection.close(() => { | ||||||
|           console.info('Mongoose default connection disconnected through app termination'); |           console.info('Mongoose default connection disconnected through app termination'); | ||||||
|           process.exit(0); |           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
	 VLE2FE
					VLE2FE