@app-studio/qa-db

中文文档
0.11.6发布于 2026/11/06UNLICENSEDTypeScriptES Module近 30 天下载 1854

A test database per run — real Postgres or embedded PGlite — created, migrated, truncated with a verified postcondition, and dropped on the way out.

原始使用文档
文档目录6 节
  1. A database per run, with nothing to remember
  2. PGlite is a first-class mode, not a fallback
  3. Resetting, and proving it happened
  4. Any client
  5. Exports
  6. Requirements

@app-studio/qa-db

createCheckpointStore, createPgliteCheckpointAdapter and createPostgresCheckpointAdapter save verified seed prefixes as native DB images, fence writers and restore compatible checkpoints before focused replay. Locks follow database identity across checkouts; restored API verification gates execution. See checkpoint development.

A test database per run — real Postgres or embedded PGlite — created, migrated, truncated with a verified postcondition, and dropped on the way out.

A database per run, with nothing to remember

The convention this replaces was "give each session its own database name", and it failed the way conventions do. Two suites sharing one database corrupt each other — phantom 401s, "record not found" on tests that pass alone — and the moment a second session in the same checkout forgets the rule, an audit has to be redone from scratch.

There is nothing to remember here. The default path is the safe one:

// tests/setup/test-db.ts
import { createTestDbGlobalSetup } from '@app-studio/qa-db';
import { execFileSync } from 'node:child_process';

export default createTestDbGlobalSetup({
  mode: 'postgres',
  prefix: 'myapp_test_run_',
  adminUrl: process.env.POSTGRES_URL ?? 'postgres://localhost:5432/postgres',
  applySchema: async ({ url }) => {
    execFileSync('pnpm', ['prisma', 'db', 'push'], { env: { ...process.env, DATABASE_URL: url } });
  },
});
// vitest.config.ts
export default { test: { globalSetup: ['tests/setup/test-db.ts'] } };

Each run gets myapp_test_run_<pid>_<timestamp>, dropped at teardown. Databases older than six hours are swept on the way in, so a killed run leaves debris for one afternoon rather than forever.

TEST_DATABASE_URL set in the shell still wins, which is how CI pins a service database. Deliberately read before any dotenv loading: a repository ships a shared default in .env for convenience, and honouring that would restore exactly the collision this prevents. TEST_DB_KEEP=1 keeps the database so a failure can be opened afterwards.

PGlite is a first-class mode, not a fallback

createTestDbGlobalSetup({
  mode: 'pglite',
  prefix: 'myapp_test_',
  applySchema: async ({ dataDir }) => { /* … */ },
  publish: ({ dataDir }) => ({ DB_TYPE: 'pglite', PGLITE_DATA_DIR: dataDir ?? '' }),
});

PGlite is Postgres compiled to WebAssembly, running in-process. pg_tables, TRUNCATE … RESTART IDENTITY CASCADE and SET LOCAL lock_timeout all behave as they do on a server, so the same tests run unchanged — with no Docker, on a laptop or in CI. This package's own reset tests run on it, which is the argument in practice rather than in principle.

Use it for development too, not only tests: an "ephemeral database" is a temporary directory, and there is no server to collide with.

Resetting, and proving it happened

import { fromPrisma, makeResetDatabase } from '@app-studio/qa-db';

const resetDatabase = makeResetDatabase(fromPrisma(prisma), { verifyTable: 'User' });

beforeEach(resetDatabase);

Two details are load-bearing.

The lock timeout. TRUNCATE needs an ACCESS EXCLUSIVE lock, and a real application legitimately issues fire-and-forget writes after a response — a session's lastSeenAt, an analytics row. Without a timeout, a race with one of those becomes an indefinite wait and the suite hangs rather than fails. Failing fast and retrying is strictly better: the same race resolves in milliseconds on the next attempt.

The postcondition. The reset verifies its own effect. A suite that starts against leftover rows does not fail here; it fails three tests later, in a way that reads as an application bug. Checking costs one query and turns a confusing failure into an obvious one.

Tables are discovered from the database rather than declared, and migration bookkeeping is left alone.

Any client

SqlExecutor is three methods, so the same reset works through Prisma, pg or PGlite:

import { fromPg, fromPglite, fromPrisma } from '@app-studio/qa-db';

Prisma is adapted structurally rather than imported — @prisma/client is generated per project, and depending on it here would pin every host to a version of a package that does not exist until they run a generator.

Exports

ExportPurpose
createTestDbGlobalSetupThe vitest globalSetup, installed in one line.
createEphemeralDatabase, sweepStaleDatabasesThe same lifecycle, imperatively, for orchestration scripts.
makeResetDatabase, tableNamesTruncate with a verified postcondition; discover what to truncate.
fromPrisma, fromPg, fromPgliteAdapters onto SqlExecutor.
explicitDatabaseUrl, withDatabase, ephemeralNameThe naming and override rules, exposed for scripts that need them.

Requirements

Node.js 20 or newer. pg and @electric-sql/pglite are optional peers — install whichever mode you use.

版本与发布记录

@app-studio/qa-db 共发布 33 个版本,首次发布于 2026/08/09;过去 12 个月发布了 33 个版本。

版本发布日期距今
0.11.6latest2026/11/062 天前
0.11.32026/11/017 天前
0.11.22026/10/2217 天前
0.11.12026/10/1622 天前
0.10.42026/10/081 个月前
0.10.3next2026/10/081 个月前

关于 @app-studio/qa-db 的常见问题

@app-studio/qa-db 是什么?

A test database per run — real Postgres or embedded PGlite — created, migrated, truncated with a verified postcondition, and dropped on the way out.

如何安装 @app-studio/qa-db?

在项目目录运行 npm install @app-studio/qa-db,或使用 pnpm add / yarn add / bun add。

@app-studio/qa-db 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@app-studio/qa-db 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@app-studio/qa-db 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@app-studio/qa-db 可以商用吗?

@app-studio/qa-db 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@app-studio/qa-db 的下载量有多少?

根据 npm 官方下载统计,@app-studio/qa-db 在 2026/10/07 – 2026/11/05 这 30 天内被下载 1,854 次,日均约 62 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@app-studio/qa-db 还在维护吗?

最新版本 0.11.6 发布于 2026/11/06(2 天前);至今共发布 33 个版本,其中过去 12 个月发布了 33 个;首次发布于 2026/08/09。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。