// The Lucia project. // Copyright 2026-2026 DSP, inc. All rights reserved. // Authors: // imacat.yang@dsp.im (imacat), 2026/03/05 import { describe, it, expect, beforeEach, vi } from "vitest"; import { setActivePinia, createPinia } from "pinia"; vi.mock("@/module/apiError.js", () => ({ default: vi.fn(), })); const { mockGet, mockPost, mockPut, mockDelete } = vi.hoisted(() => ({ mockGet: vi.fn(), mockPost: vi.fn(), mockPut: vi.fn(), mockDelete: vi.fn(), })); vi.mock("@/api/client.js", () => ({ default: { get: mockGet, post: mockPost, put: mockPut, delete: mockDelete }, })); // Mock login store to avoid its side effects vi.mock("@/stores/login", () => { const { defineStore } = require("pinia"); return { useLoginStore: defineStore("loginStore", { state: () => ({ userData: { username: "currentUser", name: "Current" }, }), actions: { getUserData: vi.fn(), }, }), }; }); import { useAcctMgmtStore } from "@/stores/acctMgmt"; describe("acctMgmtStore", () => { let store; beforeEach(() => { setActivePinia(createPinia()); store = useAcctMgmtStore(); vi.clearAllMocks(); }); it("has correct default state", () => { expect(store.allUserAccountList).toEqual([]); expect(store.isAcctMenuOpen).toBe(false); }); describe("menu actions", () => { it("openAcctMenu sets true", () => { store.openAcctMenu(); expect(store.isAcctMenuOpen).toBe(true); }); it("closeAcctMenu sets false", () => { store.openAcctMenu(); store.closeAcctMenu(); expect(store.isAcctMenuOpen).toBe(false); }); it("toggleIsAcctMenuOpen toggles", () => { store.toggleIsAcctMenuOpen(); expect(store.isAcctMenuOpen).toBe(true); store.toggleIsAcctMenuOpen(); expect(store.isAcctMenuOpen).toBe(false); }); }); describe("setCurrentViewingUser", () => { it("finds user by username", () => { store.allUserAccountList = [ { username: "alice", name: "Alice", detail: {} }, { username: "bob", name: "Bob", detail: {} }, ]; store.setCurrentViewingUser("bob"); expect(store.currentViewingUser.name).toBe("Bob"); }); }); describe("clearCurrentViewingUser", () => { it("resets to empty user", () => { store.currentViewingUser = { username: "test", detail: {} }; store.clearCurrentViewingUser(); expect(store.currentViewingUser.username).toBe(""); }); }); describe("createNewAccount", () => { it("posts to /api/users and sets flag on success", async () => { mockPost.mockResolvedValue({ status: 200 }); const user = { username: "newuser", password: "pass" }; await store.createNewAccount(user); expect(mockPost).toHaveBeenCalledWith("/api/users", user); expect(store.isOneAccountJustCreate).toBe(true); expect(store.justCreateUsername).toBe("newuser"); }); }); describe("deleteAccount", () => { it("returns true on success", async () => { mockDelete.mockResolvedValue({ status: 200 }); const result = await store.deleteAccount("alice"); expect(mockDelete).toHaveBeenCalledWith("/api/users/alice"); expect(result).toBe(true); }); it("encodes special characters in username", async () => { mockDelete.mockResolvedValue({ status: 200 }); await store.deleteAccount("user@domain/name"); expect(mockDelete).toHaveBeenCalledWith( "/api/users/user%40domain%2Fname", ); }); it("returns false on error", async () => { mockDelete.mockRejectedValue(new Error("fail")); const result = await store.deleteAccount("alice"); expect(result).toBe(false); }); }); describe("editAccount", () => { it("puts edited data", async () => { mockPut.mockResolvedValue({ status: 200 }); const detail = { username: "alice", password: "newpw", name: "Alice", is_active: true, }; const result = await store.editAccount("alice", detail); expect(mockPut).toHaveBeenCalledWith( "/api/users/alice", expect.objectContaining({ password: "newpw" }), ); expect(result).toBe(true); }); }); describe("addRoleToUser", () => { it("puts role assignment", async () => { mockPut.mockResolvedValue({ status: 200 }); const result = await store.addRoleToUser("alice", "admin"); expect(mockPut).toHaveBeenCalledWith("/api/users/alice/roles/admin"); expect(result).toBe(true); }); it("encodes special characters in username and role", async () => { mockPut.mockResolvedValue({ status: 200 }); await store.addRoleToUser("user@org", "role/special"); expect(mockPut).toHaveBeenCalledWith( "/api/users/user%40org/roles/role%2Fspecial", ); }); }); describe("deleteRoleToUser", () => { it("deletes role", async () => { mockDelete.mockResolvedValue({ status: 200 }); const result = await store.deleteRoleToUser("alice", "admin"); expect(mockDelete).toHaveBeenCalledWith("/api/users/alice/roles/admin"); expect(result).toBe(true); }); }); describe("getUserDetail", () => { it("fetches user and sets admin flag", async () => { mockGet.mockResolvedValue({ status: 200, data: { username: "alice", roles: [{ code: "admin" }], }, }); const result = await store.getUserDetail("alice"); expect(result).toBe(true); expect(store.currentViewingUser.is_admin).toBe(true); }); it("returns false on error", async () => { mockGet.mockRejectedValue(new Error("not found")); const result = await store.getUserDetail("ghost"); expect(result).toBe(false); }); }); describe("hover state actions", () => { beforeEach(() => { store.allUserAccountList = [ { username: "alice", isDeleteHovered: false, isRowHovered: false, isEditHovered: false, isDetailHovered: false, }, ]; }); it("changeIsDeleteHoveredByUser", () => { store.changeIsDeleteHoveredByUser("alice", true); expect(store.allUserAccountList[0].isDeleteHovered).toBe(true); }); it("changeIsRowHoveredByUser", () => { store.changeIsRowHoveredByUser("alice", true); expect(store.allUserAccountList[0].isRowHovered).toBe(true); }); it("changeIsEditHoveredByUser", () => { store.changeIsEditHoveredByUser("alice", true); expect(store.allUserAccountList[0].isEditHovered).toBe(true); }); it("changeIsDetailHoveredByUser", () => { store.changeIsDetailHoveredByUser("alice", true); expect(store.allUserAccountList[0].isDetailHovered).toBe(true); }); }); it("resetJustCreateFlag resets flag", () => { store.isOneAccountJustCreate = true; store.resetJustCreateFlag(); expect(store.isOneAccountJustCreate).toBe(false); }); it("setShouldUpdateList sets boolean", () => { store.setShouldUpdateList(true); expect(store.shouldUpdateList).toBe(true); }); it("updateSingleAccountPiniaState updates user", () => { store.allUserAccountList = [{ username: "alice", name: "Old" }]; store.updateSingleAccountPiniaState({ username: "alice", name: "New", }); expect(store.allUserAccountList[0].name).toBe("New"); }); });