@houserules/test
v0.1.2
Published
houserules test: shared testing infrastructure for driving the houserules CLI against synthetic repos, for the CLI's own suites and for plugin authors.
Downloads
541
Readme
@houserules/test
Shared testing infrastructure for driving the houserules CLI against synthetic repos. Built for the CLI's own suites, and published so a plugin author can write the same kind of test against their own plugin without reimplementing repo staging, subprocess running, and installed-tree assertions from scratch.
Install
pnpm add -D @houserules/testRequires @houserules/cli and
vitest as peers.
Usage
Point vitest's globalSetup at @houserules/test/global-setup so each run gets its own temp
state, then stage a repo with houserules already installed and assert against the result:
// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globalSetup: ['@houserules/test/global-setup'],
},
});// src/__tests__/typescript.test.ts
import { describe, expect, it } from 'vitest';
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { useInstalledRepo } from '@houserules/test/repo';
import { manifestOf } from '@houserules/test/installed-tree';
const PLUGIN = fileURLToPath(new URL('../..', import.meta.url));
describe('typescript', () => {
it('installs a path-scoped rule', () => {
const root = useInstalledRepo('pnpm-monorepo', {
modules: 'ts/typescript',
plugins: [{ name: PLUGIN, alias: 'ts' }],
});
const ruleText = readFileSync(
join(root, '.claude/rules/typescript.md'),
'utf8',
);
expect(ruleText).toMatch(/^ {2}- ['"]\*\*\/\*\.ts['"]$/m);
expect(manifestOf(root).modules.includes('ts/typescript')).toBe(true);
});
});useInstalledRepo stages by copying a cached post-init snapshot rather than running init in
every test, so a regression in init fails one suite instead of every suite that depends on it.
What it provides
@houserules/test/repo:useRepoanduseInstalledRepobuild synthetic repos and remove them after the test.useInstalledRepostages from a cached snapshot with houserules already installed.useRepogives a bare repo, for tests whose subject isinititself.treeHashhashes a directory tree for drift assertions.@houserules/test/run:runCliruns the houserules CLI as a subprocess without throwing, so a test can assert on the exit code.runScriptruns an installed payload script inside a target repo, hook-style with JSON on stdin.runInruns a setup command such asgit addinside a directory and throws on a non-zero exit.@houserules/test/installed-tree: readers over an installed repo, includingreadJson,settingsOf,hookCommandsFor,allHookCommands,manifestOf,writeManifest,houseConfigPath,editHouseConfig,claudeMdPath, andreadClaudeMd.@houserules/test/doctor-report:runDoctorJsonrunsdoctor --jsonand returns it as a queryableJsonReport.driftForreads the drift entry for one file.@houserules/test/runner-stub:stubRunnerwrites a fake package-manager runner that records every invocation instead of running one.recordedCallsreads back the argv each call passed.@houserules/test/global-setup: a VitestglobalSetupthat creates the per-run temp directoryuseInstalledReposnapshots into, and removes it on teardown. It does not build houserules. Installing@houserules/clifrom npm gives youdist/prebuilt, and inside this workspace eachtestscript declares a wireit dependency on the CLI's build instead.@houserules/test/hook-input:readToolInputandpromptInputbuild the JSON payloadsrunScriptexpects on stdin for hook-style scripts.
Part of houserules
houserules is portable Claude Code infrastructure that keeps the agent's context lean. The package list has the rest.
License
MIT. See LICENSE.
