Skip to content

Commit 39aff8a

Browse files
cyfung1031CodFrm
andauthored
♻️ 删除 uint8Array 重复封装 (#1340)
* 删除 uint8Array 重复封装 * 添加 ResourceService.loadByUrl 单元测试 --------- Co-authored-by: 王一之 <yz@ggnb.top>
1 parent 2f0e8d9 commit 39aff8a

File tree

3 files changed

+100
-2
lines changed

3 files changed

+100
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ yarn.lock
3636
.claude
3737

3838
CLAUDE.md
39+
.omc
3940

4041
test-results
4142
playwright-report
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { initTestEnv } from "@Tests/utils";
2+
import { ResourceService } from "./resource";
3+
import { vi, describe, it, expect, beforeEach } from "vitest";
4+
import type { Group } from "@Packages/message/server";
5+
import type { IMessageQueue } from "@Packages/message/message_queue";
6+
7+
initTestEnv();
8+
9+
// mock fetch
10+
const mockFetch = vi.fn();
11+
vi.stubGlobal("fetch", mockFetch);
12+
13+
// 创建文本 blob 和二进制 blob 的辅助函数
14+
function textBlob(content: string, contentType = "text/plain") {
15+
return new Blob([content], { type: contentType });
16+
}
17+
18+
function binaryBlob(bytes: number[]) {
19+
return new Blob([new Uint8Array(bytes)], { type: "application/octet-stream" });
20+
}
21+
22+
function mockResponse(blob: Blob, status = 200, contentType?: string) {
23+
return {
24+
status,
25+
blob: () => Promise.resolve(blob),
26+
headers: new Headers(contentType ? { "content-type": contentType } : {}),
27+
} as unknown as Response;
28+
}
29+
30+
describe("ResourceService - loadByUrl", () => {
31+
let service: ResourceService;
32+
33+
beforeEach(() => {
34+
vi.clearAllMocks();
35+
const mockGroup = {} as Group;
36+
const mockMQ = {} as IMessageQueue;
37+
service = new ResourceService(mockGroup, mockMQ);
38+
// calculateHash 不影响核心逻辑,直接 mock
39+
vi.spyOn(service, "calculateHash").mockResolvedValue({
40+
md5: "mock-md5",
41+
sha1: "",
42+
sha256: "",
43+
sha384: "",
44+
sha512: "",
45+
});
46+
});
47+
48+
it("加载文本资源(require)时应设置 content", async () => {
49+
const jsCode = "console.log('hello');";
50+
mockFetch.mockResolvedValue(mockResponse(textBlob(jsCode), 200, "application/javascript; charset=utf-8"));
51+
52+
const res = await service.loadByUrl("https://example.com/lib.js", "require");
53+
54+
expect(res.url).toBe("https://example.com/lib.js");
55+
expect(res.content).toBeTruthy();
56+
expect(res.contentType).toBe("application/javascript");
57+
expect(res.base64).toBeTruthy();
58+
expect(res.type).toBe("require");
59+
});
60+
61+
it("加载文本资源(resource)时应通过 blob.text() 设置 content", async () => {
62+
const text = "plain text content";
63+
mockFetch.mockResolvedValue(mockResponse(textBlob(text), 200, "text/plain"));
64+
65+
const res = await service.loadByUrl("https://example.com/data.txt", "resource");
66+
67+
expect(res.content).toBe(text);
68+
expect(res.type).toBe("resource");
69+
});
70+
71+
it("加载二进制资源时 content 应为空", async () => {
72+
// 包含 null 字节的二进制数据,isText 会返回 false
73+
const bytes = [0x89, 0x50, 0x4e, 0x47, 0x00, 0x00, 0x00, 0x00];
74+
mockFetch.mockResolvedValue(mockResponse(binaryBlob(bytes), 200, "image/png"));
75+
76+
const res = await service.loadByUrl("https://example.com/img.png", "resource");
77+
78+
expect(res.content).toBe("");
79+
expect(res.base64).toBeTruthy();
80+
expect(res.contentType).toBe("image/png");
81+
});
82+
83+
it("响应非200时应抛出异常", async () => {
84+
mockFetch.mockResolvedValue(mockResponse(textBlob(""), 404));
85+
86+
await expect(service.loadByUrl("https://example.com/404", "require")).rejects.toThrow(
87+
"resource response status not 200: 404"
88+
);
89+
});
90+
91+
it("没有 content-type 时应默认为 application/octet-stream", async () => {
92+
mockFetch.mockResolvedValue(mockResponse(textBlob("data"), 200));
93+
94+
const res = await service.loadByUrl("https://example.com/noct", "resource");
95+
96+
expect(res.contentType).toBe("application/octet-stream");
97+
});
98+
});

src/app/service/service_worker/resource.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ export class ResourceService {
264264
throw new Error(`resource response status not 200: ${resp.status}`);
265265
}
266266
const data = await resp.blob();
267-
const [hash, arrayBuffer, base64] = await Promise.all([
267+
const [hash, uint8Array, base64] = await Promise.all([
268268
this.calculateHash(data),
269269
blobToUint8Array(data),
270270
blobToBase64(data),
@@ -280,7 +280,6 @@ export class ResourceService {
280280
type,
281281
createtime: Date.now(),
282282
};
283-
const uint8Array = new Uint8Array(arrayBuffer);
284283
if (isText(uint8Array)) {
285284
if (type === "require" || type === "require-css") {
286285
resource.content = await readBlobContent(data, contentType); // @require和@require-css 是会转换成代码运行的,可以进行解码

0 commit comments

Comments
 (0)