Lightweight test/spec execution engine for TypeScript and JavaScript
MiniSpec is a lightweight test/spec execution engine for TypeScript and JavaScript, inspired by RSpec and minitest.
It works out-of-the-box with CommonJS, ESM and TypeScript.
Its purpose is to remain lightweight, without any runtime dependency and really low number of development dependencies.
- Why another test/spec execution engine?
- Why does weight matter?
- What's new in version 1.3.0
- Usage
- Writing tests
- More documentation
The idea of MiniSpec came from the need to write some unit-tests for a tiny library written in TypeScript. All testing framework were pretty big - with a lot of dependencies - and may not work well out-of-the-box with TypeScript.
MiniSpec goal is to remain lightweight, without runtime dependency. Its main purpose is to add a bunch of tests to small JavaScript or TypeScript projects.
Its name comes from the combination of minitest, and RSpec. Minitest for the idea of having a small and easy to maintain test/spec engine. RSpec for the spec syntax and for some output formats.
Less dependencies and a lightweight library means less resources consumed while downloading it and executing it. It also reduces the potential attack surface.
That means also fewer features. That is why MiniSpec purpose is to be used with small projects, which do not need advanced testing capabilities offered by more popular alternatives.
While full changelog is available in the repository, here's what's new in v1.3.0:
-
Added
- Official support for Chai Assertion Library: while Chai was already working fine with MiniSpec, its support is now enforced via automated integration tests. That means also that if you are facing any issue using Chai with MiniSpec, you can report it and we'll do our best to fix it.
- Support for Node.js v22
-
Changed
- [Internal] Bump development dependencies
- [Internal] Usage of npm workspaces to manage examples and integration tests
- Bump dependencies from the various examples
-
Deprecated
- Support for Node.js v16 is deprecated and will be dropped with next major version of MiniSpec: v2.0
To install MiniSpec, add it to your dev dependencies:
$ npm install --save-dev minispec
or with yarn:
$ yarn add minispec --dev
To make sure it is working as expected, create a file named
validate_minispec_install.mjs
in your project root directory:
// validate_minispec_install.mjs
import assert from 'assert'
import MiniSpec, { describe, it } from 'minispec'
describe('minispec', async () => {
it('is working', async () => {
assert.ok(true)
})
})
MiniSpec.execute()
Then run the following:
$ node validate_minispec_install.mjs
The expected output should look like the following:
minispec
is working
Finished in 3 milliseconds (discovering took 1 milliseconds, execution took 2 milliseconds)
1 test, no failure 👏
Congrats, MiniSpec is working fine! You can delete the file validate_minispec_install.mjs
and start writing your own specs.
Due to its nature, MiniSpec comes with less magic than other test framework. You'll have to write a little bit of code to set it up. But don't worry, nothing complicated: only basic JavaScript/TypeScript.
In a typical setup, you'll have an entrypoint for MiniSpec which will be responsible for loading MiniSpec, importing your tests, configuring your test environment, then executing the tests.
The following examples illustrates it in TypeScript, and in JavaScript using es Modules and CommonJS
// ./specs/minispec_entrypoint.ts
import MiniSpec from 'minispec'
import './calculator_spec'
MiniSpec.execute()
Then your test files may look like the following:
// ./specs/calculator_spec.ts
import assert from 'assert/strict'
import { describe, context, beforeEach, it } from 'minispec'
import Calculator from '../src/calculator'
describe('Calculator', async () => {
let calculator: Calculator
beforeEach(async () => {
calculator = new Calculator()
})
describe('.sum(a, b)', async () => {
context('when a and b are valid numbers', async () => {
const a = 40
const b = 2
it('returns the sum of a and b', async () => {
assert.equal(calculator.sum(a, b), 42)
})
})
})
})
Assuming the following calculator:
// ./src/calculator.ts
export default class Calculator {
constructor() {}
sum(a: number, b: number): number {
return a + b
}
}
You can then build and run your tests:
$ npx tsc src/*.ts specs/*.ts --module CommonJS --esModuleInterop true --rootDir "." --outDir "./dist"
$ node ./dist/specs/minispec_entrypoint.js
You can also make it part of your package scripts in your package.json
:
{
"scripts": {
"build:specs": "tsc src/*.ts specs/*.ts --module CommonJS --esModuleInterop true --outDir './dist'",
"test": "npm run build:specs && node ./dist/specs/minispec_entrypoint.js"
}
}
Now you can run your tests using:
$ npm test
MiniSpec is also compatible with EcmaScript modules (
es5
,es6
,esnext
, ...), and ts-node. It relies only on your own usage and configuration of TypeScript.
// ./specs/minispec_entrypoint.js
import MiniSpec from 'minispec'
import './calculator_spec.js'
MiniSpec.execute()
Then your test files may look like the following:
// ./specs/calculator_spec.js
import assert from 'assert/strict'
import { describe, context, beforeEach, it } from 'minispec'
import Calculator from '../src/calculator.js'
describe('Calculator', async () => {
let calculator
beforeEach(async () => {
calculator = new Calculator()
})
describe('.sum(a, b)', async () => {
context('when a and b are valid numbers', async () => {
const a = 40
const b = 2
it('returns the sum of a and b', async () => {
assert.equal(calculator.sum(a, b), 42)
})
})
})
})
Assuming the following calculator:
// ./src/calculator.js
export default class Calculator {
constructor() {}
sum(a, b) {
return a + b
}
}
You can then run your tests:
$ node ./specs/minispec_entrypoint.js
You can also make it part of your package scripts in your package.json
:
{
"scripts": {
"test": "node ./specs/minispec_entrypoint.js"
}
}
Now you can run your tests using:
$ npm test
// ./specs/minispec_entrypoint.js
const MiniSpec = require('minispec').default
require('./calculator_spec.js')
MiniSpec.execute()
Then your test files may look like the following:
// ./specs/calculator_spec.js
const assert = require('assert').strict
const { describe, context, beforeEach, it } = require('minispec')
const Calculator = require('../src/calculator.js').default
describe('Calculator', async () => {
let calculator
beforeEach(async () => {
calculator = new Calculator()
})
describe('.sum(a, b)', async () => {
context('when a and b are valid numbers', async () => {
const a = 40
const b = 2
it('returns the sum of a and b', async () => {
assert.equal(calculator.sum(a, b), 42)
})
})
})
})
Assuming the following calculator:
// ./src/calculator.js
exports.default = class Calculator {
constructor() {}
sum(a, b) {
return a + b
}
}
You can then run your tests:
$ node ./specs/minispec_entrypoint.js
You can also make it part of your package scripts in your package.json
:
{
"scripts": {
"test": "node ./specs/minispec_entrypoint.js"
}
}
Now you can run your tests using:
$ npm test
MiniSpec should work well with any assertion library. Yet it provides
official support for the Node.js built-in assert
one, and also for chai
.
The Node.js built-in assertion library
is simple, yet far enough for small projects where MiniSpec may be used.
Remember: MiniSpec is designed for small projects which just requires a
bunch of tests. Node.js assert
library is also perfect in such case!
Chai is a BDD/TDD assertion library which remains
relatively lightweight and offer more assertions, but mostly 3 styles:
assert
, expect
and should
.
MiniSpec officially supports Chai since version 1.3.0. It means that if you are facing issues integrating Chai with MiniSpec, you can report it and we'll do our best to find a fix or a workaround.
To go further, you can follow the documentation: