Files
novalon-website/config/test/itest/apply-schema.mts
T
zhangxiang 6bb7c557ee test(qa): e2e 装配修正 + 集成/门禁测试与工具链重构
- e2e:修死选择器与蜜罐误命中、补断言、GA4/security-headers 用例诚实标注
  skip 边界;新增 assert-helpers/fixtures/hydrated/primary-nav/touch-targets
  等复用桩。
- 集成层:config/test/jest.integration.config.js + tests-integration/ 真库
  一次性 SQLite 用例,teardown 守卫开发库指纹。
- 门禁工具链:jest.setup 归位到根、scripts/accessibility 全站 axe 节点计数、
  check-brand-text-token/check-motion-constraints 机械守卫、stryker/lighthouse
  配置收敛。
2026-09-28 10:48:08 +08:00

79 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// @ts-nocheck
/**
* 在**进程内**用真实 Prisma 客户端把 schema 应用到一次性临时 SQLite 文件。
*
* 由 config/test/itest/global-setup.js 通过 `npx tsx` 调用(与项目既有约定一致:
* package.json 的 db:seed / check:contrast 同样用 `npx tsx` 跑 TS 脚本)。
*
* 为什么不用 `prisma db push`:db push 会自行解析数据源并连接,无法在「连接之前」证明它
* 打开的是哪个文件。本脚本显式传入 `datasourceUrl`,并在建表后用
* `PRAGMA database_list` 让 **SQLite 自己回答**它打开了哪个文件,再断言该路径位于
* realpath(os.tmpdir()) 之下 —— 这是比「事后检查」更强的保证。
*/
import { createRequire } from 'node:module';
import path from 'node:path';
import fs from 'node:fs';
const require = createRequire(import.meta.url);
const guard = require('./env.js');
// 真实(非 mock)Prisma 客户端:与 src/lib/db.ts 走同一个生成产物
const { PrismaClient } = require(path.join(guard.REPO_ROOT, 'src', 'generated', 'prisma', 'client.ts'));
const url = process.env.DATABASE_URL;
const ddlFile = process.env.ITEST_DDL_FILE;
const resultFile = process.env.ITEST_RESULT_FILE;
/** 与 src/lib/db.ts 完全一致的构造方式(无参构造 → 读 env DATABASE_URL),
* 唯一区别是这里额外显式传 datasourceUrl,让「指向哪里」在代码里可读可审。 */
const client = new PrismaClient({ datasourceUrl: url });
const resolvedUrl = guard.assertSafeDatasourceUrl(url, 'apply-schema');
const statements = guard.splitStatements(fs.readFileSync(ddlFile, 'utf8'));
const applied = [];
for (const statement of statements) {
await client.$executeRawUnsafe(statement);
applied.push(statement.split('\n')[0].slice(0, 60));
}
// SQLite 自报打开的文件 —— 断言它确实是临时库,而不是 prisma/dev.db。
const dbList = await client.$queryRawUnsafe('PRAGMA database_list');
const openedFile = dbList?.[0]?.file;
if (typeof openedFile !== 'string') {
throw new Error(`[itest-guard] PRAGMA database_list 未返回文件路径:${JSON.stringify(dbList)}`);
}
const verifiedOpen = guard.assertSafeDatasourceUrl(`file:${openedFile}`, 'database_list');
const tables = await client.$queryRawUnsafe(
`SELECT name FROM sqlite_master WHERE type='table' ORDER BY name`,
);
// 建表后复查项目库指纹:db push/diff 期间不得改动 prisma/dev.db。
const after = guard.devDbBaselines();
const baseline = JSON.parse(fs.readFileSync(process.env.ITEST_BASELINE_FILE, 'utf8'));
const drift = Object.keys(baseline).filter((key) => !guard.sameFingerprint(baseline[key], after[key]));
if (drift.length > 0) {
throw new Error(`[itest-guard] 项目数据源被改动:${drift.join(', ')}`);
}
await client.$disconnect();
fs.writeFileSync(
resultFile,
JSON.stringify({
ok: true,
datasourceUrl: url,
resolvedUrl,
openedFile: verifiedOpen,
statementCount: statements.length,
applied,
tables: tables.map((t) => t.name),
devDb: after,
}, null, 2),
);
console.log('[itest] schema applied');
console.log('[itest] DATABASE_URL =', url);
console.log('[itest] sqlite opened', openedFile);
console.log('[itest] tables =', tables.map((t) => t.name).join(','));