// tests/env-store.test.js // 测试 env-store.js:环境 CRUD(数据存于 chrome.storage.session) // 运行:node --test tests/env-store.test.js const { describe, it, beforeEach } = require("node:test"); const assert = require("node:assert/strict"); // 内存版 storage,同时模拟 local 和 session function createMemoryStorage() { const local = {}; const session = {}; const makeArea = (store) => ({ async get(keys) { const result = {}; if (Array.isArray(keys)) { keys.forEach((k) => { if (k in store) result[k] = store[k]; }); } else if (typeof keys === "string") { if (keys in store) result[keys] = store[keys]; } else { Object.assign(result, store); } return result; }, async set(items) { Object.assign(store, items); }, async remove(keys) { if (Array.isArray(keys)) keys.forEach((k) => delete store[k]); else delete store[keys]; }, _dump() { return store; }, }); return { local: makeArea(local), session: makeArea(session), localStore: local, sessionStore: session }; } function loadEnvStore(storage) { global.chrome = { storage }; delete require.cache[require.resolve("../dist/env-store.js")]; return require("../dist/env-store.js"); } describe("env-store - 读写 session", () => { it("未解锁(session 空)时返回空环境", async () => { const storage = createMemoryStorage(); const EnvStore = loadEnvStore(storage); const { environments, activeEnvId } = await EnvStore.loadEnvironments(); assert.deepEqual(environments, []); assert.equal(activeEnvId, null); }); it("saveEnvironments / loadEnvironments 读写 session", async () => { const storage = createMemoryStorage(); const EnvStore = loadEnvStore(storage); const envs = [{ id: "e1", name: "个人", configs: [] }]; await EnvStore.saveEnvironments(envs, "e1"); const loaded = await EnvStore.loadEnvironments(); assert.equal(loaded.environments.length, 1); assert.equal(loaded.environments[0].name, "个人"); assert.equal(loaded.activeEnvId, "e1"); // 数据落在 session,不在 local assert.ok(storage.sessionStore.environments); assert.equal(storage.localStore.environments, undefined); }); }); describe("env-store - 环境 CRUD", () => { let EnvStore, storage; beforeEach(async () => { storage = createMemoryStorage(); EnvStore = loadEnvStore(storage); await EnvStore.saveEnvironments( [ { id: "e1", name: "个人", configs: [] }, { id: "e2", name: "测试", configs: [] }, { id: "e3", name: "生产", configs: [] }, ], "e1", ); }); it("createEnvironment 新增并激活", async () => { const env = await EnvStore.createEnvironment("客户A"); assert.equal(env.name, "客户A"); const { environments, activeEnvId } = await EnvStore.loadEnvironments(); assert.equal(environments.length, 4); assert.equal(activeEnvId, env.id); }); it("renameEnvironment", async () => { await EnvStore.renameEnvironment("e1", "个人-改"); const { environments } = await EnvStore.loadEnvironments(); assert.equal(environments[0].name, "个人-改"); }); it("deleteEnvironment 非当前环境,active 不变", async () => { await EnvStore.deleteEnvironment("e2"); const { environments, activeEnvId } = await EnvStore.loadEnvironments(); assert.equal(environments.length, 2); assert.equal(activeEnvId, "e1"); }); it("deleteEnvironment 当前环境,自动切到第一个", async () => { await EnvStore.deleteEnvironment("e1"); const { environments, activeEnvId } = await EnvStore.loadEnvironments(); assert.equal(environments.length, 2); assert.equal(activeEnvId, environments[0].id); }); it("deleteEnvironment 只剩一个时抛错", async () => { await EnvStore.deleteEnvironment("e1"); await EnvStore.deleteEnvironment("e2"); const { environments } = await EnvStore.loadEnvironments(); assert.equal(environments.length, 1); await assert.rejects(() => EnvStore.deleteEnvironment(environments[0].id), /至少保留一个环境/); }); it("setActiveEnv + getActiveEnv", async () => { await EnvStore.setActiveEnv("e3"); const env = await EnvStore.getActiveEnv(); assert.equal(env.id, "e3"); }); it("超过 5 个环境时抛错", async () => { // 已有 3 个,再加 2 个到上限 await EnvStore.createEnvironment("env4"); await EnvStore.createEnvironment("env5"); const { environments } = await EnvStore.loadEnvironments(); assert.equal(environments.length, 5); // 第 6 个应被拒绝 await assert.rejects(() => EnvStore.createEnvironment("env6"), /最多 5 个环境/); const after = await EnvStore.loadEnvironments(); assert.equal(after.environments.length, 5); }); }); describe("env-store - 配置 CRUD", () => { let EnvStore, storage; beforeEach(async () => { storage = createMemoryStorage(); EnvStore = loadEnvStore(storage); await EnvStore.saveEnvironments( [ { id: "e1", name: "个人", configs: [] }, { id: "e2", name: "测试", configs: [] }, ], "e1", ); }); it("saveConfigs / loadConfigs 读写当前环境", async () => { const cfg = { id: "c1", domain: "a.com", username: "u", password: "p" }; await EnvStore.saveConfigs([cfg]); const configs = await EnvStore.loadConfigs(); assert.equal(configs.length, 1); assert.equal(configs[0].domain, "a.com"); }); it("loadAllConfigs 扁平化并附带 envId/envName", async () => { await EnvStore.saveConfigs([{ id: "c1", domain: "a.com", username: "u1", password: "p1" }]); await EnvStore.setActiveEnv("e2"); await EnvStore.saveConfigs([{ id: "c2", domain: "b.com", username: "u2", password: "p2" }]); const all = await EnvStore.loadAllConfigs(); assert.equal(all.length, 2); assert.ok(all.every((c) => c.envId && c.envName)); assert.deepEqual(all.map((c) => c.domain).sort(), ["a.com", "b.com"]); }); it("deleteEnvironment 清理 local 中该环境的失败计数", async () => { // 失败计数存于 local await storage.local.set({ loginAttempts: { "e2::a.com": { count: 3, lastAttempt: Date.now() }, "other::b.com": { count: 1, lastAttempt: Date.now() }, }, }); await EnvStore.deleteEnvironment("e2"); const attempts = (await storage.local.get("loginAttempts")).loginAttempts; assert.equal(attempts["e2::a.com"], undefined); assert.ok(attempts["other::b.com"]); }); });