Files
dashboard/e2e/tests/team-service-users.spec.ts
Maycon Santos 7653e3411c Merge NetBird cloud edition into the dashboard (#674)
Brings the unified dashboard into the open-source repo. Premium features
ship in the open code, gated at runtime via NETBIRD_CLOUD and
NETBIRD_LICENSED, with upgrade prompts for unlicensed self-hosted
deployments. Adds the cloud-only feature areas (billing, integrations,
MSP, traffic events, notifications) and the Playwright e2e suite.
2026-06-21 16:01:08 +02:00

116 lines
4.4 KiB
TypeScript

import { test, expect } from "../helpers/fixtures";
import { navigateTo } from "../helpers/auth";
import { generateRandomName } from "../helpers/utils";
let regularUser = "";
let adminServiceUser = "";
test.describe.serial("Team - Service Users @team", () => {
test("Should create service users and verify roles", async ({ dashboardAsOwner: page }) => {
await navigateTo(page, "/team/service-users");
regularUser = generateRandomName("svc-user-");
adminServiceUser = generateRandomName("svc-admin-");
await createServiceUser(page, regularUser, "User");
await createServiceUser(page, adminServiceUser, "Admin");
await checkServiceUserRow(page, regularUser, "User");
await checkServiceUserRow(page, adminServiceUser, "Admin");
});
test("Should update role and manage access tokens", async ({ dashboardAsOwner: page }) => {
await page.locator("tr").getByText(regularUser).click();
await changeRoleTo(page, "Admin");
await page.getByTestId("save-changes").click();
// Create and delete access token
const tokenName = generateRandomName("tkn_");
await page.getByTestId("access-token-open-modal").click();
await page.getByTestId("access-token-name").fill(tokenName);
await page.getByTestId("access-token-expires-in").fill("30");
await page.getByTestId("create-access-token").click();
await expect(page.getByTestId("access-token-copy-close")).toBeVisible();
await page.getByTestId("access-token-copy-close").click();
const tokenRow = page.locator("tr").filter({ hasText: tokenName });
await tokenRow.getByTestId("access-token-delete").click();
await page.getByTestId("confirmation.confirm").click();
await expect(tokenRow).not.toBeVisible();
await page.getByText("Service Users").first().click();
});
test("Should update admin user role and verify all changes persisted", async ({
dashboardAsOwner: page,
}) => {
await page.locator("tr").getByText(adminServiceUser).click();
await changeRoleTo(page, "User");
const saveResponse = page.waitForResponse(
(resp) => resp.url().includes("/api/users/") && resp.request().method() === "PUT",
{ timeout: 30_000 },
);
await page.getByTestId("save-changes").click();
await saveResponse;
await page.getByText("Service Users").first().click();
await checkServiceUserRow(page, regularUser, "Admin");
await checkServiceUserRow(page, adminServiceUser, "User");
// Single reload to verify all changes persisted
await page.reload();
await checkServiceUserRow(page, regularUser, "Admin");
await checkServiceUserRow(page, adminServiceUser, "User");
});
test("Should delete service users", async ({ dashboardAsOwner: page }) => {
for (const name of [regularUser, adminServiceUser]) {
const row = page.locator("tr").filter({ hasText: name });
// Row actions are now behind a dropdown menu; open it, then delete.
await row.getByTestId("user-actions").click({ force: true });
await page.getByTestId("delete-user").click({ force: true });
await page.getByTestId("confirmation.confirm").click();
await expect(row).not.toBeVisible();
}
});
});
async function createServiceUser(
page: import("@playwright/test").Page,
name: string,
role: string,
) {
await page.getByTestId("open-service-user-modal").click();
await expect(page.getByTestId("service-user-name")).toBeVisible({ timeout: 5_000 });
await page.getByTestId("service-user-name").fill(name);
await page.getByTestId("user-role-selector").click({ force: true });
await page
.getByTestId("user-role-selector-item")
.getByText(role, { exact: true })
.click({ force: true });
await page.getByTestId("create-service-user").click();
// Wait for modal to close
await expect(page.getByTestId("service-user-name")).not.toBeVisible({ timeout: 5_000 });
}
async function checkServiceUserRow(
page: import("@playwright/test").Page,
name: string,
role: string,
) {
const row = page.locator("tr").filter({ hasText: name });
await expect(row).toBeVisible({ timeout: 10_000 });
await expect(row.getByText(role, { exact: true }).first()).toBeVisible({ timeout: 10_000 });
}
async function changeRoleTo(
page: import("@playwright/test").Page,
role: string,
) {
await page.getByTestId("user-role-selector").click();
await page
.getByTestId("user-role-selector-item")
.getByText(role, { exact: true })
.click();
}