Simple test library that is easy to learn, use and debug. Tests can be run with a standard node command node test.js
allowing you to use all the existing node tools. Tests are really fast. In some cases 10-20x faster than other libraries. Out of the box tests can use ES6/Babel, Promises, Async/Await, Generators, Observables, Callbacks and more.
- Easy to learn
- Works with ES6/Babel, Promises, Async/Await, Generators, Callbacks, Observables, Streams, Processes, out of the box
- No Globals
- Great diffs on errors (Shows only differences. Very helpful on large objects)
- Really fast (Has the ability to run multiple tests at the same time)
- Easy to debug (Tests are just basic node processes. No subprocesses or threads)
- Batteries included. Comes bundled with assertions and mocking (Chai and Sinon)
- 100% Test Coverage
- Supports coverage support with nyc
- Example Tests
- How to Use
- FAQs (Comparison to other test libraries)
- Assertions
- Mocking/Spy/Stubs
- Command Line Usage
- Code Coverage
ES6
import { createGroup, assert } from 'painless';
const test = createGroup();
// Sync test
test('sync test', () => {
assert.deepEqual({ a: '1' }, { a: '1'});
});
// Promise test. return assert.eventually to wait for Promise
test('promise test', () => {
return assert.eventually.deepEqual(promiseFn(), { a: '1'});
});
ES5
var painless = require('painless');
var test = painless.createGroup();
var assert = painless.assert;
// Callback test
test('callback test', function(done) {
setTimeout(function() {
assert.deepEqual({ a: '1' }, { a: '1'});
done();
}, 10);
});
npm install painless --save-dev
Execute a single test
node test/test-file.js
Or run multiple tests
./node_modules/.bin/painless test/**/*.js
Run tests with Babel
babel-node ./node_modules/.bin/painless test/**/*.js
Add tests to package.json
{
"scripts": {
"test": "babel-node painless test/**/*.js"
}
}
Painless uses Chai and Chai-as-promised. Get more info on all available assertions here. Chai Assertions. Chai-as-promised adds Promise assertions.
Access Chai
// ES6
import { assert } from 'painless';
// ES5
var painless = require('painless');
var assert = painless.assert;
It is possible to use any other assertion library as well. You will receive better errors if the library supports AssertionError
Painless comes bundled with Sinon to allow all types of mocking. Get more info here. Sinon Library
Access Spy
// ES6
import { spy } from 'painless';
// ES5
var painless = require('painless');
var spy = painless.spy;
Access Stub
// ES6
import { stub } from 'painless';
// ES5
var painless = require('painless');
var stub = painless.stub;
Access Mocks
// ES6
import { mock } from 'painless';
// ES5
var painless = require('painless');
var mock = painless.mock;
Accessing other Sinon functionality
// ES6
import { sinon } from 'painless';
const xhr = sinon.useFakeXMLHttpRequest();
// ES5
var painless = require('painless');
var sinon = painless.sinon;
var xhr = sinon.useFakeXMLHttpRequest();
Painless supports beforeEach and afterEach out of the box. You can use all the features available in tests (Promises, Async/Await, etc)
var painless = require('painless');
var assert = painless.assert;
var test = painless.createGroup();
test.beforeEach(function() {
doSomeSetup();
return promiseFn();
});
test.afterEach(function() {
doSomeCleanup();
});
test('test that needs setup 1', function() {
assert(true);
});
test('test that needs setup 2', function() {
assert(true);
});
./node_modules/.bin/painless test/**/*.js
With Babel
babel-node ./node_modules/.bin/painless test/**/*.js
--async,-a
Run tests async. This will speed up tests that use IO or network. It is not recommended while debugging. It will make tests tough to reason about.--bunch,-b
Bunch size. If using the async flag, it determines the number of tests to run at the same time. By default this is 10.--reporter,-r
Specify a different reporter. By default painlesss use dot. Options are dot, spec and tap.--include, -i
Specify other files to include. NPM modules or local code. Useful for adding polyfills or other global code.
View docs for creating custom reporters
Painless has the ability to run tests async. This will execute tests at the same time, but in a single process and thread. It uses node's standard event system to execute other tests while a test is doing IO or network tasks. This can significantly speed up your tests if you are doing IO or network tests. If your tests are CPU bound, you will not see any gains because everything is running in the same thread. Enable async using the command options below. While debugging your tests, it is not recommended to use async because it will make execution flow harder to understand.
Code coverage is really easy to use. Just install nyc
npm install nyc --save-dev
nyc --cache --reporter=text ./node_modules/bin/painless test/**/*.js
nyc --cache --reporter=html ./node_modules/bin/painless test/**/*.js
npm install coveralls
then (make sure COVERALLS_REPO_TOKEN is in your environment variables)
nyc --reporter=text-lcov ./node_modules/bin/painless test/**/*.js | ./node_modules/.bin/coveralls
Tests can run in browser with karma-painless
- Why should I use painless over other test libraries?
Go here for comparisons to other test libraries. Painless is not groundbreaking in any way. If you like it, use it. It is more important to test your javascript code. The test framework is a minor detail.
- Why bundle other libraries (Chai, Sinon, etc)? Why not let the user decide?
Painless tries to achieve a test library that just works. The goal is to be able to start writing tests as soon as possible. It is possible to switch out assertion and mocking libraries, but defaults are available.
Painless Advantages
- Has everything you need included (assertions, mocking, etc)
- Supports Generators, Observables, Streams, Processes out of the box
- Doesn't need a separate executable to run (just run
node test.js
) - Is easier to debug (single process, better error messages, easy to read diffs)
- Has no globals
- Run tests at the same time (speed improvements)
Mocha Advantages
- More widely used (more battle tested)
Painless Advantages
- Supports Browser and Node
- Better error messages (beautiful diff when tests fail)
- Easier to debug (single process and thread)
- Has everything you need included (assertions, mocking, etc)
- Doesn't need a separate executable to run (just run
node test.js
) - Faster for most types of tests (even IO tests with painless --async flag)
- Doesn't require babel (write your tests in ES5, typescript, coffeescript, etc)
- Built-in support for Node streams and processes
AVA Advantages
- Test files are isolated (provides some isolation)
Painless Advantages
- Supports Promises, Async/Await, Generators, Observables, Streams, Processes out of the box
- Doesn't need a separate executable to run (just run
node test.js
) - Easier to debug (single process, better error messages, easy to read diffs)
- Has no globals
- Run tests at the same time (speed improvements)
Jasmine Advantages
- More widely used (more battle tested)
Painless Advantages
- Exceptions are caught in each test and reported. Your tests don't stop at the first failure.
- Supports Promises, Async/Await, Generators, Observables, Streams, Processes
- Has everything you need included (assertions, mocking, etc)
- Simpler test syntax (No need to call
t.end()
. Your tests end based on the return) - Better output format out of the box (Easier to read than TAP. painless supports TAP too)
- Supports test groups (
beforeEach
andafterEach
) - Better error messages
- Run tests at the same time (speed improvements)