-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Writing tests
Instructions for writing tests in this module.
Stack
- Test runner:
node:test(built into Node.js) - Assertions:
node:assert/strict
No external test dependencies are needed. Do not introduce Mocha, Jest, or other test frameworks.
Note: Some older modules in the project use Mocha + Should.js. New tests in this module use the built-in Node.js test library instead.
File placement and naming
- Tests live in a
tests/directory at the module root - One test file per source module, named
<moduleName>.spec.js - Test data/fixtures go in
tests/data/
my-module/
├── lib/
│ ├── myModule.js
│ └── myUtils.js
└── tests/
├── data/
│ └── fixtures.json
├── myModule.spec.js
└── myUtils.spec.js
File structure
Every test file follows this structure:
import { describe, it, before } from 'node:test'
import assert from 'node:assert/strict'
import MyModule from '../lib/myModule.js'
describe('My Module', () => {
let instance
before(() => {
instance = new MyModule()
})
describe('#methodName()', () => {
it('should describe expected behaviour', () => {
assert.equal(instance.methodName(), 'expected')
})
})
})Key rules:
- Import
describe,it,before,afteretc. fromnode:test - Import
assertfromnode:assert/strict(strict mode usesdeepStrictEqualby default) - Use ES module
importsyntax — this project is"type": "module" - Group tests by method using nested
describeblocks, prefixed with#for instance methods - Store shared state in
letvariables scoped to thedescribeblock
Assertions
Use node:assert/strict. Common patterns:
// equality (uses Object.is)
assert.equal(actual, expected)
// deep equality (objects/arrays)
assert.deepEqual(actual, { key: 'value' })
// booleans
assert.equal(result, true)
assert.equal(result, false)
// truthy / falsy
assert.ok(value)
assert.ok(!value)
// type checks
assert.equal(typeof value, 'object')
assert.ok(Array.isArray(value))
assert.ok(value instanceof MyClass)
// expected errors (sync)
assert.throws(() => dangerousCall(), { name: 'TypeError' })
// expected errors (async)
await assert.rejects(asyncCall(), { name: 'Error' })
// not equal
assert.notEqual(a, b)
assert.notDeepEqual(obj1, obj2)Dynamic test generation
When testing a function against multiple inputs, generate tests in a loop:
const validInputs = ['[email protected]', '[email protected]']
const invalidInputs = ['not-an-email', '@missing.user']
validInputs.forEach((input) => {
it(`should accept ${input}`, () => {
assert.equal(validate(input), true)
})
})
invalidInputs.forEach((input) => {
it(`should reject ${input}`, () => {
assert.equal(validate(input), false)
})
})Async tests
node:test supports async/await directly:
it('should connect successfully', async () => {
const result = await instance.connect()
assert.equal(typeof result, 'object')
})Test data
Place fixture files in tests/data/. Use import or fs to load them:
import { readFileSync } from 'node:fs'
import { join, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
const __dirname = dirname(fileURLToPath(import.meta.url))
const fixtures = JSON.parse(readFileSync(join(__dirname, 'data', 'fixtures.json')))What to test
- All public methods on exported classes and utilities
- Both success and error paths
- Edge cases (empty input, missing arguments, invalid types)
- That errors are thrown or returned where expected (use
assert.throws/assert.rejects)
What NOT to do
- Don't test private/internal methods (prefixed with
_) - Don't add external test dependencies —
node:testandnode:assertare sufficient - Don't write tests that depend on execution order between
describeblocks - Don't mock more than necessary — prefer testing real behaviour
Add script to package.json
The tests should be accessible via an npm script in package.json:
"scripts": {
"test": "node --test tests/"
}
Add GitHub workflow
The following workflow should be added to /.github:
name: Tests
on: push
jobs:
default:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/setup-node@master
with:
node-version: 'lts/*'
cache: 'npm'
- run: npm ci
- run: npm test
Running tests
# run the test suite
npm test
# run the linter
npx standardBoth must pass before submitting a pull request.
Reactions are currently unavailable