优化后台界面与无操作退出体验
This commit is contained in:
@@ -9,10 +9,9 @@ vi.mock("../router", () => ({
|
||||
|
||||
vi.mock("../api/authClient", () => ({
|
||||
extendToken: vi.fn(),
|
||||
unlockSession: vi.fn(),
|
||||
}));
|
||||
|
||||
describe("session manager idle recovery", () => {
|
||||
describe("session manager idle logout", () => {
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
vi.useFakeTimers();
|
||||
@@ -50,37 +49,47 @@ describe("session manager idle recovery", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("locks instead of refreshing activity after long inactivity when user activity resumes", async () => {
|
||||
it("shows a timeout warning one minute before automatic logout", async () => {
|
||||
vi.setSystemTime(new Date("2026-03-10T01:00:00.000Z"));
|
||||
const { useSessionStore } = await import("../store/session");
|
||||
const { IDLE_TIMEOUT_MINUTES, AUTO_LOGOUT_TIMEOUT_HOURS, markUserActive } = await import("./sessionManager");
|
||||
const { IDLE_TIMEOUT_MINUTES, TIMEOUT_WARNING_SECONDS, initSessionManager } = await import("./sessionManager");
|
||||
const session = useSessionStore();
|
||||
const oldTs = Date.now() - ((IDLE_TIMEOUT_MINUTES * 60 - TIMEOUT_WARNING_SECONDS) * 1000);
|
||||
|
||||
session.recordUserActivity(oldTs);
|
||||
initSessionManager();
|
||||
|
||||
expect(session.timeoutWarningVisible).toBe(true);
|
||||
expect(session.timeoutAt).toBe(oldTs + IDLE_TIMEOUT_MINUTES * 60 * 1000);
|
||||
});
|
||||
|
||||
it("logs out after long inactivity when user activity resumes", async () => {
|
||||
vi.setSystemTime(new Date("2026-03-10T01:00:00.000Z"));
|
||||
const { useSessionStore } = await import("../store/session");
|
||||
const router = (await import("../router")).default;
|
||||
const { IDLE_TIMEOUT_MINUTES, LOGOUT_REASON_TIMEOUT, markUserActive } = await import("./sessionManager");
|
||||
const session = useSessionStore();
|
||||
const oldTs = Date.now() - (IDLE_TIMEOUT_MINUTES * 60 * 1000 + 1_000);
|
||||
|
||||
session.recordUserActivity(oldTs);
|
||||
session.recordNetworkActivity(oldTs);
|
||||
|
||||
markUserActive(Date.now());
|
||||
|
||||
expect(session.locked).toBe(true);
|
||||
expect(session.lockReason).toBe("idle");
|
||||
expect(session.lockAutoLogoutDeadlineAt).toBe(oldTs + AUTO_LOGOUT_TIMEOUT_HOURS * 60 * 60 * 1000);
|
||||
expect(window.sessionStorage.getItem("ctms_logout_reason")).toBe(LOGOUT_REASON_TIMEOUT);
|
||||
expect(router.replace).toHaveBeenCalledWith("/login");
|
||||
});
|
||||
|
||||
it("locks instead of refreshing activity after long inactivity when network activity resumes", async () => {
|
||||
it("clears the timeout warning when user activity resumes", async () => {
|
||||
vi.setSystemTime(new Date("2026-03-10T01:00:00.000Z"));
|
||||
const { useSessionStore } = await import("../store/session");
|
||||
const { IDLE_TIMEOUT_MINUTES, AUTO_LOGOUT_TIMEOUT_HOURS, markNetworkActive } = await import("./sessionManager");
|
||||
const { markUserActive } = await import("./sessionManager");
|
||||
const session = useSessionStore();
|
||||
const oldTs = Date.now() - (IDLE_TIMEOUT_MINUTES * 60 * 1000 + 1_000);
|
||||
|
||||
session.recordUserActivity(oldTs);
|
||||
session.recordNetworkActivity(oldTs);
|
||||
session.showTimeoutWarning(Date.now() + 60_000);
|
||||
|
||||
markNetworkActive(Date.now());
|
||||
markUserActive(Date.now());
|
||||
|
||||
expect(session.locked).toBe(true);
|
||||
expect(session.lockReason).toBe("idle");
|
||||
expect(session.lockAutoLogoutDeadlineAt).toBe(oldTs + AUTO_LOGOUT_TIMEOUT_HOURS * 60 * 60 * 1000);
|
||||
expect(session.timeoutWarningVisible).toBe(false);
|
||||
expect(session.timeoutAt).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user