2026-09-14 13:45:17 +08:00
|
|
|
|
// 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)) {
|
2026-09-18 00:05:20 +08:00
|
|
|
|
keys.forEach((k) => {
|
|
|
|
|
|
if (k in store) result[k] = store[k];
|
|
|
|
|
|
});
|
2026-09-14 13:45:17 +08:00
|
|
|
|
} else if (typeof keys === "string") {
|
|
|
|
|
|
if (keys in store) result[keys] = store[keys];
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Object.assign(result, store);
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
},
|
2026-09-18 00:05:20 +08:00
|
|
|
|
async set(items) {
|
|
|
|
|
|
Object.assign(store, items);
|
|
|
|
|
|
},
|
2026-09-14 13:45:17 +08:00
|
|
|
|
async remove(keys) {
|
|
|
|
|
|
if (Array.isArray(keys)) keys.forEach((k) => delete store[k]);
|
|
|
|
|
|
else delete store[keys];
|
|
|
|
|
|
},
|
2026-09-18 00:05:20 +08:00
|
|
|
|
_dump() {
|
|
|
|
|
|
return store;
|
|
|
|
|
|
},
|
2026-09-14 13:45:17 +08:00
|
|
|
|
});
|
|
|
|
|
|
return { local: makeArea(local), session: makeArea(session), localStore: local, sessionStore: session };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function loadEnvStore(storage) {
|
|
|
|
|
|
global.chrome = { storage };
|
2026-09-17 01:40:27 +08:00
|
|
|
|
delete require.cache[require.resolve("../dist/env-store.js")];
|
|
|
|
|
|
return require("../dist/env-store.js");
|
2026-09-14 13:45:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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: [] },
|
|
|
|
|
|
],
|
2026-09-18 00:05:20 +08:00
|
|
|
|
"e1",
|
2026-09-14 13:45:17 +08:00
|
|
|
|
);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
|
});
|
2026-09-14 14:40:59 +08:00
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
});
|
2026-09-14 13:45:17 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
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: [] },
|
|
|
|
|
|
],
|
2026-09-18 00:05:20 +08:00
|
|
|
|
"e1",
|
2026-09-14 13:45:17 +08:00
|
|
|
|
);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
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"]);
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|