Simple test structure 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.
ES6
import { createGroup, assert } from 'painless';
const test = createGroup();
// Sync test
test('sync test', () => {
assert.deepEqual({ a: '1' }, { a: '1'});
});
function promiseFn() {
return new Promise((resolve) => {
setTimeout(function() {
resolve({ a: '1' });
}, 10);
});
}
// Promise test. return assert.eventually to wait for Promise
test('promise test', () => {
return assert.eventually.deepEqual(promiseFn(), { a: '1'});
});
// Promise alt syntax. Return a promise and tests will wait automatically
test('promise test', () => {
return promiseFn().then((result) => {
assert.deepEqual(result, { a: '1'});
});
});
// Callback test. If a param is specified on the test function, it will wait until done() is called
test('callback test', (done) => {
setTimeout(function() {
assert.deepEqual({ a: '1' }, { a: '1'});
done();
}, 10);
});
// Async/Await Test. Works with babel
test('callback test', async () => {
var result = await apiCall();
assert.deepEqual(result, { success: true });
});
// Generator Test
test('callback test', function* () => {
var result = yield apiCall();
assert.deepEqual(result, { success: true });
});
ES5
var painless = require('painless');
var test = painless.createGroup();
var assert = painless.assert;
// Sync test
test('sync test', function() {
assert.deepEqual({ a: '1' }, { a: '1'});
});
// Callback test
test('callback test', function(done) {
setTimeout(function() {
assert.deepEqual({ a: '1' }, { a: '1'});
done();
}, 10);
});
- Really fast
- Easy to learn
- Works with ES6/Babel, Promises, Async/Await, Generators, Callbacks, Observables, Streams, Processes, out of the box
- No Globals
- Easy to debug (Tests are just basic node processes. No subprocesses or threads)
- Comes bundled with assertions and mocking (Chai and Sinon)
- 100% Test Coverage
- Coverage support with Istanbul
Painless Advantages
- Has everything you need included (assertions, mocking, etc)
- Supports Async/Await, Promises, 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)
- Has no globals
- Much faster to run tests
Mocha Advantages
- Supports browser and node (Painless is only node. It will support browsers soon.)
- More widely used (more battle tested)
- Integrated coverage
Painless Advantages
- 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 groups are isolated (Less likely for tests to affect each other)
Painless Advantages
- Supports Async/Await, Promises, 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 and thread)
- Has no globals
- Much faster
Jasmine Advantages
- Supports browser and node (Painless is only node. It will support browsers soon.)
- More widely used (more battle tested)
Painless Advantages
- Supports Async/Await, Promises, Generators, Observables, Streams, Processes
- Has everything you need included (assertions, mocking, etc)
- Simpler test syntax
- Better output format out of the box
- Supports test groups and
beforeEach
andafterEach
npm install painless --save-dev
Execute a single test
node test/test.js
Or run multiple tests
./node_modules/.bin/painless test/**/*.js
Run ES6 tests
babel-node --presets es2015 ./node_modules/.bin/painless test/**/*.js
Add tests to package.json
{
"scripts": {
"test": "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 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 testing your code, it is not recommended to use async because it will make tests harder to understand.
--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.--tap,-t
Use tap output reporter instead of the default spec reported
Code coverage is really easy to use. Just install istanbul
npm install istanbul --save-dev
Then you can run coverage by
istanbul cover ./node_modules/bin/painless -- test/**/*.js
- 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.