Various QOL updates

This commit is contained in:
2026-05-28 05:58:56 +00:00
parent 2366847151
commit c6fbec6442
7 changed files with 711 additions and 185 deletions
+100 -77
View File
@@ -38,31 +38,23 @@ vi.mock("@/hooks/useCurrentOrganization", () => ({
}),
}));
vi.mock("@/lib/api", () => ({
api: {
zerotier: {
getNetwork: H.mockGetNetwork,
getNetworkMembers: H.mockGetNetworkMembers,
activateMembership: H.mockActivateMembership,
deactivateMembership: H.mockDeactivateMembership,
getNetworkPendingRequests: H.mockGetNetworkPendingRequests,
approveRequest: H.mockApproveRequest,
rejectRequest: H.mockRejectRequest,
vi.mock("@/lib/api", async (importOriginal) => {
const actual = await importOriginal<typeof import("@/lib/api")>();
return {
...actual,
api: {
zerotier: {
getNetwork: H.mockGetNetwork,
getNetworkMembers: H.mockGetNetworkMembers,
activateMembership: H.mockActivateMembership,
deactivateMembership: H.mockDeactivateMembership,
getNetworkPendingRequests: H.mockGetNetworkPendingRequests,
approveRequest: H.mockApproveRequest,
rejectRequest: H.mockRejectRequest,
},
},
},
ApiError: class ApiError extends Error {
code: number;
type: string;
details: Record<string, unknown>;
constructor(message: string, code: number, type: string, details: Record<string, unknown> = {}) {
super(message);
this.name = "ApiError";
this.code = code;
this.type = type;
this.details = details;
}
},
}));
};
});
vi.mock("@/hooks/use-toast", () => ({
useToast: () => ({
@@ -669,10 +661,12 @@ describe("NetworkManagementPage", () => {
device_id: "dev-laptop-1",
portal_network_id: "net-abc",
user_network_approval_id: null,
state: "active_authorized",
active: true,
status: "approved",
grant_type: "assigned",
granted_by_user_id: null,
justification: null,
join_seen: true,
currently_authorized: true,
approved_for_activation: true,
created_at: "2025-01-01T00:00:00Z",
updated_at: "2025-01-01T00:00:00Z",
deleted_at: null,
@@ -701,10 +695,12 @@ describe("NetworkManagementPage", () => {
device_id: "dev-desktop-1",
portal_network_id: "net-abc",
user_network_approval_id: null,
state: "joined_deauthorized",
active: false,
status: "approved",
grant_type: "assigned",
granted_by_user_id: null,
justification: null,
join_seen: false,
currently_authorized: false,
approved_for_activation: false,
created_at: "2025-02-01T00:00:00Z",
updated_at: "2025-02-01T00:00:00Z",
deleted_at: null,
@@ -718,10 +714,12 @@ describe("NetworkManagementPage", () => {
device_id: "dev-phone-1",
portal_network_id: "net-abc",
user_network_approval_id: null,
state: "approved_inactive",
active: false,
status: "approved",
grant_type: "assigned",
granted_by_user_id: null,
justification: null,
join_seen: true,
currently_authorized: false,
approved_for_activation: true,
created_at: "2025-03-01T00:00:00Z",
updated_at: "2025-03-01T00:00:00Z",
deleted_at: null,
@@ -735,10 +733,12 @@ describe("NetworkManagementPage", () => {
device_id: "dev-server-1",
portal_network_id: "net-abc",
user_network_approval_id: null,
state: "pending_request",
active: false,
status: "pending",
grant_type: "requested",
granted_by_user_id: null,
justification: null,
join_seen: false,
currently_authorized: false,
approved_for_activation: false,
created_at: "2025-04-01T00:00:00Z",
updated_at: "2025-04-01T00:00:00Z",
deleted_at: null,
@@ -966,7 +966,7 @@ describe("NetworkManagementPage", () => {
// ── Device Details ──────────────────────────────────────────────────────────
test("renders device state badge for active_authorized membership", async () => {
test("renders Active badge for active_authorized membership", async () => {
await setupMembersTab([MEMBERSHIP_AUTHORIZED_WITH_SESSION]);
const userButton = screen.getByText("user-a").closest("button");
@@ -975,102 +975,90 @@ describe("NetworkManagementPage", () => {
await waitFor(() => {
expect(screen.getByText("Active")).toBeDefined();
});
// active_authorized → green badge classes
const badge = screen.getByText("Active");
expect(badge.className).toContain("bg-green-100");
expect(badge.className).toContain("text-green-700");
});
test("renders device state badge for joined_deauthorized membership", async () => {
test("renders Inactive badge for approved_inactive membership", async () => {
await setupMembersTab([MEMBERSHIP_UNAUTHORIZED_NO_SESSION]);
const userButton = screen.getByText("user-a").closest("button");
fireEvent.click(userButton!);
await waitFor(() => {
expect(screen.getByText("Deauthorized")).toBeDefined();
expect(screen.getByText("Inactive")).toBeDefined();
});
const badge = screen.getByText("Deauthorized");
expect(badge.className).toContain("bg-red-100");
expect(badge.className).toContain("text-red-700");
});
test("renders device state badge for pending_request membership", async () => {
test("renders Inactive badge for pending_request membership", async () => {
await setupMembersTab([MEMBERSHIP_PENDING_REQUEST]);
const userButton = screen.getByText("user-c").closest("button");
fireEvent.click(userButton!);
await waitFor(() => {
expect(screen.getByText("Pending Request")).toBeDefined();
expect(screen.getByText("Inactive")).toBeDefined();
});
const badge = screen.getByText("Pending Request");
expect(badge.className).toContain("bg-yellow-100");
expect(badge.className).toContain("text-yellow-700");
});
test("renders device state badge for approved_inactive membership", async () => {
test("renders Inactive badge for second user (approved_inactive)", async () => {
await setupMembersTab([MEMBERSHIP_SECOND_USER]);
const userButton = screen.getByText("user-b").closest("button");
fireEvent.click(userButton!);
await waitFor(() => {
expect(screen.getByText("Approved")).toBeDefined();
expect(screen.getByText("Inactive")).toBeDefined();
});
const badge = screen.getByText("Approved");
expect(badge.className).toContain("bg-blue-100");
expect(badge.className).toContain("text-blue-700");
});
// ── Authorization Status ────────────────────────────────────────────────────
test("shows 'Authorized' with green check icon when currently_authorized is true", async () => {
test("shows 'Active' badge when membership is active", async () => {
await setupMembersTab([MEMBERSHIP_AUTHORIZED_WITH_SESSION]);
const userButton = screen.getByText("user-a").closest("button");
fireEvent.click(userButton!);
await waitFor(() => {
expect(screen.getByText("Authorized")).toBeDefined();
const actives = screen.getAllByText("Active");
expect(actives.length).toBeGreaterThanOrEqual(1);
});
});
test("shows 'Unauthorized' with X icon when currently_authorized is false", async () => {
test("shows 'Inactive' badge when membership is not active", async () => {
await setupMembersTab([MEMBERSHIP_UNAUTHORIZED_NO_SESSION]);
const userButton = screen.getByText("user-a").closest("button");
fireEvent.click(userButton!);
await waitFor(() => {
expect(screen.getByText("Unauthorized")).toBeDefined();
expect(screen.getByText("Inactive")).toBeDefined();
});
});
// ── Active Session Info ─────────────────────────────────────────────────────
test("shows session info when active_session is present and is_active", async () => {
test("shows session progress bar when active_session is present and is_active", async () => {
await setupMembersTab([MEMBERSHIP_AUTHORIZED_WITH_SESSION]);
const userButton = screen.getByText("user-a").closest("button");
fireEvent.click(userButton!);
await waitFor(() => {
expect(screen.getByText(/Session active/)).toBeDefined();
expect(screen.getByText(/remaining/)).toBeDefined();
});
});
test("does NOT show session info when active_session is null", async () => {
test("does NOT show session progress when active_session is null", async () => {
await setupMembersTab([MEMBERSHIP_UNAUTHORIZED_NO_SESSION]);
const userButton = screen.getByText("user-a").closest("button");
fireEvent.click(userButton!);
await waitFor(() => {
expect(screen.getByText("Deauthorized")).toBeDefined();
expect(screen.getByText("Inactive")).toBeDefined();
});
expect(screen.queryByText(/Session active/)).toBeNull();
expect(screen.queryByText(/remaining/)).toBeNull();
});
// ── Join Seen ───────────────────────────────────────────────────────────────
@@ -1099,7 +1087,7 @@ describe("NetworkManagementPage", () => {
// ── Activate / Deactivate Buttons ───────────────────────────────────────────
test("renders Deactivate button for currently_authorized memberships", async () => {
test("renders Deactivate button for active memberships", async () => {
await setupMembersTab([MEMBERSHIP_AUTHORIZED_WITH_SESSION]);
const userButton = screen.getByText("user-a").closest("button");
@@ -1111,7 +1099,7 @@ describe("NetworkManagementPage", () => {
expect(screen.queryByRole("button", { name: "Activate" })).toBeNull();
});
test("renders Activate button for non-currently_authorized memberships", async () => {
test("renders Activate button for approved-but-inactive memberships", async () => {
await setupMembersTab([MEMBERSHIP_UNAUTHORIZED_NO_SESSION]);
const userButton = screen.getByText("user-a").closest("button");
@@ -1123,7 +1111,7 @@ describe("NetworkManagementPage", () => {
expect(screen.queryByRole("button", { name: "Deactivate" })).toBeNull();
});
test("clicking Activate calls api.zerotier.activateMembership with correct orgId and membershipId", async () => {
test("clicking Activate opens dialog then calls api.zerotier.activateMembership with correct orgId, membershipId, and lifetime", async () => {
H.mockActivateMembership.mockResolvedValue({});
// Second call to getNetworkMembers (refresh after activate)
H.mockGetNetworkMembers
@@ -1138,8 +1126,15 @@ describe("NetworkManagementPage", () => {
const activateBtn = await screen.findByRole("button", { name: "Activate" });
fireEvent.click(activateBtn);
// Dialog opens; click the Activate button in the dialog
await waitFor(() => {
expect(screen.getByText("Set Activation Duration")).toBeDefined();
});
const dialogBtns = screen.getAllByRole("button", { name: "Activate" });
fireEvent.click(dialogBtns[dialogBtns.length - 1]);
expect(H.mockActivateMembership).toHaveBeenCalledTimes(1);
expect(H.mockActivateMembership).toHaveBeenCalledWith("org-1", "mem-unauth-1");
expect(H.mockActivateMembership).toHaveBeenCalledWith("org-1", "mem-unauth-1", 480);
});
test("clicking Deactivate calls api.zerotier.deactivateMembership with correct orgId and membershipId", async () => {
@@ -1175,6 +1170,13 @@ describe("NetworkManagementPage", () => {
const activateBtn = await screen.findByRole("button", { name: "Activate" });
fireEvent.click(activateBtn);
// Confirm in dialog
await waitFor(() => {
expect(screen.getByText("Set Activation Duration")).toBeDefined();
});
const dialogBtns = screen.getAllByRole("button", { name: "Activate" });
fireEvent.click(dialogBtns[dialogBtns.length - 1]);
await waitFor(() => {
expect(H.mockToast).toHaveBeenCalledWith(expect.objectContaining({ title: "Membership activated" }));
});
@@ -1211,6 +1213,13 @@ describe("NetworkManagementPage", () => {
const activateBtn = await screen.findByRole("button", { name: "Activate" });
fireEvent.click(activateBtn);
// Confirm in dialog
await waitFor(() => {
expect(screen.getByText("Set Activation Duration")).toBeDefined();
});
const dialogBtns = screen.getAllByRole("button", { name: "Activate" });
fireEvent.click(dialogBtns[dialogBtns.length - 1]);
await waitFor(() => {
expect(H.mockToast).toHaveBeenCalledWith(expect.objectContaining({
variant: "destructive",
@@ -1252,6 +1261,13 @@ describe("NetworkManagementPage", () => {
const activateBtn = await screen.findByRole("button", { name: "Activate" });
fireEvent.click(activateBtn);
// Confirm in dialog
await waitFor(() => {
expect(screen.getByText("Set Activation Duration")).toBeDefined();
});
const dialogBtns = screen.getAllByRole("button", { name: "Activate" });
fireEvent.click(dialogBtns[dialogBtns.length - 1]);
await waitFor(() => {
expect(H.mockToast).toHaveBeenCalledWith(expect.objectContaining({
variant: "destructive",
@@ -1265,8 +1281,8 @@ describe("NetworkManagementPage", () => {
H.mockActivateMembership.mockResolvedValue({});
const updatedMembership = {
...MEMBERSHIP_UNAUTHORIZED_NO_SESSION,
state: "active_authorized",
currently_authorized: true,
active: true,
status: "approved",
};
H.mockGetNetworkMembers
.mockResolvedValueOnce({ memberships: [MEMBERSHIP_UNAUTHORIZED_NO_SESSION], count: 1 })
@@ -1280,6 +1296,13 @@ describe("NetworkManagementPage", () => {
const activateBtn = await screen.findByRole("button", { name: "Activate" });
fireEvent.click(activateBtn);
// Confirm in dialog
await waitFor(() => {
expect(screen.getByText("Set Activation Duration")).toBeDefined();
});
const dialogBtns = screen.getAllByRole("button", { name: "Activate" });
fireEvent.click(dialogBtns[dialogBtns.length - 1]);
// Verify getNetworkMembers was called twice: once on mount, once on refresh
await waitFor(() => {
expect(H.mockGetNetworkMembers).toHaveBeenCalledTimes(2);
@@ -1292,8 +1315,8 @@ describe("NetworkManagementPage", () => {
H.mockDeactivateMembership.mockResolvedValue({});
const updatedMembership = {
...MEMBERSHIP_AUTHORIZED_WITH_SESSION,
state: "joined_deauthorized",
currently_authorized: false,
active: false,
status: "approved",
};
H.mockGetNetworkMembers
.mockResolvedValueOnce({ memberships: [MEMBERSHIP_AUTHORIZED_WITH_SESSION], count: 1 })
@@ -1344,15 +1367,15 @@ describe("NetworkManagementPage", () => {
test("shows active device count in user section header", async () => {
await setupMembersTab([MEMBERSHIP_AUTHORIZED_WITH_SESSION, MEMBERSHIP_UNAUTHORIZED_NO_SESSION]);
// 1 active (currently_authorized) + 1 inactive → "1 active"
expect(screen.getByText(/1 active/)).toBeDefined();
// 1 active + 1 inactive → "1 active"
expect(screen.getByText(/^1 active$/)).toBeDefined();
});
test("does not show active count when no devices are authorized", async () => {
await setupMembersTab([MEMBERSHIP_UNAUTHORIZED_NO_SESSION]);
// 0 active devices → no "active" text
expect(screen.queryByText(/active/)).toBeNull();
// 0 active devices → no "active" count in user section
expect(screen.queryByText(/^\d+ active$/)).toBeNull();
});
// ── Adversarial: Unicode user_ids ───────────────────────────────────────────