@jterrazz/test
v19.0.0
Published
Declarative testing framework for HTTP APIs, CLIs, background jobs, websites, mobile apps, rendered components and the rules a project ships: one entry point, real infrastructure and a real browser, golden-file assertions, plus an oxlint convention plugin
Maintainers
Readme
@jterrazz/test
A testing framework on vitest for whole products: HTTP APIs, background jobs, CLIs, websites, native mobile apps, rendered components, modules against real databases, and the lint rules a project ships. You declare what a test needs (Postgres, a built binary, a real Chromium, an iOS simulator), and the framework starts it, isolates it per worker and cleans it up. Each test is one sentence: a few setups, one action, and the whole result compared with expect().
// specs/api/users/list/shape.spec.ts
import { file } from '@jterrazz/test';
import { describe, expect, test } from 'vitest';
import { api } from '../../api.specification.js';
describe('shape', () => {
test('lists the users the database holds', async () => {
// Given - two users, from the seed beside the test
const result = await api.seed(file('./__seeds__/two-users.sql')).get('/users');
// Then - the whole response
expect(result.response).toMatch(`
HTTP/1.1 200 OK
content-type: application/json
{"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]}
`);
});
});api comes from a specification file that builds it once for the suite: specification.api({ services: { db: sqlite() }, server: ... }) starts the database, wires your app to it and serves it in the test process. Getting started walks through it from npm install to a green run.
Why
- The infrastructure is declared, not scripted.
postgres(),redis(),sqlite()andprocess()are started for you, one database per worker, reset before every test. - A result is compared whole. The full response, table, output or page outline, written in the test or in a file beside it, with
{{tokens}}for values that move.TEST_UPDATE=1writes the expected values for you to review. - The conventions are a linter. Where a test lives, how it is named and what it may import are checked by an oxlint plugin and a checker, and every finding says what it found, why, how to fix this case, and where to read more.
Install
npm install -D @jterrazz/test @jterrazz/typescript vitest@jterrazz/typescript is the toolchain the framework is built for: one devDependency that builds, type-checks, lints and formats a project, run as npx typescript check and npx typescript fix (its bin is named typescript; it is not Microsoft's compiler package). It is a required peer (why), and its lint conventions are opt-in: a project that never lists the framework's preset in studio.config.ts runs none of them, and writes its tests all the same.
An ES module project on Node 24, vitest 5 and @jterrazz/typescript 11 is required (Setting up § Project requirements). A browser, a database driver or a simulator is installed only by a project that tests through it, and the error names the package when one is missing: see Setting up a project.
What you can test
| Kind | Subject | Entry point |
| ----------------------------------------------- | --------------------------------------------------------------- | ------------------------------ |
| Module | One module, beside its code, nothing started | plain vitest, <file>.test.ts |
| Integration | A module against real services, or against a golden | specification.integration() |
| Component | A React component, hook or DOM function in a real Chromium | component.render() |
| Website | A served page, fetched or driven in a browser | specification.website() |
| Mobile | A native app on an iOS simulator | specification.mobile() |
| API | An HTTP app, in this process or deployed at a url | specification.api() |
| Job | A pipeline triggered by name | specification.job() |
| CLI | A binary in a fresh working directory, often as a YAML document | specification.cli() |
| Lint | The rules a project ships, over fixture trees | specification.lint() |
Which kind a test is depends on its subject, and one ordered list of questions decides it: Which kind of test.
Documentation
The manual is docs/, mapped by the same four families as the package's exports:
- What is tested: one guide per kind, linked above.
- What surrounds the subject: stubs for the network, services for databases and processes, time and doubles.
- Acting on a screen: the visitor:
click,fill,see, and how elements are named. - Judging the result: assertions and tokens.
The conventions and their reasons are Conventions; every rule, generated from the code, is Linting. The API is the types the package publishes, one declaration file per entry (dist/index.d.ts for @jterrazz/test, dist/services.d.ts and dist/stubs.d.ts for @jterrazz/test/services and @jterrazz/test/stubs, then dist/vitest.d.ts, dist/config.d.ts and dist/oxlint.d.ts), which your editor reads, and which you can browse without one in node_modules/@jterrazz/test/dist/ or on npm's Code tab; each guide shows its kind's constructor, chain and result. Agents read skills/studio-test/SKILL.md.
