implemented code coverage
This commit is contained in:
		| @@ -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": "", | ||||
|   | ||||
							
								
								
									
										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('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; | ||||
|   } | ||||
|   | ||||
| @@ -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
	 VLE2FE
					VLE2FE