docs(tests): clarify media fixtures and response timeout coverage

This commit is contained in:
2026-11-12 17:14:54 +08:00
parent 81055e14a1
commit 2dbe68c6aa
4 changed files with 14 additions and 5 deletions
+2
View File
@@ -12,6 +12,7 @@ const source='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB';
const id='77777777-7777-4777-8777-777777777777';
const asset={id,url:`https://api.foundry.entroia.com/projects/endoleap/workspaces/w/assets/${id}`,width:1,height:1,bytes:24,mime_type:'image/png'};
// 首例直接比对 FormData.image 原字节、上传路径、POST 和幂等键形状,返回值保留服务资产元数据。
// 键的正则只检查 36 位字符集合,不完整校验 UUID 分段;替身返回固定元数据,不证明服务器实际解码成功。
test('attachment upload sends the original file bytes',async()=>{
const bytes=Buffer.from(source.split(',')[1],'base64');let calls=0;
const result=await uploadCanvasImage(async(path,options)=>{
@@ -32,6 +33,7 @@ test('uncertain upload retries the exact bytes with the same idempotency key',as
await uploadCanvasImage(async(_path,options)=>{calls++;if(!key)key=options.headers['Idempotency-Key'];assert.equal(options.headers['Idempotency-Key'],key);if(calls===1)throw new TypeError('connection lost');return asset;},'w',new Blob(['test'],{type:'image/png'}),'test.png');assert.equal(calls,2);
});
// 受管原始 URL 转同源认证代理,preview 仅加显示变体参数;普通外部图片地址保持原样。
// 这里仅比对字符串,不请求代理,也不验证登录鉴权或预览图片内容。
test('preview URLs are renderer-only and do not replace original managed references',()=>{
assert.equal(managedImageSource(asset.url),`/api/foundry/workspaces/w/assets/${id}`);assert.equal(managedImageSource(asset.url,true),`/api/foundry/workspaces/w/assets/${id}?variant=preview`);
assert.equal(managedImageSource('https://example.com/photo.png',true),'https://example.com/photo.png');
+3 -1
View File
@@ -45,7 +45,8 @@ test("icon data rejects executable shapes, events and external paint references"
// 让 setImmediate 推进到调度任务阶段;用于观察尚未开始、排队及已释放容量的加载。
const tick = () => new Promise((resolve) => setImmediate(resolve));
// request 后立即 abort,尚未进入调度时不能启动网络加载,也不能把未完成值留入缓存。
// request 后立即 abort,尚未进入调度时不能调用加载函数,也不能把未完成值留入缓存。
// 测试名中的 unmounted 由 AbortController 模拟:没有挂载 React 图标,也没有发真实网络请求。
test("an immediately unmounted icon does not start a network request", async () => {
let calls = 0;
const loader = createResourceLoader(async () => { calls++; return "unused"; });
@@ -86,6 +87,7 @@ test("unused queued loads never start; a remaining subscriber keeps a shared loa
});
// active abort 后释放容量,失败 key 可重新加载;容量二的 LRU 在加入 a/b 后淘汰更早 fail,保留仍在缓存的 a。
// abort 替身监听内部 signal 后拒绝;fail 替身只失败一次,区分“取消后可继续调度”和“失败未永久缓存”。
test("active aborts and failed requests can retry; least recently used cache is bounded", async () => {
let fail = true;
const loader = createResourceLoader(async (key, signal) => {
+5 -2
View File
@@ -10,6 +10,7 @@ import { resizeFromPointer } from "../src/lib/canvas-geometry.ts";
import { iconCatalog, iconsById, searchIcons } from "../src/components/canvas/icon-catalog.ts";
// PlainImageElement 继承通用变换但不继承 CardElement,比例缩放、名称和 src 可恢复,重命名可撤销。
// YQ== 只是单字节 a 的 data URL:用于来源字段往返,不是可解码图片;尺寸断言来自模型默认值。
test("plain images inherit transforms without card connections and preserve source/name on restore", () => {
const image = new PlainImageElement({ x: 0, y: 0 }, "", "data:image/png;base64,YQ==");
assert(image instanceof CanvasElement); assert.equal(image instanceof CardElement, false);
@@ -23,7 +24,8 @@ test("plain images inherit transforms without card connections and preserve sour
assert.equal(canvasReducer(renamed, { type: "undo" }).present.nodes[0].data.title, "图片");
});
// 纯图片不能作为卡片连线目标;删除连线后 javascript: src 仍必须被解码器拒绝。
// emptyCanvas 的 schema 1 快照拒绝连向 plainImage 的旧卡片边;这不是 schema 2 的通用连线规则。
// 两次断言分别隔离非法连线和非法来源:先保持有效 src 测边,再清空 edges 测 javascript: src。
test("plain image sources are required and pure images cannot acquire card connections", () => {
const image = makeCanvasNode("plain-image", { x: 0, y: 0 }, "data:image/png;base64,YQ==");
const card = makeCanvasNode("text", { x: 300, y: 0 });
@@ -33,7 +35,8 @@ test("plain image sources are required and pure images cannot acquire card conne
assert.throws(() => decodeCanvas(JSON.stringify(document)));
});
// 图标 ID 唯一并符合后端字符形状,中文类别与英文词可搜索;仅验证当前本地目录,不请求后端搜索。
// 图标 ID 唯一并符合后端字符形状,中文类别与英文词可搜索;当前本地目录同时含 Lucide 和实验性 Tabler。
// 数量下限与两个固定 slug 是回归样本,不证明上游图标库的每个版本都已完整收录,也不请求后端搜索。
test("the complete Lucide catalog has unique backend-compatible identifiers and searchable names", () => {
assert(iconCatalog.length > 2000);
assert.equal(iconsById.size, iconCatalog.length);
+4 -2
View File
@@ -1,5 +1,6 @@
/**
* 响应头、body 总传输与空闲三类截止时间的组合测试。用 Response/ReadableStream 和 fetch 替身验证读取、取消与诊断。
* 配置响应头、body 总传输与空闲三类时限,用 Response/ReadableStream 和 fetch 替身验证读取、取消与诊断。
* 本文件直接触发 header 和 idle 超时;body 总时限只参与配置,没有独立触发其到期分支。
* HTTP 状态 200 不代表 body 可用:传输中断、非法 JSON、后端错误和 204 在 api 层需要分别表达。
*/
import test from 'node:test';
@@ -28,7 +29,8 @@ test('snapshot idle timeout aborts unfinished bodies instead of returning a vali
test('header deadline rejects a server that has not responded',async()=>{
await assert.rejects(fetchCanvasResponse('https://example.test',{}, {headersMs:10,bodyMs:500,idleMs:100},(_url,options)=>new Promise((_resolve,reject)=>options.signal.addEventListener('abort',()=>reject(options.signal.reason)))),{name:'TimeoutError'});
});
// 调用方 abort 和 consumer 直接 cancel 两条路径都释放上游读取,分别核对 AbortError 和 cancel 总次数。
// 调用方 abort 和 consumer 直接 cancel 两条路径分别核对 AbortError 和上游 cancel 总次数。
// make 返回永不产出数据的流,让取消发生于等待阶段;断言不检查 reader.releaseLock,也不模拟真实连接断开。
test('disconnect and consumer cancellation release the upstream read',async()=>{
const abort=new AbortController();let cancelled=0;
const make=()=>new Response(new ReadableStream({cancel(){cancelled++;}}));