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.
116 lines
4.4 KiB
TypeScript
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();
|
|
}
|