style: 优化个人中心和偏好设置弹窗样式,重构工作入口为精致分屏布局并移除首字徽标
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { DESKTOP_SERVER_URL_KEY } from "./desktopServerConfig";
|
||||
import {
|
||||
clearLoginCredential,
|
||||
getSavedLoginCredential,
|
||||
saveLoginCredential,
|
||||
} from "./savedLoginCredentials";
|
||||
|
||||
const invokeMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("@tauri-apps/api/core", () => ({
|
||||
invoke: invokeMock,
|
||||
}));
|
||||
|
||||
const SERVER_ORIGIN = "https://ctms.example.com/";
|
||||
|
||||
const createStorage = (): Storage => {
|
||||
const data = new Map<string, string>();
|
||||
return {
|
||||
get length() {
|
||||
return data.size;
|
||||
},
|
||||
clear: () => data.clear(),
|
||||
getItem: (key) => data.get(key) ?? null,
|
||||
key: (index) => Array.from(data.keys())[index] ?? null,
|
||||
removeItem: (key) => data.delete(key),
|
||||
setItem: (key, value) => {
|
||||
data.set(key, String(value));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
describe("saved login credentials", () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date("2026-07-08T00:00:00.000Z"));
|
||||
Object.defineProperty(window, "localStorage", { value: createStorage(), configurable: true });
|
||||
localStorage.clear();
|
||||
invokeMock.mockReset();
|
||||
Reflect.deleteProperty(window, "__TAURI_INTERNALS__");
|
||||
Reflect.deleteProperty(window, "PasswordCredential");
|
||||
Reflect.deleteProperty(navigator, "credentials");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
localStorage.clear();
|
||||
Reflect.deleteProperty(window, "__TAURI_INTERNALS__");
|
||||
Reflect.deleteProperty(window, "PasswordCredential");
|
||||
Reflect.deleteProperty(navigator, "credentials");
|
||||
});
|
||||
|
||||
it("stores desktop remembered passwords in the system credential store", async () => {
|
||||
Object.defineProperty(window, "__TAURI_INTERNALS__", { value: {}, configurable: true });
|
||||
localStorage.setItem(DESKTOP_SERVER_URL_KEY, SERVER_ORIGIN);
|
||||
let stored = "";
|
||||
invokeMock.mockImplementation(async (command: string, args: any) => {
|
||||
if (command === "login_credential_set") {
|
||||
stored = args.credential;
|
||||
return undefined;
|
||||
}
|
||||
if (command === "login_credential_get") return stored;
|
||||
if (command === "login_credential_delete") {
|
||||
stored = "";
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
await expect(saveLoginCredential("Admin@Example.com", "secret-password")).resolves.toBe(true);
|
||||
|
||||
expect(invokeMock).toHaveBeenCalledWith("login_credential_set", {
|
||||
serverOrigin: SERVER_ORIGIN,
|
||||
credential: expect.any(String),
|
||||
});
|
||||
expect(JSON.parse(stored)).toMatchObject({
|
||||
version: 1,
|
||||
email: "admin@example.com",
|
||||
password: "secret-password",
|
||||
savedAt: Date.now(),
|
||||
});
|
||||
await expect(getSavedLoginCredential()).resolves.toEqual({
|
||||
email: "admin@example.com",
|
||||
password: "secret-password",
|
||||
});
|
||||
await expect(clearLoginCredential()).resolves.toBe(true);
|
||||
expect(invokeMock).toHaveBeenCalledWith("login_credential_delete", { serverOrigin: SERVER_ORIGIN });
|
||||
});
|
||||
|
||||
it("deletes malformed desktop remembered credentials", async () => {
|
||||
Object.defineProperty(window, "__TAURI_INTERNALS__", { value: {}, configurable: true });
|
||||
localStorage.setItem(DESKTOP_SERVER_URL_KEY, SERVER_ORIGIN);
|
||||
invokeMock.mockImplementation(async (command: string) => {
|
||||
if (command === "login_credential_get") return JSON.stringify({ password: "missing-email" });
|
||||
return undefined;
|
||||
});
|
||||
|
||||
await expect(getSavedLoginCredential()).resolves.toBeNull();
|
||||
|
||||
expect(invokeMock).toHaveBeenCalledWith("login_credential_delete", { serverOrigin: SERVER_ORIGIN });
|
||||
});
|
||||
|
||||
it("uses browser credential management without writing passwords to localStorage", async () => {
|
||||
const storeMock = vi.fn();
|
||||
const preventSilentAccessMock = vi.fn();
|
||||
Object.defineProperty(window, "PasswordCredential", {
|
||||
configurable: true,
|
||||
value: class {
|
||||
id: string;
|
||||
password: string;
|
||||
constructor(data: { id: string; password: string }) {
|
||||
this.id = data.id;
|
||||
this.password = data.password;
|
||||
}
|
||||
},
|
||||
});
|
||||
Object.defineProperty(navigator, "credentials", {
|
||||
configurable: true,
|
||||
value: {
|
||||
get: vi.fn(async () => ({ id: "Browser@Example.com", password: "browser-secret" })),
|
||||
store: storeMock,
|
||||
preventSilentAccess: preventSilentAccessMock,
|
||||
},
|
||||
});
|
||||
|
||||
await expect(getSavedLoginCredential()).resolves.toEqual({
|
||||
email: "browser@example.com",
|
||||
password: "browser-secret",
|
||||
});
|
||||
await expect(saveLoginCredential("Browser@Example.com", "browser-secret")).resolves.toBe(true);
|
||||
await expect(clearLoginCredential()).resolves.toBe(true);
|
||||
|
||||
expect(storeMock).toHaveBeenCalledTimes(1);
|
||||
expect(preventSilentAccessMock).toHaveBeenCalledTimes(1);
|
||||
expect(JSON.stringify(localStorage)).not.toContain("browser-secret");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user