| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- // 会话回归测试:加载实际请求层和 store,以可控 HTTP 响应验证过期恢复,避免时间等待造成不稳定。
- import assert from "node:assert/strict";
- import { readFile } from "node:fs/promises";
- import ts from "typescript";
- import { createPinia, setActivePinia } from "pinia";
- const storage = new Map();
- globalThis.sessionStorage = {
- getItem: (key) => storage.get(key) ?? null,
- setItem: (key, value) => storage.set(key, value),
- removeItem: (key) => storage.delete(key),
- };
- let expired = 0;
- globalThis.window = {
- dispatchEvent: (event) => {
- if (event.type === "session-expired") expired++;
- },
- };
- // Node 不提供 Vite 的 import.meta.env;只替换构建时基地址,不改动被测函数。
- const asModule = (source) =>
- "data:text/javascript;base64," +
- Buffer.from(
- ts.transpileModule(source, {
- compilerOptions: { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.ES2022 },
- }).outputText,
- ).toString("base64");
- const apiSource = await readFile(new URL("../src/api.ts", import.meta.url), "utf8");
- const apiUrl = asModule(apiSource.replace("import.meta.env.VITE_API_BASE", '"/api/v1"'));
- const api = await import(apiUrl);
- const storeSource = await readFile(new URL("../src/store.ts", import.meta.url), "utf8");
- const { useSession } = await import(
- asModule(
- storeSource
- .replace('from "./api"', `from ${JSON.stringify(apiUrl)}`)
- .replace('from "pinia"', `from ${JSON.stringify(import.meta.resolve("pinia"))}`),
- )
- );
- setActivePinia(createPinia());
- const session = useSession();
- const oldTokens = { access_token: "expired-test-access", refresh_token: "old-test-refresh" };
- const newTokens = { access_token: "renewed-test-access", refresh_token: "rotated-test-refresh" };
- const result = (status, data) =>
- Response.json(status < 400 ? { data, message: "ok", request_id: "test" } : {
- error: { code: "UNAUTHORIZED", message: "测试过期凭据" }, request_id: "test",
- }, { status });
- api.saveTokens(oldTokens);
- let refreshes = 0;
- globalThis.fetch = async (url, options = {}) => {
- if (url.endsWith("/auth/refresh")) {
- refreshes++;
- assert.equal(JSON.parse(options.body).refresh_token, oldTokens.refresh_token);
- return result(200, newTokens);
- }
- return options.headers.get("Authorization") === `Bearer ${newTokens.access_token}`
- ? result(200, { id: 1, role: "employee" }) : result(401);
- };
- await session.load();
- assert.equal(session.user.id, 1);
- assert.equal(refreshes, 1);
- assert.equal(api.tokens().refresh_token, newTokens.refresh_token);
- console.log("PASS /auth/me 过期时自动刷新并恢复用户");
- api.saveTokens(oldTokens);
- refreshes = 0;
- await Promise.all([api.api("/audit"), api.api("/dashboard/stats")]);
- assert.equal(refreshes, 1);
- console.log("PASS 并发请求只轮换一次刷新令牌");
- api.saveTokens(oldTokens);
- refreshes = 0;
- await assert.rejects(api.api("/auth/login", "POST", { username: "test", password: "test" }), (error) => error.status === 401);
- assert.equal(refreshes, 0);
- console.log("PASS 登录失败不触发递归刷新");
- api.saveTokens(oldTokens);
- let revoked = false;
- globalThis.fetch = async (url, options = {}) => {
- if (url.endsWith("/auth/refresh")) return result(200, newTokens);
- if (url.endsWith("/auth/logout")) {
- assert.equal(JSON.parse(options.body).refresh_token, newTokens.refresh_token);
- assert.equal(options.headers.get("Authorization"), `Bearer ${newTokens.access_token}`);
- revoked = true;
- return result(200, { revoked: true });
- }
- return options.headers.get("Authorization") === `Bearer ${newTokens.access_token}`
- ? result(200, { id: 1, role: "employee" }) : result(401);
- };
- await session.logout();
- assert.equal(revoked, true);
- assert.equal(api.tokens().access_token, undefined);
- assert.equal(session.user, null);
- console.log("PASS 退出撤销轮换后的令牌并清理本地会话");
- api.saveTokens(oldTokens);
- expired = 0;
- let calls = 0;
- globalThis.fetch = async () => { calls++; return result(401); };
- await assert.rejects(api.api("/auth/me"), (error) => error.status === 401);
- assert.equal(calls, 2);
- assert.equal(expired, 1);
- assert.equal(api.tokens().access_token, undefined);
- console.log("PASS 刷新失败终止重试并通知登录页面");
|