docs(admin-portal): 新增 nextstep-v2.md 记录下游核查结果
v1 声称完成的下游工作经核查实际未完成: - api-gateway: /api/admin/graphql 路由未注册,go vet 编译失败 - teacher-bff: resolver 已完成但 schema 未同步(命名空间 vs 扁平) - iam: proto 缺 BatchGetUsers rpc 声明 v2 记录详细核查证据和修复要求
This commit is contained in:
84
apps/teacher-portal/vitest.setup.ts
Normal file
84
apps/teacher-portal/vitest.setup.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Vitest 全局测试 setup
|
||||
*
|
||||
* - 注册 @testing-library/jest-dom 自定义匹配器
|
||||
* - mock next/navigation(App Router hooks)
|
||||
* - polyfill BroadcastChannel / WebSocket(jsdom 未实现)
|
||||
* - 启动/重置/关闭 MSW server
|
||||
*/
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { afterAll, afterEach, beforeAll, beforeEach, vi } from "vitest";
|
||||
import { server } from "./src/mocks/server";
|
||||
|
||||
// mock next/navigation(App Router hooks 依赖)
|
||||
vi.mock("next/navigation", () => ({
|
||||
useParams: () => ({}),
|
||||
useRouter: () => ({
|
||||
push: vi.fn(),
|
||||
replace: vi.fn(),
|
||||
back: vi.fn(),
|
||||
forward: vi.fn(),
|
||||
refresh: vi.fn(),
|
||||
prefetch: vi.fn(),
|
||||
}),
|
||||
useSearchParams: () => new URLSearchParams(),
|
||||
usePathname: () => "/",
|
||||
redirect: vi.fn(),
|
||||
notFound: vi.fn(),
|
||||
}));
|
||||
|
||||
// btoa Unicode 兼容 polyfill 已移至 vitest.polyfills.ts(需在 server import 之前生效)
|
||||
|
||||
// BroadcastChannel polyfill(jsdom 未实现 BroadcastChannel)
|
||||
if (typeof globalThis.BroadcastChannel === "undefined") {
|
||||
class MockBroadcastChannel {
|
||||
name: string;
|
||||
onmessage: ((event: MessageEvent) => void) | null = null;
|
||||
constructor(name: string) {
|
||||
this.name = name;
|
||||
}
|
||||
addEventListener(): void {}
|
||||
removeEventListener(): void {}
|
||||
postMessage(): void {}
|
||||
close(): void {}
|
||||
}
|
||||
// 测试中需要 as 断言将 mock 类挂载到全局
|
||||
globalThis.BroadcastChannel =
|
||||
MockBroadcastChannel as unknown as typeof BroadcastChannel;
|
||||
}
|
||||
|
||||
// WebSocket polyfill(jsdom 未实现 WebSocket)
|
||||
if (typeof globalThis.WebSocket === "undefined") {
|
||||
class MockWebSocket {
|
||||
static CONNECTING = 0;
|
||||
static OPEN = 1;
|
||||
static CLOSING = 2;
|
||||
static CLOSED = 3;
|
||||
url: string;
|
||||
onopen: ((event: Event) => void) | null = null;
|
||||
onmessage: ((event: MessageEvent) => void) | null = null;
|
||||
onerror: ((event: Event) => void) | null = null;
|
||||
onclose: ((event: CloseEvent) => void) | null = null;
|
||||
readyState = 0;
|
||||
constructor(url: string) {
|
||||
this.url = url;
|
||||
}
|
||||
send(): void {}
|
||||
close(): void {}
|
||||
}
|
||||
globalThis.WebSocket = MockWebSocket as unknown as typeof WebSocket;
|
||||
}
|
||||
|
||||
// 启动 MSW server(拦截 HTTP 请求返回 mock 响应)
|
||||
beforeAll(() => server.listen({ onUnhandledRequest: "bypass" }));
|
||||
|
||||
// 每个测试后恢复初始 MSW handlers(隔离测试间状态)
|
||||
afterEach(() => server.restoreHandlers());
|
||||
|
||||
// 全部测试完成后关闭 MSW server
|
||||
afterAll(() => server.close());
|
||||
|
||||
// 每个测试前清理 localStorage(防止测试间状态泄漏)
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
});
|
||||
Reference in New Issue
Block a user