Files
dashboard/e2e/tests/access-control.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

152 lines
4.6 KiB
TypeScript

import { test, expect } from "../helpers/fixtures";
import { generateRandomName } from "../helpers/utils";
import { navigateTo } from "../helpers/auth";
import { deleteGroupsByPrefix } from "../helpers/api";
let policies: string[] = [];
let createdGroups: string[] = [];
test.describe.serial("Access Controls @access-control", () => {
test("Should have default policy", async ({ dashboardAsOwner: page }) => {
await navigateTo(page, "/access-control");
await expect(page.getByText("Default", { exact: true })).toBeVisible();
await expect(page.getByText("This is a default rule")).toBeVisible();
});
test("Should create new policy", async ({ dashboardAsOwner: page }) => {
const srcGroup = generateRandomName("ac-src-");
const dstGroup = generateRandomName("ac-dst-");
createdGroups.push(srcGroup, dstGroup);
const name = generateRandomName("Policy ");
await createPolicy(page, {
name,
source_groups: [srcGroup],
destination_groups: [dstGroup],
protocol: "TCP",
ports: ["80", "443"],
direction: "in",
description: "This is a test policy",
});
policies.push(name);
});
test("Should delete created policies", async ({ dashboardAsOwner: page }) => {
for (const policy of policies) {
await deletePolicy(page, policy);
}
policies = [];
});
test("Should delete created groups", async ({ dashboardAsOwner: page }) => {
for (const prefix of createdGroups) {
await deleteGroupsByPrefix(page, prefix);
}
createdGroups = [];
});
});
async function createPolicy(
page: import("@playwright/test").Page,
opts: {
protocol?: "ALL" | "TCP" | "UDP" | "ICMP";
source_groups: string[];
destination_groups: string[];
direction?: "bi" | "in";
ports?: string[];
name: string;
description?: string;
},
) {
await page.getByTestId("open-add-policy").click();
if (opts.protocol !== "ALL") {
await page.getByTestId("protocol-select-button").click();
await page
.getByTestId("protocol-selection")
.getByText(opts.protocol!)
.click();
}
if (opts.direction === "in") {
await page.getByTestId("policy-direction").click();
}
// Add source groups
if (opts.source_groups.length > 0) {
await page.getByTestId("source-group-selector").click();
for (const group of opts.source_groups) {
const search = page.getByTestId("source-group-selector-search");
await expect(search).toBeVisible();
await search.fill(group);
await search.press("Enter");
}
await page.getByTestId("source-group-selector-search").press("Escape");
await expect(
page.getByTestId("source-group-selector-search"),
).not.toBeVisible();
}
// Add destination groups
if (opts.destination_groups.length > 0) {
await page.getByTestId("destination-group-selector").click();
for (const group of opts.destination_groups) {
const search = page.getByTestId("destination-group-selector-search");
await expect(search).toBeVisible();
await search.fill(group);
await search.press("Enter");
}
await page
.getByTestId("destination-group-selector-search")
.press("Escape");
await expect(
page.getByTestId("destination-group-selector-search"),
).not.toBeVisible();
}
// Add ports
if (
opts.ports &&
(opts.protocol === "TCP" || opts.protocol === "UDP")
) {
await page.getByTestId("port-selector").click();
for (const port of opts.ports) {
const input = page.getByTestId("port-input");
await expect(input).toBeVisible();
await input.fill(port);
await input.press("Enter");
}
await page.getByTestId("port-input").press("Escape");
}
// Click Continue (policy → posture checks)
await page.getByTestId("policy-continue").click();
// Skip posture checks and continue (posture checks → general)
await page.getByTestId("policy-continue").click();
// Enter name
await page.getByTestId("policy-name").fill(opts.name);
if (opts.description) {
await page.getByTestId("policy-description").fill(opts.description);
}
// Create policy
await page.getByTestId("submit-policy").click();
await expect(page.getByTestId(opts.name)).toBeVisible();
}
async function deletePolicy(
page: import("@playwright/test").Page,
name: string,
) {
// Row actions are now behind a dropdown menu.
await page
.locator("tr")
.filter({ hasText: name })
.getByTestId("policy-actions")
.click({ force: true });
await page.getByTestId("delete-policy").click({ force: true });
await page.getByTestId("confirmation.confirm").click();
await expect(page.getByTestId(name)).not.toBeVisible({ timeout: 10_000 });
}