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

express-unit

v2.1.1

Published

Express middleware testing made easy.

Downloads

56

Readme

express-unit

Express middleware testing made easy.

Build Status Coverage Status Dependency Status Dev Dependency Status Greenkeeper badge

λ npm install express-unit

Contents


Usage

Express Unit exports a helper function for running a single middleware. To use, just import it and pass it a setup function, your middleware, and an optional callback.

import run from 'express-unit'

run(setup|null, middleware[, callback])

Parameters

  • setup - A function defined to set up the Request/Response lifecycle before it enters middleware. Pass null if not needed. setup is called with three arguments:
    • req - A dummy Request object.
    • res - A dummy Response object.
    • next - A function used to proceed to middleware.
  • middleware - The middleware function under test. Passed different arguments depending on whether it is an "error handling" middleware.
    • err - forwarded from next(err) in setup if the middleware is an error handler.
    • req - The dummy Request object visited by setup.
    • res - The dummy Response object visited by setup.
    • next - A function used to signal the completion of the middlware.
  • callback - An optional function used to inspect the outcome of passing the Request/Response lifecycle through setup and middleware.
    • err - Forwarded from next(err) in middleware (if any).
    • req - The dummy Request object visited by setup and middleware.
    • res - The dummy Response object visited by setup and middleware.
import run from 'express-unit'
import { expect, spy } from './test-utils'
import myMiddleware from './my-middleware'

describe('myMiddleware', () => {
  it('gets called!', () => {
    const setup = spy((req, res, next) => next())
    const middleware = spy(myMiddleware)
    run(setup, middleware)
    expect(setup).to.have.been.calledBefore(middleware)
  })
})

setup

Your setup function will be called with a req, res, and next to prepare the request lifecycle for your middleware. This is your opportunity to set headers on req or spy/stub any relevant methods on res. Call next to execute your middleware.

If for some reason you don't want to supply a setup, just pass null.

run(null, middleware[, callback])
// middleware.js
export default function middleware(req, res, next) {
  const token = req.get('x-access-token')
  if (token) return next()
  const err = new Error('where is your token?')
  next(err)
}
// middleware.test.js
describe('middleware', () => {
  describe('when the request has a token header', () => {
    const setup = (req, res, next) => {
      req.headers['x-access-token'] = 'myToken'
      next()
    }
    it('calls next without error', done => {
      run(setup, middleware, done)
    })
  })
})

Callback

Express Unit supports callbacks. Pass a callback as the third argument to inspect the results.

// middleware.js
export default function middleware(req, res, next) {
  const token = req.get('x-access-token')
  if (token) return next()
  const err = new Error('Access token required.')
  return next(err)
}
// middleware.test.js
describe('middleware', () => {
  describe('when the request does not have a token header', () => {
    it('passes an Error', done => {
      run(null, middleware, (err, req, res) => {
        expect(err)
          .to.be.an('error')
          .with.property('message', 'Access token required.')
        done()
      })
    })
  })
})

Async/Await

Express Unit also supports async middleware. This is any middleware that is an async function or simply returns a Promise. express-unit will resolve an array of [err, req, res] that you can either await or receive in a call to then. Works great with express-async-wrap.

// middleware.js
import wrap from 'express-async-wrap'

export const middleware = users => wrap(async ({ params }, res, next) => {
  const { userId } = params
  const user = await users.findById(userId)
  if (!user) throw new NotFound(`User ${userId} does not exist.`)
  res.locals.user = user
  next()
})
// middleware.test.js
describe('middleware', () => {
  const user = { id: 1, name: 'foo' }
  afterEach(() => {
    users.findById.restore()
  })
  describe('when the user is found', () => {
    const setup = (req, res, next) => {
      req.params.userId = 1
      stub(users, 'findById').resolves(user)
      next()
    }
    it('sets the user on locals', async () => {
      const [ err, , res] = await run(setup, middleware(users))
      expect(err).to.be.null
      expect(users.findById).to.have.been.calledWith(user.id)
      expect(res.locals).to.have.property('user', user)
    })
  })
})

Why Express Unit?

Express Unit puts the "unit" back in unit testing for Express.js apps. It's a small, simple helper for exercising individual middleware functions in isolation. Most testing tutorials and examples for express apps will utilize supertest (or similar).

import request from 'supertest'
import app from '../app'

describe('app', () => {
  describe('/hello-test', () => {
    it('handles GET requests', done => {
      request(app)
        .get('/hello-test')
        .set('Accept', 'application/json')
        .expect(200, (err, res) => {
          /* make more assertions */
          done()
        })
    })
  })
})

This is great for testing your entire app or a given router within your app. For some endpoints, various middleware functions are put in place to determine the response, e.g. confirming a user's identity, verifying their access rights, and bailing out of a request early if preconditions are not met. But testing all of this in concert is integration testing, which is often best left at testing the "happy path". A single route could employ a middleware stack like this:

router
  .use(authorize)
  .route('/users/:userId/permissions')
  .put(userIs('admin'), updatePermissions(permissions))

router
  .use(errorHandler(logger))

There are 4 different middleware functions involved in this single route. At least one of which needs access to some kind of data store. But each middleware is very focused and can be reused or replaced (Yay!).