Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

aqa

Wiiseguy251MIT1.6.13TypeScript support: included

Dependency-less Test Runner for Node.js

tests, testing, dependencyless, test, runner, fast, tdd, cli-app, cli, aqa, ava, jest, mocha, tape, tap, qunit, jasmine, assert, assertion, unit, expect, coverage, sourcemap

readme

aqa ci codecov npm

Dependency-less Test Runner for Node.js

aqa is a light-weight and a** **quick alternative to ava, with a similar API.


Installation

npm i aqa -D

Features

  • Dependency-free: No dependencies, leverages many of Node.js modern built-in modules.
  • Fast: Runs tests in parallel by default.
  • Watch mode: Automatically re-run tests when files change.
  • Simple: No configuration needed, just run your tests!
  • Powerful: Supports many asserts, async/await, Sourcemaps
  • Coverage: Code coverage support via your favorite coverage tool.
  • TypeScript: First-class TypeScript support, with type definitions for all assertions.
  • CI integration: Easily run tests in CI pipelines.
  • Reporting: Generate JUnit and TAP reports.

Usage

Simple single-file usage

your.tests.js:

const test = require('aqa')
const myLib = require('./my-lib')

test('Test our library', t => {    
  t.is(myLib.add(1, 1), 2);
  t.not(myLib.add(2, 2), 3);
  t.true(myLib.isPrime(3));
  t.false(myLib.isOdd(2));
})

test('Test something async', async t => {
  let result = await myLib.asyncAdd(1, 1); 
  t.is(result, 2);
})

node your.tests.js

Integration

To run multiple tests and integrate CI testing with your package, you need to change your package.json's test in the scripts section to "aqa":

"scripts": {
  "test": "aqa"
},

Then, to run all your tests: npm run test

All files anywhere in your package's directory (and subdirectories, excluding node_modules and directories that start with a single _ ) that match the following patterns will be run:

test.js
tests.js
*.test.js
*.tests.js
*/test-*.js
*.spec.js
**/test/*.js
**/tests/*.js
**/__tests__/*.js

If your test files are named differently, for instance *.unit-test.js, you can write your test script like this:

"scripts": {
  "test": "aqa *.unit-test.js"
},

Watch mode

To automatically run tests whenever you modify your files, aqa has a watch mode. If you desire this functionality, add a new script to your package.json:

"scripts": {
  "test": "aqa",
  "test:watch": "aqa --watch"
},

To start the watch script, run npm run test:watch.

Like with the test script, you can watch files other than *.test.js:

"test:watch": "aqa *.foo.js --watch"

Coverage

aqa can be easily integrated with coverage tools such as nyc and c8.

To enable coverage with c8, add the following to your package.json:

"scripts": {
  // Other scripts
  "test:coverage": "c8 npm test"
},

Or to run tests with nyc:

"scripts": {
  // Other scripts
  "test:coverage": "nyc aqa"
},

Running test:coverage will produce something like this:

--------------|---------|----------|---------|---------|-----------------------
File          | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------|---------|----------|---------|---------|-----------------------
All files     |    99.2 |    96.63 |   98.57 |    99.2 | 
 my-lib.js    |   97.74 |    95.18 |   98.55 |   97.74 | 20-21,190-191,231-232
 test.js      |     100 |      100 |     100 |     100 | 
--------------|---------|----------|---------|---------|-----------------------

To add special reporters such as LCOV and HTML, check the README pages of the code coverage package.

Note: c8 is recommended, because it uses Node's built-in V8 coverage tools and it is many times faster than nyc.


API

Assertion

The callback parameter for test() wraps many assertion methods (in this case t):

test('Test name', t => {    
  // Your assertions
})

These assertion methods are currently supported:

t.is(actual, expected, message?)

Asserts that actual is equal to expected.

t.not(actual, notEpected, message?)

Asserts that actual is not equal to notEpected.

t.near(actual, expected, delta, message?)

Asserts that actual is equal to expected within the precision of delta.

t.notNear(actual, expected, delta, message?)

Asserts that actual is not equal to expected within the precision of delta.

t.deepEqual(actual, expected, message?)

Asserts that actual is deeply equal to expected. test.ignore can be used to skip certain properties, i.e.:

let actual = { a: 3, b: 'ok', c: 7 }
t.deepEqual(actual, {
  a: 3,
  b: 'ok',
  c: test.ignore
})

Differences are reported with a minus - for actual values and plus + for expected values.

You may also use test.ignoreExtra() to only assert the given properties in the expected object:

let actual = { a: 3, b: 'ok', c: 7 }
t.deepEqual(actual, test.ignoreExtra({
  b: 'ok',
}))

t.notDeepEqual(actual, expected, message?)

Asserts that actual is not deeply equal to expected.

t.true(value, message?)

Asserts that value is true.

t.false(value, message?)

Asserts that value is false.

t.throws(fn, opts?, message?)

Asserts that fn throws an exception.

function uhOh() {
  throw new Error("Uh oh.");
}

t.throws(_ => {
  uhOh();
})

You can also check for specific types of exception. If the exception does not match it, the test will fail:

t.throws(_ => {
  uhOh();
}, { instanceOf: TypeError })

t.throwsAsync(fn, opts?, message?)

The asynchronous version of t.throws(). Note the addition of async/await.

test('Async test', async t => {
  await t.throwsAsync(async _ => {
    await uhOhAsync();
  })
})

You can also check for specific types of exception. If the exception does not match it, the test will fail:

await t.throws(async _ => {
  await uhOhAsync();
}, { instanceOf: TypeError })

t.notThrows(fn, message?)

Asserts that fn does not throw an exception.

t.notThrowsAsync(fn, message?)

Asserts that async function or Promise fn does not throw an exception.

Utility methods

t.log(message, ...arguments?)

Similar to console.log, but helps you easily find for which test method you've logged information.

t.disableLogging()

Suppresses any calls to console.log, console.warn, console.error, etc. for the current testcase. Note that logging is enabled again automatically after the testcase has completed.

Mocking

(Available in 1.6.8+) aqa supports mocking with the t.mock() method. This method lets you mock a method on an object or library. Mocked methods are restored automatically after each test.

const test = require('aqa')
const Http = require('SomeHttpLibrary')

test('Mocking', async t => {
  const mockedGet = t.mock(Http, 'get', async _ => {
    return { statusCode: 200, body: 'Hello World!' }
  })

  const result = await Http.get('https://example.com')
  t.is(result.statusCode, 200)
  t.is(result.body, 'Hello World!')

  t.is(mockedGet.calls.length, 1)
})

In the example above, we mock the get method on the Http object. The mocked method returns a promise that resolves to a response object. We then assert that the response object has the expected properties. Finally, we assert that the mocked method was called once.

By mocking the get method here, any other code that imports SomeHttpLibrary and calls Http.get will also use the mocked method. This is useful for testing code that uses external libraries.

t.mock() returns a Mock object with the following properties:

Mock.restore()

Restores the mocked method back to its original implementation. If you don't call this method, the mocked method will be restored automatically after each test.

Mock.calls

An array of all calls to the mocked method. Each call is an array of arguments passed to the mocked method.

Global mocking

(Available in 1.6.9+) aqa also supports global mocking via the test.mock() method. This method works similarly to t.mock(), but it mocks the method globally for all tests in the current file.

const test = require('aqa')
const Http = require('SomeHttpLibrary')

const mockedGet = test.mock(Http, 'get', async _ => {
  return { statusCode: 200, body: 'Hello World!' }
})

test('Mocking', async t => {
  let result = await Http.get('https://example.com')
  t.is(result.statusCode, 200)
  t.is(result.body, 'Hello World!')

  t.is(mockedGet.calls.length, 1)
})

Hooks

(Available in 1.6.0+) The following hooks are available:

const test = require('aqa')

test.before(t => {    
  // Your set-up and assertions
  // This is only ran once per test file
})

test.after(t => {    
  // Your tear-down and assertions
  // This is only ran once per test file
})

test.beforeEach(t => {    
  // Your set-up and assertions
  // This is ran before each test
})

test.afterEach(t => {    
  // Your tear-down and assertions
  // This is ran after each test
})

Skipping a test file

(Available in 1.6.7+) You can skip all tests in a file by calling test.skipFile():

const test = require('aqa')

test.skipFile('Reason for skipping this file here');

Skipping a test

(Available in 1.6.9+) You can skip individual tests by calling test.skip() instead of the usual test():

const test = require('aqa')

test('This test will run', t => {
  // Your assertions
})

test.skip('This test will not run', t => {
  // ...
})

Solo running tests

(Available in 1.6.9+) You can run only a single test by calling test.solo() instead of the usual test(). This will effectively skip all other tests in the file.

const test = require('aqa')

test('This test will not run', t => {
  // ...
})

test.solo('Test name', t => {    
  // Your assertions
})

test('This test will not run either', t => {
  // ...
})

Note: Any defined tests hooks (before, after) will still run as usual.


TypeScript

(Available in 1.3.7+) To write aqa test files TypeScript, you will need to enable source maps in your tsconfig.json.

"compilerOptions": {
  // Can be any other path, but .js files will need to be emitted
  "outDir": "./dist",   
  "sourceMap": true,
  "module": "commonjs",
  // other compiler options
}

For an optimal development flow, run the following tasks (add them to package.json scripts first):

  • tsc --watch
  • aqa --watch

Now let's create a file named your.tests.ts:

import test = require('aqa')
import myLib from './my-lib'

test('Should fail', t => {
    t.is(myLib.add(1, 1), 3)
})

This will fail with something like the following output:

FAILED:  "Should fail"
D:\DEV\YourProject\tests\your.tests.ts:6:10 [SourceMap]

Note the source-mapped location. This will allow you to Ctrl+Click on the location in your IDE to easily jump to the original test file.


Source maps

Source maps are a way to map the original source code to the generated code. This is useful for debugging and development. Languages or tools that compile to JavaScript, like TypeScript, CoffeeScript, ClojureScript, BabelJS, etc., can generate source maps. We've only covered TypeScript here, but if you're using another language that has a compiler that generates source maps, it should work with aqa.


Reporting

(Available in 1.6.1+) aqa supports reporting test results to a file. The current supported reporters are junit and tap. To enable it, add the following to your package.json:

{  
  "aqa": {
    "reporter": "junit"
  }
}

JUnit

The junit reporter will generate a JUnit XML file for each test file in the .aqa-output/reports folder. You can then use this file in your CI/CD pipeline to generate reports.

See Config for more information.

TAP

The tap reporter will output the test results in the TAP version 13 format to the console / stdout. Currently, this report is simplified and does not include stack traces.


CLI parameters

aqa can be run from the terminal like npx aqa tests/test-*.js with the following supported parameters:

--watch

Runs aqa in watch mode. See watch mode for more information.

--verbose

Adds verbose logging. Example: aqa --verbose

--no-concurrency

Disables concurrency. This will run all tests sequentially. Example: aqa --no-concurrency


Config

aqa will try to check the package.json from where it was ran from for a section named "aqa".

{  
  "aqa": {
    "verbose": true,
    "concurrency": true,
    "reporter": "", 
    "reporterOptions": {
      "outputDir": "test-results/" 
    }
  }
}

Supported config:

  • verbose - If true, enables verbose output. (default = false)
    • Can also be set via the AQA_VERBOSE environment variable.
  • concurrency - If false, disables concurrency. (default = true)
    • Can also be set via the AQA_CONCURRENCY environment variable.
  • reporter - The reporter to use, can be junit or tap. Default = "" (no reporter)
    • Can also be set via the AQA_REPORTER environment variable.
  • reporterOptions - Options for the reporter.
    • outputDir - The output directory for the reporter. Default = ".aqa-output/reports"
      • Can also be set via the AQA_REPORTER_OUTPUT_DIR environment variable.

changelog

aqa Changelog

2024

[1.6.13] (04-jul-2024)

  • Fix: made opts param optional in throws and throwsAsync

[1.6.12] (03-jul-2024)

  • Fix: fixed TS definition for test.skip

[1.6.11] (30-jun-2024)

  • Fix: added missing test.skip to index.d.ts

[1.6.10] (29-jun-2024)

  • Cleaned up source code, added prettier
  • Fix: incorrect RegExp for matching test files that was added in 1.6.9

[1.6.9] (28-jun-2024)

  • Added test.mock() to mock library methods on a global level
  • Added test.solo() to run only a single test
  • Added test.skip() to skip individual tests
  • Re-added support for 'test.js' and 'tests.js' in root directory
  • If no tests were ran, it will no longer report 'Ran 0 tests ran successfully!', but rather 'No tests were ran.'

2023

[1.6.8] (21-dec-2023)

  • Added warning to error messages when a non-Error object is caught. Stack information is not available in this case.
  • Added t.mock() to mock library methods per individual test
  • CLI: current file name in test feedback gets prepended with its directory name if it's not unique

[1.6.7] (03-mar-2023)

  • Added test.skipFile() to skip files from being run
  • Config: concurrency option to disable parallel test file execution

[1.6.6] (01-mar-2023)

  • Added tap reporter support
  • Fixed JUnit file naming convention, allowing for multiple test files with the same name in different directories

[1.6.5] (05-feb-2023)

  • Added logging for skipped tests
  • Improved file detection in exceptions
  • Added NPM badge to README
  • Increased code coverage to > 97%

[1.6.4] (04-feb-2023)

  • Before/after tests are now always in report + file name is now in report

[1.6.3] (04-feb-2023)

  • Changed skip logic in error reporting

[1.6.2] (04-feb-2023)

  • Improved error reporting

[1.6.1] (04-feb-2023)

  • Added reporting! The only supported reporter is JUnit for now.

[1.6.0] (02-feb-2023)

  • Added before, after, beforeEach and afterEach hooks
  • Exposed Asserts TypeScript interface
  • Fixed issue in error line matching

2022

[1.5.1] (26-aug-2022)

  • GitHub Action: CI + Coverage
  • Added watch tests / E2E watch tests
  • Fixed recursive directory watch not working on Linux
  • Fixed Node 14 support by not using fancy ??= syntax anymore

[1.5.0] (26-aug-2022)

  • HUGE speed improvement by running test files in parallel
    • In some cases up to 8x faster!
  • Prettier test feedback with ✔ and ❌

[1.4.1] (23-aug-2022)

  • Added Config section to README

[1.4.0] (23-aug-2022)

  • Added support for "aqa" section in package.json
    • Only verbose is supported for now:
      {
      "aqa": {
        "verbose": true
      }
      }
  • Added support for globs for --watch
  • Added tests to increase code coverage to 95%
  • Added color for -/+ difference notations on test failures
  • Changed t.is() to report differences similar to the same format as t.deepEqual()
  • Code split of CLI
  • Removed the undocumented --tap feature

[1.3.8] (20-aug-2022)

  • Added strict check for the type of the equality param of deepEqual
  • Added Coverage documentation to README
  • Improved examples in README
  • Fixed error line matching in stack traces
  • Removed some source code to leverage more of Node's util.inspect, like BigInt rendering
  • Caching of Source Maps

[1.3.7] (14-aug-2022)

  • Added Source Map support
  • Created this changelog + all entries retroactively

[1.3.6] (13-aug-2022)

  • Added index.d.ts for auto-complete purposes
  • Fixed directory watch filter

[1.3.5] (10-aug-2022)

  • Improved clickability of file paths on test fail (Cmd/Ctrl+Click in IDE terminals)

[1.3.4] (20-jul-2022)

  • Added deepEqual getter handling support

[1.3.3] (15-jul-2022)

  • Added JSDoc documentation for auto-completion

[1.3.2] (30-jun-2022)

  • Removed inspect limitations

[1.3.1] (08-apr-2022)

  • Added t.near() + t.notNear()
  • Added more granular unit tests

[1.3.0] (07-apr-2022)

  • Reworked watcher, added directory watching

[1.2.15] (01-jan-2022)

  • Fixed aqa.ignore usage in extra expected properties

2021

[1.2.14] (08-dec-2021)

  • Fixed issue with Data comparison on dates with a few milliseconds difference

[1.2.13] (08-dec-2021)

  • Re-added ignore dirs that start with a single underscore
  • Color helper
  • Fixed normalize slashes in file filter

[1.2.12] (06-dec-2021)

  • Added log suppressing via t.disableLogging()
  • Minor spelling fixes in README.md
  • Added CLI parameters chapter to README.md

[1.2.11] (05-dec-2021)

  • Fixed relative glob matching

[1.2.10] (04-dec-2021)

  • Added small fix to make debugging easier
  • Merged JJ's PR

[1.2.9] (26-oct-2021)

  • Improved string difference rendering

[1.2.8] (12-oct-2021)

  • Improved global backup mechanism

[1.2.7] (11-oct-2021)

  • global backup mechanism, for when (rogue) tests overwrite crucial globals like console and process.

[1.2.6] (17-aug-2021)

  • Added test.ignoreExtra(obj) to only compare the properties specified by the obj and ignore the rest.

[1.2.5] (05-aug-2021)

  • Improved JSON diff by using Node's util.inspect()
  • Duplicate test case name detection
  • stdout + stderr merge

[1.2.4] (04-aug-2021)

  • Fixed 0 == -0 equality

[1.2.3] (04-aug-2021)

  • Fixed deepEqual not reporting extra or getter properties

[1.2.2] (04-aug-2021)

  • Fixed deepEqual so it only checks enumerable properties

[1.2.1] (03-aug-2021)

  • Fixed deepEqual diff detection for getters

[1.2.0] (23-jun-2021)

  • Added support for many common test file patterns
  • Added support for ignores
  • Added extra unit tests

[1.1.15] (14-jun-2021)

  • Added support for special numbers like NaN, Infinity and -Infinity

[1.1.14] (07-may-2021)

  • Added stricter value checking for deepEqual

[1.1.13] (07-apr-2021)

  • Updated README with new features and instructions that I forgot for 1.1.12

[1.1.12] (07-apr-2021)

  • Removed superfluous code
  • Added common tests
  • Added support for RegExp comparison

[1.1.11] (06-apr-2021)

  • Added support for module packages

[1.1.10] (06-apr-2021)

  • Improved error stacktrace

[1.1.9] (02-apr-2021)

  • Added fail tests
  • Improved error and success message output

[1.1.8] (02-apr-2021)

  • Smarter file watcher for non test files
  • Added t.log

[1.1.7] (01-apr-2021)

  • Added --verbose flag
  • Improved timing information
  • Improved terminal colors and formatting
  • Updated .gitignore
  • Changed install hint to a devDependency

[1.1.0 - 1.1.6] (25-mar-2021)

  • Made error handling more reliable
  • Added notThrows and notThrowsAsync
  • Added test.ignore support for deepEqual objects
  • Changed 'undefined' detection
  • NaN equality check
  • Simplified deepEqual
  • Added deepEqual and notDeepEqual
  • Added message parameter support for all assert methods

[1.0.0] (26-feb-2021)

  • Added throwsAsync
  • Added self-testing
  • Added single file/glob run

[0.4.0] (25-feb-2021)

  • Added async test support
  • Added fatal error detection
  • Added common.js

[0.3.0] (22-feb-2021)

  • Added watch support!

[0.2.0] (19-feb-2021)

  • Added CLI support
    • Run all tests in project
  • Added assertion documentation

[0.1.2] (18-feb-2021)

  • Added throws
  • Added terminal colors
  • Added tests

[0.1.1] (17-feb-2021)

  • Added new README.md

[0.1.0] (17-feb-2021)

  • Initial release
  • Added is(), not(), true(), false()
  • Added CLI test running
  • Added unit test to test aqa with itself