
Security News
Free Certified Patch for Critical Rails Active Storage Vulnerability
Socket has released a free Certified Patch for a critical Rails Active Storage vulnerability, giving developers time to upgrade to a secure Rails version.
expect-node
Advanced tools
node:test with the expect and mock API of Jest and Vitest, its coverage of subprocesses and workers included
node:test with the expect and mock API of Jest and Vitest, like esmocha gives it
over mocha. The runner, the timeouts and the coverage are node's: the coverage of the code a test runs in a subprocess
or a worker thread counts too, and TypeScript runs as node strips it, without a transform between the tests and the
code. The assertions are the expect of Jest, the mock functions jest-mock.
import { beforeAll, describe, expect, extest, it } from 'expect-node';
describe('a module', () => {
it('works', () => {
expect({ a: 1, b: [1, 2] }).toMatchObject({ b: expect.arrayContaining([2]) });
});
});
The tests run the code as it runs in production: node strips the types of TypeScript in place, without a transform, a bundler or source maps between the tests and the code.
exports of the packages, the module hooks (module.registerHooks), ESM and CommonJS
behave as when the code runs. A link error only node gives fails the test too, like a module importing a name another
one does not export, which a transform may let through.expect and jest-mock
only.Two problems of coverage, which expect-node solves apart:
NODE_V8_COVERAGE, with Monocart or c8) does not map either:
the coverage of the code Vite transformed has offsets of its own, not the ones of the sources. node:test measures the
test files, their subprocesses and their worker threads with NODE_V8_COVERAGE and merges them, and node runs
TypeScript by stripping its types in place, the offsets of the sources kept. This is why expect-node runs on
node:test.mock.module), and quibble, run off-thread module
hooks: the thread of the hooks compiles the module mocked and records a coverage of zero under its URL, which node
merges over the one of the tests by URL alone (nodejs/node#65946). A module covered at 92% by its tests was reported at
11% once another test file mocked it. expect-node mocks by in-thread hooks of its own (module.registerHooks), which
compile nothing on another thread. This one is a problem of node:test only: vi.mock goes through the module runner of
Vite, not through the loader hooks of node, so the hooks change nothing for Vitest.The names Jest and Vitest share, so that a migration renames the imports and vi or jest:
describe, it (and test), with .each(table) (its name with %s, %d, %i, %j, %o), .skipIf(condition),
.runIf(condition), .only, .skip and .todo(name); the options before the function ({ timeout }), or the
timeout after it.
The function of a test gets a context whose skip() ends it skipped.beforeAll, afterAll, beforeEach, afterEach, a timeout after the function.expect: the one of Jest, with a message after the value like Vitest (expect(value, 'the value').toBe(1)).extest, the vi of Vitest, the jest of Jest, the esmocha of esmocha:
fn, spyOn, isMockFunction, mocked, clearAllMocks, resetAllMocks, restoreAllMocks: jest-mock.await extest.mock(specifier, exports | importOriginal => exports): mocks a module for the imports after it, a
relative specifier from the calling file, and gives its exports. The exports given are over the ones of the module,
so the modules importing other names of it still link; without them, every export is mocked by jest-mock (its
functions mock functions). unmock(specifier) and resetModules() give the module itself again to the imports
after them, importActual(specifier) gives it mocked or not; doMock and doUnmock are mock and unmock. Unlike vi.mock, it is not hoisted: import the module under test after
it, with await import(...). The mocks are in-thread hooks (module.registerHooks): the module mocks of node run
off-thread hooks, whose thread records a coverage of zero for the module mocked, which node merges over the one of
the tests (nodejs/node#65946).stubEnv(name, value) (undefined deletes it), stubGlobal(name, value): given back after each test
(unstubAllEnvs, unstubAllGlobals).With jest-snapshot installed, an optional peer dependency (npm install --save-dev jest-snapshot): toMatchSnapshot,
toMatchInlineSnapshot, toThrowErrorMatchingSnapshot, toThrowErrorMatchingInlineSnapshot and
expect.addSnapshotSerializer, the snapshot files of Jest and esmocha read and written as they are: in
__snapshots__/<test file>.snap, named by the titles of the suites and of the test joined by spaces, in the format of
Jest 29 and later. The new snapshots are written, but in CI (CI set); --update-snapshot of the bin writes every
one again, and removes the ones of the tests no longer there when no test of the file failed (UPDATE_SNAPSHOT=all,
or new, or none).
extest [--coverage] [--update-snapshot] [--reporter <name>[:<file>]]... [--config <file>] [files...] runs the test files of the configuration, or the ones given, in
parallel, each in a process of its own. A failed test fails the run; with --coverage, a coverage under its minimum too.
The configuration is an expect-node.config.ts (or .mts, .js, .mjs) of the cwd:
import { defineConfig } from 'expect-node/config';
export default defineConfig({
// The test files, the default patterns of node:test when none.
files: ['packages/*/test/**/*.test.ts'],
// Imported first by each test file and the workers it starts, by their absolute path.
import: ['test/setup.ts'],
timeout: 600_000,
// Run once in the runner: the test files inherit its environment.
setup: () => {
process.env.MY_CACHE = '/tmp/my-cache';
},
coverage: { include: ['packages/*/src/**/*.ts'], lines: 100, branches: 90, functions: 100 },
// The reporters, spec to the terminal when none: the --reporter of the bin replaces them.
reporters: ['spec', 'lcov:coverage/lcov.info'],
});
A reporter is one of node:test (spec, tap, dot, junit, lcov) or the path of a module of one (its default
export, like an async generator of the events), to the terminal or, after a :, to a file: --reporter dot --reporter lcov:coverage/lcov.info prints dots and writes the coverage for a CI to publish.
What is not worth a test is ignored where it is, with node's comments: /* node:coverage ignore next */,
/* node:coverage disable */ and /* node:coverage enable */. A comment line inside a block that never runs counts as
not covered: put the disable at the end of the last line that runs.
Node.js 22.15 or newer (module.registerHooks, util.getCallSites); a configuration and tests in TypeScript need the
type stripping of Node.js, on by default from 22.18.
FAQs
node:test with the expect and mock API of Jest and Vitest, its coverage of subprocesses and workers included
The npm package expect-node receives a total of 0 weekly downloads. As such, expect-node popularity was classified as not popular.
We found that expect-node demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
Socket has released a free Certified Patch for a critical Rails Active Storage vulnerability, giving developers time to upgrade to a secure Rails version.

Security News
/Threat Research
A malicious Ruby gem runs a credential-stealing worm during installation, poisons AI coding tools, and can wipe files when a stolen GitHub token is revoked.

Security News
GitHub is tightening GitHub Actions security with new restrictions on privileged pull request workflows. Here's what changes and how maintainers are affected.