- Introduced `.prettierrc.json` to enforce consistent code formatting across the project. - Updated unit and e2e test files to address formatting issues, improve readability, and ensure alignment with the new Prettier configuration.
175 lines
8.4 KiB
JavaScript
175 lines
8.4 KiB
JavaScript
import { expect, test } from "@playwright/test";
|
|
import { mockApi, seedAuthenticatedState } from "./support/network.js";
|
|
|
|
async function primeSuperuserSession(page) {
|
|
const token = "superuser-edge-gateway-token";
|
|
await seedAuthenticatedState(page, token);
|
|
await page.goto("/login");
|
|
await page.evaluate(async (sessionToken) => {
|
|
const sessionModule = await import("/src/components/session/token/SessionUser.vue");
|
|
window.localStorage.setItem("token", sessionToken);
|
|
sessionModule.SessionUser.token.value = sessionToken;
|
|
sessionModule.SessionUser.authenticated.value = true;
|
|
sessionModule.SessionUser.permissions.value = ["superuser", "user"];
|
|
sessionModule.SessionUser.initiated.value = true;
|
|
}, token);
|
|
}
|
|
|
|
test.describe("Edge gateway management smoke", () => {
|
|
test("@smoke manages installers, bindings, queued updates, and shell approval", async ({ page }) => {
|
|
await mockApi(page, {
|
|
authenticated: true,
|
|
permissions: ["superuser", "user"],
|
|
});
|
|
await primeSuperuserSession(page);
|
|
|
|
await page.goto("/superuser/gateways");
|
|
|
|
await expect(page).toHaveURL(/\/superuser\/gateways$/);
|
|
await expect(page.locator("body")).toContainText("Edge gateways");
|
|
await expect(page.locator("body")).toContainText("Valgt gateway");
|
|
await expect(page.locator("body")).toContainText("CPH Edge 01");
|
|
await expect(page.locator("body")).toContainText("Shelly Plus 2PM");
|
|
await expect(page.locator("body")).toContainText("Latens");
|
|
await expect(page.locator("body")).toContainText("184 ms");
|
|
await expect(page.locator("body")).toContainText("CPU");
|
|
await expect(page.locator("body")).toContainText("27%");
|
|
await expect(page.locator("body")).toContainText("RAM");
|
|
await expect(page.locator("body")).toContainText("61%");
|
|
await expect(page.locator("body")).toContainText("Disk");
|
|
await expect(page.locator("body")).toContainText("58%");
|
|
|
|
const bindingRows = page.locator(".edge-table--editor tbody tr");
|
|
const primaryBindingRow = bindingRows.nth(0);
|
|
const legacyBindingRow = bindingRows.nth(1);
|
|
const primaryDeviceSelect = primaryBindingRow.locator("select").first();
|
|
const primaryChannelSelect = primaryBindingRow.locator("select").nth(1);
|
|
const primaryIpInput = primaryBindingRow.locator('input[type="text"]').nth(1);
|
|
|
|
const primaryOnlineOption = primaryDeviceSelect.locator("option").nth(1);
|
|
await expect(primaryOnlineOption).toContainText("Shelly Plus 2PM");
|
|
await expect(primaryOnlineOption).toContainText("shelly-plus-01");
|
|
await expect(primaryOnlineOption).toContainText("10.1.0.31");
|
|
await expect(primaryOnlineOption).toContainText("2 kanaler");
|
|
await expect(primaryOnlineOption).toContainText("Gen 2");
|
|
|
|
const primaryOfflineOption = primaryDeviceSelect.locator("option").nth(2);
|
|
await expect(primaryOfflineOption).toContainText("Shelly Mini 1");
|
|
await expect(primaryOfflineOption).toContainText("shelly-mini-offline");
|
|
await expect(primaryOfflineOption).toContainText("10.1.0.34");
|
|
await expect(primaryOfflineOption).toContainText("1 kanal");
|
|
await expect(primaryOfflineOption).toContainText("Gen 3");
|
|
await expect(primaryOfflineOption).toContainText("Offline");
|
|
|
|
const staleOption = legacyBindingRow.locator("select").first().locator("option").last();
|
|
await expect(staleOption).toContainText("Ukendt Shelly-device");
|
|
await expect(staleOption).toContainText("shelly-missing-legacy");
|
|
await expect(staleOption).toContainText("10.1.0.99");
|
|
await expect(staleOption).toContainText("2 kanaler");
|
|
await expect(staleOption).toContainText("Mangler i discovery");
|
|
|
|
await primaryChannelSelect.selectOption("1");
|
|
await primaryDeviceSelect.selectOption("shelly-mini-offline");
|
|
await expect(primaryIpInput).toHaveValue("10.1.0.34");
|
|
await expect(primaryChannelSelect).toHaveValue("0");
|
|
|
|
const relayBindingInput = primaryBindingRow.locator('input[type="text"]').first();
|
|
await relayBindingInput.fill("M-7-CANARY");
|
|
await page.getByRole("button", { name: "Gem bindinger" }).click();
|
|
await expect(relayBindingInput).toHaveValue("M-7-CANARY");
|
|
await expect(primaryDeviceSelect).toHaveValue("shelly-mini-offline");
|
|
await expect(primaryIpInput).toHaveValue("10.1.0.34");
|
|
await expect(primaryChannelSelect).toHaveValue("0");
|
|
|
|
await page.getByLabel("Installer afdeling").selectOption("1");
|
|
await page.locator('input[placeholder="F.eks. Roskilde Pi 01"]').fill("Canary Pi");
|
|
await page.getByRole("button", { name: /installer/i }).click();
|
|
await expect(page.getByLabel("Installationskommando")).toHaveValue(/curl -fsSL/);
|
|
|
|
await page.getByRole("button", { name: /discovery/i }).click();
|
|
await expect(page.locator("body")).toContainText("Discovery er");
|
|
await expect(page.locator("body")).toContainText("Afventer");
|
|
await expect(page.locator("body")).toContainText("shelly-plus-new");
|
|
|
|
await page.locator('input[placeholder="F.eks. 1.3.0"]').fill("1.3.0");
|
|
await page.getByRole("button", { name: /opdatering/i }).click();
|
|
await expect(page.locator("body")).toContainText("Opdatering er");
|
|
await expect(page.locator("body")).toContainText("1.3.0");
|
|
await expect(page.locator("body")).toContainText("COMPLETED");
|
|
|
|
await page.getByRole("button", { name: /root shell/i }).click();
|
|
await page.getByRole("textbox", { name: /begrundelse/i }).fill("Investigate offline relay");
|
|
await page.getByRole("button", { name: "Godkend root shell" }).click();
|
|
|
|
const terminalBuffer = page.locator('[aria-label="Root shell buffer"]');
|
|
await expect(page.locator("body")).toContainText("Live");
|
|
await expect(terminalBuffer).toContainText("[Live shell forbundet]");
|
|
await expect(terminalBuffer).toContainText("root@pi:~#");
|
|
|
|
const terminalSurface = page.locator('[aria-label="Root shell terminal"]');
|
|
await terminalSurface.focus();
|
|
await terminalSurface.press("l");
|
|
await terminalSurface.press("s");
|
|
await terminalSurface.press("Enter");
|
|
await expect(terminalBuffer).toContainText("agent.mjs");
|
|
|
|
await page.getByRole("button", { name: "Terminate session" }).click();
|
|
await expect(page.locator("body")).toContainText("Lukket");
|
|
await expect(terminalBuffer).toContainText("Session lukket");
|
|
});
|
|
|
|
test("@smoke shows a shell connection error when the API-polled shell closes before open", async ({ page }) => {
|
|
await mockApi(page, {
|
|
authenticated: true,
|
|
permissions: ["superuser", "user"],
|
|
edgeGateways: {
|
|
shellSocket: {
|
|
mode: "fail-before-open",
|
|
},
|
|
},
|
|
});
|
|
await primeSuperuserSession(page);
|
|
|
|
await page.goto("/superuser/gateways");
|
|
await page.getByRole("button", { name: /root shell/i }).click();
|
|
await page.getByRole("textbox", { name: /begrundelse/i }).fill("Test broken shell");
|
|
await page.getByRole("button", { name: "Godkend root shell" }).click();
|
|
|
|
await expect(page.locator("body")).toContainText("Fejl");
|
|
await expect(page.getByRole("button", { name: "Terminate session" })).toBeDisabled();
|
|
await expect(page.locator('[aria-label="Root shell buffer"]')).toContainText("Gateway-shell blev lukket");
|
|
});
|
|
|
|
test("@smoke applies department cutover mode from department page", async ({ page }) => {
|
|
await mockApi(page, {
|
|
authenticated: true,
|
|
permissions: ["superuser", "user"],
|
|
});
|
|
await primeSuperuserSession(page);
|
|
|
|
await page.goto("/superuser/departments/1/gateways");
|
|
|
|
await expect(page).toHaveURL(/\/superuser\/departments\/1\/gateways$/);
|
|
await expect(page.locator("body")).toContainText("Gateway for afdelingen");
|
|
await page.getByLabel("Transporttilstand").selectOption("cloud");
|
|
await page.getByRole("button", { name: "Anvend cutover" }).click();
|
|
await expect(page.getByLabel("Transporttilstand")).toHaveValue("cloud");
|
|
await expect(page.locator("body")).toContainText("Cloud fallback");
|
|
});
|
|
|
|
test("@smoke shows API polling as the control channel while discovery still works", async ({ page }) => {
|
|
await mockApi(page, {
|
|
authenticated: true,
|
|
permissions: ["superuser", "user"],
|
|
});
|
|
await primeSuperuserSession(page);
|
|
|
|
await page.goto("/superuser/gateways");
|
|
|
|
await expect(page.locator("body")).toContainText("API polling");
|
|
await page.getByRole("button", { name: /discovery/i }).click();
|
|
await expect(page.locator("body")).toContainText("Discovery er");
|
|
await expect(page.locator("body")).toContainText("shelly-plus-new");
|
|
});
|
|
});
|