Files
ctms/frontend/src/views/admin/ProjectMembers.test.ts
T
2026-05-26 11:32:14 +08:00

47 lines
2.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
const readProjectMembers = () => readFileSync(resolve(__dirname, "./ProjectMembers.vue"), "utf8");
describe("ProjectMembers user directory access", () => {
it("does not load the admin-only global user directory", () => {
const source = readProjectMembers();
expect(source).not.toContain("fetchUsers");
expect(source).not.toContain("../../api/users");
expect(source).toContain('const canManageMembers = computed(() => permission.can("project.members.manage"));');
expect(source).toContain("if (!canManageMembers.value");
expect(source).toContain("return;");
expect(source).toContain('v-if="canManageMembers"');
expect(source).toContain("listMemberCandidates(projectId.value, { limit: 500 })");
});
it("uses the member API embedded user data when the global directory is unavailable", () => {
const source = readProjectMembers();
expect(source).toContain("users.value = members.value");
expect(source).toContain(".map((member) => member.user)");
expect(source).toContain("users.value.find((u) => u.id === m.user_id) || m.user");
});
it("prevents project managers from editing themselves or assigning higher roles", () => {
const source = readProjectMembers();
expect(source).toContain("const roleRank: Record<string, number>");
expect(source).toContain("if (row.user_id === auth.user?.id) return false;");
expect(source).toContain("if (row.user?.is_admin) return false;");
expect(source).toContain("const canAssignRole = (role: string)");
expect(source).toContain(':disabled="!canAssignRole(\'ADMIN\')"');
expect(source).toContain(':disabled="!canEditMember(scope.row)');
});
it("does not offer QA as a project member role preset", () => {
const source = readProjectMembers();
expect(source).not.toContain('value="QA"');
expect(source).not.toContain("canAssignRole('QA')");
expect(source).not.toContain("QA: 60");
});
});