@zyplux/tests-fixtures
v0.4.0
Published
Story-test fixtures for zyplux workspaces: Bun.$ shell fake, console capture, fetch routing, temp dirs, domain matchers, and vitest test.extend bases per app type
Maintainers
Readme
@zyplux/tests-fixtures
Story-test fixtures for code built on Bun and @zyplux/util. Fakes swap in at the lowest boundary (Bun.$, fetch, console, prompt, Bun.sleep, process.env) so tests exercise only public interfaces. Ships TypeScript source, consumed directly under Bun.
Install
bun add -d @zyplux/tests-fixturesUse
Pick a base per app type, extend it with suite fixtures, and keep the binding named test:
import { cliTest } from '@zyplux/tests-fixtures';
export const test = cliTest;
export { describe, expect } from 'vitest';import { describe, expect, test } from '#fixtures';
describe('1.1 pushing a branch', () => {
test('1.1.1 pushes and reports the PR url', async ({ logs, shell }) => {
shell.on('git rev-parse --abbrev-ref HEAD', 'feat-x');
shell.on('git push', '');
await runPushBranch({ command: 'push-branch', hold: false, ready: false });
expect(shell).toHaveRun('git push --set-upstream origin feat-x');
expect(logs).toHaveLogged('PR (draft): https://github.com/acme/repo/pull/1');
});
});Bases
libraryTest— lazy fixtures:shell(fakeBun.$, installed only when destructured),tempDir(auto-removed scratch directory withpath,write,exists).cliTest— extendslibraryTest; auto-silences and capturesconsole(logs), makesBun.sleepinstant; adds lazynetwork(fakefetch),prompt(fakeglobalThis.promptthat accepts and records every message), andenv(set(name, value)stubs an env var for the test).
Fakes
createShellFake()— routes commands (on(pattern, ...replies), later routes win, the last reply repeats;otherwise(reply)sets a fallback, unrouted commands throw) and recordscalls({ argv, program }),commands(rendered strings),commandsMatching(pattern).createConsoleCapture()— recordslogLines/warnLines/errorLines.createFetchFake()— routes urls (on(prefixOrRegExp, reply),otherwise(reply)) and recordsrequests;okResponse()/notFoundResponse()build replies.createPromptFake()— accepts everyprompt()call and recordsmessages.createTempDir()—path,write(relativePath, content),exists(relativePath),remove().fakeShellOutput(stdout, exitCode?),fakeShellPromise(result),toArgv(values)— rawBun.$doubles behindcreateShellFake.
Matchers
Importing a base registers domain matchers via expect.extend:
expect(shell).toHaveRun(command)— the exact rendered command ran.expect(shell).toHaveRunMatching(pattern)— some command matches (string = command prefix at a word boundary, same ason; RegExp = test); negate with.notfor "never ran".expect(logs).toHaveLogged(line?)/toHaveWarned(line?)/toHaveErrored(line?)— a captured line equals the string (or matches the RegExp); with no argument, that the channel captured anything, so.not.toHaveWarned()asserts silence.
