






















@@ -104,9 +104,30 @@ describe("refreshChatAvatar", () => {
104104});
105105106106it("uses a route-relative avatar endpoint before basePath bootstrap finishes", async () => {
107-const fetchMock = vi.fn().mockResolvedValue({
108-ok: true,
109-json: async () => ({ avatarUrl: "/avatar/main" }),
107+const createObjectURL = vi.fn(() => "blob:local-avatar");
108+const revokeObjectURL = vi.fn();
109+vi.stubGlobal(
110+"URL",
111+class extends URL {
112+static createObjectURL = createObjectURL;
113+static revokeObjectURL = revokeObjectURL;
114+},
115+);
116+const fetchMock = vi.fn((input: string | URL | Request) => {
117+const url = requestUrl(input);
118+if (url === "/avatar/main?meta=1") {
119+return Promise.resolve({
120+ok: true,
121+json: async () => ({ avatarUrl: "/avatar/main" }),
122+});
123+}
124+if (url === "/avatar/main") {
125+return Promise.resolve({
126+ok: true,
127+blob: async () => new Blob(["avatar"]),
128+});
129+}
130+throw new Error(`Unexpected avatar URL: ${url}`);
110131});
111132vi.stubGlobal("fetch", fetchMock as unknown as typeof fetch);
112133@@ -117,7 +138,17 @@ describe("refreshChatAvatar", () => {
117138"/avatar/main?meta=1",
118139expect.objectContaining({ method: "GET" }),
119140);
120-expect(host.chatAvatarUrl).toBe("/avatar/main");
141+expect(fetchMock).toHaveBeenCalledWith(
142+"/avatar/main",
143+expect.objectContaining({ method: "GET" }),
144+);
145+const avatarFetchInit = (
146+fetchMock.mock.calls as Array<[string | URL | Request, RequestInit?]>
147+)[1]?.[1];
148+expect(avatarFetchInit).not.toHaveProperty("headers");
149+expect(createObjectURL).toHaveBeenCalledTimes(1);
150+expect(revokeObjectURL).not.toHaveBeenCalled();
151+expect(host.chatAvatarUrl).toBe("blob:local-avatar");
121152});
122153123154it("prefers the paired device token for avatar metadata and local avatar URLs", async () => {
@@ -261,6 +292,15 @@ describe("refreshChatAvatar", () => {
261292});
262293263294it("ignores stale avatar responses after switching sessions", async () => {
295+const createObjectURL = vi.fn(() => "blob:ops-avatar");
296+const revokeObjectURL = vi.fn();
297+vi.stubGlobal(
298+"URL",
299+class extends URL {
300+static createObjectURL = createObjectURL;
301+static revokeObjectURL = revokeObjectURL;
302+},
303+);
264304const mainRequest = createDeferred<{ avatarUrl?: string }>();
265305const opsRequest = createDeferred<{ avatarUrl?: string }>();
266306const fetchMock = vi.fn((input: string | URL | Request) => {
@@ -277,6 +317,12 @@ describe("refreshChatAvatar", () => {
277317json: async () => opsRequest.promise,
278318});
279319}
320+if (url === "/avatar/ops") {
321+return Promise.resolve({
322+ok: true,
323+blob: async () => new Blob(["avatar"]),
324+});
325+}
280326throw new Error(`Unexpected avatar URL: ${url}`);
281327});
282328vi.stubGlobal("fetch", fetchMock as unknown as typeof fetch);
@@ -294,7 +340,8 @@ describe("refreshChatAvatar", () => {
294340opsRequest.resolve({ avatarUrl: "/avatar/ops" });
295341await secondRefresh;
296342297-expect(host.chatAvatarUrl).toBe("/avatar/ops");
343+expect(createObjectURL).toHaveBeenCalledTimes(1);
344+expect(host.chatAvatarUrl).toBe("blob:ops-avatar");
298345expect(fetchMock).toHaveBeenNthCalledWith(
2993461,
300347"/avatar/main?meta=1",
@@ -305,6 +352,11 @@ describe("refreshChatAvatar", () => {
305352"/avatar/ops?meta=1",
306353expect.objectContaining({ method: "GET" }),
307354);
355+expect(fetchMock).toHaveBeenNthCalledWith(
356+3,
357+"/avatar/ops",
358+expect.objectContaining({ method: "GET" }),
359+);
308360});
309361});
310362此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。