191 lines
5.0 KiB
TypeScript
191 lines
5.0 KiB
TypeScript
import { describe, expect, mock, test } from "bun:test";
|
|
import { act, createElement, useState } from "react";
|
|
|
|
import type { Logger } from "../../../src/web/utils/logger";
|
|
|
|
import { useLogger } from "../../../src/web/hooks/use-logger";
|
|
import { renderWithProviders } from "../test-utils";
|
|
|
|
function BindingsHookTester({
|
|
bindings,
|
|
onMount,
|
|
}: {
|
|
bindings?: Record<string, unknown>;
|
|
onMount: (logger: Logger) => void;
|
|
}) {
|
|
const logger = useLogger(bindings);
|
|
onMount(logger);
|
|
return null;
|
|
}
|
|
|
|
function HookTester({ onMount }: { onMount: (logger: Logger) => void }) {
|
|
const logger = useLogger();
|
|
onMount(logger);
|
|
return null;
|
|
}
|
|
|
|
describe("useLogger", () => {
|
|
test("返回 Logger 实例含所有方法", () => {
|
|
let logger: Logger | undefined;
|
|
const onMount = (l: Logger) => {
|
|
logger = l;
|
|
};
|
|
|
|
renderWithProviders(createElement(HookTester, { onMount }));
|
|
|
|
expect(logger).toBeDefined();
|
|
expect(typeof logger!.debug).toBe("function");
|
|
expect(typeof logger!.info).toBe("function");
|
|
expect(typeof logger!.warn).toBe("function");
|
|
expect(typeof logger!.error).toBe("function");
|
|
expect(typeof logger!.child).toBe("function");
|
|
expect(typeof logger!.setLevel).toBe("function");
|
|
});
|
|
|
|
test("调用 logger.warn 时静默不抛异常", () => {
|
|
const warnSpy = mock(() => {});
|
|
const origWarn = console.warn;
|
|
console.warn = warnSpy;
|
|
|
|
let logger: Logger | undefined;
|
|
renderWithProviders(
|
|
createElement(HookTester, {
|
|
onMount: (l: Logger) => {
|
|
logger = l;
|
|
},
|
|
}),
|
|
);
|
|
|
|
expect(() => logger!.warn("测试警告")).not.toThrow();
|
|
|
|
console.warn = origWarn;
|
|
expect(warnSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
test("调用 logger.error 时静默不抛异常", () => {
|
|
const errorSpy = mock(() => {});
|
|
const origError = console.error;
|
|
console.error = errorSpy;
|
|
|
|
let logger: Logger | undefined;
|
|
renderWithProviders(
|
|
createElement(HookTester, {
|
|
onMount: (l: Logger) => {
|
|
logger = l;
|
|
},
|
|
}),
|
|
);
|
|
|
|
expect(() => logger!.error("测试错误")).not.toThrow();
|
|
|
|
console.error = origError;
|
|
expect(errorSpy).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("useLogger bindings 参数", () => {
|
|
test("传入 bindings 返回带上下文前缀的 Logger", () => {
|
|
const spy = mock((..._args: unknown[]) => {});
|
|
const origWarn = console.warn;
|
|
console.warn = spy;
|
|
|
|
let logger: Logger | undefined;
|
|
renderWithProviders(
|
|
createElement(BindingsHookTester, {
|
|
bindings: { component: "TestComp" },
|
|
onMount: (l: Logger) => {
|
|
logger = l;
|
|
},
|
|
}),
|
|
);
|
|
|
|
logger!.warn("绑定测试");
|
|
|
|
console.warn = origWarn;
|
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
expect(spy.mock.calls[0]![0]).toMatch(/\[component=TestComp\]/);
|
|
});
|
|
|
|
test("无参调用与空 bindings 行为一致", () => {
|
|
let noBindingsLogger: Logger | undefined;
|
|
let emptyBindingsLogger: Logger | undefined;
|
|
|
|
const spy = mock((..._args: unknown[]) => {});
|
|
const origWarn = console.warn;
|
|
console.warn = spy;
|
|
|
|
renderWithProviders(
|
|
createElement(HookTester, {
|
|
onMount: (l: Logger) => {
|
|
noBindingsLogger = l;
|
|
},
|
|
}),
|
|
);
|
|
|
|
renderWithProviders(
|
|
createElement(BindingsHookTester, {
|
|
bindings: {},
|
|
onMount: (l: Logger) => {
|
|
emptyBindingsLogger = l;
|
|
},
|
|
}),
|
|
);
|
|
|
|
noBindingsLogger!.warn("a");
|
|
emptyBindingsLogger!.warn("b");
|
|
|
|
console.warn = origWarn;
|
|
expect(spy).toHaveBeenCalledTimes(2);
|
|
expect(spy.mock.calls[0]![0]).not.toMatch(/\[component=/);
|
|
expect(spy.mock.calls[1]![0]).not.toMatch(/\[component=/);
|
|
});
|
|
|
|
test("相同 bindings 值多次渲染返回同一 Logger 引用", () => {
|
|
const refs: Logger[] = [];
|
|
|
|
function StableTester() {
|
|
const logger = useLogger({ component: "Stable" });
|
|
const [, setTick] = useState(0);
|
|
refs.push(logger);
|
|
return createElement("button", {
|
|
onClick: () => setTick((t) => t + 1),
|
|
});
|
|
}
|
|
|
|
const result = renderWithProviders(createElement(StableTester));
|
|
const initialCount = refs.length;
|
|
|
|
act(() => {
|
|
result.getByRole("button").click();
|
|
});
|
|
act(() => {
|
|
result.getByRole("button").click();
|
|
});
|
|
|
|
expect(refs.length).toBeGreaterThan(initialCount);
|
|
for (let i = 1; i < refs.length; i++) {
|
|
expect(refs[i]).toBe(refs[0]);
|
|
}
|
|
});
|
|
|
|
test("bindings 值变化时返回新 Logger 引用", () => {
|
|
const refs: Logger[] = [];
|
|
let currentBindings: Record<string, unknown> = { component: "A" };
|
|
|
|
function DynamicTester() {
|
|
const logger = useLogger(currentBindings);
|
|
refs.push(logger);
|
|
return null;
|
|
}
|
|
|
|
const { rerender } = renderWithProviders(createElement(DynamicTester));
|
|
const countBefore = refs.length;
|
|
|
|
currentBindings = { component: "B" };
|
|
rerender(createElement(DynamicTester));
|
|
|
|
expect(refs.length).toBe(countBefore + 1);
|
|
expect(refs[refs.length - 1]).not.toBe(refs[0]);
|
|
});
|
|
});
|