Files
tutti/packages/agent/gui/agent-gui/agentGuiNode/agentGuiHeroCarouselImageLoad.spec.ts
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

134 lines
3.9 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from "vitest";
import { AgentGuiHeroCarouselImageLoad } from "./agentGuiHeroCarouselImageLoad";
class FakeImage {
static instances: FakeImage[] = [];
static autoLoad = true;
static failuresByUrl = new Map<string, number>();
complete = false;
crossOrigin: string | null = null;
decoding = "auto";
loading = "auto";
naturalWidth = 100;
onerror: (() => void) | null = null;
onload: (() => void) | null = null;
private value = "";
constructor() {
FakeImage.instances.push(this);
}
decode(): Promise<void> {
return Promise.resolve();
}
get src(): string {
return this.value;
}
set src(value: string) {
this.value = value;
if (value && FakeImage.autoLoad) {
this.complete = true;
const failuresRemaining = FakeImage.failuresByUrl.get(value) ?? 0;
if (failuresRemaining > 0) {
FakeImage.failuresByUrl.set(value, failuresRemaining - 1);
this.naturalWidth = 0;
this.onerror?.();
} else {
this.onload?.();
}
}
}
setAttribute(): void {}
}
describe("AgentGuiHeroCarouselImageLoad", () => {
const originalImage = globalThis.Image;
afterEach(() => {
globalThis.Image = originalImage;
FakeImage.instances.length = 0;
FakeImage.autoLoad = true;
FakeImage.failuresByUrl.clear();
vi.useRealTimers();
});
it("loads every canvas-bound image anonymously before decoding", async () => {
globalThis.Image = FakeImage as unknown as typeof Image;
const load = new AgentGuiHeroCarouselImageLoad([
{
agentTargetId: "local:codex",
badge: { iconUrl: "https://cdn.example.com/owner.png" },
iconUrl: "app://codex.png",
heroImageUrl: "app://codex-hero.jpg",
label: "Codex",
provider: "codex",
targetId: "local:codex"
}
]);
const result = await load.result;
expect(FakeImage.instances).toHaveLength(3);
expect(FakeImage.instances.map((image) => image.crossOrigin)).toEqual([
"anonymous",
"anonymous",
"anonymous"
]);
expect(FakeImage.instances[1]?.src).toBe("app://codex-hero.jpg");
expect(result.icons[0]).toBe(FakeImage.instances[0]);
expect(result.covers[0]).toBe(FakeImage.instances[1]);
expect(result.badges[0]).toBe(FakeImage.instances[2]);
});
it("cancels every in-flight image and resolves a stale generation empty", async () => {
globalThis.Image = FakeImage as unknown as typeof Image;
FakeImage.autoLoad = false;
const load = new AgentGuiHeroCarouselImageLoad([
{
agentTargetId: "local:codex",
badge: { iconUrl: "https://cdn.example.com/owner.png" },
iconUrl: "app://codex.png",
label: "Codex",
provider: "codex",
targetId: "local:codex"
}
]);
load.cancel();
const result = await load.result;
expect(FakeImage.instances.every((image) => image.src === "")).toBe(true);
expect(result).toEqual({ badges: [null], covers: [null], icons: [null] });
});
it("retries a transient owner badge failure", async () => {
vi.useFakeTimers();
globalThis.Image = FakeImage as unknown as typeof Image;
const badgeUrl = "https://cdn.example.com/owner.png";
FakeImage.failuresByUrl.set(badgeUrl, 1);
const load = new AgentGuiHeroCarouselImageLoad([
{
agentTargetId: "local:codex",
badge: { iconUrl: badgeUrl },
iconUrl: "app://codex.png",
label: "Codex",
provider: "codex",
targetId: "local:codex"
}
]);
await vi.advanceTimersByTimeAsync(150);
const result = await load.result;
expect(FakeImage.instances).toHaveLength(4);
expect(FakeImage.instances[2]?.src).toBe("");
expect(FakeImage.instances[3]?.crossOrigin).toBe("anonymous");
expect(FakeImage.instances[3]?.src).toBe(badgeUrl);
expect(result.badges[0]).toBe(FakeImage.instances[3]);
});
});