diff --git a/.sequelizerc b/.sequelizerc index 0d73769..e2fb905 100644 --- a/.sequelizerc +++ b/.sequelizerc @@ -5,6 +5,6 @@ const path = require('path'); module.exports = { 'config': path.resolve('server/database/config', 'config.js'), 'models-path': path.resolve('server/database/models'), - 'seeds-path': path.resolve('server/database/seeds'), + 'seeders-path': path.resolve('server/database/seeds'), 'migrations-path': path.resolve('server/database/migrations') } diff --git a/package-lock.json b/package-lock.json index 5f0ef02..982cf6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -879,6 +879,38 @@ "any-observable": "^0.3.0" } }, + "@sinonjs/commons": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.4.0.tgz", + "integrity": "sha512-9jHK3YF/8HtJ9wCAbG+j8cD0i0+ATS9A7gXFqS36TblLPNy6rEEc+SB0imo91eCboGaBYGV/MT1/br/J+EE7Tw==", + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/formatio": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.1.tgz", + "integrity": "sha512-tsHvOB24rvyvV2+zKMmPkZ7dXX6LSLKZ7aOtXY6Edklp0uRcgGpOsQTTGTcWViFyx4uhWc6GV8QdnALbIbIdeQ==", + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" + } + }, + "@sinonjs/samsam": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.2.tgz", + "integrity": "sha512-ILO/rR8LfAb60Y1Yfp9vxfYAASK43NFC2mLzpvLUbCQY/Qu8YwReboseu8aheCEkyElZF2L2T9mHcR2bgdvZyA==", + "requires": { + "@sinonjs/commons": "^1.0.2", + "array-from": "^2.1.1", + "lodash": "^4.17.11" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" + }, "@types/chai": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", @@ -1151,6 +1183,11 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=" + }, "array-includes": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", @@ -1338,6 +1375,11 @@ "tweetnacl": "^0.14.3" } }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + }, "binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", @@ -2283,8 +2325,7 @@ "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" }, "dir-glob": { "version": "3.0.1", @@ -4230,8 +4271,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbols": { "version": "1.0.0", @@ -5163,6 +5203,11 @@ "verror": "1.10.0" } }, + "just-extend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", + "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==" + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -5609,6 +5654,11 @@ } } }, + "lolex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.1.0.tgz", + "integrity": "sha512-BYxIEXiVq5lGIXeVHnsFzqa1TxN5acnKnPCdlZSpzm8viNEOhiigupA4vTQ9HEFQ6nLTQ9wQOgBknJgzUYQ9Aw==" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -6245,6 +6295,33 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "nise": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.0.tgz", + "integrity": "sha512-Z3sfYEkLFzFmL8KY6xnSJLRxwQwYBjOXi/24lb62ZnZiGA0JUzGGTI6TBIgfCSMIDl9Jlu8SRmHNACLTemDHww==", + "requires": { + "@sinonjs/formatio": "^3.1.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "lolex": "^4.1.0", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "requires": { + "isarray": "0.0.1" + } + } + } + }, "node-environment-flags": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", @@ -8150,6 +8227,20 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, + "sinon": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.3.2.tgz", + "integrity": "sha512-thErC1z64BeyGiPvF8aoSg0LEnptSaWE7YhdWWbWXgelOyThent7uKOnnEh9zBxDbKixtr5dEko+ws1sZMuFMA==", + "requires": { + "@sinonjs/commons": "^1.4.0", + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/samsam": "^3.3.1", + "diff": "^3.5.0", + "lolex": "^4.0.1", + "nise": "^1.4.10", + "supports-color": "^5.5.0" + } + }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -8550,7 +8641,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -8903,8 +8993,7 @@ "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" }, "type-fest": { "version": "0.6.0", diff --git a/package.json b/package.json index 3a237a2..74814c1 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,11 @@ "coverage": "nyc report --reporter=text-lcov | coveralls", "db:migrate": "sequelize db:migrate", "db:migrate-undo": "sequelize db:migrate:undo:all", - "db:rollback": "npm run db:back && npm run db:roll && npm run db:seed", + "db:rollback": "npm run db:migrate-undo && npm run db:migrate && npm run db:seed", "db:seed": "sequelize db:seed:all", "start": "node dist/index.js", "start:dev": "cross-env NODE_ENV=development DEBUG=dev nodemon --exec babel-node server", - "test": "nyc mocha --timeout 1000 -r esm --exit" + "test": "npm run db:rollback && nyc mocha --timeout 1000 -r esm --exit" }, "husky": { "hooks": { @@ -26,18 +26,20 @@ "author": "Andela Simulations Programme", "license": "MIT", "dependencies": { + "bcryptjs": "^2.4.3", "coveralls": "^3.0.5", "debug": "^4.1.1", "dotenv": "^8.0.0", "express": "^4.17.1", "morgan": "^1.9.1", - "swagger-ui-express": "^4.0.7", - "yamljs": "^0.3.0", "pg": "^7.11.0", "pg-hstore": "^2.3.3", "sequelize": "^5.10.2", "sequelize-cli": "^5.5.0", - "sqlite3": "^4.0.9" + "sinon": "^7.3.2", + "sqlite3": "^4.0.9", + "swagger-ui-express": "^4.0.7", + "yamljs": "^0.3.0" }, "devDependencies": { "@babel/cli": "^7.5.5", diff --git a/server/controllers/user.js b/server/controllers/user.js new file mode 100644 index 0000000..a654e90 --- /dev/null +++ b/server/controllers/user.js @@ -0,0 +1,50 @@ +import helpers from '../helpers'; + +const { + comparePassword, findUser, serverResponse, serverError +} = helpers; +// const { +// comparePassword, findUser, generateToken, serverResponse, serverError +// } = helpers; +/** + * + * + * @class User + */ +class User { + /** + * + * + * @static + * @param {object} req - request object + * @param {object} res - response object + * @memberof User + * @returns {json} object + */ + static async login(req, res) { + try { + const { userLogin, password } = req.body; + if (!/\D/.test(userLogin)) { + return serverResponse(res, 400, { + message: 'user login must be a string' + }); + } + const user = await findUser(userLogin); + let verifyPassword; + if (user) verifyPassword = await comparePassword(password, user.password); + if (!user || !verifyPassword) { + return serverResponse(res, 403, { + message: 'incorrect username or password' + }); + } + const { dataValues } = user; + // const token = generateToken(id); + delete dataValues.password; + return serverResponse(res, 200, { user: { ...dataValues } }); + } catch (error) { + serverError(res); + } + } +} + +export default User; diff --git a/server/database/migrations/20190729172658-create-user.js b/server/database/migrations/20190729172658-create-user.js new file mode 100644 index 0000000..7000c98 --- /dev/null +++ b/server/database/migrations/20190729172658-create-user.js @@ -0,0 +1,64 @@ +module.exports = { + up: (queryInterface, Sequelize) => queryInterface.createTable('Users', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + firstName: { + allowNull: false, + type: Sequelize.STRING + }, + lastName: { + allowNull: false, + type: Sequelize.STRING + }, + userName: { + allowNull: false, + unique: true, + type: Sequelize.STRING + }, + email: { + allowNull: false, + unique: true, + type: Sequelize.STRING + }, + password: { + allowNull: false, + type: Sequelize.STRING + }, + avatarUrl: { + allowNull: false, + type: Sequelize.STRING + }, + facebookId: { + type: Sequelize.BIGINT + }, + googleId: { + type: Sequelize.BIGINT + }, + twitterId: { + type: Sequelize.BIGINT + }, + verified: { + allowNull: false, + type: Sequelize.BOOLEAN, + defaultValue: false + }, + status: { + allowNull: false, + type: Sequelize.STRING, + defaultValue: 'active' + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }), + down: queryInterface => queryInterface.dropTable('Users') +}; diff --git a/server/database/models/index.js b/server/database/models/index.js index 473df6a..efafaae 100644 --- a/server/database/models/index.js +++ b/server/database/models/index.js @@ -1,3 +1,4 @@ +/* istanbul ignore file */ import fs from 'fs'; import path from 'path'; import Sequelize from 'sequelize'; @@ -36,4 +37,4 @@ Object.keys(db).forEach((modelName) => { db.sequelize = sequelize; db.Sequelize = Sequelize; -module.exports = db; +export default db; diff --git a/server/database/models/user.js b/server/database/models/user.js new file mode 100644 index 0000000..3afddc3 --- /dev/null +++ b/server/database/models/user.js @@ -0,0 +1,23 @@ +module.exports = (sequelize, DataTypes) => { + const User = sequelize.define( + 'User', + { + firstName: DataTypes.STRING, + lastName: DataTypes.STRING, + userName: DataTypes.STRING, + email: DataTypes.STRING, + password: DataTypes.STRING, + avatarUrl: DataTypes.STRING, + facebookId: DataTypes.BIGINT, + googleId: DataTypes.BIGINT, + twitterId: DataTypes.BIGINT, + verified: DataTypes.BOOLEAN, + status: DataTypes.STRING + }, + {} + ); + User.associate = (models) => { + // associations can be defined here + }; + return User; +}; diff --git a/server/database/seeds/20190729181912-user.js b/server/database/seeds/20190729181912-user.js new file mode 100644 index 0000000..202f62c --- /dev/null +++ b/server/database/seeds/20190729181912-user.js @@ -0,0 +1,26 @@ +module.exports = { + up: queryInterface => queryInterface.bulkInsert( + 'Users', + [ + { + firstName: 'Chukwualuka', + lastName: 'Adekorede', + userName: 'adechukwu', + email: 'adechukwu@gmail.com', + password: + '$2y$10$sO/43iWnXUU7bj14tU3jSOY0l4H0OSaFdlXpCKUSn1Ei3D5gL3uw2', + avatarUrl: 'https://picsum.photos/200', + facebookId: '2938473479238', + googleId: '29384756390847', + twitterId: '227293844790847', + verified: true, + status: 'active', + createdAt: new Date(), + updatedAt: new Date() + } + ], + {} + ), + + down: queryInterface => queryInterface.bulkDelete('Users', null, {}) +}; diff --git a/server/docs/authors-haven-api.yml b/server/docs/authors-haven-api.yml index 0432413..03b6bfb 100644 --- a/server/docs/authors-haven-api.yml +++ b/server/docs/authors-haven-api.yml @@ -32,9 +32,74 @@ paths: schema: type: string example: Welcome to Authors Haven + "/api/v1/auth/login": + summary: Login Route + post: + description: Login Route + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - email + - password + properties: + userLogin: + type: string + minLength: 2 + example: adechukwu + password: + type: string + minLength: 4 + example: password + responses: + '200': + description: Login successful + content: + application/json: + schema: + "$ref": "#/components/schemas/loginResponse" + '400': + description: Bad request + content: + application/json: + schema: + "$ref": "#/components/schemas/errorResponse" + '403': + description: Incorrect username or password + content: + application/json: + schema: + "$ref": "#/components/schemas/errorResponse" + '500': + description: Server Error + content: + application/json: + schema: + "$ref": "#/components/schemas/serverResponse" + + components: securitySchemes: BearerAuth: type: http scheme: bearer + schemas: + loginResponse: + type: object + properties: + user: + type: object + errorResponse: + type: object + properties: + message: + type: string + serverResponse: + type: object + properties: + error: + type: string diff --git a/server/helpers/findUser.js b/server/helpers/findUser.js new file mode 100644 index 0000000..e9e57e1 --- /dev/null +++ b/server/helpers/findUser.js @@ -0,0 +1,21 @@ +import models from '../database/models'; + +const { User } = models; +/** + * @name finUser + * @param {string} parameter - user input + * @returns {object} user object + */ +const findUser = async (parameter) => { + let param; + if (!/\D/.test(parameter)) { + param = { id: parameter }; + } else if (/\D/.test(parameter) && /@.{2,9}\./.test(parameter)) { + param = { email: parameter }; + } else { + param = { userName: parameter }; + } + return User.findOne({ where: param }); +}; + +export default findUser; diff --git a/server/helpers/index.js b/server/helpers/index.js new file mode 100644 index 0000000..2dfcb6c --- /dev/null +++ b/server/helpers/index.js @@ -0,0 +1,12 @@ +import passwords from './passwords'; +import findUser from './findUser'; +import { serverResponse, serverError } from './serverResponse'; + +const { comparePassword } = passwords; + +export default { + comparePassword, + findUser, + serverResponse, + serverError +}; diff --git a/server/helpers/passwords.js b/server/helpers/passwords.js new file mode 100644 index 0000000..3a0e986 --- /dev/null +++ b/server/helpers/passwords.js @@ -0,0 +1,13 @@ +import bcrypt from 'bcryptjs'; + +/** + * @name comparePassword + * @param {string} password + * @param {string} hash + * @returns {boolean} password compared success or failure + */ +const comparePassword = (password, hash) => bcrypt.compare(password, hash); + +export default { + comparePassword +}; diff --git a/server/helpers/serverResponse.js b/server/helpers/serverResponse.js new file mode 100644 index 0000000..dac9278 --- /dev/null +++ b/server/helpers/serverResponse.js @@ -0,0 +1,19 @@ +/** + * @name serverResponse + * @param {object} res - response object + * @param {integer} code - status code + * @param {object} data - data to send in response + * @returns {json} response to user + */ +const serverResponse = (res, code, data) => res.status(code).json({ ...data }); + +/** + * @name serverError + * @param {object} res - response object + * @returns {json} server response to user + */ +const serverError = res => res + .status(500) + .json({ error: "Something went wrong we're trying to fix this" }); + +export { serverResponse, serverError }; diff --git a/server/index.js b/server/index.js index c73545b..8407b5e 100644 --- a/server/index.js +++ b/server/index.js @@ -5,6 +5,7 @@ import swaggerUi from 'swagger-ui-express'; import YAML from 'yamljs'; import path from 'path'; import Debug from 'debug'; +import routes from './routes'; const PORT = process.env.PORT || 9000; @@ -23,9 +24,11 @@ app.use(urlencoded({ extended: false })); app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDoc)); app.get('/', (request, response) => { - response.status(200).send('Welcome to Authors Haven '); + response.status(200).send('Welcome to Authors Haven'); }); +app.use('/api/v1', routes); + app.use('*', (request, response) => { response.status(404).send('Not Found'); }); diff --git a/server/routes/index.js b/server/routes/index.js new file mode 100644 index 0000000..9711109 --- /dev/null +++ b/server/routes/index.js @@ -0,0 +1,8 @@ +import express from 'express'; +import user from './user'; + +const router = express.Router(); + +router.use('/', user); + +export default router; diff --git a/server/routes/user.js b/server/routes/user.js new file mode 100644 index 0000000..f61912b --- /dev/null +++ b/server/routes/user.js @@ -0,0 +1,10 @@ +import express from 'express'; +import user from '../controllers/user'; + +const { login } = user; + +const router = express.Router(); + +router.post('/auth/login', login); + +export default router; diff --git a/test/helpers/findUser.test.js b/test/helpers/findUser.test.js new file mode 100644 index 0000000..49fd59a --- /dev/null +++ b/test/helpers/findUser.test.js @@ -0,0 +1,13 @@ +import chai, { expect } from 'chai'; +import helpers from '../../server/helpers'; + +const { findUser } = helpers; + +describe('Find User Test', () => { + it('find user by id', async () => { + const user = await findUser(1); + expect(user).to.have.property('dataValues'); + }); +}); + +export default chai; diff --git a/test/helpers/index.test.js b/test/helpers/index.test.js new file mode 100644 index 0000000..0829855 --- /dev/null +++ b/test/helpers/index.test.js @@ -0,0 +1,3 @@ +import findUSer from './findUser.test'; + +export default findUSer; diff --git a/test/index.test.js b/test/index.test.js index 72e2298..03f5ff1 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,6 +1,8 @@ import chai from 'chai'; import chaiHttp from 'chai-http'; import server from '../server'; +import './users/index.test'; +import './helpers/index.test'; const { expect } = chai; diff --git a/test/users/__mocks__/user.js b/test/users/__mocks__/user.js new file mode 100644 index 0000000..1ede5d9 --- /dev/null +++ b/test/users/__mocks__/user.js @@ -0,0 +1,26 @@ +const rightUserWithEmail = { + userLogin: 'adechukwu@gmail.com', + password: 'password' +}; + +const rightUserWithUserName = { + userLogin: 'adechukwu', + password: 'password' +}; + +const userWithId = { + userLogin: 1, + password: 'password' +}; + +const wrongUser = { + userLogin: 'a54678yujkomnibvr5fgrht6y78umiouh@gmail.com', + password: 'password' +}; + +export default { + rightUserWithUserName, + rightUserWithEmail, + userWithId, + wrongUser +}; diff --git a/test/users/index.test.js b/test/users/index.test.js new file mode 100644 index 0000000..e4e2f87 --- /dev/null +++ b/test/users/index.test.js @@ -0,0 +1,5 @@ +import user from './user.test'; + +export default { + user +}; diff --git a/test/users/user.test.js b/test/users/user.test.js new file mode 100644 index 0000000..970c498 --- /dev/null +++ b/test/users/user.test.js @@ -0,0 +1,91 @@ +import chai, { expect } from 'chai'; +import sinon from 'sinon'; +import chaiHttp from 'chai-http'; +import app from '../../server'; +import userData from './__mocks__/user'; +import user from '../../server/controllers/user'; + +chai.use(chaiHttp); + +const BASE_URL = '/api/v1/auth'; +const { login } = user; +const { + rightUserWithUserName, + rightUserWithEmail, + userWithId, + wrongUser +} = userData; + +describe('LOGIN TEST', () => { + it('should login in user if the right email is provided', async () => { + const response = await chai + .request(app) + .post(`${BASE_URL}/login`) + .send(rightUserWithEmail); + expect(response).to.have.status(200); + // expect(res.body).to.have.key('user', 'status', 'token'); + expect(response.body.user).to.not.have.property('password'); + expect(response.body.user).to.have.any.keys( + 'id', + 'userName', + 'email', + 'status' + ); + }); + + it('should login in user if the right username is provided', async () => { + const response = await chai + .request(app) + .post(`${BASE_URL}/login`) + .send(rightUserWithUserName); + expect(response).to.have.status(200); + // expect(res.body).to.have.key('user', 'status', 'token'); + expect(response.body.user).to.not.have.property('password'); + expect(response.body.user).to.have.any.keys( + 'id', + 'userName', + 'email', + 'status' + ); + }); + + it("should not login in user if the user's id is provided", async () => { + const response = await chai + .request(app) + .post(`${BASE_URL}/login`) + .send(userWithId); + expect(response).to.have.status(400); + expect(response.body).to.have.property('message'); + expect(response.body.message).to.be.a('string'); + }); + + it('should not login in user with the wrong credentials', async () => { + const response = await chai + .request(app) + .post(`${BASE_URL}/login`) + .send(wrongUser); + expect(response).to.have.status(403); + expect(response.body).to.not.have.property('user, token'); + expect(response.body).to.have.property('message'); + expect(response.body.message).to.be.a('string'); + }); +}); + +describe('SERVER TEST', () => { + it("should not login in user if there's a server error", async () => { + const stubfunc = { login }; + const sandbox = sinon.createSandbox(); + sandbox.stub(stubfunc, 'login').rejects(new Error('Server Error')); + + const next = sinon.spy(); + const res = { + status: () => ({ + json: next + }) + }; + await login({}, res); + sinon.assert.calledOnce(next); + }); +}); + +export default chai;