- 使用内部 checkout 镜像,并校验运行环境中的 Node.js 22 - 检测预览服务端口冲突并重试,避免并行测试误连其他进程 - 调整布局测试的视口宽度和溢出断言,兼容经典滚动条 - 增加时钟暂停的时间余量,避免 CI 调度延迟导致测试失败
This commit is contained in:
4 files changed
+69
-48
No files matched your search
@@ -87,6 +87,57 @@ async function freePort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
// node --test 并行运行各验收文件:freePort 释放端口到预览进程绑定之间,其他文件的进程可能占用同一端口。
|
||||
// Nitro 绑定失败时只记录 EADDRINUSE 而不退出,HTTP 探测还会命中别的文件的预览服务,
|
||||
// 因此只以本进程输出的监听地址为准,冲突时换端口重试。
|
||||
async function startApp(attempts = 5) {
|
||||
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
||||
const port = await freePort();
|
||||
const origin = `http://127.0.0.1:${port}`;
|
||||
const app = startProcess(
|
||||
[join(appRoot, ".output", "server", "index.mjs")],
|
||||
{
|
||||
cwd: appRoot,
|
||||
env: {
|
||||
// 使用生产已有的公开 API 配置接入外部边界,不读取或修改项目 .env。
|
||||
...process.env,
|
||||
NODE_ENV: "production",
|
||||
HOST: "127.0.0.1",
|
||||
PORT: String(port),
|
||||
NITRO_HOST: "127.0.0.1",
|
||||
NITRO_PORT: String(port),
|
||||
NUXT_PUBLIC_API_BASE: backendOrigin,
|
||||
},
|
||||
},
|
||||
);
|
||||
const state = await eventually(
|
||||
async () => {
|
||||
if (app.exitCode !== null || app.signalCode !== null) return "exited";
|
||||
if (app.log.includes("EADDRINUSE")) return "collision";
|
||||
if (!app.log.includes(`Listening on ${origin}`)) return false;
|
||||
try {
|
||||
const response = await fetch(`${origin}/login`, {
|
||||
signal: AbortSignal.timeout(1000),
|
||||
});
|
||||
return response.ok && "ready";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
Boolean,
|
||||
"Built app did not start",
|
||||
30000,
|
||||
);
|
||||
if (state === "ready") return origin;
|
||||
if (state === "exited") throw new Error(`Preview exited: ${app.log}`);
|
||||
children.splice(children.indexOf(app), 1);
|
||||
const exited = new Promise((resolve_) => app.once("exit", resolve_));
|
||||
app.kill("SIGKILL");
|
||||
await exited;
|
||||
}
|
||||
throw new Error(`Built app could not bind a free port in ${attempts} tries`);
|
||||
}
|
||||
|
||||
before(
|
||||
async () => {
|
||||
// 必须先构建;此处运行 .output,而非开发服务器,确保测试走实际交付入口。
|
||||
@@ -121,42 +172,7 @@ before(
|
||||
);
|
||||
});
|
||||
|
||||
const port = await freePort();
|
||||
appOrigin = `http://127.0.0.1:${port}`;
|
||||
const app = startProcess(
|
||||
[join(appRoot, ".output", "server", "index.mjs")],
|
||||
{
|
||||
cwd: appRoot,
|
||||
env: {
|
||||
// 使用生产已有的公开 API 配置接入外部边界,不读取或修改项目 .env。
|
||||
...process.env,
|
||||
NODE_ENV: "production",
|
||||
HOST: "127.0.0.1",
|
||||
PORT: String(port),
|
||||
NITRO_HOST: "127.0.0.1",
|
||||
NITRO_PORT: String(port),
|
||||
NUXT_PUBLIC_API_BASE: backendOrigin,
|
||||
},
|
||||
},
|
||||
);
|
||||
await eventually(
|
||||
async () => {
|
||||
if (app.exitCode !== null)
|
||||
throw new Error(`Preview exited: ${app.log}`);
|
||||
try {
|
||||
return (
|
||||
await fetch(`${appOrigin}/login`, {
|
||||
signal: AbortSignal.timeout(1000),
|
||||
})
|
||||
).ok;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
Boolean,
|
||||
"Built app did not start",
|
||||
30000,
|
||||
);
|
||||
appOrigin = await startApp();
|
||||
|
||||
browser = await chromium.launch({
|
||||
executablePath: chromePath,
|
||||
|
||||
Reference in new issue
Block a user