Files
meshcore-hub/e2e/tests/routes-operator.spec.ts
T
Louis King acacea0d85 feat(routes): add 'my routes only' filter
Adds a checkbox filter to the Routes page that narrows the list to
routes owned by the current user. The filter is URL-driven (?mine=true),
cached server-side automatically via the existing key builder, and only
shown to operators/admins (members can't own routes).

Backend: mine query param on GET /api/v1/routes filters by created_by
matching the caller's X-User-Id. Legacy NULL routes are excluded.

Tests:
- Backend: 6 new TestRouteMineFilter tests (own/other/null/admin/default)
- Vitest: 6 new tests (param passing, role gating, checkbox state)
- E2E: new seed route owned by pw-operator + mine filter spec
2026-07-24 22:22:17 +01:00

99 lines
3.8 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { OPERATOR_STATE } from "../utils/helpers";
test.use({ storageState: OPERATOR_STATE });
const ROUTE_LABEL = "Op From \u2192 Op To";
const SEEDED_LEGACY = "Alpha Site \u2192 Bravo Site";
const SEEDED_OWNED = "Op North \u2192 Op South";
test.describe.serial("routes (operator)", () => {
test("operator can manage routes; admin visibility tier is hidden", async ({
page,
}) => {
await page.goto("/routes");
// Operators see the seeded community route and the add button.
const seededCard = page.locator(
`[data-testid="route-card"][data-route-label="${SEEDED_LEGACY}"]`,
);
await expect(seededCard).toBeVisible();
await expect(page.getByTestId("add-route")).toBeVisible();
// The seeded route has NULL created_by — operator must NOT see edit/delete.
await expect(seededCard.getByTestId("edit-route")).toHaveCount(0);
await expect(seededCard.getByTestId("delete-route")).toHaveCount(0);
// The visibility dropdown must NOT offer the admin tier to an operator.
await page.getByTestId("add-route").click();
const modal = page.locator('[data-testid="route-modal"]');
await expect(modal).toBeVisible();
const visibility = page.getByTestId("route-visibility");
await expect(visibility.locator("option[value='admin']")).toHaveCount(0);
await visibility.selectOption("operator");
await expect(visibility).toHaveValue("operator");
await page.getByTestId("route-from").fill("Op From");
await page.getByTestId("route-to").fill("Op To");
await page.getByTestId("route-path-search").fill("Alpha");
await page.getByTestId("node-search-result").first().click();
await page.getByTestId("route-path-search").fill("Bravo");
await page.getByTestId("node-search-result").first().click();
await expect(page.getByTestId("route-path-chip")).toHaveCount(2);
await page.getByTestId("route-save").click();
await expect(modal).toHaveCount(0);
const card = page.locator(
`[data-testid="route-card"][data-route-label="${ROUTE_LABEL}"]`,
);
await expect(card).toBeVisible();
// Operator owns the route they just created — edit/delete should be present.
await card.getByTestId("edit-route").click();
await expect(modal).toBeVisible();
await expect(page.getByTestId("route-from")).toHaveValue("Op From");
await page.getByTestId("route-cancel").click();
// Operator can delete the route they created.
await card.getByTestId("delete-route").click();
const confirm = page.locator("dialog.modal-open");
await expect(confirm).toBeVisible();
await confirm.getByRole("button", { name: "Delete" }).click();
await expect(card).toHaveCount(0);
});
test("mine filter shows only routes the operator owns", async ({ page }) => {
await page.goto("/routes");
const legacyCard = page.locator(
`[data-testid="route-card"][data-route-label="${SEEDED_LEGACY}"]`,
);
const ownedCard = page.locator(
`[data-testid="route-card"][data-route-label="${SEEDED_OWNED}"]`,
);
// Both the legacy (NULL created_by) and operator-owned routes are visible.
await expect(legacyCard).toBeVisible();
await expect(ownedCard).toBeVisible();
// Open the filter panel and toggle "mine".
await page.locator("#filter-toggle").check();
await page.getByTestId("routes-mine-toggle").check();
// URL reflects the filter state.
await expect(page).toHaveURL(/mine=true/);
// Legacy route (NULL created_by) disappears; owned route stays.
await expect(legacyCard).toHaveCount(0);
await expect(ownedCard).toBeVisible();
// Turn the filter off — both routes return.
await page.getByTestId("routes-mine-toggle").uncheck();
await expect(page).not.toHaveURL(/mine=true/);
await expect(legacyCard).toBeVisible();
await expect(ownedCard).toBeVisible();
});
});