This probably has to do with asynchronous code, but I'm not sure what. The both pass when I run them apart from each other: mocha test/models.coffee
and mocha test/login.coffee
But describe 'saving another user with same username', ->
fails when I run the tests together with npm test
. I imagine the database gets cleared as it's running that step so it saves instead of producing an error because it's supposed to be a unique value.
ALSO: I am extremely new at this software testing stuff, if anyone has any tips, or wants to criticize my blatant mistakes, feel free to email me (check my profile)
Thanks!!
Here are my two test files (coffeescript):
/test/models.coffee
should = require 'should'
{User} = require '../models'
# function to find our test user, John Egbert
findJohn = (cb) ->
User.findOne {'public.username': 'john'}, (err, john) ->
throw err if err
cb(john)
before (done) ->
# Drop all users from database
User.collection.drop()
# Create our test user, his username is John Egbert
User.create
password: 'test123'
public: {username: 'john'}, done
describe 'create user', ->
it 'should create a document that can be found', (done) ->
findJohn (user) ->
should.exist user
done()
describe 'user password', ->
it 'should NOT be stored in plaintext', (done) ->
findJohn (user) ->
user.password.should.not.eql 'test123'
done()
it 'should return true for matching password', (done) ->
findJohn (user) ->
user.comparePassword 'test123', (err, isMatch) ->
isMatch.should.eql true
done()
it 'should return false for non-matching password', (done) ->
findJohn (user) ->
user.comparePassword 'wrong_password', (err, isMatch) ->
isMatch.should.not.eql true
done()
describe 'saving another user with same username', ->
it 'should produce an error', (done) ->
User.create public: {username: 'john'}, (err) ->
should.exist err
done()
/test/login.coffee
:
should = require 'should'
{User} = require '../models'
login = require '../services/login'
before (done) ->
# Drop all users from database
User.collection.drop()
# Create our test user, his username is John Egbert
User.create
password: 'test123'
public: {username: 'john'}, done
describe 'login', ->
it 'should return true for an existing username/password combo', (done) ->
login username: 'john', password: 'test123', (err, loggedIn) ->
should.not.exist(err)
loggedIn.should.be.true
done()
it 'should return false for a bad username/password combo', (done) ->
login username: 'john', password: 'wrong_pass', (err, loggedIn) ->
should.not.exist(err)
loggedIn.should.be.false
done()
And /models.coffee
fs = require 'fs'
path = require 'path'
mongoose = require 'mongoose'
#Connect to mongodb
#TODO: env variable to choose production/development/testing databases
mongoose.connect 'localhost', 'siglr'
models = {}
for file in fs.readdirSync './schemas'
if path.extname(file) is '.coffee'
modelName = path.basename file, '.coffee'
schema = require "./schemas/#{modelName}"
models[modelName] = mongoose.model modelName, schema
# key is model name, value is actual mongoose model
module.exports = models
Here's one thing that could be creating race conditions that will make you crazy. You aren't passing a callback when dropping the users collection. I can't say for sure if this will ever cause a problem such as the test user being inserted before the collection gets dropped, but this pattern of failing to use callbacks properly to wait for asynchronous operations to complete is a recipe for your program to misbehave in hard-to-debug ways. Try this:
before (done) ->
# Drop all users from database
User.collection.drop (err) ->
# Create our test user, his username is John Egbert
User.create
password: 'test123'
public: {username: 'john'}, done
2nd suggestion: put console.log
statements at the beginning (1st statement) of every describe/before/it
and another one immediately prior to calling done()
and see if they appear in exactly the order you expect.
I found that for some reason the public.username
index is removed when running the tests together with npm test
. But was maintained when running each test alone.
I changed the following in the test/models.coffee
:
# Create our test user, his username is John Egbert
User.create
password: 'test123'
public: {username: 'john'}, done
To the following:
# Create our test user, his username is John Egbert
User.create
password: 'test123'
public: {username: 'john'}, ->
User.collection.ensureIndex { 'public.username': 1 }, { unique: true }, (err) ->
throw err if err
done()
...which calls ensureIndex an internal mongoose function which is called when the model is compiled initially, but is removed for some reason during the test's life-cycle.
Using Mongoose 3.5.4
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With