diff --git a/README.md b/README.md index 6a80dc3..2f19013 100644 --- a/README.md +++ b/README.md @@ -2,91 +2,94 @@ A runner for `node:test`, `jest`, and `tape` test suites on top of `node:test` (and any runtime) -Most likely it will just work on your simple jest tests as as drop-in replacement - -Comes with typescript support, optional esm/cjs interop, and also loading babel transforms! - -Use `--coverage` to generate coverage output - -Default `NODE_ENV` value is "test", use `NODE_ENV=` to override (e.g. to empty) - -## Why? - -- Can run your tests on Node.js, Bun, Deno, JavaScriptCore and Hermes without extra churn - -- Unlike `jest`, it is fast - -- Unlike `node:test`, it is a drop-in replacement for `jest` - - - With `expect`, support for snapshots, mocks and matchers - - - `jest-when` and `jest-extended` are fully compatible and can just be used - - - Snapshots are compatible with Jest and can just be used both ways - - - Also compatible to `node:test` - -- Unlike `bun:test`, it runs all test files in isolated contexts - - Bun leaks globals / side effects between test files and has incompatible `test()` lifecycle / order - -- Can use Jest config - -- Native coverage support (enable via `--coverage`) - -- Can record / replay `fetch` and `WebSocket` sessions. And run them on all runtimes (including Hermes) - -- Automatic polyfills for JavaScriptCore / Hermes, including crypto - -- Hanging tests error by default (unlike `jest`) - -- Native ESM out of the box +## Features +- Native ESM, including in Jest tests - Esbuild on the fly for babelified ESM interop (enable via `--esbuild`) - -- TypeScript support in both transform (enable via `--esbuild`) and typestrip (via `--typescript`) modes - -- Babel support, picks up your Babel config (enable via `--babel`) - +- TypeScript support in both transform (through [tsx](https://tsx.is/), enable via `--esbuild`) + and typestrip (via `--typescript`) modes +- Runs on `node:test`, and (experimental) on bun, deno, d8, JSC and + [Hermes](https://hermesengine.dev) +- Testsuite-agnostic --- can run any file as long as it sets exit code based on test results +- Built-in [Jest](https://jestjs.io) compatibility (with `--jest`) + - Up to ~10x faster depending on the original setup + - Actual `expect` module, also `jest-extended` and `jest-when` just work on top + - Snapshots, including snapshot matchers + - Function and timer mocks + - [test.concurrent]() + - Module mocks (on top of Node.js runtime only) + - Loads Jest configuration + - It works on Hermes too! +- Built-in network record/replay for offline tests, mocking `fetch` and `WebSocket` sessions - `--drop-network` support for guaranteed offline testing - -## Library - -### Using with `node:test` natively - -You can just use pure [`node:test`](https://nodejs.org/api/test.html) in your tests, -this runner is fully compatible with that (and will set version-specific options for you)! - -### Moving from jest - -```js -import { - jest, - expect, - describe, - it, - beforeEach, - afterEach, - beforeAll, - afterAll, -} from '@exodus/test/jest' -``` - -Or, run with [`--jest` option](#options) to register jest globals - -### Moving from tap/tape - -```js -import test from '@exodus/test/tape' +- Native code coverage via v8 (Node.js or [c8](https://github.com/bcoe/c8)), with istanbul reporters +- GitHub reporter (auto-enabled by default) +- JSDOM env support +- Hanging tests error by default (unlike `jest`) +- Babel support, picks up your Babel config (enable via `--babel`) +- Unlike `bun:test`, it runs test files in isolated contexts + Bun leaks globals / side effects between test files and has incompatible `test()` lifecycle / order + ([Ref](https://github.com/oven-sh/bun/issues/6024)) +- Also features a tape API for drop-in replacement + +## Reporter samples + +#### CLI (but uses colors when output supports them, e.g. in terminal): + +```console +# tests/jest/expect.mock.test.js +✔ PASS drinkAll > drinks something lemon-flavoured (1.300417ms) +✔ PASS drinkAll > does not drink something octopus-flavoured (0.191791ms) +✔ PASS drinkAll (1.842959ms) +✔ PASS drinkEach > drinkEach drinks each drink (0.360625ms) +✔ PASS drinkEach (0.463416ms) +✔ PASS toHaveBeenCalledWith > registration applies correctly to orange La Croix (0.53325ms) +✔ PASS toHaveBeenCalledWith (0.564166ms) +✔ PASS toHaveBeenLastCalledWith > applying to all flavors does mango last (0.380375ms) +✔ PASS toHaveBeenLastCalledWith (0.473417ms) +# tests/jest/fn.invocationCallOrder.test.js +✔ PASS mock.invocationCallOrder (4.221042ms) ``` -### Running tests asynchronously +#### GitHub Actions collapses test results per-file, like this: + +
+ tests/jest/lifecycle.test.js +
+  ✔ PASS A > B > C (3.26166ms)
+  ✔ PASS A > B > D (1.699463ms)
+  ✔ PASS A > B (6.72719ms)
+  ✔ PASS A > E > F (1.117997ms)
+  ✔ PASS A > E > G > H (1.330904ms)
+  ✔ PASS A > E > G (1.94971ms)
+  ✔ PASS A > E (3.821825ms)
+  ✔ PASS A > I (0.533096ms)
+  ✔ PASS A (13.887889ms)
+  ✔ PASS J (0.373187ms)
+  ✔ PASS K > L (0.659852ms)
+  ✔ PASS K (1.143195ms)
+ 
+
+ tests/jest/timers.async.test.js +
+  ✔ PASS advanceTimersByTime() does not let microtasks to pass (5.326604ms)
+  ✔ PASS advanceTimersByTime() does not let microtasks to pass even with await (1.336064ms)
+  ✔ PASS advanceTimersByTimeAsync() lets microtasks to pass (6.99526ms)
+  ✔ PASS advanceTimersByTimeAsync() lets microtasks to pass, chained (10.131664ms)
+  ✔ PASS advanceTimersByTimeAsync() lets microtasks to pass, longer chained (8.635472ms)
+  ✔ PASS advanceTimersByTimeAsync() lets microtasks to pass, async chain (56.937983ms)
+ 
+
+ +See live output in [CI](https://github.com/ExodusMovement/test/actions/workflows/checks.yaml) -Add `{ concurrency: true }`, like this: `describe('my testsuite', { concurrency: true }, () => {` +## Library ### List of exports -- `@exodus/test/jest` -- `jest` mock +- `@exodus/test/node` -- `node:test` API, working under non-Node.js platforms + +- `@exodus/test/jest` -- `jest` implementation - `@exodus/test/tape` -- `tape` mock (can also be helpful when moving from `tap`)