diff --git a/package.json b/package.json index 3cb5d8c..21de91d 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,13 @@ "coverage": "nyc npm test && nyc report --reporter=text-lcov | coveralls", "build": "rm -rf build && babel -d ./build ./src -s", "start": "npm run build && node ./build/index.js", - "pretest": "cross-env NODE_ENV=test npm run down && NODE_ENV=test npm run migrate && NODE_ENV=test npm run seed", - "test": "cross-env NODE_ENV=test nyc --reporter=text mocha --require @babel/register --require @babel/polyfill ./src/tests/*.js --timeout 30000 --exit", + "pretest": "cross-env NODE_ENV=test npm run dropdb && NODE_ENV=test npm run createdb && npm run down && NODE_ENV=test npm run migrate && NODE_ENV=test npm run seed", + "test": "cross-env NODE_ENV=test nyc --reporter=text mocha --require @babel/register --require @babel/polyfill ./src/tests/*.test.js --timeout 30000 --exit", "down": "cross-env NODE_ENV=test node_modules/.bin/sequelize db:migrate:undo", "migrate": "cross-env NODE_ENV=test node_modules/.bin/sequelize db:migrate", - "seed": "node_modules/.bin/sequelize db:seed:all" + "seed": "node_modules/.bin/sequelize db:seed:all", + "dropdb": "node_modules/.bin/sequelize db:drop", + "createdb": "node_modules/.bin/sequelize db:create authors-haven-test" }, "engines": { "node": "10.16.0" diff --git a/src/controllers/articleController.js b/src/controllers/articleController.js index 26a3e86..0dc70fd 100644 --- a/src/controllers/articleController.js +++ b/src/controllers/articleController.js @@ -28,8 +28,10 @@ class ArticleController { description: description.trim(), body: body.trim() }; - if (req.body.tags || req.body.category) { + if (req.body.tags) { payload.tagList = req.body.tags.trim().split(/[ ,]+/); + } + if (req.body.category) { payload.category = req.body.category.trim(); } payload.images = await uploadImage(req.files.image); @@ -114,7 +116,11 @@ class ArticleController { } article.description = (description || originalArticle.description).trim(); article.body = (body || originalArticle.body).trim(); - article.tagList = (tags || originalArticle.tagList.toString()).trim().split(/[ ,]+/); + if (originalArticle.tagList) { + article.tagList = (tags || originalArticle.tagList.toString()).trim().split(/[ ,]+/); + } else { + article.tagList = tags.trim().split(/[ ,]+/); + } article.category = (category || originalArticle.category).trim(); if (req.files.image) { article.images = await uploadImage(req.files.image); @@ -125,7 +131,7 @@ class ArticleController { ); if (updatedArticle) { return res.status(200).json({ - message: 'Profile updated successfully', + message: 'Article updated successfully', article: updatedArticle[1] }); } @@ -143,7 +149,7 @@ class ArticleController { static async deteleArticle(req, res) { try { const deleted = await Article.destroy({ - where: { slug: req.userData.slug } + where: { id: req.userData.articleId } }); if (deleted) { return res.status(200).json({ diff --git a/src/middleware/findOwner.js b/src/middleware/findOwner.js index 5c4b365..4a316c6 100644 --- a/src/middleware/findOwner.js +++ b/src/middleware/findOwner.js @@ -18,6 +18,7 @@ const isOwner = async (req, res, next) => { }); } req.userData.slug = slug; + req.userData.articleId = foundArticle.id; next(); }; diff --git a/src/sequelize/seeders/20190820163908-create-admin-and-user.js b/src/sequelize/seeders/20190820163908-create-admin-and-user.js deleted file mode 100644 index 12163fd..0000000 --- a/src/sequelize/seeders/20190820163908-create-admin-and-user.js +++ /dev/null @@ -1,22 +0,0 @@ -import bcrypt from 'bcrypt'; - -export const up = queryInterface => queryInterface.bulkInsert('Users', [{ - firstName: 'Raymond', - lastName: 'Gakwaya', - userName: 'rayGakwa', - email: 'ray@gmail.com', - password: bcrypt.hashSync('Admin1234', 10), - role: 'admin', - verified: true -}, -{ - firstName: 'Carlos', - lastName: 'Gringo', - userName: 'carlosG', - email: 'carlos@gmail.com', - password: bcrypt.hashSync('User1234', 10), - role: 'user', - verified: true -}], {}); - -export const down = queryInterface => queryInterface.bulkDelete('Users', null, {}); diff --git a/src/tests/article.test.js b/src/tests/article.test.js index 01b65f6..be4bf0c 100644 --- a/src/tests/article.test.js +++ b/src/tests/article.test.js @@ -40,8 +40,8 @@ describe('POST AND GET /api/v1/articles', () => { .request(app) .post('/api/v1/users/login') .send({ - email: 'carlos@gmail.com', - password: 'User1234' + email: 'eric.malaba@gmail.com', + password: 'Superadmin12' }) .end((err, res) => { if (err) done(err); @@ -169,6 +169,19 @@ describe('POST AND GET /api/v1/articles', () => { done(); }); }); + it('Should return error if category is empty', (done) => { + chai + .request(app) + .post('/api/v1/articles') + .set('Authorization', userToken) + .field(dummyArticle.lessCategory) + .end((err, res) => { + if (err) done(err); + expect(res).have.status(201); + expect(res.body).to.have.keys('article'); + done(); + }); + }); it('Should return error if category is not a string', (done) => { chai .request(app) @@ -197,6 +210,19 @@ describe('POST AND GET /api/v1/articles', () => { done(); }); }); + it('Should return error if taglist is not set', (done) => { + chai + .request(app) + .post('/api/v1/articles') + .set('Authorization', userToken) + .field(dummyArticle.lessTags) + .end((err, res) => { + if (err) done(err); + expect(res).have.status(201); + expect(res.body).to.have.key('article'); + done(); + }); + }); it('Should create and return an article', (done) => { chai .request(app) @@ -325,7 +351,7 @@ describe('UPDATE /api/v1/articles/:slug', () => { if (err) done(err); expect(res).have.status(200); expect(res.body).to.have.key('article', 'message'); - expect(res.body.message).to.deep.equal('Profile updated successfully'); + expect(res.body.message).to.deep.equal('Article updated successfully'); done(); }); }); @@ -355,6 +381,19 @@ describe('UPDATE /api/v1/articles/:slug', () => { done(); }); }); + it('Should return error if taglist is not set', (done) => { + chai + .request(app) + .put(`/api/v1/articles/${articleSlug}`) + .set('Authorization', userToken) + .field(dummyArticle.updateMissingtags) + .end((err, res) => { + if (err) done(err); + expect(res).have.status(200); + expect(res.body).to.have.key('article', 'message'); + done(); + }); + }); it('Should return the old body if it was not updated', (done) => { chai .request(app) @@ -405,7 +444,7 @@ describe('UPDATE /api/v1/articles/:slug', () => { if (err) done(err); expect(res).have.status(200); expect(res.body).to.have.key('article', 'message'); - expect(res.body.message).to.deep.equal('Profile updated successfully'); + expect(res.body.message).to.deep.equal('Article updated successfully'); newArticleSlug = res.body.article.slug; done(); }); diff --git a/src/tests/dummyData/dummyArticle.js b/src/tests/dummyData/dummyArticle.js index b4bc70b..3d54dff 100644 --- a/src/tests/dummyData/dummyArticle.js +++ b/src/tests/dummyData/dummyArticle.js @@ -1,8 +1,21 @@ export default { validArticle: { + title: 'Growth mindset', + description: 'How to demonstrate growth mindsewt', + category: 'Eductaion', + body: + 'is simply dummy text of the printing and typesetting industry Lorem Ipsum has' + }, + lessCategory: { title: 'Growth mindset', description: 'How to demonstrate growth mindsewt', tags: 'Fixed mind, Confidence, low self-esteem', + body: + 'is simply dummy text of the printing and typesetting industry Lorem Ipsum has' + }, + lessTags: { + title: 'Growth mindset', + description: 'How to demonstrate growth mindsewt', category: 'Eductaion', body: 'is simply dummy text of the printing and typesetting industry Lorem Ipsum has' @@ -44,13 +57,12 @@ export default { 'is simply dummy text of the printing and typesetting industry Lorem Ipsum has' }, updateMissingBody: { + description: 'How to demonstrate growth mindsewt', tags: 'Bango, Hip-Hop, R&B', - category: 'Music', }, updateMissingtags: { - tags: 'Bango, Hip-Hop, R&B', - body: - 'Music is the best medicine. It can get you out of bed and wiggle your body' + description: 'How to demonstrate growth mindsewt', + category: 'Music', }, updateMissingCategory: { tags: 'Bango, Hip-Hop, R&B', @@ -76,14 +88,16 @@ export default { description: 'How to demonstrate growth mindsewt', tags: [12, 356, 78, 90], category: 'Fixed mind Confidence', - body: 'is simply dummy text of the printing and typesetting industry Lorem Ipsum has' + body: + 'is simply dummy text of the printing and typesetting industry Lorem Ipsum has' }, incorrectCategory: { title: 'Growth mindset', description: 'How to demonstrate growth mindsewt', tags: 'Fixed mind-Confidence, Fixed-mind-Confidence', category: [12, 356, 78, 90], - body: 'is simply dummy text of the printing and typesetting industry Lorem Ipsum has' + body: + 'is simply dummy text of the printing and typesetting industry Lorem Ipsum has' }, invalidUserToken: { id: 1000, @@ -95,5 +109,5 @@ export default { confirmPassword: 'Jamal1230!', role: 'user', verified: true - }, + } }; diff --git a/swagger.json b/swagger.json index 97cbb72..21957eb 100644 --- a/swagger.json +++ b/swagger.json @@ -1039,6 +1039,19 @@ } } } + }, + "404": { + "description": "Article not found", + "schema": { + "properties": { + "error": { + "type": "string" + }, + "me": { + "type": "string" + } + } + } } } } @@ -1196,6 +1209,19 @@ } } }, + "401": { + "description": "User is not authenticated", + "schema": { + "properties": { + "error": { + "type": "string" + }, + "me": { + "type": "string" + } + } + } + }, "403": { "description": "Fobidden to make changes", "schema": { @@ -1261,7 +1287,7 @@ } } }, - "404": { + "403": { "description": "User is fobidden to delete", "schema": { "properties": {