sequelize-test-helpers-ts
v1.0.0
Published
Sequelize test helpers for typescript.
Downloads
51
Maintainers
Readme
sequelize-test-helpers
A collection of utilities to help with unit-testing Sequelize models and code that needs those models.
Branches
| Branch | Status | Coverage | |
| ------ | ------ | -------- | - |
| develop
| | | Work in progress |
| master
| | | Latest stable release |
Prerequisites
This library assumes:
Install
Add sequelize-test-helpers
as a devDependency
:
npm i -D sequelize-test-helpers
Examples
Unit Testing Models
Let's say you have a Sequelize model User
as follows:
src/models/User.js
const model = (sequelize, DataTypes) => {
const User = sequelize.define(
'User',
{
age: {
type: DataTypes.INTEGER.UNSIGNED
},
firstname: {
type: DataTypes.STRING,
allowNull: false,
validate: {
notEmpty: true
}
},
lastname: {
type: DataTypes.STRING,
allowNull: false,
validate: {
notEmpty: true
}
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
lowercase: true,
validate: {
isEmail: true,
notEmpty: true
}
},
token: {
type: DataTypes.STRING,
validate: {
notEmpty: true
}
}
},
{
indexes: [
{ unique: true, fields: ['email'] },
{ unique: true, fields: ['token'] }
]
}
)
User.associate = ({ Company }) => {
User.belongsTo(Company)
}
return User
}
module.exports = model
You can use sequelize-test-helpers
to unit-test this as follows:
test/unit/models/User.spec.js
const { expect } = require('chai')
const {
sequelize,
dataTypes,
checkModelName,
checkUniqueIndex,
checkPropertyExists
} = require('sequelize-test-helpers')
const UserModel = require('../../src/models/User')
describe('src/models/User', () => {
const User = UserModel(sequelize, dataTypes)
const user = new User()
checkModelName(User)('User')
context('properties', () => {
;[
'age',
'firstname',
'lastname',
'email',
'token'
].forEach(checkPropertyExists(user))
})
context('associations', () => {
const Company = 'some dummy company'
before(() => {
User.associate({ Company })
})
it('defined a belongsTo association with Company', () => {
expect(User.belongsTo).to.have.been.calledWith(Company)
})
})
context('indexes', () => {
;['email', 'token'].forEach(checkUniqueIndex(user))
})
})
Built in checks
| Check | What it does |
| -------------------------- | ------------ |
| checkHookDefined
| Checks that a particular hook is defined. |
| checkModelName
| Checks that the model is named correctly. |
| checkNonUniqueIndex
| Checks that a specific non-unique index is defined. |
| checkPropertyExists
| Checks that the model has defined the given property. |
| checkUniqueCompoundIndex
| Checks that a specific unique compound index is defined. |
| checkUniqueIndex
| Checks that a specific unique index is defined. |
Checking associations
The various association functions are stubbed so you can simply invoke the the model's associate
function in a before
block then use sinon
's standard expectation syntax to check they were called with the correct values.
hasOne
it("defined a hasOne association with Image as 'profilePic'", () => {
expect(User.hasOne).to.have.been.calledWith(Image, {
as: 'profilePic'
})
})
belongsTo
it('defined a belongsTo association with Company', () => {
expect(User.belongsTo).to.have.been.calledWith(Company)
})
hasMany
it("defined a hasMany association with User as 'employees'", () => {
expect(Company.hasMany).to.have.been.calledWith(User, {
as: 'employees'
})
})
belongsToMany
it("defined a belongsToMany association with Category through CategoriesCompanies as 'categories'", () => {
expect(Company.belongsToMany).to.have.been.calledWith(Category, {
through: CategoriesCompanies,
as: 'categories'
})
})
Unit testing code that requires models
Let's say you have a utility function that takes some data and uses it to update a user record. If the user does not exist it returns null
. (Yes I know this is a contrived example)
src/utils/save.js
const { User } = require('../models')
const save = async ({ id, ...data }) => {
const user = await User.findOne({ where: { id } })
if (user) return await user.update(data)
return null
}
module.exports = save
You want to unit-test this without invoking a database connection (so you can't require('src/models')
in your test).
This is where makeMockModels
, sinon
, and proxyquire
come in handy.
test/unit/utils/save.spec.js
const { expect } = require('chai')
const sinon = require('sinon')
const proxyquire = require('proxyquire')
const { makeMockModels } = require('sequelize-test-helpers')
const mockModels = makeMockModels({ User: { findOne: sinon.stub() } })
const save = proxyquire('../../../src/utils/save', { '../models': mockModels })
const fakeUser = { update: sinon.stub() }
describe('src/save', () => {
const data = {
firstname: 'Testy',
lastname: 'McTestface',
email: 'testy.mctestface.test.tes',
token: 'some-token'
}
const resetStubs = () => {
mockModels.User.findOne.resetHistory()
fakeUser.update.resetHistory()
}
let result
context('user does not exist', () => {
before(async () => {
mockModels.User.findOne.resolves(undefined)
result = await save(data)
})
after(resetStubs)
it('called User.findOne', () => {
expect(mockModels.User.findOne).to.have.been.called
})
it("didn't call user.update", () => {
expect(fakeUser.update).not.to.have.been.called
})
it('returned null', () => {
expect(result).to.be.null
})
})
context('user exists', () => {
before(async () => {
fakeUser.update.resolves(fakeUser)
mockModels.User.findOne.resolves(fakeUser)
result = await save(data)
})
after(resetStubs)
it('called User.findOne', () => {
expect(mockModels.User.findOne).to.have.been.called
})
it('called user.update', () => {
expect(fakeUser.update).to.have.been.calledWith(sinon.match(data))
})
it('returned the user', () => {
expect(result).to.deep.equal(fakeUser)
})
})
})
As a convenience, makeMockModels
will automatically populate your mockModels
with mocks of all of the models defined in your src/models
folder (or if you have a .sequelizerc
file it will look for the model-path
in that). Simply override any of the specific models you need to do stuff with.
Listing your models
It's useful to be able to generate a list of the names of your models.
const { listModels } = require('sequelize-test-helpers')
console.log(listModels()) // will spit out a list of your model names.
Similarly to makeMockModels
above, listModels
will find all of the models defined in your src/models
folder (or if you have a .sequelizerc
file it will look for the model-path
in that).
Contributing
Please see the contributing notes.