UNPKG

8.63 kBMarkdownView Raw
1# node-tap
2
3A <abbr title="Test Anything Protocol">TAP</abbr> test framework
4for Node.js.
5
6_Just wanna see some code? [Get
7started!](http://www.node-tap.org/basics/)_
8
9It includes a command line test runner for consuming
10TAP-generating test scripts, and a JavaScript framework for
11writing such scripts.
12
13<!-- TODO: update with new website docs links -->
14
15- [Getting started guide](http://node-tap.org/basics/)
16- Built-in [test coverage](http://node-tap.org/coverage/)
17- Many [reporter formats](http://node-tap.org/reporter/)
18- Extensive [API](http://node-tap.org/api/)
19- [Command-line interface](http://node-tap.org/cli/) for
20 running tests (whether they use node-tap or not)
21- [Machine-generated API docs](https://tapjs.github.io/tapjs)
22
23See [the changelog](http://node-tap.org/changelog/) for recent
24updates, or just get started with [the
25basics](http://www.node-tap.org/basics/).
26
27All this is too much to manage in a single README file, so head
28over to [the website](http://node-tap.org/) to learn more.
29
30## Why TAP?
31
32Why should you use this thing!? **LET ME TELL YOU!**
33
34Just kidding.
35
36Most frameworks spend a lot of their documentation telling you
37why they're the greatest. This isn't that.
38
39### <i lang="it" title="all tastes are tastes">tutti i gusti sono gusti</i>
40
41Software testing is a software and user experience design
42challenge that balances on the intersection of many conflicting
43demands.
44
45Node-tap is based on [my](http://izs.me) opinions about how a
46test framework should work, and what it should let you do. I do
47_not_ have any opinion about whether or not you share those
48opinions. If you do share them, you will probably enjoy this test
49library.
50
51Here are the design principles that shape this test framework.
52
53### Test files are "normal" programs
54
55Any TAP test can be run directly as a plain old JavaScript
56program. Of course, if it's written in TypeScript, you'll
57have to run it with a TypeScript loader, but otherwise, they
58should be just like normal programs that run in a normal
59environment.
60
61But there's no runner required to run tests, they don't
62execute in a special simulated memory space with injected
63globals, and so on. Because each test runs in its own process,
64there's no chance of tests becoming dependent on one another's
65leaked globals or causing other confusing situations.
66
67### Tests should help, not get in the way
68
69The goal of tests is to help you write code. They add reliability
70to your program by adding a layer of "yes, this does what I think
71it does". Whether you're doing strict Red-Green-Refactor style
72TDD, or just finger-painting until it feels right and then
73writing tests to verify what it actually does, writing the tests
74should feel empowering and straightforward, _reducing_ cognitive
75load rather than increasing it.
76
77### All types must be accurate and complete
78
79This is simply not reasonable to do with a hand-edited type
80definition in `.d.ts` file.
81
82TAP's exported types are built up from its set of plugins and
83internal classes, assembled into the `Test` class that your test
84programs interact with. When a plugin is added or removed, the
85`t` in your editor can accurately tell you its new shape.
86
87If you have to look at the docs too often, that's a bug in my
88opinion. Lean into the beautiful power of code completion.
89
90### TypeScript, ESM, and CommonJS supported out of the box
91
92With the changes to the module system in Node.js over the
93last several years, TAP fell down on this requirement in
94versions prior to v18. As of version 18, the entire system has
95been rewritten in TypeScript, and built as hybrid ESM/CommonJS
96packages.
97
98Your tests should be written just like your program, with as few
99barriers as possible. If you can do it in CommonJS, you can do it
100in ESM, and vice versa (at least as far as TAP is concerned).
101Whatever is in your `tsconfig.json` or `package.json`, it should
102Just Work.
103
104### Anything that _can_ be a plugin _is_ a plugin
105
106The plugin system is leveraged for anything that does not
107absolutely need to be included in the core.
108
109Basic [TAP](https://testanything.org) generation and flow
110control, error handling, config loading, process management and
111so on, are all included in the core. But TypeScript support,
112mocking, almost all assertion methods, method and property
113interception and spying, spawning/forking subtests, creating
114fixtures, snapshots, and attaching lifecycle methods (among
115others) are all relegated to plugins.
116
117This means that features can be switched on or off or extended
118very easily.
119
120### Plugins must be powerful and trivial to write correctly
121
122The plugin interface is extremely simple. Export a `plugin`
123function that returns an object. That's it, that's a plugin.
124
125Plugins can also export configuration definitions, which are
126folded into the set of fields that TAP knows how to parse from
127the command line or from your `.taprc` file, or export a `loader`
128string, which will be invoked when spawning test processes.
129
130### High Signal, Low Noise
131
132It is important to give a lot of information about test failures,
133throws, and so on, so that you can easily jump straight to the
134appropriate place in the code to fix the problem. And, it's
135usually helpful to see which tests are actually running.
136
137However, a screen full of green checkmarks and `100% Covered!`
138isn't very useful. It should be just enough to know what happened
139and easily diagnose any problems, and otherwise fairly quiet.
140
141Low information output has been trimmed down as much as possible
142from the default reporters. Coverage information is only shown
143when it has something relevant to say. TAP tries to show you
144exactly what you need to see, and nothing else. Stack traces have
145noisy internals trimmed out, so it's easier to see exactly where
146in _your_ code the problem happened. Source maps are always
147enabled, because you need to know where the actual code is, not
148just which built artifact failed.
149
150If the default reporter isn't terse enough for your liking, try
151`tap -Rterse`.
152
153### Assertions don't throw (but throws are handled nicely)
154
155I frequently write programs that have many hundreds of assertions
156based on some list of test cases. If the first failure throws,
157then I don't know if I've failed 100 tests or 1, without wrapping
158everything in a try-catch. Furthermore, I usually want to see
159some kind of output or reporting to verify that each one actually
160ran.
161
162Basically, it should be your decision whether you want to throw
163or not. The test framework shouldn't force that on you, and
164should make either case easy.
165
166### Test reporting should be useful, extensible, and accessible
167
168The [raw test output](https://www.node-tap.org/tap-format/)
169is machine-parseable and human-intelligible, a separate component
170consumes test output and turns it into a [pretty summarized
171report](https://www.node-tap.org/reporting/). This means that
172test data can be stored and parsed later, dug into for additional
173details, and so on.
174
175Red and green are the conventional colors meaning "removed" and
176"added", but they're also exactly the same color for many people.
177All of the color choices in the reporter are tested rigorously
178against simulators for protanopia, deuteranopia, tritanopia, and
179monochromicity.
180
181### Test coverage is always on
182
183Running tests with coverage changes the way that you think
184about your programs, and provides much deeper insight.
185TAP uses V8's internal coverage mechanisms directly, and verifies
186that tests provide 100% coverage of all lines, branches,
187functions, and statements in the system under test. It uses
188[C8](https://npmjs.com/c8) to analyze the V8 coverage data and
189generate coverage reports.
190
191Missing coverage means that you are relying on untested code, so
192this is treated as a test failure. If you have some bit of code
193which is actually _impossible_ to test for some reason, wrap it
194in the appropriate `/* c8 ignore start */` / `/* c8 ignore end
195*/` comments to exclude those lines from the analysis. But think
196carefully about whether that's really the case. Usually, if you
197have to coverage-ignore something, it's a sign that you need to
198either delete that code or refactor it into a more easily tested
199module.
200
201-----
202
203Software testing should help you build software. It should be a
204security blanket and a quality ratchet, giving you the support to
205undertake massive refactoring and fix bugs without worrying. It
206shouldn't be a purification rite or a hazing ritual. It should be
207fun, because making stuff is fun, and it helps you make better
208stuff.
209
210There are many opinions left off of this list! Reasonable people
211can disagree. But if you find yourself nodding along, [maybe tap
212is for you](https://www.node-tap.org/basics/).