Files
novalon-website/config/test/itest/global-setup.js
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

123 lines
4.4 KiB
JavaScript
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
/**
* 集成测试 globalSetup:创建 /tmp 一次性 SQLite 库并应用 Prisma schema。
*
* 步骤(每一步都可审计):
* 1. 记录项目数据源(prisma/dev.db、<root>/dev.db、<root>/data.db)指纹基线。
* 2. 用 `prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script`
* 离线生成最终 DDL —— 该命令只输出 SQL 文本,不连接任何数据库。作为第二道保险,
* 子进程的 DATABASE_URL 同样被强制指向临时库,并在执行后复验项目库指纹未变。
* 3. 用 `npx tsx config/test/itest/apply-schema.mts` 在进程内以真实 Prisma 客户端把 DDL
* 应用到临时库,并由 SQLite 的 PRAGMA database_list 自证它打开的是哪个文件。
* 4. 复验项目库指纹,写入 manifest(worker 的 setupFiles 与 globalTeardown 都读它)。
*/
const fs = require('fs');
const path = require('path');
const { execFileSync } = require('child_process');
const guard = require('./env.js');
function stamp(msg) {
console.log(`[itest:setup] ${msg}`);
}
function assertProjectDbUntouched(baseline, where) {
const now = guard.devDbBaselines();
const drift = Object.keys(baseline).filter((k) => !guard.sameFingerprint(baseline[k], now[k]));
if (drift.length > 0) {
throw new Error(`[itest:setup] ${where} 之后项目数据源指纹发生变化:${JSON.stringify(drift)}`);
}
return now;
}
module.exports = async function globalSetup() {
// 0) URL 合法性先于任何文件操作
guard.assertSafeDatasourceUrl(guard.DATASOURCE_URL, 'globalSetup');
const baseline = guard.devDbBaselines();
stamp(`tmp realpath = ${guard.TMP_REALPATH}`);
stamp(`integration db = ${guard.DB_PATH}`);
stamp(`prisma/dev.db fp = ${JSON.stringify(baseline.prismaDevDb)}`);
// 1) 干净起步:只删除 /tmp 下属于本次运行的文件
for (const f of [
guard.DB_PATH,
`${guard.DB_PATH}-journal`,
`${guard.DB_PATH}-wal`,
`${guard.DB_PATH}-shm`,
guard.DDL_PATH,
]) {
if (!f.startsWith(`${guard.TMP_REALPATH}${path.sep}`)) {
throw new Error(`[itest:setup] 拒绝删除非临时目录文件 ${f}`);
}
try {
fs.rmSync(f);
} catch {
/* 不存在即正常 */
}
}
// 2) 离线生成 DDL(migrate diff 不连接数据库;DATABASE_URL 仍指向临时库作为第二道保险)
const diffOut = execFileSync(
'npx',
[
'prisma', 'migrate', 'diff',
'--from-empty',
'--to-schema-datamodel', 'prisma/schema.prisma',
'--script',
],
{
cwd: guard.REPO_ROOT,
encoding: 'utf8',
env: { ...process.env, DATABASE_URL: guard.DATASOURCE_URL },
stdio: ['ignore', 'pipe', 'pipe'],
},
);
const statements = guard.splitStatements(diffOut);
if (statements.length < 5) {
throw new Error(`[itest:setup] migrate diff 产出的语句数量异常(${statements.length}),拒绝继续`);
}
fs.writeFileSync(guard.DDL_PATH, diffOut);
stamp(`ddl statements = ${statements.length}`);
assertProjectDbUntouched(baseline, 'migrate diff');
// 3) 进程内应用 schema
const resultFile = `${guard.MANIFEST_PATH}.apply.json`;
const baselineFile = `${guard.MANIFEST_PATH}.baseline.json`;
try { fs.rmSync(resultFile); } catch { /* ignore */ }
fs.writeFileSync(baselineFile, JSON.stringify(baseline));
execFileSync('npx', ['tsx', path.join(__dirname, 'apply-schema.mts')], {
cwd: guard.REPO_ROOT,
encoding: 'utf8',
env: {
...process.env,
DATABASE_URL: guard.DATASOURCE_URL,
ITEST_DDL_FILE: guard.DDL_PATH,
ITEST_RESULT_FILE: resultFile,
ITEST_BASELINE_FILE: baselineFile,
},
stdio: ['ignore', 'inherit', 'inherit'],
});
const applyResult = JSON.parse(fs.readFileSync(resultFile, 'utf8'));
if (!applyResult.ok) throw new Error('[itest:setup] apply-schema 未报告成功');
stamp(`sqlite opened file= ${applyResult.openedFile}`);
stamp(`tables = ${applyResult.tables.join(',')}`);
// 4) 复验 + manifest 落盘
const afterSetup = assertProjectDbUntouched(baseline, 'apply-schema');
fs.writeFileSync(
guard.MANIFEST_PATH,
JSON.stringify(
{ datasourceUrl: guard.DATASOURCE_URL, baseline, afterSetup, applyResult, startedAt: new Date().toISOString() },
null,
2,
),
);
process.env.DATABASE_URL = guard.DATASOURCE_URL;
process.env.NOVALON_ITEST_MANIFEST = guard.MANIFEST_PATH;
};