mirror of
https://github.com/Permissionless-Software-Foundation/x402-base-facilitator.git
synced 2026-09-21 16:52:01 -07:00
Fixing package.json
This commit is contained in:
+4
-1
@@ -12,7 +12,10 @@ const cors = require('kcors')
|
|||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const config = require('../config') // this first.
|
const config = require('../config') // this first.
|
||||||
const adminLib = require('../src/lib/admin')
|
|
||||||
|
const AdminLib = require('../src/lib/admin')
|
||||||
|
const adminLib = new AdminLib()
|
||||||
|
|
||||||
const errorMiddleware = require('../src/middleware')
|
const errorMiddleware = require('../src/middleware')
|
||||||
const wlogger = require('../src/lib/wlogger')
|
const wlogger = require('../src/lib/wlogger')
|
||||||
|
|
||||||
|
|||||||
Generated
+856
-1900
File diff suppressed because it is too large
Load Diff
+4
-3
@@ -8,7 +8,7 @@
|
|||||||
"test": "export KOA_ENV=test && npm run prep-test && nyc --reporter=text --timeout 15000 ./node_modules/.bin/mocha --exit",
|
"test": "export KOA_ENV=test && npm run prep-test && nyc --reporter=text --timeout 15000 ./node_modules/.bin/mocha --exit",
|
||||||
"lint": "standard --env mocha --fix",
|
"lint": "standard --env mocha --fix",
|
||||||
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
|
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
|
||||||
"coverage": "nyc report --reporter=text-lcov | coveralls",
|
"coverage": "export KOA_ENV=test && npm run prep-test && nyc report --reporter=text-lcov | coveralls",
|
||||||
"coverage:report": "export KOA_ENV=test && npm run prep-test && nyc --reporter=html mocha --exit",
|
"coverage:report": "export KOA_ENV=test && npm run prep-test && nyc --reporter=html mocha --exit",
|
||||||
"prep-test": "node util/users/delete-all-test-users.js"
|
"prep-test": "node util/users/delete-all-test-users.js"
|
||||||
},
|
},
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
"koa-router": "^9.0.1",
|
"koa-router": "^9.0.1",
|
||||||
"koa-static": "^5.0.0",
|
"koa-static": "^5.0.0",
|
||||||
"line-reader": "^0.4.0",
|
"line-reader": "^0.4.0",
|
||||||
"mongoose": "^5.7.5",
|
"mongoose": "^5.10.15",
|
||||||
"nodemailer": "^6.4.10",
|
"nodemailer": "^6.4.10",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"winston": "^3.2.1",
|
"winston": "^3.2.1",
|
||||||
@@ -65,7 +65,8 @@
|
|||||||
"husky": "^4.2.5",
|
"husky": "^4.2.5",
|
||||||
"mocha": "^7.0.1",
|
"mocha": "^7.0.1",
|
||||||
"nyc": "^15.0.0",
|
"nyc": "^15.0.0",
|
||||||
"semantic-release": "^17.0.0",
|
"semantic-release": "^17.2.3",
|
||||||
|
"sinon": "^9.2.1",
|
||||||
"standard": "^14.3.1"
|
"standard": "^14.3.1"
|
||||||
},
|
},
|
||||||
"release": {
|
"release": {
|
||||||
|
|||||||
+110
-97
@@ -13,8 +13,9 @@
|
|||||||
const axios = require('axios').default
|
const axios = require('axios').default
|
||||||
const mongoose = require('mongoose')
|
const mongoose = require('mongoose')
|
||||||
const User = require('../models/users')
|
const User = require('../models/users')
|
||||||
const jsonFiles = require('./utils/json-files')
|
|
||||||
const config = require('../../config')
|
const config = require('../../config')
|
||||||
|
const JsonFiles = require('./utils/json-files')
|
||||||
|
const jsonFiles = new JsonFiles()
|
||||||
|
|
||||||
const JSON_FILE = `system-user-${config.env}.json`
|
const JSON_FILE = `system-user-${config.env}.json`
|
||||||
const JSON_PATH = `${__dirname}/../../config/${JSON_FILE}`
|
const JSON_PATH = `${__dirname}/../../config/${JSON_FILE}`
|
||||||
@@ -22,125 +23,137 @@ const JSON_PATH = `${__dirname}/../../config/${JSON_FILE}`
|
|||||||
const LOCALHOST = `http://localhost:${config.port}`
|
const LOCALHOST = `http://localhost:${config.port}`
|
||||||
const context = {}
|
const context = {}
|
||||||
|
|
||||||
// Create the first user in the system. A 'admin' level system user that is
|
let _this
|
||||||
// used by the Listing Manager and test scripts, in order access private API
|
class Admin {
|
||||||
// functions.
|
constructor () {
|
||||||
async function createSystemUser () {
|
this.axios = axios
|
||||||
// Create the system user.
|
this.User = User
|
||||||
try {
|
this.config = config
|
||||||
context.password = _randomString(20)
|
this.jsonFiles = jsonFiles
|
||||||
|
this.context = context
|
||||||
|
|
||||||
const options = {
|
_this = this
|
||||||
method: 'POST',
|
}
|
||||||
url: `${LOCALHOST}/users`,
|
|
||||||
data: {
|
// Create the first user in the system. A 'admin' level system user that is
|
||||||
user: {
|
// used by the Listing Manager and test scripts, in order access private API
|
||||||
email: 'system@system.com',
|
// functions.
|
||||||
password: context.password
|
async createSystemUser () {
|
||||||
|
// Create the system user.
|
||||||
|
try {
|
||||||
|
context.password = _this._randomString(20)
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
url: `${LOCALHOST}/users`,
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
email: 'system@system.com',
|
||||||
|
password: context.password
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
const result = await _this.axios.request(options)
|
||||||
const result = await axios(options)
|
context.email = result.data.user.email
|
||||||
|
context.id = result.data.user._id
|
||||||
|
context.token = result.data.token
|
||||||
|
|
||||||
context.email = result.data.user.email
|
// Get the mongoDB entry
|
||||||
context.id = result.data.user._id
|
const user = await _this.User.findById(context.id)
|
||||||
context.token = result.data.token
|
|
||||||
|
|
||||||
// Get the mongoDB entry
|
// Change the user type to admin
|
||||||
const user = await User.findById(context.id)
|
user.type = 'admin'
|
||||||
|
// console.log(`user created: ${JSON.stringify(user, null, 2)}`)
|
||||||
|
|
||||||
// Change the user type to admin
|
// Save the user model.
|
||||||
user.type = 'admin'
|
await user.save()
|
||||||
// console.log(`user: ${JSON.stringify(user, null, 2)}`)
|
|
||||||
|
|
||||||
// Save the user model.
|
// console.log(`admin user created: ${JSON.stringify(result.body, null, 2)}`)
|
||||||
await user.save()
|
// console.log(`with password: ${context.password}`)
|
||||||
|
|
||||||
// console.log(`admin user created: ${JSON.stringify(result.body, null, 2)}`)
|
// Write out the system user information to a JSON file that external
|
||||||
// console.log(`with password: ${context.password}`)
|
// applications like the Task Manager and the test scripts can access.
|
||||||
|
|
||||||
// Write out the system user information to a JSON file that external
|
await jsonFiles.writeJSON(context, JSON_PATH)
|
||||||
// applications like the Task Manager and the test scripts can access.
|
|
||||||
await jsonFiles.writeJSON(context, JSON_PATH)
|
|
||||||
|
|
||||||
return context
|
return context
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Handle existing system user.
|
// Handle existing system user.
|
||||||
if (err.response.status === 422) {
|
if (err.response.status === 422) {
|
||||||
try {
|
try {
|
||||||
// Delete the existing user
|
// Delete the existing user
|
||||||
await deleteExistingSystemUser()
|
await _this.deleteExistingSystemUser()
|
||||||
|
|
||||||
// Call this function again.
|
// Call this function again.
|
||||||
return createSystemUser()
|
return _this.createSystemUser()
|
||||||
} catch (err2) {
|
} catch (err2) {
|
||||||
console.error('Error in admin.js/createSystemUser() while trying generate new system user.')
|
console.error('Error in admin.js/createSystemUser() while trying generate new system user.')
|
||||||
|
// process.end(1)
|
||||||
|
throw err2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Error in admin.js/createSystemUser: ')
|
||||||
// process.end(1)
|
// process.end(1)
|
||||||
throw err2
|
throw err
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
console.log('Error in admin.js/createSystemUser: ' + JSON.stringify(err, null, 2))
|
}
|
||||||
// process.end(1)
|
|
||||||
|
async deleteExistingSystemUser () {
|
||||||
|
try {
|
||||||
|
mongoose.Promise = global.Promise
|
||||||
|
mongoose.set('useCreateIndex', true) // Stop deprecation warning.
|
||||||
|
|
||||||
|
await mongoose.connect(config.database, { useNewUrlParser: true, useUnifiedTopology: true })
|
||||||
|
|
||||||
|
await _this.User.deleteOne({ email: 'system@system.com' })
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Error in admin.js/deleteExistingSystemUser()')
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async function deleteExistingSystemUser () {
|
async loginAdmin () {
|
||||||
try {
|
// console.log(`loginAdmin() running.`)
|
||||||
mongoose.Promise = global.Promise
|
let existingUser
|
||||||
mongoose.set('useCreateIndex', true) // Stop deprecation warning.
|
|
||||||
|
|
||||||
await mongoose.connect(config.database, { useNewUrlParser: true, useUnifiedTopology: true })
|
try {
|
||||||
|
// Read the exising file
|
||||||
|
existingUser = await _this.jsonFiles.readJSON(JSON_PATH)
|
||||||
|
// console.log(`existingUser: ${JSON.stringify(existingUser, null, 2)}`)
|
||||||
|
|
||||||
await User.deleteOne({ email: 'system@system.com' })
|
// Log in as the user.
|
||||||
} catch (err) {
|
const options = {
|
||||||
console.log('Error in admin.js/deleteExistingSystemUser()')
|
method: 'POST',
|
||||||
throw err
|
url: `${LOCALHOST}/auth`,
|
||||||
}
|
headers: {
|
||||||
}
|
Accept: 'application/json'
|
||||||
|
},
|
||||||
async function loginAdmin () {
|
data: {
|
||||||
// console.log(`loginAdmin() running.`)
|
email: 'system@system.com',
|
||||||
let existingUser
|
password: existingUser.password
|
||||||
|
}
|
||||||
try {
|
|
||||||
// Read the exising file
|
|
||||||
existingUser = await jsonFiles.readJSON(JSON_PATH)
|
|
||||||
// console.log(`existingUser: ${JSON.stringify(existingUser, null, 2)}`)
|
|
||||||
|
|
||||||
// Log in as the user.
|
|
||||||
const options = {
|
|
||||||
method: 'POST',
|
|
||||||
url: `${LOCALHOST}/auth`,
|
|
||||||
data: {
|
|
||||||
email: 'system@system.com',
|
|
||||||
password: existingUser.password
|
|
||||||
}
|
}
|
||||||
|
const result = await _this.axios.request(options)
|
||||||
|
// console.log(`result1: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
return result
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in admin.js/loginAdmin().')
|
||||||
|
|
||||||
|
// console.error(`existingUser: ${JSON.stringify(existingUser, null, 2)}`)
|
||||||
|
|
||||||
|
throw err
|
||||||
}
|
}
|
||||||
const result = await axios(options)
|
}
|
||||||
// console.log(`result1: ${JSON.stringify(result, null, 2)}`)
|
|
||||||
|
|
||||||
return result
|
_randomString (length) {
|
||||||
} catch (err) {
|
var text = ''
|
||||||
console.error('Error in admin.js/loginAdmin().')
|
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||||||
|
for (var i = 0; i < length; i++) {
|
||||||
// console.error(`existingUser: ${JSON.stringify(existingUser, null, 2)}`)
|
text += possible.charAt(Math.floor(Math.random() * possible.length))
|
||||||
|
}
|
||||||
throw err
|
return text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _randomString (length) {
|
module.exports = Admin
|
||||||
var text = ''
|
|
||||||
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
||||||
for (var i = 0; i < length; i++) {
|
|
||||||
text += possible.charAt(Math.floor(Math.random() * possible.length))
|
|
||||||
}
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
createSystemUser,
|
|
||||||
loginAdmin
|
|
||||||
}
|
|
||||||
|
|||||||
+18
-18
@@ -17,6 +17,20 @@ class NodeMailer {
|
|||||||
this.config = config
|
this.config = config
|
||||||
|
|
||||||
_this = this
|
_this = this
|
||||||
|
_this.transporter = _this.createTransporter()
|
||||||
|
}
|
||||||
|
|
||||||
|
createTransporter () {
|
||||||
|
const transporter = _this.nodemailer.createTransport({
|
||||||
|
host: _this.config.emailServer,
|
||||||
|
port: 587,
|
||||||
|
secure: false, // true for 465, false for other ports
|
||||||
|
auth: {
|
||||||
|
user: _this.config.emailUser, // generated ethereal user
|
||||||
|
pass: _this.config.emailPassword // generated ethereal password
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return transporter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate email
|
// Validate email
|
||||||
@@ -44,10 +58,7 @@ class NodeMailer {
|
|||||||
throw new Error("Property 'to' must be a array!")
|
throw new Error("Property 'to' must be a array!")
|
||||||
}
|
}
|
||||||
|
|
||||||
const isEmailList = await _this.validateEmailArray(data.to)
|
await _this.validateEmailArray(data.to)
|
||||||
if (!isEmailList) {
|
|
||||||
throw new Error("Property 'to' must be array of email format!")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.formMessage || typeof data.formMessage !== 'string') {
|
if (!data.formMessage || typeof data.formMessage !== 'string') {
|
||||||
throw new Error("Property 'message' must be a string!")
|
throw new Error("Property 'message' must be a string!")
|
||||||
@@ -61,18 +72,6 @@ class NodeMailer {
|
|||||||
throw new Error("Property 'payloadTitle' must be a string!")
|
throw new Error("Property 'payloadTitle' must be a string!")
|
||||||
}
|
}
|
||||||
|
|
||||||
// create reusable transporter object using the default SMTP transport
|
|
||||||
const transporter = await _this.nodemailer.createTransport({
|
|
||||||
host: _this.config.emailServer,
|
|
||||||
port: 587,
|
|
||||||
secure: false, // true for 465, false for other ports
|
|
||||||
auth: {
|
|
||||||
user: _this.config.emailUser, // generated ethereal user
|
|
||||||
pass: _this.config.emailPassword // generated ethereal password
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// console.log(`transporter: ${JSON.stringify(transporter)}`)
|
|
||||||
|
|
||||||
const msg = data.formMessage.replace(/(\r\n|\n|\r)/g, '<br />')
|
const msg = data.formMessage.replace(/(\r\n|\n|\r)/g, '<br />')
|
||||||
|
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
@@ -115,7 +114,7 @@ class NodeMailer {
|
|||||||
${htmlData}
|
${htmlData}
|
||||||
</p>`
|
</p>`
|
||||||
// send mail with defined transport object
|
// send mail with defined transport object
|
||||||
const info = await transporter.sendMail({
|
const info = await _this.transporter.sendMail({
|
||||||
// from: `${data.email}`, // sender address
|
// from: `${data.email}`, // sender address
|
||||||
from: 'noreply@launchpadip.net',
|
from: 'noreply@launchpadip.net',
|
||||||
to: `${to}`, // list of receivers
|
to: `${to}`, // list of receivers
|
||||||
@@ -125,8 +124,9 @@ class NodeMailer {
|
|||||||
html: htmlMsg
|
html: htmlMsg
|
||||||
})
|
})
|
||||||
console.log('Message sent: %s', info.messageId)
|
console.log('Message sent: %s', info.messageId)
|
||||||
|
return info
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('Error in sendEmail()')
|
wlogger.error('Error in lib/nodemailer.js/sendEmail()')
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+60
-46
@@ -1,61 +1,75 @@
|
|||||||
/*
|
/*
|
||||||
A utility file for reading and writing JSON files.
|
A utility file for reading and writing JSON files.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
|
||||||
// Writes out a JSON file of any object passed to the function.
|
let _this
|
||||||
// This is used for testing.
|
|
||||||
function writeJSON (obj, fileName) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
try {
|
|
||||||
const fileStr = JSON.stringify(obj, null, 2)
|
|
||||||
|
|
||||||
fs.writeFile(fileName, fileStr, function (err) {
|
class JsonFiles {
|
||||||
if (err) {
|
constructor () {
|
||||||
console.error('Error while trying to write file: ', err)
|
this.fs = fs
|
||||||
return reject(err)
|
|
||||||
} else {
|
_this = this
|
||||||
// console.log(`${fileName} written successfully!`)
|
}
|
||||||
return resolve()
|
|
||||||
|
// Writes out a JSON file of any object passed to the function.
|
||||||
|
// This is used for testing.
|
||||||
|
writeJSON (obj, fileName) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
try {
|
||||||
|
if (!obj) {
|
||||||
|
throw new Error('obj property is required')
|
||||||
}
|
}
|
||||||
})
|
if (!fileName || typeof fileName !== 'string') {
|
||||||
} catch (err) {
|
throw new Error('fileName property must be a string')
|
||||||
console.error('Error trying to write out object in util.js/_writeJSON().', err)
|
}
|
||||||
return reject(err)
|
const fileStr = JSON.stringify(obj, null, 2)
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read and parse a JSON file.
|
_this.fs.writeFile(fileName, fileStr, function (err) {
|
||||||
function readJSON (fileName) {
|
if (err) {
|
||||||
return new Promise(function (resolve, reject) {
|
console.error('Error while trying to write file: ')
|
||||||
try {
|
throw err
|
||||||
fs.readFile(fileName, (err, data) => {
|
|
||||||
if (err) {
|
|
||||||
if (err.code === 'ENOENT') {
|
|
||||||
console.log('Admin .json file not found!')
|
|
||||||
} else {
|
} else {
|
||||||
console.log(`err: ${JSON.stringify(err, null, 2)}`)
|
// console.log(`${fileName} written successfully!`)
|
||||||
|
return resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error trying to write out object in util.js/_writeJSON().')
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
readJSON (fileName) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
try {
|
||||||
|
if (!fileName || typeof fileName !== 'string') {
|
||||||
|
throw new Error('fileName property must be a string')
|
||||||
|
}
|
||||||
|
|
||||||
|
_this.fs.readFile(fileName, (err, data) => {
|
||||||
|
if (err) {
|
||||||
|
if (err.code === 'ENOENT') {
|
||||||
|
console.log('Admin .json file not found!')
|
||||||
|
} else {
|
||||||
|
console.log(`err: ${JSON.stringify(err, null, 2)}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err
|
||||||
}
|
}
|
||||||
|
|
||||||
return reject(err)
|
const obj = JSON.parse(data)
|
||||||
}
|
|
||||||
|
|
||||||
const obj = JSON.parse(data)
|
return resolve(obj)
|
||||||
|
})
|
||||||
return resolve(obj)
|
} catch (err) {
|
||||||
})
|
console.error('Error trying to read JSON file in util.js/_readJSON().')
|
||||||
} catch (err) {
|
return reject(err)
|
||||||
console.error('Error trying to read JSON file in util.js/_readJSON().', err)
|
}
|
||||||
return reject(err)
|
})
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = JsonFiles
|
||||||
writeJSON,
|
|
||||||
readJSON
|
|
||||||
}
|
|
||||||
|
|||||||
+131
-109
@@ -4,124 +4,146 @@ const getToken = require('../lib/auth')
|
|||||||
const jwt = require('jsonwebtoken')
|
const jwt = require('jsonwebtoken')
|
||||||
const wlogger = require('../lib/wlogger')
|
const wlogger = require('../lib/wlogger')
|
||||||
|
|
||||||
async function ensureUser (ctx, next) {
|
let _this
|
||||||
// console.log(`getToken: ${typeof (getToken)}`)
|
|
||||||
const token = getToken(ctx)
|
|
||||||
|
|
||||||
if (!token) {
|
class Validators {
|
||||||
// console.log(`Err: Token not provided.`)
|
constructor () {
|
||||||
ctx.throw(401)
|
this.User = User
|
||||||
|
this.getToken = getToken
|
||||||
|
this.jwt = jwt
|
||||||
|
this.config = config
|
||||||
|
|
||||||
|
_this = this
|
||||||
}
|
}
|
||||||
|
|
||||||
let decoded = null
|
async ensureUser (ctx, next) {
|
||||||
try {
|
try {
|
||||||
// console.log(`token: ${JSON.stringify(token, null, 2)}`)
|
// console.log(`getToken: ${typeof (getToken)}`)
|
||||||
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
|
const token = _this.getToken(ctx)
|
||||||
decoded = jwt.verify(token, config.token)
|
|
||||||
} catch (err) {
|
|
||||||
// console.log(`Err: Token could not be decoded: ${err}`)
|
|
||||||
ctx.throw(401)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.state.user = await User.findById(decoded.id, '-password')
|
if (!token) {
|
||||||
if (!ctx.state.user) {
|
// console.log(`Err: Token not provided.`)
|
||||||
// console.log(`Err: Could not find user.`)
|
ctx.throw(401)
|
||||||
ctx.throw(401)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return next()
|
let decoded = null
|
||||||
}
|
try {
|
||||||
|
// console.log(`token: ${JSON.stringify(token, null, 2)}`)
|
||||||
|
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
|
||||||
|
decoded = _this.jwt.verify(token, config.token)
|
||||||
|
} catch (err) {
|
||||||
|
// console.log(`Err: Token could not be decoded: ${err}`)
|
||||||
|
ctx.throw(401)
|
||||||
|
}
|
||||||
|
|
||||||
// This funciton is almost identical to ensureUser, except at the end, it verifies
|
ctx.state.user = await _this.User.findById(decoded.id, '-password')
|
||||||
// that the 'type' associated with the user equals 'admin'.
|
if (!ctx.state.user) {
|
||||||
async function ensureAdmin (ctx, next) {
|
// console.log(`Err: Could not find user.`)
|
||||||
// console.log(`getToken: ${typeof (getToken)}`)
|
ctx.throw(401)
|
||||||
const token = getToken(ctx)
|
}
|
||||||
|
|
||||||
if (!token) {
|
return next()
|
||||||
// console.log(`Err: Token not provided.`)
|
} catch (error) {
|
||||||
ctx.throw(401)
|
ctx.throw(401)
|
||||||
}
|
|
||||||
|
|
||||||
let decoded = null
|
|
||||||
try {
|
|
||||||
// console.log(`token: ${JSON.stringify(token, null, 2)}`)
|
|
||||||
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
|
|
||||||
decoded = jwt.verify(token, config.token)
|
|
||||||
} catch (err) {
|
|
||||||
// console.log(`Err: Token could not be decoded: ${err}`)
|
|
||||||
ctx.throw(401)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.state.user = await User.findById(decoded.id, '-password')
|
|
||||||
if (!ctx.state.user) {
|
|
||||||
// console.log(`Err: Could not find user.`)
|
|
||||||
ctx.throw(401)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx.state.user.type !== 'admin') {
|
|
||||||
ctx.throw(401, 'not admin')
|
|
||||||
}
|
|
||||||
|
|
||||||
return next()
|
|
||||||
}
|
|
||||||
|
|
||||||
// This middleware ensures that the :id used in the API endpoint matches the
|
|
||||||
// the ID used in the JWT, or failing that, the ID used in the JWT matches
|
|
||||||
// an Admin user. This prevents situations like users updating other users
|
|
||||||
// profiles or non-admins deleting users.
|
|
||||||
// TODO Tests must be developed before developing this function.
|
|
||||||
async function ensureTargetUserOrAdmin (ctx, next) {
|
|
||||||
// console.log(`getToken: ${typeof (getToken)}`)
|
|
||||||
const token = getToken(ctx)
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
// console.log(`Err: Token not provided.`)
|
|
||||||
ctx.throw(401)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The user ID targeted in this API call.
|
|
||||||
const targetId = ctx.params.id
|
|
||||||
// console.log(`targetId: ${JSON.stringify(targetId, null, 2)}`)
|
|
||||||
|
|
||||||
let decoded = null
|
|
||||||
try {
|
|
||||||
// console.log(`token: ${JSON.stringify(token, null, 2)}`)
|
|
||||||
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
|
|
||||||
decoded = jwt.verify(token, config.token)
|
|
||||||
} catch (err) {
|
|
||||||
// console.log(`Err: Token could not be decoded: ${err}`)
|
|
||||||
ctx.throw(401)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.state.user = await User.findById(decoded.id, '-password')
|
|
||||||
if (!ctx.state.user) {
|
|
||||||
// console.log(`Err: Could not find user.`)
|
|
||||||
ctx.throw(401)
|
|
||||||
}
|
|
||||||
|
|
||||||
// console.log(`ctx.state.user: ${JSON.stringify(ctx.state.user, null, 2)}`)
|
|
||||||
// Ensure the calling user and the target user are the same.
|
|
||||||
if (ctx.state.user._id.toString() !== targetId.toString()) {
|
|
||||||
wlogger.verbose(
|
|
||||||
`Calling user and target user do not match! Calling user: ${
|
|
||||||
ctx.state.user._id
|
|
||||||
}, Target user: ${targetId}`
|
|
||||||
)
|
|
||||||
|
|
||||||
// If they don't match, then the calling user better be an admin.
|
|
||||||
if (ctx.state.user.type !== 'admin') {
|
|
||||||
ctx.throw(401, 'not admin')
|
|
||||||
} else {
|
|
||||||
wlogger.verbose('It\'s ok. The user is an admin.')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return next()
|
// This funciton is almost identical to ensureUser, except at the end, it verifies
|
||||||
|
// that the 'type' associated with the user equals 'admin'.
|
||||||
|
async ensureAdmin (ctx, next) {
|
||||||
|
try {
|
||||||
|
// console.log(`getToken: ${typeof (getToken)}`)
|
||||||
|
const token = _this.getToken(ctx)
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
// console.log(`Err: Token not provided.`)
|
||||||
|
ctx.throw(401)
|
||||||
|
}
|
||||||
|
|
||||||
|
let decoded = null
|
||||||
|
try {
|
||||||
|
// console.log(`token: ${JSON.stringify(token, null, 2)}`)
|
||||||
|
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
|
||||||
|
decoded = _this.jwt.verify(token, config.token)
|
||||||
|
} catch (err) {
|
||||||
|
// console.log(`Err: Token could not be decoded: ${err}`)
|
||||||
|
ctx.throw(401)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.state.user = await _this.User.findById(decoded.id, '-password')
|
||||||
|
if (!ctx.state.user) {
|
||||||
|
// console.log(`Err: Could not find user.`)
|
||||||
|
ctx.throw(401)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.state.user.type !== 'admin') {
|
||||||
|
ctx.throw(401, 'not admin')
|
||||||
|
}
|
||||||
|
|
||||||
|
return next()
|
||||||
|
} catch (error) {
|
||||||
|
ctx.throw(401, error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This middleware ensures that the :id used in the API endpoint matches the
|
||||||
|
// the ID used in the JWT, or failing that, the ID used in the JWT matches
|
||||||
|
// an Admin user. This prevents situations like users updating other users
|
||||||
|
// profiles or non-admins deleting users.
|
||||||
|
// TODO Tests must be developed before developing this function.
|
||||||
|
async ensureTargetUserOrAdmin (ctx, next) {
|
||||||
|
try {
|
||||||
|
// console.log(`getToken: ${typeof (getToken)}`)
|
||||||
|
const token = _this.getToken(ctx)
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
// console.log(`Err: Token not provided.`)
|
||||||
|
ctx.throw(401)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The user ID targeted in this API call.
|
||||||
|
const targetId = ctx.params.id
|
||||||
|
// console.log(`targetId: ${JSON.stringify(targetId, null, 2)}`)
|
||||||
|
|
||||||
|
let decoded = null
|
||||||
|
try {
|
||||||
|
// console.log(`token: ${JSON.stringify(token, null, 2)}`)
|
||||||
|
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
|
||||||
|
decoded = _this.jwt.verify(token, config.token)
|
||||||
|
} catch (err) {
|
||||||
|
// console.log(`Err: Token could not be decoded: ${err}`)
|
||||||
|
ctx.throw(401)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.state.user = await _this.User.findById(decoded.id, '-password')
|
||||||
|
if (!ctx.state.user) {
|
||||||
|
// console.log(`Err: Could not find user.`)
|
||||||
|
ctx.throw(401)
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(`ctx.state.user: ${JSON.stringify(ctx.state.user, null, 2)}`)
|
||||||
|
// Ensure the calling user and the target user are the same.
|
||||||
|
|
||||||
|
if (ctx.state.user._id.toString() !== targetId.toString()) {
|
||||||
|
wlogger.verbose(
|
||||||
|
`Calling user and target user do not match! Calling user: ${
|
||||||
|
ctx.state.user._id
|
||||||
|
}, Target user: ${targetId}`
|
||||||
|
)
|
||||||
|
|
||||||
|
// If they don't match, then the calling user better be an admin.
|
||||||
|
if (ctx.state.user.type !== 'admin') {
|
||||||
|
ctx.throw(401, 'not admin')
|
||||||
|
} else {
|
||||||
|
wlogger.verbose('It\'s ok. The user is an admin.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return next()
|
||||||
|
} catch (error) {
|
||||||
|
ctx.throw(401, error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = Validators
|
||||||
ensureUser,
|
|
||||||
ensureAdmin,
|
|
||||||
ensureTargetUserOrAdmin
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -65,11 +65,13 @@ class Contact {
|
|||||||
success: true
|
success: true
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ctx.body = {
|
// ctx.body = {
|
||||||
success: false
|
// success: false
|
||||||
}
|
// }
|
||||||
// console.error(`Error: `, err)
|
// console.error(`Error: `, err)
|
||||||
throw err
|
// throw err
|
||||||
|
|
||||||
|
ctx.throw(422, err.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ let _this
|
|||||||
class LogsApi {
|
class LogsApi {
|
||||||
constructor () {
|
constructor () {
|
||||||
_this = this
|
_this = this
|
||||||
|
_this.fs = fs
|
||||||
|
_this.lineReader = lineReader
|
||||||
|
_this.config = config
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,30 +59,29 @@ class LogsApi {
|
|||||||
// console.log(`password: ${password}`)
|
// console.log(`password: ${password}`)
|
||||||
|
|
||||||
// Password matches the password set in the config file.
|
// Password matches the password set in the config file.
|
||||||
if (password === config.logPass) {
|
if (password === _this.config.logPass) {
|
||||||
// Generate the full path and file name for the current log file.
|
// Generate the full path and file name for the current log file.
|
||||||
const fullPath = _this.generateFileName()
|
const fullPath = _this.generateFileName()
|
||||||
|
// console.log(`fullPath: ${JSON.stringify(fullPath, null, 2)}`)
|
||||||
|
|
||||||
// Throw an error if the file does not exist.
|
// Throw an error if the file does not exist.
|
||||||
fs.stat(fullPath, (err, stat) => {
|
if (!_this.fs.existsSync(fullPath)) {
|
||||||
if (err) {
|
ctx.body = {
|
||||||
ctx.body = {
|
success: false,
|
||||||
success: false,
|
data: 'file does not exist'
|
||||||
data: 'file does not exist'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
|
// Read in the data from the log file.
|
||||||
|
const data = await _this.readLines(fullPath)
|
||||||
|
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||||
|
|
||||||
// Read in the data from the log file.
|
// Filter the logs before passing them to the front end.
|
||||||
const data = await _this.readLines(fullPath)
|
const filteredData = _this.filterLogs(data)
|
||||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
||||||
|
|
||||||
// Filter the logs before passing them to the front end.
|
ctx.body = {
|
||||||
const filteredData = _this.filterLogs(data)
|
success: true,
|
||||||
|
data: filteredData
|
||||||
ctx.body = {
|
}
|
||||||
success: true,
|
|
||||||
data: filteredData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Password does not match password in config file.
|
// Password does not match password in config file.
|
||||||
@@ -89,21 +91,23 @@ class LogsApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err) {
|
if (err && err.message) {
|
||||||
ctx.throw(500, err.message)
|
ctx.throw(500, err.message)
|
||||||
} else {
|
} else {
|
||||||
ctx.throw(500, 'Unhandled error')
|
ctx.throw(500, 'Unhandled error')
|
||||||
console.log('unhandled error: ', err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sorts the log data by their timestamp. Returns the LIMIT or less elements.
|
// Sorts the log data by their timestamp. Returns the LIMIT or less elements.
|
||||||
filterLogs (data) {
|
filterLogs (data, LIMIT = 100) {
|
||||||
try {
|
try {
|
||||||
|
if (!Array.isArray(data)) {
|
||||||
|
throw new Error('Data must be array')
|
||||||
|
}
|
||||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||||
|
|
||||||
const LIMIT = 100 // Max number of entries to return.
|
// const LIMIT = 100 // Max number of entries to return.
|
||||||
|
|
||||||
// Sort the elements by date.
|
// Sort the elements by date.
|
||||||
data.sort(function (a, b) {
|
data.sort(function (a, b) {
|
||||||
@@ -142,7 +146,7 @@ class LogsApi {
|
|||||||
const thisYear = now.getFullYear()
|
const thisYear = now.getFullYear()
|
||||||
|
|
||||||
const filename = `koa-${
|
const filename = `koa-${
|
||||||
config.env
|
_this.config.env
|
||||||
}-${thisYear}-${thisMonth}-${thisDate}.log`
|
}-${thisYear}-${thisMonth}-${thisDate}.log`
|
||||||
// console.log(`filename: ${filename}`)
|
// console.log(`filename: ${filename}`)
|
||||||
const logDir = `${__dirname}/../../../logs/`
|
const logDir = `${__dirname}/../../../logs/`
|
||||||
@@ -157,23 +161,33 @@ class LogsApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Promise based read-file
|
// Promise based read-file
|
||||||
readFile (path, opts = 'utf8') {
|
/* readFile (path, opts = 'utf8') {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
fs.readFile(path, opts, (err, data) => {
|
_this.fs.readFile(path, opts, (err, data) => {
|
||||||
if (err) reject(err)
|
if (err) reject(err)
|
||||||
else resolve(data)
|
else resolve(data)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
} */
|
||||||
|
|
||||||
// Returns an array with each element containing a line of the file.
|
// Returns an array with each element containing a line of the file.
|
||||||
readLines (filename) {
|
readLines (filename) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
|
if (!filename || typeof filename !== 'string') {
|
||||||
|
throw new Error('filename must be a string')
|
||||||
|
}
|
||||||
|
// Throw an error if the file does not exist.
|
||||||
|
|
||||||
|
if (!_this.fs.existsSync(filename)) {
|
||||||
|
throw new Error('file does not exist')
|
||||||
|
}
|
||||||
|
|
||||||
const data = []
|
const data = []
|
||||||
|
|
||||||
// let i = 0
|
// let i = 0
|
||||||
|
|
||||||
lineReader.eachLine(filename, function (line, last) {
|
_this.lineReader.eachLine(filename, function (line, last) {
|
||||||
try {
|
try {
|
||||||
data.push(JSON.parse(line))
|
data.push(JSON.parse(line))
|
||||||
|
|
||||||
@@ -183,7 +197,8 @@ class LogsApi {
|
|||||||
|
|
||||||
if (last) return resolve(data)
|
if (last) return resolve(data)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err: ', err)
|
// console.log('err: ', err)
|
||||||
|
if (last) return resolve(data)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -47,15 +47,14 @@ class UserController {
|
|||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async createUser (ctx) {
|
async createUser (ctx) {
|
||||||
const user = new _this.User(ctx.request.body.user)
|
const userObj = ctx.request.body.user
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/*
|
/*
|
||||||
* ERROR HANDLERS
|
* ERROR HANDLERS
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
// Required property
|
// Required property
|
||||||
if (!user.email || typeof user.email !== 'string') {
|
if (!userObj.email || typeof userObj.email !== 'string') {
|
||||||
throw new Error("Property 'email' must be a string!")
|
throw new Error("Property 'email' must be a string!")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,14 +65,15 @@ class UserController {
|
|||||||
// throw new Error("Property 'email' must be email format!")
|
// throw new Error("Property 'email' must be email format!")
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (!user.password || typeof user.password !== 'string') {
|
if (!userObj.password || typeof userObj.password !== 'string') {
|
||||||
throw new Error("Property 'password' must be a string!")
|
throw new Error("Property 'password' must be a string!")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.name && typeof user.name !== 'string') {
|
if (userObj.name && typeof userObj.name !== 'string') {
|
||||||
throw new Error("Property 'name' must be a string!")
|
throw new Error("Property 'name' must be a string!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const user = new _this.User(userObj)
|
||||||
// Enforce default value of 'user'
|
// Enforce default value of 'user'
|
||||||
user.type = 'user'
|
user.type = 'user'
|
||||||
|
|
||||||
@@ -160,6 +160,7 @@ class UserController {
|
|||||||
*
|
*
|
||||||
* @apiUse TokenError
|
* @apiUse TokenError
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async getUser (ctx, next) {
|
async getUser (ctx, next) {
|
||||||
try {
|
try {
|
||||||
const user = await _this.User.findById(ctx.params.id, '-password')
|
const user = await _this.User.findById(ctx.params.id, '-password')
|
||||||
@@ -171,12 +172,18 @@ class UserController {
|
|||||||
user
|
user
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err === 404 || err.name === 'CastError') {
|
// Handle different error types.
|
||||||
|
if (
|
||||||
|
err === 404 ||
|
||||||
|
err.name === 'CastError' ||
|
||||||
|
err.message.toString().includes('Not Found')
|
||||||
|
) {
|
||||||
ctx.throw(404)
|
ctx.throw(404)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.throw(500)
|
ctx.throw(500)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next) {
|
if (next) {
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
@@ -239,7 +246,8 @@ class UserController {
|
|||||||
if (userObj.email && typeof userObj.email !== 'string') {
|
if (userObj.email && typeof userObj.email !== 'string') {
|
||||||
throw new Error("Property 'email' must be a string!")
|
throw new Error("Property 'email' must be a string!")
|
||||||
}
|
}
|
||||||
const isEmail = await _this.validateEmail(user.email)
|
|
||||||
|
const isEmail = await _this.validateEmail(userObj.email)
|
||||||
if (userObj.email && !isEmail) {
|
if (userObj.email && !isEmail) {
|
||||||
throw new Error("Property 'email' must be email format!")
|
throw new Error("Property 'email' must be email format!")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
const validator = require('../../middleware/validators')
|
const VALIDATOR = require('../../middleware/validators')
|
||||||
|
const validator = new VALIDATOR()
|
||||||
|
|
||||||
const CONTROLLER = require('./controller')
|
const CONTROLLER = require('./controller')
|
||||||
const controller = new CONTROLLER()
|
const controller = new CONTROLLER()
|
||||||
|
|
||||||
|
|||||||
+324
-131
@@ -2,6 +2,7 @@ const testUtils = require('./utils')
|
|||||||
const assert = require('chai').assert
|
const assert = require('chai').assert
|
||||||
const config = require('../config')
|
const config = require('../config')
|
||||||
const axios = require('axios').default
|
const axios = require('axios').default
|
||||||
|
const sinon = require('sinon')
|
||||||
|
|
||||||
const util = require('util')
|
const util = require('util')
|
||||||
util.inspect.defaultOptions = { depth: 1 }
|
util.inspect.defaultOptions = { depth: 1 }
|
||||||
@@ -10,6 +11,12 @@ const LOCALHOST = `http://localhost:${config.port}`
|
|||||||
|
|
||||||
const context = {}
|
const context = {}
|
||||||
|
|
||||||
|
const UserController = require('../src/modules/users/controller')
|
||||||
|
let uut
|
||||||
|
let sandbox
|
||||||
|
|
||||||
|
const mockContext = require('./mocks/ctx-mock').context
|
||||||
|
|
||||||
describe('Users', () => {
|
describe('Users', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
|
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
|
||||||
@@ -38,6 +45,14 @@ describe('Users', () => {
|
|||||||
// console.log(`admin: ${JSON.stringify(admin, null, 2)}`)
|
// console.log(`admin: ${JSON.stringify(admin, null, 2)}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
uut = new UserController()
|
||||||
|
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
describe('POST /users', () => {
|
describe('POST /users', () => {
|
||||||
it('should reject signup when data is incomplete', async () => {
|
it('should reject signup when data is incomplete', async () => {
|
||||||
try {
|
try {
|
||||||
@@ -49,11 +64,11 @@ describe('Users', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await axios(options)
|
await axios(options)
|
||||||
|
|
||||||
console.log(
|
/* console.log(
|
||||||
`result stringified: ${JSON.stringify(result.data, null, 2)}`
|
`result stringified: ${JSON.stringify(result.data, null, 2)}`
|
||||||
)
|
) */
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert(err.response.status === 422, 'Error code 422 expected.')
|
assert(err.response.status === 422, 'Error code 422 expected.')
|
||||||
@@ -128,6 +143,28 @@ describe('Users', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should reject if name property property is not string', async () => {
|
||||||
|
try {
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
url: `${LOCALHOST}/users`,
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
email: 'test322@test.com',
|
||||||
|
password: 'supersecretpassword',
|
||||||
|
name: 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await axios(options)
|
||||||
|
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.response.status, 422)
|
||||||
|
assert.include(err.response.data, "Property 'name' must be a string")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
it("should signup of type 'user' by default", async () => {
|
it("should signup of type 'user' by default", async () => {
|
||||||
const options = {
|
const options = {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
@@ -251,6 +288,22 @@ describe('Users', () => {
|
|||||||
assert.hasAnyKeys(users[0], ['type', '_id', 'email'])
|
assert.hasAnyKeys(users[0], ['type', '_id', 'email'])
|
||||||
assert.isNumber(users.length)
|
assert.isNumber(users.length)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should catch and handle errors', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(uut.User, 'find').rejects(new Error('test error'))
|
||||||
|
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
|
||||||
|
await uut.getUsers(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'Not Found')
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('GET /users/:id', () => {
|
describe('GET /users/:id', () => {
|
||||||
@@ -321,6 +374,40 @@ describe('Users', () => {
|
|||||||
'Password property should not be returned'
|
'Password property should not be returned'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should catch and handle errors', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(uut.User, 'findById').rejects(new Error('test error'))
|
||||||
|
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
|
||||||
|
await uut.getUser(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'Internal Server Error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle user not found', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(uut.User, 'findById').resolves(false)
|
||||||
|
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.params = { id: 1 }
|
||||||
|
|
||||||
|
await uut.getUser(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
// console.log(err)
|
||||||
|
assert.include(err.message, 'Not Found')
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('PUT /users/:id', () => {
|
describe('PUT /users/:id', () => {
|
||||||
@@ -362,6 +449,240 @@ describe('Users', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should not be able to update user type', async () => {
|
||||||
|
try {
|
||||||
|
const options = {
|
||||||
|
method: 'PUT',
|
||||||
|
url: `${LOCALHOST}/users/${context.user._id.toString()}`,
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${context.token}`
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
name: 'new name',
|
||||||
|
type: 'test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await axios(options)
|
||||||
|
|
||||||
|
// console.log(`Users: ${JSON.stringify(result.data, null, 2)}`)
|
||||||
|
|
||||||
|
// assert(result.status === 200, 'Status Code 200 expected.')
|
||||||
|
// assert(result.data.user.type === 'user', 'Type should be unchanged.')
|
||||||
|
assert.equal(true, false, 'Unexpected behavior')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.response.status, 422)
|
||||||
|
assert.include(
|
||||||
|
err.response.data,
|
||||||
|
"Property 'type' can only be changed by Admin user"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not be able to update other user when not admin', async () => {
|
||||||
|
try {
|
||||||
|
const options = {
|
||||||
|
method: 'PUT',
|
||||||
|
url: `${LOCALHOST}/users/${context.user2._id.toString()}`,
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${context.token}`
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
name: 'This should not work'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await axios(options)
|
||||||
|
|
||||||
|
// console.log(`result: ${JSON.stringify(result.data, null, 2)}`)
|
||||||
|
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.response.status, 401)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not be able to update if name property is wrong', async () => {
|
||||||
|
try {
|
||||||
|
const _id = context.user._id
|
||||||
|
const token = context.token
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'PUT',
|
||||||
|
url: `${LOCALHOST}/users/${_id}`,
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
Authorization: `Bearer ${token}`
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
email: 'testToUpdate@test.com',
|
||||||
|
name: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await axios(options)
|
||||||
|
} catch (error) {
|
||||||
|
assert.equal(error.response.status, 422)
|
||||||
|
assert.include(error.response.data, "Property 'name' must be a string!")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should not be able to update if password property is not string', async () => {
|
||||||
|
const { token } = context
|
||||||
|
const _id = context.user._id
|
||||||
|
try {
|
||||||
|
const options = {
|
||||||
|
method: 'PUT',
|
||||||
|
url: `${LOCALHOST}/users/${_id}`,
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
Authorization: `Bearer ${token}`
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
password: 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await axios(options)
|
||||||
|
|
||||||
|
assert.equal(true, false, 'Unexpected behavior')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.response.status, 422)
|
||||||
|
assert.include(
|
||||||
|
err.response.data,
|
||||||
|
"Property 'password' must be a string!"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should not be able to update if project property is not array', async () => {
|
||||||
|
const { token } = context
|
||||||
|
const _id = context.user._id
|
||||||
|
try {
|
||||||
|
const options = {
|
||||||
|
method: 'PUT',
|
||||||
|
url: `${LOCALHOST}/users/${_id}`,
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
Authorization: `Bearer ${token}`
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
projects: 'projects'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await axios(options)
|
||||||
|
|
||||||
|
assert.equal(true, false, 'Unexpected behavior')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.response.status, 422)
|
||||||
|
assert.include(
|
||||||
|
err.response.data,
|
||||||
|
"Property 'projects' must be a Array!"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should not be able to update if email is not string', async () => {
|
||||||
|
const { token } = context
|
||||||
|
const _id = context.user._id
|
||||||
|
try {
|
||||||
|
const options = {
|
||||||
|
method: 'PUT',
|
||||||
|
url: `${LOCALHOST}/users/${_id}`,
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
Authorization: `Bearer ${token}`
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
email: 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await axios(options)
|
||||||
|
|
||||||
|
assert.equal(true, false, 'Unexpected behavior')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.response.status, 422)
|
||||||
|
assert.include(err.response.data, "Property 'email' must be a string!")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should not be able to update if email is wrong format', async () => {
|
||||||
|
try {
|
||||||
|
const _id = context.user._id
|
||||||
|
const token = context.token
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'PUT',
|
||||||
|
url: `${LOCALHOST}/users/${_id}`,
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
Authorization: `Bearer ${token}`
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
email: 'badEmailFormat'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await axios(options)
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.response.status, 422)
|
||||||
|
assert.include(
|
||||||
|
err.response.data,
|
||||||
|
"Property 'email' must be email format!"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should not be able to update type property if is not string', async () => {
|
||||||
|
try {
|
||||||
|
const _id = context.user._id
|
||||||
|
const token = context.token
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'PUT',
|
||||||
|
url: `${LOCALHOST}/users/${_id}`,
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
Authorization: `Bearer ${token}`
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
type: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await axios(options)
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.response.status, 422)
|
||||||
|
assert.include(err.response.data, "Property 'type' must be a string!")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should be able to update other user when admin', async () => {
|
||||||
|
const adminJWT = context.adminJWT
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'PUT',
|
||||||
|
url: `${LOCALHOST}/users/${context.user2._id.toString()}`,
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${adminJWT}`
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
name: 'This should work'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const result = await axios(options)
|
||||||
|
// console.log(`result stringified: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
|
||||||
|
const userName = result.data.user.name
|
||||||
|
assert.equal(userName, 'This should work')
|
||||||
|
})
|
||||||
it('should update user with minimum inputs', async () => {
|
it('should update user with minimum inputs', async () => {
|
||||||
const _id = context.user._id
|
const _id = context.user._id
|
||||||
const token = context.token
|
const token = context.token
|
||||||
@@ -435,134 +756,6 @@ describe('Users', () => {
|
|||||||
assert.equal(user.email, 'testToUpdate@test.com')
|
assert.equal(user.email, 'testToUpdate@test.com')
|
||||||
assert.equal(user.username, 'myUsername')
|
assert.equal(user.username, 'myUsername')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not be able to update user type', async () => {
|
|
||||||
try {
|
|
||||||
const options = {
|
|
||||||
method: 'PUT',
|
|
||||||
url: `${LOCALHOST}/users/${context.user._id.toString()}`,
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${context.token}`
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
user: {
|
|
||||||
name: 'new name',
|
|
||||||
type: 'test'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const result = await axios(options)
|
|
||||||
|
|
||||||
console.log(`Users: ${JSON.stringify(result.data, null, 2)}`)
|
|
||||||
|
|
||||||
// assert(result.status === 200, 'Status Code 200 expected.')
|
|
||||||
// assert(result.data.user.type === 'user', 'Type should be unchanged.')
|
|
||||||
assert.equal(true, false, 'Unexpected behavior')
|
|
||||||
} catch (err) {
|
|
||||||
assert.equal(err.response.status, 422)
|
|
||||||
assert.include(
|
|
||||||
err.response.data,
|
|
||||||
"Property 'type' can only be changed by Admin user"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should not be able to update other user when not admin', async () => {
|
|
||||||
try {
|
|
||||||
const options = {
|
|
||||||
method: 'PUT',
|
|
||||||
url: `${LOCALHOST}/users/${context.user2._id.toString()}`,
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${context.token}`
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
user: {
|
|
||||||
name: 'This should not work'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const result = await axios(options)
|
|
||||||
|
|
||||||
console.log(`result: ${JSON.stringify(result.data, null, 2)}`)
|
|
||||||
|
|
||||||
assert(false, 'Unexpected result')
|
|
||||||
} catch (err) {
|
|
||||||
assert.equal(err.response.status, 401)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should be able to update other user when admin', async () => {
|
|
||||||
const adminJWT = context.adminJWT
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
method: 'PUT',
|
|
||||||
url: `${LOCALHOST}/users/${context.user2._id.toString()}`,
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${adminJWT}`
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
user: {
|
|
||||||
name: 'This should work'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const result = await axios(options)
|
|
||||||
// console.log(`result stringified: ${JSON.stringify(result, null, 2)}`)
|
|
||||||
|
|
||||||
const userName = result.data.user.name
|
|
||||||
assert.equal(userName, 'This should work')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should not be able to update if name property is wrong', async () => {
|
|
||||||
try {
|
|
||||||
const _id = context.user._id
|
|
||||||
const token = context.token
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
method: 'PUT',
|
|
||||||
url: `${LOCALHOST}/users/${_id}`,
|
|
||||||
headers: {
|
|
||||||
Accept: 'application/json',
|
|
||||||
Authorization: `Bearer ${token}`
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
user: {
|
|
||||||
email: 'testToUpdate@test.com',
|
|
||||||
name: {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await axios(options)
|
|
||||||
} catch (error) {
|
|
||||||
assert.equal(error.response.status, 422)
|
|
||||||
assert.include(error.response.data, "Property 'name' must be a string!")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should not be able to update if email is wrong format', async () => {
|
|
||||||
try {
|
|
||||||
const _id = context.user._id
|
|
||||||
const token = context.token
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
method: 'PUT',
|
|
||||||
url: `${LOCALHOST}/users/${_id}`,
|
|
||||||
headers: {
|
|
||||||
Accept: 'application/json',
|
|
||||||
Authorization: `Bearer ${token}`
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
user: {
|
|
||||||
email: 'badEmailFormat'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await axios(options)
|
|
||||||
} catch (err) {
|
|
||||||
assert.equal(err.response.status, 422)
|
|
||||||
assert.include(err.response.data, 'not a valid Email format')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('DELETE /users/:id', () => {
|
describe('DELETE /users/:id', () => {
|
||||||
|
|||||||
+61
-28
@@ -1,9 +1,23 @@
|
|||||||
const assert = require('chai').assert
|
const assert = require('chai').assert
|
||||||
|
|
||||||
const NodeMailer = require('../src/lib/nodemailer')
|
const NodeMailer = require('../src/lib/nodemailer')
|
||||||
const nodemailer = new NodeMailer()
|
|
||||||
|
|
||||||
|
const sinon = require('sinon')
|
||||||
|
|
||||||
|
const util = require('util')
|
||||||
|
util.inspect.defaultOptions = { depth: 1 }
|
||||||
|
|
||||||
|
let sandbox
|
||||||
|
let uut
|
||||||
describe('NodeMailer', () => {
|
describe('NodeMailer', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
uut = new NodeMailer()
|
||||||
|
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
describe('sendEmail()', () => {
|
describe('sendEmail()', () => {
|
||||||
it('should throw error if email property is not provided', async () => {
|
it('should throw error if email property is not provided', async () => {
|
||||||
try {
|
try {
|
||||||
@@ -13,7 +27,7 @@ describe('NodeMailer', () => {
|
|||||||
subject: 'test subject',
|
subject: 'test subject',
|
||||||
to: ['test2@email.com']
|
to: ['test2@email.com']
|
||||||
}
|
}
|
||||||
await nodemailer.sendEmail(data)
|
await uut.sendEmail(data)
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.include(err.message, 'Property \'email\' must be a string!')
|
assert.include(err.message, 'Property \'email\' must be a string!')
|
||||||
@@ -28,7 +42,7 @@ describe('NodeMailer', () => {
|
|||||||
subject: 'test subject',
|
subject: 'test subject',
|
||||||
to: ['test2@email.com']
|
to: ['test2@email.com']
|
||||||
}
|
}
|
||||||
await nodemailer.sendEmail(data)
|
await uut.sendEmail(data)
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.include(err.message, 'Property \'email\' must be email format!')
|
assert.include(err.message, 'Property \'email\' must be email format!')
|
||||||
@@ -42,7 +56,7 @@ describe('NodeMailer', () => {
|
|||||||
subject: 'test subject',
|
subject: 'test subject',
|
||||||
to: ['test2@email.com']
|
to: ['test2@email.com']
|
||||||
}
|
}
|
||||||
await nodemailer.sendEmail(data)
|
await uut.sendEmail(data)
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.include(err.message, 'Property \'message\' must be a string!')
|
assert.include(err.message, 'Property \'message\' must be a string!')
|
||||||
@@ -55,7 +69,7 @@ describe('NodeMailer', () => {
|
|||||||
name: 'test name',
|
name: 'test name',
|
||||||
subject: 'test subject'
|
subject: 'test subject'
|
||||||
}
|
}
|
||||||
await nodemailer.sendEmail(data)
|
await uut.sendEmail(data)
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.include(err.message, 'Property \'to\' must be a array!')
|
assert.include(err.message, 'Property \'to\' must be a array!')
|
||||||
@@ -71,7 +85,7 @@ describe('NodeMailer', () => {
|
|||||||
subject: 'test subject',
|
subject: 'test subject',
|
||||||
to: ['test']
|
to: ['test']
|
||||||
}
|
}
|
||||||
await nodemailer.sendEmail(data)
|
await uut.sendEmail(data)
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.include(err.message, 'Array must contain emails format!')
|
assert.include(err.message, 'Array must contain emails format!')
|
||||||
@@ -86,7 +100,7 @@ describe('NodeMailer', () => {
|
|||||||
name: 'test name',
|
name: 'test name',
|
||||||
to: ['test2@email.com']
|
to: ['test2@email.com']
|
||||||
}
|
}
|
||||||
await nodemailer.sendEmail(data)
|
await uut.sendEmail(data)
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.include(err.message, 'Property \'subject\' must be a string!')
|
assert.include(err.message, 'Property \'subject\' must be a string!')
|
||||||
@@ -101,34 +115,53 @@ describe('NodeMailer', () => {
|
|||||||
subject: 'test subject',
|
subject: 'test subject',
|
||||||
to: ['test2@email.com']
|
to: ['test2@email.com']
|
||||||
}
|
}
|
||||||
await nodemailer.sendEmail(data)
|
await uut.sendEmail(data)
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'Property \'payloadTitle\' must be a string!')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw error if payloadTitle property is not string', async () => {
|
||||||
|
try {
|
||||||
|
const data = {
|
||||||
|
email: 'test@email.com',
|
||||||
|
formMessage: 'test msg',
|
||||||
|
name: 'test name',
|
||||||
|
subject: 'test subject',
|
||||||
|
to: ['test2@email.com'],
|
||||||
|
payloadTitle: true
|
||||||
|
|
||||||
|
}
|
||||||
|
await uut.sendEmail(data)
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.include(err.message, 'Property \'payloadTitle\' must be a string!')
|
assert.include(err.message, 'Property \'payloadTitle\' must be a string!')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
/* it('should send email', async () => {
|
it('should send email', async () => {
|
||||||
try {
|
try {
|
||||||
const data = {
|
sandbox.stub(uut.transporter, 'sendMail').resolves({ messageId: 'messageId' })
|
||||||
email: 'test@email.com',
|
const data = {
|
||||||
formMessage: 'test msg',
|
email: 'test@email.com',
|
||||||
name: 'test name',
|
formMessage: 'test msg',
|
||||||
to: 'test2@email.com',
|
name: 'test name',
|
||||||
subject: 'test subject',
|
to: ['test2@email.com'],
|
||||||
payloadTitle: 'test title'
|
subject: 'test subject',
|
||||||
}
|
payloadTitle: 'test title'
|
||||||
await nodemailer.sendEmail(data)
|
}
|
||||||
assert(false, 'Unexpected result')
|
const info = await uut.sendEmail(data)
|
||||||
} catch (err) {
|
assert.isObject(info)
|
||||||
assert.include(err.message, 'Property \'subject\' must be a string!')
|
assert.isString(info.messageId)
|
||||||
}
|
} catch (err) {
|
||||||
}) */
|
assert(false, 'Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
describe('validateEmailArray()', () => {
|
describe('validateEmailArray()', () => {
|
||||||
it('should throw error if email list is not provided ', async () => {
|
it('should throw error if email list is not provided ', async () => {
|
||||||
try {
|
try {
|
||||||
await nodemailer.validateEmailArray()
|
await uut.validateEmailArray()
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.include(err.message, 'Property \'emailList\' must be a array!')
|
assert.include(err.message, 'Property \'emailList\' must be a array!')
|
||||||
@@ -137,7 +170,7 @@ describe('NodeMailer', () => {
|
|||||||
it('should throw error if email list is empty', async () => {
|
it('should throw error if email list is empty', async () => {
|
||||||
try {
|
try {
|
||||||
const emailList = []
|
const emailList = []
|
||||||
await nodemailer.validateEmailArray(emailList)
|
await uut.validateEmailArray(emailList)
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.include(err.message, 'Property \'emailList\' cant be empty!')
|
assert.include(err.message, 'Property \'emailList\' cant be empty!')
|
||||||
@@ -149,7 +182,7 @@ describe('NodeMailer', () => {
|
|||||||
'wrongEmail',
|
'wrongEmail',
|
||||||
'bad format'
|
'bad format'
|
||||||
]
|
]
|
||||||
await nodemailer.validateEmailArray(emailList)
|
await uut.validateEmailArray(emailList)
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.include(err.message, 'Array must contain emails format!')
|
assert.include(err.message, 'Array must contain emails format!')
|
||||||
@@ -161,7 +194,7 @@ describe('NodeMailer', () => {
|
|||||||
'test@email.com',
|
'test@email.com',
|
||||||
'simple@email.com'
|
'simple@email.com'
|
||||||
]
|
]
|
||||||
const result = await nodemailer.validateEmailArray(emailList)
|
const result = await uut.validateEmailArray(emailList)
|
||||||
assert.isTrue(result)
|
assert.isTrue(result)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
|
|||||||
+142
-17
@@ -1,13 +1,27 @@
|
|||||||
const config = require('../config')
|
const config = require('../config')
|
||||||
const axios = require('axios').default
|
const axios = require('axios').default
|
||||||
const assert = require('chai').assert
|
const assert = require('chai').assert
|
||||||
|
const sinon = require('sinon')
|
||||||
|
|
||||||
// Mock data
|
// Mock data
|
||||||
// const mockData = require('./mocks/contact-mocks')
|
// const mockData = require('./mocks/contact-mocks')
|
||||||
|
|
||||||
const LOCALHOST = `http://localhost:${config.port}`
|
const LOCALHOST = `http://localhost:${config.port}`
|
||||||
|
|
||||||
|
const mockContext = require('./mocks/ctx-mock').context
|
||||||
|
const ContactController = require('../src/modules/contact/controller')
|
||||||
|
let uut
|
||||||
|
let sandbox
|
||||||
|
|
||||||
describe('Contact', () => {
|
describe('Contact', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
uut = new ContactController()
|
||||||
|
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
describe('POST /contact/email', () => {
|
describe('POST /contact/email', () => {
|
||||||
it('should throw error if email property is not provided', async () => {
|
it('should throw error if email property is not provided', async () => {
|
||||||
try {
|
try {
|
||||||
@@ -28,10 +42,11 @@ describe('Contact', () => {
|
|||||||
// console.log(`result stringified: ${JSON.stringify(result, null, 2)}`)
|
// console.log(`result stringified: ${JSON.stringify(result, null, 2)}`)
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.equal(err.response.status, 500)
|
assert.equal(err.response.status, 422)
|
||||||
assert.include(err.response.data, "Property 'email' must be a string!")
|
assert.include(err.response.data, "Property 'email' must be a string!")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should throw error if email property is wrong format', async () => {
|
it('should throw error if email property is wrong format', async () => {
|
||||||
try {
|
try {
|
||||||
const options = {
|
const options = {
|
||||||
@@ -52,13 +67,14 @@ describe('Contact', () => {
|
|||||||
// console.log(`result stringified: ${JSON.stringify(result, null, 2)}`)
|
// console.log(`result stringified: ${JSON.stringify(result, null, 2)}`)
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.equal(err.response.status, 500)
|
assert.equal(err.response.status, 422)
|
||||||
assert.include(
|
assert.include(
|
||||||
err.response.data,
|
err.response.data,
|
||||||
"Property 'email' must be email format!"
|
"Property 'email' must be email format!"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should throw error if formMessage property is not provided', async () => {
|
it('should throw error if formMessage property is not provided', async () => {
|
||||||
try {
|
try {
|
||||||
const options = {
|
const options = {
|
||||||
@@ -78,13 +94,14 @@ describe('Contact', () => {
|
|||||||
// console.log(`result stringified: ${JSON.stringify(result, null, 2)}`)
|
// console.log(`result stringified: ${JSON.stringify(result, null, 2)}`)
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.equal(err.response.status, 500)
|
assert.equal(err.response.status, 422)
|
||||||
assert.include(
|
assert.include(
|
||||||
err.response.data,
|
err.response.data,
|
||||||
"Property 'message' must be a string!"
|
"Property 'message' must be a string!"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should throw error if payloadTitle property is not provided', async () => {
|
it('should throw error if payloadTitle property is not provided', async () => {
|
||||||
try {
|
try {
|
||||||
const options = {
|
const options = {
|
||||||
@@ -105,19 +122,15 @@ describe('Contact', () => {
|
|||||||
// console.log(`result stringified: ${JSON.stringify(result, null, 2)}`)
|
// console.log(`result stringified: ${JSON.stringify(result, null, 2)}`)
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.equal(err.response.status, 500)
|
assert.equal(err.response.status, 422)
|
||||||
assert.include(
|
assert.include(
|
||||||
err.response.data,
|
err.response.data,
|
||||||
"Property 'payloadTitle' must be a string!"
|
"Property 'payloadTitle' must be a string!"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
/* I presented problems here trying to use sandbox in this test */
|
|
||||||
/* it('should send email with all input', async () => {
|
it('should throw error if payloadTitle property is not string', async () => {
|
||||||
// Mock live network calls.
|
|
||||||
sandbox.stub(
|
|
||||||
contactController.transporter, 'sendMail')
|
|
||||||
.resolves(mockData)
|
|
||||||
try {
|
try {
|
||||||
const options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -125,18 +138,130 @@ describe('Contact', () => {
|
|||||||
data: {
|
data: {
|
||||||
obj: {
|
obj: {
|
||||||
email: 'email@email.com',
|
email: 'email@email.com',
|
||||||
formMessage: 'test email',
|
formMessage: 'test message',
|
||||||
name: 'test name',
|
payloadTitle: 1
|
||||||
payloadtitle: 'test title'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const result = await axios(options)
|
|
||||||
console.log('RESULT', result.data)
|
await axios(options)
|
||||||
|
|
||||||
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
|
||||||
|
// console.log(`result stringified: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.response.status, 422)
|
||||||
|
assert.include(
|
||||||
|
err.response.data,
|
||||||
|
"Property 'payloadTitle' must be a string!"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error if email list provided is not a array', async () => {
|
||||||
|
try {
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
url: `${LOCALHOST}/contact/email`,
|
||||||
|
data: {
|
||||||
|
obj: {
|
||||||
|
email: 'email@email.com',
|
||||||
|
formMessage: 'test message',
|
||||||
|
payloadTitle: 'title',
|
||||||
|
emailList: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await axios(options)
|
||||||
|
|
||||||
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
|
||||||
|
// console.log(`result stringified: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.response.status, 422)
|
||||||
|
assert.include(
|
||||||
|
err.response.data,
|
||||||
|
"Property 'emailList' must be a array of emails!"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error if email list provided is a empty array', async () => {
|
||||||
|
try {
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
url: `${LOCALHOST}/contact/email`,
|
||||||
|
data: {
|
||||||
|
obj: {
|
||||||
|
email: 'email@email.com',
|
||||||
|
formMessage: 'test message',
|
||||||
|
payloadTitle: 'title',
|
||||||
|
emailList: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await axios(options)
|
||||||
|
|
||||||
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
|
||||||
|
// console.log(`result stringified: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.response.status, 422)
|
||||||
|
assert.include(
|
||||||
|
err.response.data,
|
||||||
|
"Property 'emailList' must be a array of emails!"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should send email with minimun input', async () => {
|
||||||
|
try {
|
||||||
|
// Mock live network calls.
|
||||||
|
sandbox.stub(uut.nodemailer, 'sendEmail').resolves(true)
|
||||||
|
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.request = {
|
||||||
|
body: {
|
||||||
|
obj: {
|
||||||
|
email: 'email@email.com',
|
||||||
|
formMessage: 'test message',
|
||||||
|
payloadTitle: 'title'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await uut.email(ctx)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// console.log(err)
|
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
}
|
}
|
||||||
}) */
|
})
|
||||||
|
|
||||||
|
it('should send email with all input', async () => {
|
||||||
|
try {
|
||||||
|
// Mock live network calls.
|
||||||
|
sandbox.stub(uut.nodemailer, 'sendEmail').resolves(true)
|
||||||
|
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.request = {
|
||||||
|
body: {
|
||||||
|
obj: {
|
||||||
|
email: 'email@email.com',
|
||||||
|
formMessage: 'test message',
|
||||||
|
payloadTitle: 'title',
|
||||||
|
emailList: ['email@email.com']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await uut.email(ctx)
|
||||||
|
} catch (err) {
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+18
-12
@@ -1,17 +1,24 @@
|
|||||||
const assert = require('chai').assert
|
const assert = require('chai').assert
|
||||||
const PassportLib = require('../src/lib/passport')
|
const PassportLib = require('../src/lib/passport')
|
||||||
|
|
||||||
describe('#passport.js', () => {
|
const sinon = require('sinon')
|
||||||
let passportLib
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
let uut
|
||||||
passportLib = new PassportLib()
|
let sandbox
|
||||||
|
|
||||||
|
describe('#passport.js', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
uut = new PassportLib()
|
||||||
|
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
describe('authUser()', () => {
|
describe('authUser()', () => {
|
||||||
it('should throw error if ctx is not provided', async () => {
|
it('should throw error if ctx is not provided', async () => {
|
||||||
try {
|
try {
|
||||||
await passportLib.authUser()
|
await uut.authUser()
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.include(err.message, 'ctx is required')
|
assert.include(err.message, 'ctx is required')
|
||||||
@@ -20,17 +27,16 @@ describe('#passport.js', () => {
|
|||||||
|
|
||||||
it('Should throw error if the passport library fails', async () => {
|
it('Should throw error if the passport library fails', async () => {
|
||||||
try {
|
try {
|
||||||
// This is a mock to handle the callback error
|
|
||||||
// when the passport library fails or throws error
|
|
||||||
const error = new Error('cant auth user')
|
const error = new Error('cant auth user')
|
||||||
const user = null
|
const user = null
|
||||||
const authMock = (value, callback) => {
|
|
||||||
callback(error, user)
|
// Mock calls
|
||||||
}
|
// https://sinonjs.org/releases/latest/stubs/
|
||||||
passportLib.passport.authenticate = authMock
|
// About yields
|
||||||
|
sandbox.stub(uut.passport, 'authenticate').yields(error, user)
|
||||||
|
|
||||||
const ctx = {}
|
const ctx = {}
|
||||||
await passportLib.authUser(ctx)
|
await uut.authUser(ctx)
|
||||||
assert(false, 'Unexpected result')
|
assert(false, 'Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.include(err.message, 'cant auth user')
|
assert.include(err.message, 'cant auth user')
|
||||||
|
|||||||
@@ -0,0 +1,251 @@
|
|||||||
|
const config = require('../config')
|
||||||
|
const assert = require('chai').assert
|
||||||
|
|
||||||
|
const axios = require('axios').default
|
||||||
|
const sinon = require('sinon')
|
||||||
|
|
||||||
|
const util = require('util')
|
||||||
|
util.inspect.defaultOptions = { depth: 1 }
|
||||||
|
|
||||||
|
const LOCALHOST = `http://localhost:${config.port}`
|
||||||
|
|
||||||
|
const LogsController = require('../src/modules/logapi/controller')
|
||||||
|
const mockContext = require('./mocks/ctx-mock').context
|
||||||
|
const mockData = require('./mocks/log-api-mock')
|
||||||
|
|
||||||
|
const context = {}
|
||||||
|
let sandbox
|
||||||
|
let uut
|
||||||
|
describe('LogsApi', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
uut = new LogsController()
|
||||||
|
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
|
describe('POST /logapi', () => {
|
||||||
|
it('should return false if password is not provided', async () => {
|
||||||
|
try {
|
||||||
|
const options = {
|
||||||
|
method: 'post',
|
||||||
|
url: `${LOCALHOST}/logapi`,
|
||||||
|
data: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await axios(options)
|
||||||
|
assert.isFalse(result.data.success)
|
||||||
|
} catch (err) {
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should return log', async () => {
|
||||||
|
try {
|
||||||
|
const options = {
|
||||||
|
method: 'post',
|
||||||
|
url: `${LOCALHOST}/logapi`,
|
||||||
|
data: {
|
||||||
|
password: 'test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await axios(options)
|
||||||
|
|
||||||
|
assert.isTrue(result.data.success)
|
||||||
|
assert.isArray(result.data.data)
|
||||||
|
assert.property(result.data.data[0], 'message')
|
||||||
|
assert.property(result.data.data[0], 'level')
|
||||||
|
assert.property(result.data.data[0], 'timestamp')
|
||||||
|
} catch (err) {
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should return false if files are not found!', async () => {
|
||||||
|
try {
|
||||||
|
sandbox.stub(uut, 'generateFileName').resolves('bad router')
|
||||||
|
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.request = {
|
||||||
|
body: {
|
||||||
|
password: 'test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await uut.getLogs(ctx)
|
||||||
|
|
||||||
|
assert.isFalse(ctx.body.success)
|
||||||
|
assert.include(ctx.body.data, 'file does not exist')
|
||||||
|
} catch (err) {
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should catch and handle errors', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(uut.fs, 'existsSync').throws(new Error('test error'))
|
||||||
|
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
|
||||||
|
ctx.request = {
|
||||||
|
body: {
|
||||||
|
password: 'test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await uut.getLogs(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw unhandled error', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(uut.fs, 'existsSync').throws(new Error())
|
||||||
|
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
|
||||||
|
ctx.request = {
|
||||||
|
body: {
|
||||||
|
password: 'test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await uut.getLogs(ctx)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'Unhandled error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('#filterLogs()', () => {
|
||||||
|
it('should throw error if data is not provided', async () => {
|
||||||
|
try {
|
||||||
|
await uut.filterLogs()
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'Data must be array')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw error if data provided is not an array', async () => {
|
||||||
|
try {
|
||||||
|
const data = 'data'
|
||||||
|
await uut.filterLogs(data)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'Data must be array')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should sort the log data', async () => {
|
||||||
|
try {
|
||||||
|
const data = mockData.data
|
||||||
|
const result = await uut.filterLogs(data)
|
||||||
|
assert.isArray(result)
|
||||||
|
assert.property(result[1], 'message')
|
||||||
|
assert.property(result[1], 'level')
|
||||||
|
assert.property(result[1], 'timestamp')
|
||||||
|
} catch (err) {
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should sort the log data with a limit', async () => {
|
||||||
|
try {
|
||||||
|
const data = mockData.data
|
||||||
|
const limit = 1
|
||||||
|
const result = await uut.filterLogs(data, limit)
|
||||||
|
assert.isArray(result)
|
||||||
|
assert.equal(result.length, limit)
|
||||||
|
assert.property(result[0], 'message')
|
||||||
|
assert.property(result[0], 'level')
|
||||||
|
assert.property(result[0], 'timestamp')
|
||||||
|
} catch (err) {
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#generateFileName()', () => {
|
||||||
|
it('should return file name', async () => {
|
||||||
|
try {
|
||||||
|
const fileName = await uut.generateFileName()
|
||||||
|
assert.isString(fileName)
|
||||||
|
context.fileName = fileName
|
||||||
|
} catch (err) {
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw error if something fails', async () => {
|
||||||
|
try {
|
||||||
|
uut.config = null
|
||||||
|
await uut.generateFileName()
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.exists(err)
|
||||||
|
assert.isString(err.message)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('#readLines()', () => {
|
||||||
|
it('should throw error if fileName is not provided', async () => {
|
||||||
|
try {
|
||||||
|
await uut.readLines()
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'filename must be a string')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw error if fileName provided is not string', async () => {
|
||||||
|
try {
|
||||||
|
const fileName = true
|
||||||
|
await uut.readLines(fileName)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'filename must be a string')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw error if the file does not exist', async () => {
|
||||||
|
try {
|
||||||
|
const fileName = 'test/logs/'
|
||||||
|
await uut.readLines(fileName)
|
||||||
|
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'file does not exist')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should ignore fileReader callback errors', async () => {
|
||||||
|
try {
|
||||||
|
// https://sinonjs.org/releases/latest/stubs/
|
||||||
|
// About yields
|
||||||
|
sandbox.stub(uut.lineReader, 'eachLine').yieldsRight({}, true)
|
||||||
|
|
||||||
|
const fileName = context.fileName
|
||||||
|
const result = await uut.readLines(fileName)
|
||||||
|
assert.isArray(result)
|
||||||
|
} catch (err) {
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should return data', async () => {
|
||||||
|
try {
|
||||||
|
const fileName = context.fileName
|
||||||
|
const result = await uut.readLines(fileName)
|
||||||
|
|
||||||
|
assert.isArray(result)
|
||||||
|
assert.property(result[1], 'message')
|
||||||
|
assert.property(result[1], 'level')
|
||||||
|
assert.property(result[1], 'timestamp')
|
||||||
|
} catch (err) {
|
||||||
|
assert.fail('Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
const assert = require('chai').assert
|
||||||
|
const fs = require('fs')
|
||||||
|
const sinon = require('sinon')
|
||||||
|
|
||||||
|
const util = require('util')
|
||||||
|
util.inspect.defaultOptions = { depth: 1 }
|
||||||
|
|
||||||
|
const JsonFiles = require('../src/lib/utils/json-files')
|
||||||
|
|
||||||
|
const JSON_FILE = 'test-json-file.json'
|
||||||
|
const JSON_PATH = `${__dirname}/${JSON_FILE}`
|
||||||
|
|
||||||
|
const deleteFile = filepath => {
|
||||||
|
try {
|
||||||
|
// Delete state if exist
|
||||||
|
fs.unlinkSync(filepath)
|
||||||
|
} catch (error) {}
|
||||||
|
}
|
||||||
|
let sandbox
|
||||||
|
let uut
|
||||||
|
describe('JsonFiles', () => {
|
||||||
|
const obj = {
|
||||||
|
json: 'file'
|
||||||
|
}
|
||||||
|
beforeEach(() => {
|
||||||
|
uut = new JsonFiles()
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
})
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
deleteFile(JSON_PATH)
|
||||||
|
})
|
||||||
|
describe('writeJSON()', () => {
|
||||||
|
it('should throw error if inputs is not provided', async () => {
|
||||||
|
try {
|
||||||
|
await uut.writeJSON()
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'obj property is required')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw error if filename property is not provided', async () => {
|
||||||
|
try {
|
||||||
|
await uut.writeJSON(obj)
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'fileName property must be a string')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw error if filename property is not string', async () => {
|
||||||
|
try {
|
||||||
|
await uut.writeJSON(obj, 1)
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'fileName property must be a string')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw error if fs library return an error', async () => {
|
||||||
|
try {
|
||||||
|
// https://sinonjs.org/releases/latest/stubs/
|
||||||
|
// About yields
|
||||||
|
sandbox.stub(uut.fs, 'writeFile').yields(new Error('test error'))
|
||||||
|
|
||||||
|
await uut.writeJSON(obj, JSON_PATH)
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should write a json file', async () => {
|
||||||
|
try {
|
||||||
|
await uut.writeJSON(obj, JSON_PATH)
|
||||||
|
|
||||||
|
assert.isTrue(fs.existsSync(JSON_PATH))
|
||||||
|
} catch (err) {
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('readJSON()', () => {
|
||||||
|
it('should throw error if filename property is not provided', async () => {
|
||||||
|
try {
|
||||||
|
await uut.readJSON(obj)
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'fileName property must be a string')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw error if filename property is not string', async () => {
|
||||||
|
try {
|
||||||
|
await uut.readJSON(obj, 1)
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'fileName property must be a string')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw error if fs library return an error', async () => {
|
||||||
|
try {
|
||||||
|
// https://sinonjs.org/releases/latest/stubs/
|
||||||
|
// About yields
|
||||||
|
sandbox.stub(uut.fs, 'readFile').yields(new Error('test error'))
|
||||||
|
|
||||||
|
await uut.readJSON(JSON_PATH)
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw error if file not found', async () => {
|
||||||
|
try {
|
||||||
|
const testError = new Error('test error')
|
||||||
|
testError.code = 'ENOENT'
|
||||||
|
|
||||||
|
sandbox.stub(uut.fs, 'readFile').yields(testError)
|
||||||
|
|
||||||
|
await uut.readJSON(JSON_PATH)
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should read a json file', async () => {
|
||||||
|
try {
|
||||||
|
const result = await uut.readJSON(JSON_PATH)
|
||||||
|
|
||||||
|
const objKeys = Object.keys(obj)
|
||||||
|
const resultKeys = Object.keys(result)
|
||||||
|
|
||||||
|
assert.isObject(result)
|
||||||
|
assert.equal(objKeys.length, resultKeys.length)
|
||||||
|
} catch (err) {
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,317 @@
|
|||||||
|
const assert = require('chai').assert
|
||||||
|
const testUtils = require('./utils')
|
||||||
|
|
||||||
|
const Validators = require('../src/middleware/validators')
|
||||||
|
|
||||||
|
const sinon = require('sinon')
|
||||||
|
const mockContext = require('./mocks/ctx-mock').context
|
||||||
|
|
||||||
|
const util = require('util')
|
||||||
|
util.inspect.defaultOptions = { depth: 1 }
|
||||||
|
|
||||||
|
const context = {}
|
||||||
|
|
||||||
|
let sandbox
|
||||||
|
let uut
|
||||||
|
describe('Validators', () => {
|
||||||
|
before(async () => {
|
||||||
|
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
|
||||||
|
|
||||||
|
// Create a second test user.
|
||||||
|
const userObj = {
|
||||||
|
email: 'test2@test.com',
|
||||||
|
password: 'pass2'
|
||||||
|
}
|
||||||
|
const testUser = await testUtils.createUser(userObj)
|
||||||
|
// console.log(`testUser2: ${JSON.stringify(testUser, null, 2)}`)
|
||||||
|
|
||||||
|
context.user = testUser.user
|
||||||
|
context.token = testUser.token
|
||||||
|
context.id = testUser.user._id
|
||||||
|
|
||||||
|
// Get the JWT used to log in as the admin 'system' user.
|
||||||
|
const adminJWT = await testUtils.getAdminJWT()
|
||||||
|
// console.log(`adminJWT: ${adminJWT}`)
|
||||||
|
context.adminJWT = adminJWT
|
||||||
|
|
||||||
|
// const admin = await testUtils.loginAdminUser()
|
||||||
|
// context.adminJWT = admin.token
|
||||||
|
|
||||||
|
// const admin = await adminLib.loginAdmin()
|
||||||
|
// console.log(`admin: ${JSON.stringify(admin, null, 2)}`)
|
||||||
|
})
|
||||||
|
beforeEach(() => {
|
||||||
|
uut = new Validators()
|
||||||
|
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
|
describe('ensureUser()', () => {
|
||||||
|
it('should throw 401 if user cant be found', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(uut.User, 'findById').resolves(false)
|
||||||
|
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.request = {
|
||||||
|
header: {
|
||||||
|
authorization: `Bearer ${context.token}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await uut.ensureUser(ctx)
|
||||||
|
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 401)
|
||||||
|
assert.include(err.message, 'Unauthorized')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw 401 if token not found', async () => {
|
||||||
|
try {
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
|
||||||
|
await uut.ensureUser(ctx)
|
||||||
|
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 401)
|
||||||
|
assert.include(err.message, 'Unauthorized')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw 401 if token is invalid', async () => {
|
||||||
|
try {
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.request = {
|
||||||
|
header: {
|
||||||
|
authorization: 'Bearer 1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await uut.ensureUser(ctx)
|
||||||
|
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 401)
|
||||||
|
assert.include(err.message, 'Unauthorized')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should trigger the "next" function if user is admin', async () => {
|
||||||
|
try {
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.params = { id: context.id }
|
||||||
|
|
||||||
|
ctx.request = {
|
||||||
|
header: {
|
||||||
|
authorization: `Bearer ${context.adminJWT}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Function that execute if the validations
|
||||||
|
// are successful
|
||||||
|
const next = () => { return 'next function' }
|
||||||
|
|
||||||
|
const result = await uut.ensureUser(ctx, next)
|
||||||
|
|
||||||
|
assert.isString(result)
|
||||||
|
assert.equal(result, 'next function')
|
||||||
|
} catch (err) {
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('ensureAdmin()', () => {
|
||||||
|
it('should throw 401 if token not found', async () => {
|
||||||
|
try {
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
|
||||||
|
await uut.ensureAdmin(ctx)
|
||||||
|
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 401)
|
||||||
|
assert.include(err.message, 'Unauthorized')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw 401 if token is invalid', async () => {
|
||||||
|
try {
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.request = {
|
||||||
|
header: {
|
||||||
|
authorization: 'Bearer 1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await uut.ensureAdmin(ctx)
|
||||||
|
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 401)
|
||||||
|
assert.include(err.message, 'Unauthorized')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw 401 if user cant be found', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(uut.User, 'findById').resolves(false)
|
||||||
|
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.request = {
|
||||||
|
header: {
|
||||||
|
authorization: `Bearer ${context.token}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await uut.ensureAdmin(ctx)
|
||||||
|
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 401)
|
||||||
|
assert.include(err.message, 'Unauthorized')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw 401 if user is not admin type', async () => {
|
||||||
|
try {
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.request = {
|
||||||
|
header: {
|
||||||
|
authorization: `Bearer ${context.token}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await uut.ensureAdmin(ctx)
|
||||||
|
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 401)
|
||||||
|
assert.include(err.message, 'not admin')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should trigger the "next" function if user is admin', async () => {
|
||||||
|
try {
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.request = {
|
||||||
|
header: {
|
||||||
|
authorization: `Bearer ${context.adminJWT}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Function that execute if the validations
|
||||||
|
// are successful
|
||||||
|
const next = () => { return 'next function' }
|
||||||
|
|
||||||
|
const result = await uut.ensureAdmin(ctx, next)
|
||||||
|
|
||||||
|
assert.isString(result)
|
||||||
|
assert.equal(result, 'next function')
|
||||||
|
} catch (err) {
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('ensureTargetUserOrAdmin()', () => {
|
||||||
|
it('should throw 401 if token not found', async () => {
|
||||||
|
try {
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.params = { id: context.id }
|
||||||
|
await uut.ensureTargetUserOrAdmin(ctx)
|
||||||
|
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 401)
|
||||||
|
assert.include(err.message, 'Unauthorized')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw 401 if token is invalid', async () => {
|
||||||
|
try {
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.params = { id: context.id }
|
||||||
|
|
||||||
|
ctx.request = {
|
||||||
|
header: {
|
||||||
|
authorization: 'Bearer 1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await uut.ensureTargetUserOrAdmin(ctx)
|
||||||
|
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 401)
|
||||||
|
assert.include(err.message, 'Unauthorized')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw 401 if user cant be found', async () => {
|
||||||
|
try {
|
||||||
|
// Force an error
|
||||||
|
sandbox.stub(uut.User, 'findById').resolves(false)
|
||||||
|
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.params = { id: context.id }
|
||||||
|
|
||||||
|
ctx.request = {
|
||||||
|
header: {
|
||||||
|
authorization: `Bearer ${context.token}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await uut.ensureTargetUserOrAdmin(ctx)
|
||||||
|
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 401)
|
||||||
|
assert.include(err.message, 'Unauthorized')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw 401 if user is not admin type', async () => {
|
||||||
|
try {
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.params = { id: 'Target Id' }
|
||||||
|
|
||||||
|
ctx.request = {
|
||||||
|
header: {
|
||||||
|
authorization: `Bearer ${context.token}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await uut.ensureTargetUserOrAdmin(ctx)
|
||||||
|
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.status, 401)
|
||||||
|
assert.include(err.message, 'not admin')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should trigger the "next" function if user is admin', async () => {
|
||||||
|
try {
|
||||||
|
// Mock the context object.
|
||||||
|
const ctx = mockContext()
|
||||||
|
ctx.params = { id: context.id }
|
||||||
|
|
||||||
|
ctx.request = {
|
||||||
|
header: {
|
||||||
|
authorization: `Bearer ${context.adminJWT}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Function that execute if the validations
|
||||||
|
// are successful
|
||||||
|
const next = () => { return 'next function' }
|
||||||
|
|
||||||
|
const result = await uut.ensureTargetUserOrAdmin(ctx, next)
|
||||||
|
|
||||||
|
assert.isString(result)
|
||||||
|
assert.equal(result, 'next function')
|
||||||
|
} catch (err) {
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
const assert = require('chai').assert
|
||||||
|
|
||||||
|
const Admin = require('../src/lib/admin')
|
||||||
|
|
||||||
|
const sinon = require('sinon')
|
||||||
|
|
||||||
|
const util = require('util')
|
||||||
|
util.inspect.defaultOptions = { depth: 1 }
|
||||||
|
|
||||||
|
let sandbox
|
||||||
|
let uut
|
||||||
|
describe('Admin', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
uut = new Admin()
|
||||||
|
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
describe('loginAdmin()', () => {
|
||||||
|
it('should logind admin', async () => {
|
||||||
|
try {
|
||||||
|
const error = new Error('test error')
|
||||||
|
error.response = {
|
||||||
|
status: 422
|
||||||
|
}
|
||||||
|
// sandbox.stub(uut.axios, 'request').onFirstCall().throws(error)
|
||||||
|
|
||||||
|
const result = await uut.loginAdmin()
|
||||||
|
const user = result.data.user
|
||||||
|
|
||||||
|
assert.property(user, '_id')
|
||||||
|
assert.property(user, 'email')
|
||||||
|
assert.property(user, 'type')
|
||||||
|
|
||||||
|
assert.isString(user._id)
|
||||||
|
assert.isString(user.email)
|
||||||
|
assert.isString(user.type)
|
||||||
|
|
||||||
|
assert.equal(user.type, 'admin')
|
||||||
|
} catch (err) {
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should handle axios error', async () => {
|
||||||
|
try {
|
||||||
|
// Returns an erroneous password to force
|
||||||
|
// an auth error
|
||||||
|
sandbox
|
||||||
|
.stub(uut.jsonFiles, 'readJSON').resolves({ password: 'wrong' })
|
||||||
|
|
||||||
|
await uut.loginAdmin()
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.response.status, 401)
|
||||||
|
assert.include(err.response.data, 'Unauthorized')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('createSystemUser()', () => {
|
||||||
|
it('should create admin', async () => {
|
||||||
|
try {
|
||||||
|
const result = await uut.createSystemUser()
|
||||||
|
|
||||||
|
assert.property(result, 'email')
|
||||||
|
assert.property(result, 'password')
|
||||||
|
assert.property(result, 'id')
|
||||||
|
assert.property(result, 'token')
|
||||||
|
} catch (err) {
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should handle axios error', async () => {
|
||||||
|
try {
|
||||||
|
const error1 = new Error('test error')
|
||||||
|
error1.response = {
|
||||||
|
status: 422
|
||||||
|
}
|
||||||
|
const error2 = new Error('test error')
|
||||||
|
error1.response = {
|
||||||
|
status: 500
|
||||||
|
}
|
||||||
|
// The loginAdmin() function in some use cases is recursive
|
||||||
|
// after handling the 422 error, it gets called again
|
||||||
|
sandbox
|
||||||
|
.stub(uut.axios, 'request')
|
||||||
|
.onFirstCall()
|
||||||
|
.throws(error1)
|
||||||
|
.onSecondCall()
|
||||||
|
.throws(error2)
|
||||||
|
|
||||||
|
await uut.createSystemUser()
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should handle errors when remove user', async () => {
|
||||||
|
try {
|
||||||
|
const error1 = new Error('test error')
|
||||||
|
error1.response = {
|
||||||
|
status: 422
|
||||||
|
}
|
||||||
|
sandbox
|
||||||
|
.stub(uut.axios, 'request').throws(error1)
|
||||||
|
sandbox
|
||||||
|
.stub(uut.User, 'deleteOne').throws(new Error('test error'))
|
||||||
|
|
||||||
|
await uut.createSystemUser()
|
||||||
|
assert(false, 'Unexpected result')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// Ripped from https://github.com/koajs/koa/blob/master/test/helpers/context.js
|
||||||
|
// Solution courtesy of user @fl0w. See: https://github.com/koajs/koa/issues/999#issuecomment-309270599
|
||||||
|
// Take from this gist: https://gist.github.com/emmanuelnk/f1254eed8f947a81e8d715476d9cc92c
|
||||||
|
|
||||||
|
// if you want more comprehensive Koa Context object to test stuff like Cookies etc
|
||||||
|
// then use https://www.npmjs.com/package/@shopify/jest-koa-mocks (requires Jest)
|
||||||
|
|
||||||
|
// INSTRUCTIONS:
|
||||||
|
// Import in test file as below:
|
||||||
|
//
|
||||||
|
// const mockContext = require('./mocks/ctx-mock').context
|
||||||
|
// const ctx = mockContext()
|
||||||
|
// ...
|
||||||
|
|
||||||
|
const Stream = require('stream')
|
||||||
|
const Koa = require('koa')
|
||||||
|
|
||||||
|
const context = (req, res, app) => {
|
||||||
|
const socket = new Stream.Duplex()
|
||||||
|
|
||||||
|
req = Object.assign(
|
||||||
|
{ headers: {}, socket },
|
||||||
|
Stream.Readable.prototype,
|
||||||
|
req || {}
|
||||||
|
)
|
||||||
|
res = Object.assign(
|
||||||
|
{ _headers: {}, socket },
|
||||||
|
Stream.Writable.prototype,
|
||||||
|
res || {}
|
||||||
|
)
|
||||||
|
req.socket.remoteAddress = req.socket.remoteAddress || '127.0.0.1'
|
||||||
|
app = app || new Koa()
|
||||||
|
res.getHeader = k => res._headers[k.toLowerCase()]
|
||||||
|
res.setHeader = (k, v) => (res._headers[k.toLowerCase()] = v)
|
||||||
|
res.removeHeader = (k, v) => delete res._headers[k.toLowerCase()]
|
||||||
|
|
||||||
|
const retApp = app.createContext(req, res)
|
||||||
|
|
||||||
|
return retApp
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = (req, res, app) => context(req, res, app).request
|
||||||
|
|
||||||
|
const response = (req, res, app) => context(req, res, app).response
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
context,
|
||||||
|
request,
|
||||||
|
response
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// Mocks representing an array of logs for the
|
||||||
|
// Unit tests of logapi
|
||||||
|
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
message: 'Error in lib/nodemailer.js/validateEmailArray()',
|
||||||
|
level: 'error',
|
||||||
|
timestamp: '2020-11-14T12:15:55.230Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: 'Error in lib/nodemailer.js/validateEmailArray()',
|
||||||
|
level: 'error',
|
||||||
|
timestamp: '2020-11-14T12:15:55.231Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: 'Error in lib/nodemailer.js/validateEmailArray()',
|
||||||
|
level: 'error',
|
||||||
|
timestamp: '2020-11-14T12:15:55.230Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: 'Error in lib/nodemailer.js/validateEmailArray()',
|
||||||
|
level: 'error',
|
||||||
|
timestamp: '2020-11-14T12:15:55.231Z'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
module.exports = {
|
||||||
|
data
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user