docs(tests): clarify API smoke timing and proxy assertions

This commit is contained in:
2026-11-12 18:33:39 +08:00
parent bb84e8a4da
commit 772ce80ad2
+6 -2
View File
@@ -142,6 +142,7 @@ app.stdout.on("data", (x) => (startup += x));
app.stderr.on("data", (x) => (startup += x));
try {
// 最多轮询 100 次,失败后等待 100ms,再检查首页是否可用;不能只凭 spawn 返回就宣称服务已启动。
// 单次 fetch 没有 AbortSignal 截止时间,因此 100 次是尝试次数上限,不等于严格十秒的启动总超时。
let ready = false;
for (let n = 0; n < 100; n++) {
if (app.exitCode !== null)
@@ -200,9 +201,10 @@ try {
assert(cookie?.includes("HttpOnly"));
assert(cookie.includes("SameSite=Lax"));
assert(cookie.includes("Max-Age=2592000"));
// Node fetch 不在此维护浏览器 cookie jar;从登录响应取 name=value 后,后续受认证请求显式携带 Cookie。
const session = cookie.split(";")[0];
// Hold the upstream tail: snapshot headers and its first chunk must arrive
// before the proxy has the full JSON body (the old buffering path deadlocks).
// 上游尾部等 releaseStream 才返回,先取响应头和首块,再放行尾部;整体缓冲代理会在此形成循环等待。
// 2500ms 的 Promise.race 只限制 fetch 返回响应头,后面的 reader.read 不在该 deadline 内,不能据此声称首块也受同一计时约束。
let streamTimer;
try {
const streamed = await Promise.race([fetch(host + "/api/foundry/workspaces/space/materials/stream-board/canvas", { headers: { Cookie: session } }), new Promise((_, reject) => { streamTimer = setTimeout(() => reject(new Error("Snapshot proxy buffered the body")), 2500); })]);
@@ -236,6 +238,7 @@ try {
assert.equal((await fetch(host + "/api/foundry/workspaces/space/assets/bad", { headers: { Cookie: session } })).status, 502);
const form = new FormData(); form.set("image", new Blob([new Uint8Array([137,80,78,71])], { type: "image/png" }), "test.png");
const upload = await (await fetch(host + "/api/foundry/workspaces/space/assets", { method: "POST", headers: { Cookie: session, Origin: host, "Idempotency-Key": idem }, body: form })).json();
// 这里只核对 multipart Content-Type、image 字段标记及幂等键;未解析 multipart,也未逐字节比较上传文件内容。
assert.match(upload.type, /^multipart\/form-data; boundary=/); assert.equal(upload.key, idem); assert.ok(upload.multipart);
// 有效会话首页重定向且不缓存私有结果;dashboard 初始 HTML 不应包含画布或 landing。
const signedInHome = await fetch(host + "/", { headers: { Cookie: session }, redirect: "manual" });
@@ -319,6 +322,7 @@ try {
assert.deepEqual(renamed.content, stored.content);
// workspace/board 各自使用 ID 或 slug 的四种组合都应定位同一图谱和独立画布版本。
// 替身通过 canonical 字符串替换提供该映射;此处验证代理接受四种路径,不验证真实 Foundry 的 slug 解析实现。
for (const workspace of ["space", "creative-space"]) for (const board of ["foundry-generated-id", "my-board"]) {
const path = `/api/foundry/workspaces/${workspace}/materials/${board}`;
const material = await (await fetch(host + path, { headers: { Cookie: session } })).json();