tap
TypeScript icon, indicating that this package has built-in type declarations

21.1.0 • Public • Published

node-tap

A TAP test framework for Node.js.

Just wanna see some code? Get started!

It includes a command line test runner for consuming TAP-generating test scripts, and a JavaScript framework for writing such scripts.

See the changelog for recent updates, or just get started with the basics.

All this is too much to manage in a single README file, so head over to the website to learn more.

Why TAP?

Why should you use this thing!? LET ME TELL YOU!

Just kidding.

Most frameworks spend a lot of their documentation telling you why they're the greatest. This isn't that.

tutti i gusti sono gusti

Software testing is a software and user experience design challenge that balances on the intersection of many conflicting demands.

Node-tap is based on my opinions about how a test framework should work, and what it should let you do. I do not have any opinion about whether or not you share those opinions. If you do share them, you will probably enjoy this test library.

Here are the design principles that shape this test framework.

Test files are "normal" programs

Any TAP test can be run directly as a plain old JavaScript program. Of course, if it's written in TypeScript, you'll have to run it with a TypeScript loader, but otherwise, they should be just like normal programs that run in a normal environment.

But there's no runner required to run tests, they don't execute in a special simulated memory space with injected globals, and so on. Because each test runs in its own process, there's no chance of tests becoming dependent on one another's leaked globals or causing other confusing situations.

Tests should help, not get in the way

The goal of tests is to help you write code. They add reliability to your program by adding a layer of "yes, this does what I think it does". Whether you're doing strict Red-Green-Refactor style TDD, or just finger-painting until it feels right and then writing tests to verify what it actually does, writing the tests should feel empowering and straightforward, reducing cognitive load rather than increasing it.

All types must be accurate and complete

This is simply not reasonable to do with a hand-edited type definition in .d.ts file.

TAP's exported types are built up from its set of plugins and internal classes, assembled into the Test class that your test programs interact with. When a plugin is added or removed, the t in your editor can accurately tell you its new shape.

If you have to look at the docs too often, that's a bug in my opinion. Lean into the beautiful power of code completion.

TypeScript, ESM, and CommonJS supported out of the box

With the changes to the module system in Node.js over the last several years, TAP fell down on this requirement in versions prior to v18. As of version 18, the entire system has been rewritten in TypeScript, and built as hybrid ESM/CommonJS packages.

Your tests should be written just like your program, with as few barriers as possible. If you can do it in CommonJS, you can do it in ESM, and vice versa (at least as far as TAP is concerned). Whatever is in your tsconfig.json or package.json, it should Just Work.

Anything that can be a plugin is a plugin

The plugin system is leveraged for anything that does not absolutely need to be included in the core.

Basic TAP generation and flow control, error handling, config loading, process management and so on, are all included in the core. But TypeScript support, mocking, almost all assertion methods, method and property interception and spying, spawning/forking subtests, creating fixtures, snapshots, and attaching lifecycle methods (among others) are all relegated to plugins.

This means that features can be switched on or off or extended very easily.

Plugins must be powerful and trivial to write correctly

The plugin interface is extremely simple. Export a plugin function that returns an object. That's it, that's a plugin.

Plugins can also export configuration definitions, which are folded into the set of fields that TAP knows how to parse from the command line or from your .taprc file, or export a loader string, which will be invoked when spawning test processes.

High Signal, Low Noise

It is important to give a lot of information about test failures, throws, and so on, so that you can easily jump straight to the appropriate place in the code to fix the problem. And, it's usually helpful to see which tests are actually running.

However, a screen full of green checkmarks and 100% Covered! isn't very useful. It should be just enough to know what happened and easily diagnose any problems, and otherwise fairly quiet.

Low information output has been trimmed down as much as possible from the default reporters. Coverage information is only shown when it has something relevant to say. TAP tries to show you exactly what you need to see, and nothing else. Stack traces have noisy internals trimmed out, so it's easier to see exactly where in your code the problem happened. Source maps are always enabled, because you need to know where the actual code is, not just which built artifact failed.

If the default reporter isn't terse enough for your liking, try tap -Rterse.

Assertions don't throw (but throws are handled nicely)

I frequently write programs that have many hundreds of assertions based on some list of test cases. If the first failure throws, then I don't know if I've failed 100 tests or 1, without wrapping everything in a try-catch. Furthermore, I usually want to see some kind of output or reporting to verify that each one actually ran.

Basically, it should be your decision whether you want to throw or not. The test framework shouldn't force that on you, and should make either case easy.

Test reporting should be useful, extensible, and accessible

The raw test output is machine-parseable and human-intelligible, a separate component consumes test output and turns it into a pretty summarized report. This means that test data can be stored and parsed later, dug into for additional details, and so on.

Red and green are the conventional colors meaning "removed" and "added", but they're also exactly the same color for many people. All of the color choices in the reporter are tested rigorously against simulators for protanopia, deuteranopia, tritanopia, and monochromicity.

Test coverage is always on

Running tests with coverage changes the way that you think about your programs, and provides much deeper insight. TAP uses V8's internal coverage mechanisms directly, and verifies that tests provide 100% coverage of all lines, branches, functions, and statements in the system under test. It uses C8 to analyze the V8 coverage data and generate coverage reports.

Missing coverage means that you are relying on untested code, so this is treated as a test failure. If you have some bit of code which is actually impossible to test for some reason, wrap it in the appropriate /* c8 ignore start */ / /* c8 ignore end */ comments to exclude those lines from the analysis. But think carefully about whether that's really the case. Usually, if you have to coverage-ignore something, it's a sign that you need to either delete that code or refactor it into a more easily tested module.


Software testing should help you build software. It should be a security blanket and a quality ratchet, giving you the support to undertake massive refactoring and fix bugs without worrying. It shouldn't be a purification rite or a hazing ritual. It should be fun, because making stuff is fun, and it helps you make better stuff.

There are many opinions left off of this list! Reasonable people can disagree. But if you find yourself nodding along, maybe tap is for you.

Versions

Current Tags

VersionDownloads (Last 7 Days)Tag
16.3.10108,379legacy-v16
12.7.064,481legacy
21.1.046,099latest
14.11.032,347v14-legacy
14.10.2-unbundled1unbundled
14.10.2-totally-bundled.11totally-bundled
15.0.0-30v15-beta

Version History

VersionDownloads (Last 7 Days)Published
21.1.046,099
21.0.2186
21.0.13,855
21.0.0751
20.0.35,683
20.0.212
20.0.112
20.0.03
19.2.5119,288
19.2.4379
19.2.355
19.2.211
19.2.18
19.2.013
19.1.13
19.1.02
19.0.2772
19.0.10
19.0.014
18.8.016,810
18.7.313
18.7.21,400
18.7.190
18.7.03,604
16.3.10108,379
18.6.15,201
18.6.09
18.5.8290
18.5.76
18.5.61
18.5.511
18.5.44
18.5.30
18.5.2552
18.5.127
18.5.016
18.4.62
18.4.53
18.4.45
18.4.31
18.4.25
18.4.11
18.4.012
18.3.11
18.3.00
18.2.20
18.2.13
18.2.06
16.3.9873
18.1.50
18.1.412
18.1.32
18.1.20
18.1.16
18.1.01
18.0.40
18.0.31
18.0.22
18.0.10
18.0.08
18.0.0-260
18.0.0-250
18.0.0-240
18.0.0-230
18.0.0-221
18.0.0-211
18.0.0-200
18.0.0-191
18.0.0-181
18.0.0-170
18.0.0-160
18.0.0-151
18.0.0-140
18.0.0-130
18.0.0-120
18.0.0-111
18.0.0-100
18.0.0-90
18.0.0-81
18.0.0-71
18.0.0-61
18.0.0-51
18.0.0-40
18.0.0-30
18.0.0-20
18.0.0-12
16.3.8638
16.3.72,007
16.3.6549
16.3.522
16.3.42,958
16.3.3319
16.3.2208
16.3.154
16.3.02,741
16.2.01,574
16.1.0164
16.0.132,161
16.0.0112
15.2.323,546
15.2.216
15.2.112
15.2.012
15.1.6706
15.1.5261
15.1.416
15.1.313
15.1.27,138
15.1.125
15.1.00
15.0.10242
15.0.91,563
15.0.813
15.0.715
15.0.669
15.0.525
15.0.4583
15.0.316
15.0.234
15.0.117
15.0.016
15.0.0-30
15.0.0-20
15.0.0-11
15.0.0-01
14.11.032,347
14.10.81,650
14.10.72,213
14.10.62,214
14.10.5274
14.10.412
14.10.311
14.10.2-totally-bundled.11
14.10.2-totally-bundled0
14.10.2-unbundled1
14.10.2368
14.10.120
14.10.04
14.9.241
14.9.119
14.9.09
14.8.364
14.8.216
14.8.19
14.8.01
14.7.30
14.7.20
14.7.10
14.7.016
14.6.934
14.6.87
14.6.76
14.6.613
14.6.517
14.6.4573
14.6.38
14.6.215
14.6.147
14.6.09
14.5.0825
14.4.3206
14.4.2157
14.4.132
14.4.020
14.3.128
14.3.016
14.2.524
14.2.420
14.2.317
14.2.210
14.2.130
14.2.08
14.1.111
14.1.100
14.1.95
14.1.85
14.1.73
14.1.69
14.1.56
14.1.44
14.1.30
14.1.25
14.1.12
14.1.01
14.0.028
13.1.11413
13.1.101
13.1.94
13.1.867
13.1.71
13.1.61
13.1.50
13.1.40
13.1.30
13.1.24
13.1.147
12.7.064,481
13.1.01
13.0.40
13.0.33
12.6.6212
13.0.12
13.0.00
12.6.510
13.0.0-rc.301
13.0.0-rc.290
12.6.40
13.0.0-rc.280
13.0.0-rc.270
13.0.0-rc.261
12.6.319
13.0.0-rc.251
12.6.29
13.0.0-rc.241
13.0.0-rc.233
13.0.0-rc.221
13.0.0-rc.211
13.0.0-rc.200
13.0.0-rc.191
13.0.0-rc.183
13.0.0-rc.171
13.0.0-rc.161
13.0.0-rc.151
13.0.0-rc.140
12.6.1254
13.0.0-rc.130
13.0.0-rc.120
13.0.0-rc.111
13.0.0-rc.101
13.0.0-rc.91
13.0.0-rc.80
13.0.0-rc.71
13.0.0-rc.60
13.0.0-rc.50
13.0.0-rc.40
13.0.0-rc.30
13.0.0-rc.21
13.0.0-rc.11
13.0.0-rc.01
12.6.0867
12.5.3481
12.5.2113
12.5.122
12.5.01
12.4.155
12.4.067
12.3.016
12.2.12
12.2.01
12.1.43
12.1.32
12.1.22
12.1.174
12.1.0103
12.0.22
12.0.11,093
12.0.045
11.1.56,495
11.1.424
11.1.352
11.1.221
11.1.1130
11.1.019
11.0.170
11.0.060
11.0.0-rc.31
11.0.0-rc.20
11.0.0-rc.11
11.0.0-rc.00
10.7.324,894
10.7.2912
10.7.12
10.7.0957
10.6.03
10.5.21
10.5.12
10.5.02
10.4.04
10.3.412
10.3.317
10.3.218
10.3.113
10.3.021
10.2.286
10.2.10
10.2.00
10.1.23
10.1.10
10.1.03
10.0.20
10.0.11
10.0.012
9.0.35,098
9.0.22
9.0.10
9.0.04
8.0.16,385
8.0.08
7.1.225,541
7.1.11
7.1.02
7.0.113
7.0.021
6.3.2269
6.3.02
6.2.09,019
6.1.112
6.1.01
6.0.00
5.8.06,505
5.7.3133
5.7.213
5.7.133
5.7.017
5.6.011
5.5.01
5.4.512
5.4.43
5.4.32
5.4.24
5.4.12
5.4.01
5.3.00
5.2.018
5.1.215
5.1.12
5.1.06
5.0.14
5.0.02
4.0.03
3.1.210
3.1.11
3.1.00
3.0.00
2.3.416,613
2.3.33
2.3.23
2.3.16
2.3.05
2.2.117
2.2.04
2.1.14
2.1.01
2.0.13
2.0.08
1.4.11,529
1.4.02
1.3.429
1.3.34
1.3.2245
1.3.11
1.3.02
1.2.15
1.2.04
1.1.410
1.1.34
1.1.05
1.0.106
1.0.84
1.0.72
1.0.62
1.0.51
1.0.45
1.0.34
1.0.27
1.0.16
1.0.07
1.0.0-beta.50
1.0.0-beta.40
1.0.0-beta.30
1.0.0-beta.20
1.0.0-beta.10
1.0.0-beta.00
0.7.15,326
0.7.02
0.6.0803
0.5.067
0.4.1333,587
0.4.124
0.4.112
0.4.97
0.4.873
0.4.74
0.4.63
0.4.55
0.4.428
0.4.3155
0.4.2583
0.4.12
0.4.06
0.3.31,710
0.3.23
0.3.18
0.3.0158
0.2.67,229
0.2.513
0.2.448
0.2.32
0.2.20
0.2.10
0.2.02
0.1.4155
0.1.35
0.1.22
0.0.81
0.0.61
0.0.11
0.0.51
0.1.11
0.0.34
0.0.22
0.0.42
0.0.72
0.0.90
0.1.04
0.0.14192
0.0.134
0.0.121
0.0.112
0.0.101

Package Sidebar

Install

npm i tap

Weekly Downloads

658,118

Version

21.1.0

License

BlueOak-1.0.0

Unpacked Size

80.2 kB

Total Files

33

Last publish

Collaborators

  • isaacs