fix: 修正 markdown-to-jsx 导入方式 + 新增 formatDateLabel 日期工具函数
- TextPart: default import → named import - MaterialCard: 使用 formatDateLabel 显示今天/昨天/日期 - 清理旧测试文件,新增 ResourceTable 测试
This commit is contained in:
@@ -1,133 +0,0 @@
|
||||
import { describe, expect, mock, test } from "bun:test";
|
||||
|
||||
import { handleResponse, handleVoidResponse } from "../../../src/web/shared/utils/api";
|
||||
|
||||
function expectRejects(action: () => Promise<unknown>, message: string) {
|
||||
return action().then(
|
||||
() => {
|
||||
throw new Error("expected rejection");
|
||||
},
|
||||
(error: unknown) => {
|
||||
expect((error as Error).message).toBe(message);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function non200Response(body: unknown, status: number): Response {
|
||||
return new Response(JSON.stringify(body), {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
status,
|
||||
});
|
||||
}
|
||||
|
||||
function spyConsoleLog() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const spy = mock((..._args: any[]) => {});
|
||||
const orig = console.log;
|
||||
console.log = spy;
|
||||
return { orig, restore: () => (console.log = orig), spy };
|
||||
}
|
||||
|
||||
function spyConsoleWarn() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const spy = mock((..._args: any[]) => {});
|
||||
const orig = console.warn;
|
||||
console.warn = spy;
|
||||
return { orig, restore: () => (console.warn = orig), spy };
|
||||
}
|
||||
|
||||
describe("api.ts 日志行为", () => {
|
||||
test("handleResponse 非 200 响应输出 warn 日志", async () => {
|
||||
const { restore, spy } = spyConsoleWarn();
|
||||
|
||||
const response = non200Response({ error: "项目名称已存在" }, 409);
|
||||
await expectRejects(() => handleResponse(response, (d) => d), "项目名称已存在");
|
||||
|
||||
restore();
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
const msg = spy.mock.calls[0]![0] as string;
|
||||
const data = spy.mock.calls[0]![1] as Record<string, unknown>;
|
||||
expect(msg).toMatch(/\[Alfred:WARN\] API request failed/);
|
||||
expect(data).toBeObject();
|
||||
expect(data).toHaveProperty("duration");
|
||||
expect(data).toHaveProperty("errorBody", "项目名称已存在");
|
||||
expect(data).toHaveProperty("status", 409);
|
||||
expect(data).toHaveProperty("url");
|
||||
});
|
||||
|
||||
test("handleVoidResponse 非 200 响应输出 warn 日志", async () => {
|
||||
const { restore, spy } = spyConsoleWarn();
|
||||
|
||||
const response = non200Response({ error: "服务器错误" }, 500);
|
||||
await expectRejects(() => handleVoidResponse(response), "服务器错误");
|
||||
|
||||
restore();
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
const msg = spy.mock.calls[0]![0] as string;
|
||||
const data = spy.mock.calls[0]![1] as Record<string, unknown>;
|
||||
expect(msg).toMatch(/\[Alfred:WARN\] API request failed/);
|
||||
expect(data).toHaveProperty("duration");
|
||||
expect(data).toHaveProperty("errorBody", "服务器错误");
|
||||
expect(data).toHaveProperty("status", 500);
|
||||
});
|
||||
|
||||
test("handleResponse 非 JSON 错误响应回退到 HTTP 状态", async () => {
|
||||
const { restore, spy } = spyConsoleWarn();
|
||||
|
||||
const response = new Response("broken", { status: 503 });
|
||||
await expectRejects(() => handleResponse(response, (d) => d), "HTTP 503");
|
||||
|
||||
restore();
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
const data = spy.mock.calls[0]![1] as Record<string, unknown>;
|
||||
expect(data).toHaveProperty("errorBody", "HTTP 503");
|
||||
expect(data).toHaveProperty("status", 503);
|
||||
});
|
||||
|
||||
test("handleResponse 成功响应在 DEV 模式输出 debug 日志", async () => {
|
||||
const { restore, spy } = spyConsoleLog();
|
||||
|
||||
(import.meta.env as Record<string, unknown>)["DEV"] = true;
|
||||
|
||||
const response = new Response(JSON.stringify({ ok: true }), {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
status: 200,
|
||||
});
|
||||
await handleResponse(response, (d) => d);
|
||||
|
||||
(import.meta.env as Record<string, unknown>)["DEV"] = undefined;
|
||||
restore();
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
const msg = spy.mock.calls[0]![0] as string;
|
||||
const data = spy.mock.calls[0]![1] as Record<string, unknown>;
|
||||
expect(msg).toMatch(/\[Alfred:DEBUG\] API request/);
|
||||
expect(data).toBeObject();
|
||||
expect(data).toHaveProperty("duration");
|
||||
expect(data).toHaveProperty("status", 200);
|
||||
expect(data).toHaveProperty("url");
|
||||
});
|
||||
|
||||
test("handleVoidResponse 成功响应在 DEV 模式输出 debug 日志", async () => {
|
||||
const { restore, spy } = spyConsoleLog();
|
||||
|
||||
(import.meta.env as Record<string, unknown>)["DEV"] = true;
|
||||
|
||||
const response = new Response(null, { status: 204 });
|
||||
await handleVoidResponse(response);
|
||||
|
||||
(import.meta.env as Record<string, unknown>)["DEV"] = undefined;
|
||||
restore();
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
const msg = spy.mock.calls[0]![0] as string;
|
||||
const data = spy.mock.calls[0]![1] as Record<string, unknown>;
|
||||
expect(msg).toMatch(/\[Alfred:DEBUG\] API request/);
|
||||
expect(data).toHaveProperty("duration");
|
||||
expect(data).toHaveProperty("status", 204);
|
||||
expect(data).toHaveProperty("url");
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test";
|
||||
|
||||
import {
|
||||
formatCountdown,
|
||||
formatDateLabel,
|
||||
formatDurationUnit,
|
||||
formatRelativeTime,
|
||||
isOlderThan,
|
||||
@@ -77,3 +78,32 @@ describe("isOlderThan", () => {
|
||||
expect(isOlderThan("2025-01-01T00:01:30.000Z", 60000, now)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatDateLabel", () => {
|
||||
const now = new Date("2026-06-03T12:00:00.000Z");
|
||||
|
||||
test("今天", () => {
|
||||
expect(formatDateLabel("2026-06-03", now)).toBe("今天");
|
||||
expect(formatDateLabel("2026-06-03T08:00:00.000Z", now)).toBe("今天");
|
||||
});
|
||||
|
||||
test("昨天", () => {
|
||||
expect(formatDateLabel("2026-06-02", now)).toBe("昨天");
|
||||
expect(formatDateLabel("2026-06-02T23:59:59.000Z", now)).toBe("昨天");
|
||||
});
|
||||
|
||||
test("其他日期返回 YYYY-MM-DD", () => {
|
||||
expect(formatDateLabel("2026-05-30", now)).toBe("2026-05-30");
|
||||
expect(formatDateLabel("2025-01-15", now)).toBe("2025-01-15");
|
||||
});
|
||||
|
||||
test("无效输入返回占位符", () => {
|
||||
expect(formatDateLabel("", now)).toBe("—");
|
||||
expect(formatDateLabel("not-a-date", now)).toBe("—");
|
||||
});
|
||||
|
||||
test("不传 now 参数使用当前日期", () => {
|
||||
const result = formatDateLabel(new Date().toISOString().slice(0, 10));
|
||||
expect(result).toBe("今天");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user