npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

sequelize-test-helpers-ts

v1.0.0

Published

Sequelize test helpers for typescript.

Downloads

51

Readme

sequelize-test-helpers

A collection of utilities to help with unit-testing Sequelize models and code that needs those models.

Greenkeeper badge

Branches

| Branch | Status | Coverage | | | ------ | ------ | -------- | - | | develop | CircleCI | codecov | Work in progress | | master | CircleCI | codecov | Latest stable release |

Prerequisites

This library assumes:

  1. You are using chai
  2. You are using sinon

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.