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

chai-express

v1.3.0

Published

Chai's assertions for Express.

Downloads

13

Readme

chai-express

Build Status NPM version

It provides useful Chai's assertions to use in Express' routes.

Installation

npm install --save-dev chai-express
npm install --save-dev sinon sinon-chai # if you want to use  my approach for simulateRouteDispatch.

How to use

src/app.js (minimal configuration for tests to work)

import express from 'express';

const app = express();
const router = express.Router();

app.use(router);

require('./routes/user')(router);

export { router, app as default };

src/controllers/user.js

import User from '../models/user';

export function getAll(req, res) {
  res.send(User.findAll());
}

src/routes/user.js

import * as UserController from '../controllers/user';

export default function (router) {
  router.get('/users', UserController.getAll);
}

test/routes/user.js

import chai from 'chai';
import chaiExpress, { simulateRouteDispatch } from 'chai-express';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';

import { router } from '../src/app';
import * as UserController from '../src/controllers/user';

chai.use(chaiExpress);
chai.use(sinonChai);

describe('routes', () => {
  describe('GET /users', () => {
    it('should define it', () => {
      expect(router).to.have.route(/^\/users_1\/?$/i);
    });

    it('should call to the right controller', () => {
      sinon.spy(UserController, 'getAll');

      simulateRouteDispatch(router, 'get', /^\/users_1\/?$/i);

      expect(UserController.getAll).to.be.calledOnce;

      UserController.getAll.restore();
    });
  });
});

Motivation

I'll write this from my point of view using what I learned so far and trying to use as many references as I can. Feel free to put your comments or thoughts in an issue if you want.

The problem I found

In every single article or post I've read related to testing routes I found the same problems:

  1. Those are not unit tests.
  2. Those tests are not testing only the routes, but also the controllers.

As J.B. Rainsberger said it's almost impossible to write unit tests. Instead we try to isolate functionality and test it in an isolated and reduced scope. Hence Rainsberger prefers to use the term Isolated tests. And I do prefer it too.

Before moving on I should mention another thing I noticed in these articles. They do not divide controllers from routes. They show source code like this:

route/users.js:

// ...
router.get('/users/all', (req, res) => res.send(User.findAll()));
// ...

In that code the route and the controller are defined in a single line. There is no clearly distinction between controller and route's responsibility.

Again, this is not what I learned. Christopher Okhravi is very clear in this video about what Single Responsibility is: a single reason to change.

In the code above there are multiple reasons to change. Just to mention some:

  1. The route could change from /users/all to just /users.
  2. We could expect a JSON output instead of a plain stringified object.
  3. The User model's method findAll could change to getAll, or change its arguments.

A possible solution

The first refactor we should perform in this code is to lift up the controller's function to an another file:

controllers/user.js:

// ...
export function getAll(req, res) {
  return res.send(User.findAll();
}

routes/user.js:

import * as UserController from '../controllers/user';

//...
router.get('/users/all', UserController.getAll);
//...

A lot better, isn't it?

So, what should we test now? Remember, we are testing our API router.

What should you test in an API router?

This checklist is meant to suit in a well modularized API framework. This means that you will need at least to move your route handlers to controllers as shown here.

So, the checklist:

  • Check if the route is defined.
  • Check if the route accepts the right parameters.
  • Check if the route calls to the right controller's method.
  • Check if the route has the right ACLs.

You will notice that we are not testing the endpoints. In this point we don't care if they work properly or respond as expected.

Why? Express has (or should have) its own tests. So, we delegate the responsibility of responding to a route to Express. Thus, the router is not responsible for calling to any model or perform no other action but calling a controller's function. In that way, the responsible for calling to models and perform actions would be the controller and, of course, we have another test/controllers directoy testing all our controllers.

Changelog

CHANGELOG

Contribute

Please do it! If you have any idea please create an issue and we can discuss about it.

Issues

https://github.com/abelosorio/chai-express/issues