I wrote an express API for a document management service (repo to be found here) and even though I understand the importance of unit-testing I never quite managed to wrap my head around how I would test an API like this. I have no idea if my test are actually testing something useful or are covering everything that could be tested:
describe('User', () => {
before((done) => {
user.deleteMany({}, (err) => {
done()
})
})
describe('/POST signup', () => {
it('should not create a new user with invalid mail syntax', (done) => {
let body = {
username: 'test_user',
password: 'test_password',
mail: 'invalid',
diplayName: 'Testi Test',
}
chai
.request(server)
.post('/user/signup')
.send(body)
.end((err, res) => {
res.should.have.status(500)
res.body.should.be.a('object')
res.body.payload.should.have.a.property('message')
res.body.payload.message.should.be.a('string')
done()
})
})
it('should create a new user with valid syntax', (done) => {
let body = {
username: 'test_user',
password: 'test_password',
mail: '[email protected]',
diplayName: 'Testi Test',
}
chai
.request(server)
.post('/user/signup')
.send(body)
.end((err, res) => {
res.should.have.status(200)
res.body.should.be.a('object')
res.body.payload.should.have.a.property('user')
res.body.payload.should.have.a.property('token')
res.body.payload.user.should.be.a('object')
res.body.payload.token.should.be.a('string')
done()
})
})
})
describe('/POST login', () => {
it('should not login without password or username', (done) => {
let body = {
username: 'test_user',
}
chai
.request(server)
.post('/user/login')
.send(body)
.end((err, res) => {
res.should.have.status(401)
res.body.should.be.a('object')
res.body.payload.should.have.a.property('message')
res.body.payload.message.should.be.a('string')
})
body = {
password: 'test_password',
}
chai
.request(server)
.post('/user/login')
.send(body)
.end((err, res) => {
res.should.have.status(401)
res.body.should.be.a('object')
res.body.payload.should.have.a.property('message')
res.body.payload.message.should.be.a('string')
})
done()
})
it('should not login with wrong credentials', (done) => {
body = { username: 'wrong_name', password: 'test_password' }
chai
.request(server)
.post('/user/login')
.send(body)
.end((err, res) => {
res.should.have.status(401)
res.body.should.be.a('object')
res.body.payload.should.have.a.property('message')
res.body.payload.message.should.be.a('string')
done()
})
})
it('should login with correct credentials', (done) => {
body = { username: 'test_user', password: 'test_password' }
chai
.request(server)
.post('/user/login')
.send(body)
.end((err, res) => {
res.should.have.status(200)
res.body.should.be.a('object')
res.body.payload.should.have.a.property('user')
res.body.payload.should.have.a.property('token')
res.body.payload.user.should.be.a('object')
res.body.payload.token.should.be.a('string')
done()
})
})
})
})
These are the routes to be tested:
router
.route('/login')
/**
* @api {post} /user/login User login
* @apiName userLogin
* @apiGroup User
* @apiDescription Logs user in and returns the user and API token
* @apiParam {String} username
* @apiParam {String} password
* @apiSuccess {Object} user User profile
* @apiSuccess {String} token API token
* @apiError (401) {String} LoginFailed
*/
.post(async (req, res) => {
try {
let result = await user.getAuthenticated(
req.body.username,
req.body.password
)
const token = await jwt.sign(result.toJSON(), process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES,
})
res.status(200).json({ payload: { user: result, token: token } })
} catch (error) {
res.status(401).json({ payload: { message: 'Login failed' } })
}
})
router
.route('/signup')
/**
* @api {post} /user/signup User signup
* @apiName userSignup
* @apiGroup User
* @apiDescription Signs user up and logs in automatically
* @apiParam {String} username Username
* @apiParam {String} password Password according to policy
* @apiParam {String} mail Valid email
* @apiParam {String} displayName Full name
* @apiSuccess {Object} user User profile
* @apiSuccess {String} token API token
* @apiError (500) {String} InternalError Something went wrong during signup. Most likely to be during validation.
* @apiDeprecated Users should not be allowed to sign up by themselfes but rather be invited to use docSys
*/
.post(async (req, res) => {
try {
let newUser = new user({
username: req.body.username,
password: req.body.password,
mail: req.body.mail,
settings: {
language: 'en',
displayName: req.body.displayName,
},
})
const token = jwt.sign(newUser.toObject(), process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES,
})
await newUser.save()
res.status(200).json({ payload: { user: newUser, token: token } })
} catch (error) {
res.status(500).json({ payload: { message: error.message } })
}
})
My questions are:
- Are these tests sufficient to cover these routes?
- Am I testing the mongoose model in a seperate test or can I just assume that it's doing its thing correctly if tests like these pass?
I know it's quite stupid to write tests after big portions of the API have already been written, but I figured I'll have to start at some point.