node-express-mongodb-jwt-rest-api-skeleton
Version:
Node.js express.js MongoDB JWT REST API - This is a basic API REST skeleton written on JavaScript using async/await. Great for building a starter web API for your front-end (Android, iOS, Vue, react, angular, or anything that can consume an API)
267 lines (251 loc) • 6.94 kB
JavaScript
/* eslint handle-callback-err: "off"*/
process.env.NODE_ENV = 'test'
const User = require('../app/models/user')
const faker = require('faker')
const chai = require('chai')
const chaiHttp = require('chai-http')
const server = require('../server')
// eslint-disable-next-line no-unused-vars
const should = chai.should()
const loginDetails = {
email: 'admin@admin.com',
password: '12345'
}
let token = ''
const createdID = []
let verification = ''
let verificationForgot = ''
const email = faker.internet.email()
const failedLoginAttempts = 5
const badUser = {
name: 'Bad user',
email: 'bad@user.com',
password: '54321'
}
const badLoginDetails = {
email: 'bad@user.com',
password: '12345'
}
chai.use(chaiHttp)
describe('*********** AUTH ***********', () => {
describe('/GET /', () => {
it('it should GET home API url', (done) => {
chai
.request(server)
.get('/')
.end((err, res) => {
res.should.have.status(200)
done()
})
})
})
describe('/GET /404url', () => {
it('it should GET 404 url', (done) => {
chai
.request(server)
.get('/404url')
.end((err, res) => {
res.should.have.status(404)
res.body.should.be.an('object')
done()
})
})
})
describe('/POST login', () => {
it('it should GET token', (done) => {
chai
.request(server)
.post('/login')
.send(loginDetails)
.end((err, res) => {
res.should.have.status(200)
res.body.should.be.an('object')
res.body.should.have.property('token')
token = res.body.token
done()
})
})
})
describe('/POST register', () => {
it('it should POST register', (done) => {
const user = {
name: faker.random.words(),
email,
password: faker.random.words()
}
chai
.request(server)
.post('/register')
.send(user)
.end((err, res) => {
res.should.have.status(201)
res.body.should.be.an('object')
res.body.should.include.keys('token', 'user')
createdID.push(res.body.user._id)
verification = res.body.user.verification
done()
})
})
it('it should NOT POST a register if email already exists', (done) => {
const user = {
name: faker.random.words(),
email,
password: faker.random.words()
}
chai
.request(server)
.post('/register')
.send(user)
.end((err, res) => {
res.should.have.status(422)
res.body.should.be.a('object')
res.body.should.have.property('errors')
done()
})
})
})
describe('/POST verify', () => {
it('it should POST verify', (done) => {
chai
.request(server)
.post('/verify')
.send({
id: verification
})
.end((err, res) => {
res.should.have.status(200)
res.body.should.be.an('object')
res.body.should.include.keys('email', 'verified')
res.body.verified.should.equal(true)
done()
})
})
})
describe('/POST forgot', () => {
it('it should POST forgot', (done) => {
chai
.request(server)
.post('/forgot')
.send({
email
})
.end((err, res) => {
res.should.have.status(200)
res.body.should.be.an('object')
res.body.should.include.keys('msg', 'verification')
verificationForgot = res.body.verification
done()
})
})
})
describe('/POST reset', () => {
it('it should POST reset', (done) => {
chai
.request(server)
.post('/reset')
.send({
id: verificationForgot,
password: '12345'
})
.end((err, res) => {
res.should.have.status(200)
res.body.should.be.a('object')
res.body.should.have.property('msg').eql('PASSWORD_CHANGED')
done()
})
})
})
describe('/GET token', () => {
it('it should NOT be able to consume the route since no token was sent', (done) => {
chai
.request(server)
.get('/token')
.end((err, res) => {
res.should.have.status(401)
done()
})
})
it('it should GET a fresh token', (done) => {
chai
.request(server)
.get('/token')
.set('Authorization', `Bearer ${token}`)
.end((err, res) => {
res.should.have.status(200)
res.body.should.be.an('object')
res.body.should.have.property('token')
done()
})
})
})
describe('/POST register', () => {
it('it should POST register', (done) => {
chai
.request(server)
.post('/register')
.send(badUser)
.end((err, res) => {
res.should.have.status(201)
res.body.should.be.an('object')
res.body.should.include.keys('token', 'user')
createdID.push(res.body.user._id)
done()
})
})
})
describe('/POST login', () => {
for (let x = 1; x < failedLoginAttempts + 1; x++) {
it(`it should NOT POST login after password fail #${x}`, (done) => {
chai
.request(server)
.post('/login')
.send(badLoginDetails)
.end((err, res) => {
res.should.have.status(409)
res.body.should.be.a('object')
res.body.should.have.property('errors').that.has.property('msg')
res.body.errors.should.have.property('msg').eql('WRONG_PASSWORD')
done()
})
})
}
it('it should NOT POST login after password fail #6 and be blocked', (done) => {
chai
.request(server)
.post('/login')
.send(badLoginDetails)
.end((err, res) => {
res.should.have.status(409)
res.body.should.be.a('object')
res.body.should.have.property('errors').that.has.property('msg')
res.body.errors.should.have.property('msg').eql('BLOCKED_USER')
done()
})
})
it('it should NOT POST login after being blocked sending post with correct password', (done) => {
chai
.request(server)
.post('/login')
.send({
email: badUser.email,
password: badUser.password
})
.end((err, res) => {
res.should.have.status(409)
res.body.should.be.a('object')
res.body.should.have.property('errors').that.has.property('msg')
res.body.errors.should.have.property('msg').eql('BLOCKED_USER')
done()
})
})
})
after(() => {
createdID.forEach((id) => {
User.findByIdAndRemove(id, (err) => {
if (err) {
console.log(err)
}
})
})
})
})