Supplementary tools
Published: 2022-11-30 by Lars tooltestcode
This is part 2 of Build your own test runner.
All of the remaining features that we often find in popular test runners, but were left out of our minimalistic test runner in part 1, can be provided by separate complementary tools and libraries. Those features therefore doesn't really have to be part of the test runner as such, and in this part we briefly show how each of those features can be provided. For each feature, we provide links to working demos in the repo https://github.com/larsthorup/testrunner/.
Reporting results
Instead of including various reporters in our test runner, we can provide reporting modules as plugins.
Working demo here: @larsthorup/console-reporter-plugin.
Finding test files
It is cumbersome to list the names of each test file on the command line, but instead of adding support for finding test files to our test runner, we can use Unix commands like ls
and xargs
to search for test files and pass the names to the test runner, like this:
ls -1 src/*.test.js | xargs testrunner
For more advanced "glob" searches, we can use the glob
package.
Working demo here: @larsthorup/testfinder.
Writing assertions
Instead of adding support for specialized assertions to our test runner, some assertion libraries, like Chai, allows developers to plugin additional assertions.
Working demo here: @larsthorup/chai-jest-matchers.
Expecting a test to fail
Instead of adding special syntax to our test runner to expect a test to fail (like it.fails
), we can use a function to "invert" the test result.
Working demo here: @larsthorup/testutils.
Skipping a test
Instead of adding special syntax to our test runner to skip a test (like it.skip
), we can write plugins to add generic "options" (like {skip: true}
) to it
and describe
.
Working demo here: @larsthorup/skip-testrunner-plugin.
Repeating a test
Instead of adding special syntax to our test runner to repeat a test (like it.each
), we can simply use the built-in JavaScript
map
function.
Working demo here: Array.map.
Timing out tests
Instead of adding special syntax to our test runner to timeout a long running test, we can use a function to fail the test if it takes too long.
Working demo here: @larsthorup/testutils.
Having tests in source files
Instead of adding special syntax to our test runner to allow tests to live inside the source files of the code under test, we can set an environment variable IS_TEST
, and have the test runner also process sources files.
Working demo here: in-source/lib.js.
Isolating tests from each other
Instead of adding special support for isolating tests from each other (e.g. global variables), we can use the Node.js node:vm
module to run specific tests in isolation.
No demo yet...
Mocking timers
Instead of adding special syntax to our test runner for mocking timers, we can use popular mocking libraries like Sinon.
Working demo here: @sinonjs/fake-timers.
Mocking objects
Instead of adding special syntax to our test runner for mocking objects, we can use modern object mocking libraries like tinyspy.
Working demo here: tinyspy.
Mocking modules
Instead of adding special syntax to our test runner for mocking ES modules, we can use modern module mocking libraries like esmock.
Working demo here: esmock.
Emulating a browser
Instead of adding support for DOM emulation to our test runner, we can use popular libraries like "jsdom" or happy-dom which works well with DOM assertions of testing-library.
Working demo here: happy-dom.
Reporting coverage
Instead of adding support for code coverage reporting to our test runner, we can use popular tools like c8.
Working demo here: c8.
Transpiling
Instead of adding support for TypeScript or JSX or any other transpilable language to our test runner, we can run the transpilation, before running tests.
Working demo here: tsc.
Watching
Instead of adding support for "watching" to our test runner, we can watch for changes and only run the subset of tests affected (directly or indirectly) by those changes by recording dependencies in an ESM loader.
Working demo here: @larsthorup/esm-tracer.
Debugging
Instead of adding support for debugging tests to our test runner, we can simply use the built-in JavaScript debugger;
statement and run the test runner under a debugger, like ndb.
Working demo here: ndb.