• Stars
    star
    121
  • Rank 293,924 (Top 6 %)
  • Language
    JavaScript
  • Created almost 11 years ago
  • Updated almost 9 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An example of Sails.js-project testing with Mocha and Barrels for fixtures

How do I test my Sails.js application?

Build Status Dependency Status

Nowadays, testing became an essential part of the modern software development process. However, the tools we're using for development often define some particularities in the testing setup. In this example we'll learn to write unit and functional tests for your Sails.js application.

Database Connection

First, define a connection to your test database. It can be as simple as adding

  test: {
    adapter: 'sails-memory'
  }

to the module.exports.connections object in ./config/connections.js. Which adapter you'll be using depends on how complex your application (and, hence, tests) is: in simplest cases sails-memory can work just fine, but in more complex situations you may have to create a separate Mongo (or whatever else you're using) database.

Add Dependencies

Use npm i --save-dev <package> to add testing dependencies to your project.

In this example we're using the following packages:

Feel free to use these or replace them with your own favorites.

Test Command

Add your test command to the scripts section of package.json. In our case it'll be:

  ...
  "scripts": {
    ...
    "test": "PORT=9999 NODE_ENV=test mocha -R spec -b --recursive"
  },
  ...

Here we are lifting our test Sails application on a non-standard port in case you'd like to run tests while the development version of your application is still running.

Write Your Tests

Finally, we got to the step where we have to write some tests. But first we are going to need our Sails application to be lifted while running the tests.

Bootstrapping

Let's create a ./test folder (if it doesn't exist yet) and put a file named bootstrap.test.js in it. This file will contain global hooks for setting up and tearing down our test environment. With Mocha, it will be something like that:

  var Sails = require('sails');

  // Global before hook
  before(function (done) {
    // Lift Sails with test database
    Sails.lift({
      log: {
        level: 'error'
      },
      models: {
        connection: 'test',
        migrate: 'drop'
      }
    }, function(err) {
      if (err)
        return done(err);

      // Anything else you need to set up
      // ...

      done();
    });
  });

  // Global after hook
  after(function (done) {
    console.log(); // Skip a line before displaying Sails lowering logs
    Sails.lower(done);
  });

Don't hesitate to add to these hooks any other steps specific to your application.

Unit Tests for Your Models

Given the setup we got, we can place our tests anywhere within the ./test folder. However, it makes sense to organize them in a structure similar to the one of our application.

Thus, skipping the api folder (as more or less all the code we are supposed to be testing resides within ./api), we can put our model unit tests in ./test/models.

For example, if we are testing a model called Apples, we could put something like this in ./test/models/Apples.test.js:

  describe('Apples', function() {
    it ('should not be empty', function(done) {
      Apples.find().exec(function(err, apples) {
        apples.length.should.not.be.eql(0);

        done();
      });
    });
  });

Fixtures

The example in the previous section assumes that the test database contains some data already. But if it gets dropped every time the tests finish (which is the case when sails-memory adapter is being used), you might want to initialize your test database with some fixture data before you start testing. There is a lot of ways to do it, but the idea is that you have to populate your tables / collections in the global before hook we put in ./test/bootstrap.test.js:

  before(function (done) {
    Sails.lift({
      log: {
        level: 'error'
      },
      models: {
        connection: 'test',
        migrate: 'drop'
      }
    }, function(err) {
      if (err)
        return done(err);

      // Load fixtures
      var barrels = new Barrels();

      // Populate the DB
      barrels.populate(function(err) {
        done(err);
      });
    });
  });

In this example we are using Barrels package, which reads fixture data from JSON files in a specified path (./test/fixtures by default) and populates the corresponding database collections. Obviously, you can use any other fixture library or just populate the test data in your own way, but the point is that before hook is the place to do it.

Functional Tests for Controllers

Even though most of your code is supposed to reside within the models, writing functional tests for controllers is an important part of making your API solid and maintainable.

Following the convention we started with the model tests, let's put our code in ./test/controllers/ApplesController.test.js:

var request = require('supertest');

describe('ApplesController', function() {
  describe('index', function() {
    it('should return success', function (done) {
      request(sails.hooks.http.app)
        .get('/apples')
        .expect(200, done);
    });
  });
});

In this (very basic) example we only check the status code, but, of course, you are free to do a more complex analysis of the response. Check out the Supertest API for more helpers and assertions.

Wallaby.js

Support is included for Wallaby.js in the form of a bootstrap in the ./wallaby.js file in the root that replicates what the ./test/bootstrap.test.js does for normal mocha.

Wallaby.js is an intelligent test runner for JavaScript that continuously runs your tests. It reports code coverage and other results directly to your code editor immediately as you change your code. Wallaby.js uses various tricks to run your tests as fast as possible, such as dependency analysis to only execute tests affected by your code changes and parallel test execution.

Conclusion

Sails.js is a very powerful tool that can help you create APIs in almost no time. Still, if you have long term goals for your application, having properly written tests for your code is highly recommended. Here, we looked at some aspects of writing such tests and listed several useful packages that could help you, but feel free to add your own components, experiment with other testing frameworks or assertion libraries.

License

The MIT License

Copyright (c) 2013-2015 Ruslan Bredikhin

More Repositories

1

barrels

Simple DB Fixtures for Sails.js
JavaScript
85
star
2

rfid-based-asset-tracking-with-nodejs-and-mongodb

RFID-based Asset Tracking with Node.js and MongoDB
JavaScript
34
star
3

homekit-compatible-temperature-and-humidity-sensor

Build a HomeKit-compatible Bluetooth Temperature and Humidity Sensor
Arduino
19
star
4

phoenix-rethinkdb-elm-webpack-example

Rephink: A real-time stack based on Phoenix Framework, RethinkDB, Elm, Webpack
Elixir
16
star
5

your-own-rfid-gateway-written-in-nodejs

Your Own RFID Gateway Written in Node.js
JavaScript
16
star
6

phoenix-postgresql-notify-listen-example

Publish/subscribe with PostgreSQL and Phoenix Framework
Elixir
15
star
7

meteor-contact-form

Simple contact form for Meteor applications
JavaScript
13
star
8

sailsjs-skipper-thumbnail-example

Example of uploading and resizing images with Sails.js and Skipper
JavaScript
5
star
9

sailsjs-angularjs-mongodb-example

Sails.js, Angular.js, MongoDB example application
JavaScript
4
star
10

voimo

Voice-control your Wemo lights
JavaScript
3
star
11

skipper-thumbnail

Thumbnailing receiver for Skipper
JavaScript
3
star
12

colsole

Yet another colored console
JavaScript
3
star
13

meteor-cj

Commission Junction (CJ Affiliate by Conversant) API wrapper for Meteor
JavaScript
3
star
14

meteor-linkshare

Rakuten Affiliate Network (Linkshare) API wrapper for Meteor
JavaScript
3
star
15

dotfiles

Opinionated dotfiles
Shell
3
star
16

react-compound-interest

React component representing a compound interest calculator
TypeScript
3
star
17

indico

Indico.io API wrapper in Elixir
Elixir
2
star
18

sssh

Streaming SSH
JavaScript
2
star
19

hitme

An example of a command line application in Elixir: fetches a random reminder / quote / inspirational phrase from a number of previously saved or default phrases
Elixir
2
star
20

linx

Links to some stuff I read or watched recently
2
star
21

meteor-posts

Basic blog functionality for Meteor.js applications
JavaScript
2
star
22

bredikhin.github.io

Personal website
HTML
2
star
23

react-hooks-compound-interest-calculator-demo

Compound interest calculator demo with React Hooks and TypeScript
TypeScript
2
star
24

meli

Menubar icon dropdown for note taking
JavaScript
2
star
25

zaz

Simple Node.js deployment, Capistrano-style
JavaScript
1
star
26

bo-weather

Teaches Bo to fetch the weather report
JavaScript
1
star
27

oauth2-ccg

OAuth 2.0 Client Credentials Grant
JavaScript
1
star
28

bo

Simple CLI bot
JavaScript
1
star
29

mockout

Mocking a series of objects being sent through stdout
JavaScript
1
star
30

bo-slug

Teaches Bo to slugify strings
JavaScript
1
star
31

victory-chart-native-custom-fonts

JavaScript
1
star
32

sailsjs-zaz-naught-deployment-example

Deploying a Sails.js project with Zaz and Naught
JavaScript
1
star
33

prelog

Prefixing transform stream
JavaScript
1
star