291 lines
9.0 KiB
TypeScript
291 lines
9.0 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import { mockApi, seedAuthenticatedState } from "./support/network.js";
|
|
|
|
const QUEUE_LIST_PATH = "/collected-invoices/economic/queue";
|
|
const QUEUE_MONITOR_PATH = "/collected-invoices/economic/queue/monitor";
|
|
const QUEUE_DISMISS_PATH = "/collected-invoices/economic/queue/dismiss";
|
|
const QUEUE_DISMISS_TERMINAL_PATH = "/collected-invoices/economic/queue/dismiss-terminal";
|
|
|
|
function json(body: unknown, status = 200) {
|
|
return {
|
|
status,
|
|
contentType: "application/json",
|
|
body: JSON.stringify(body),
|
|
};
|
|
}
|
|
|
|
function matchesApiPath(urlString: string, expectedPath: string) {
|
|
const url = new URL(urlString);
|
|
return url.pathname === expectedPath || url.pathname === `/api${expectedPath}`;
|
|
}
|
|
|
|
async function suppressVueDevtoolsOverlay(page) {
|
|
await page.addInitScript(() => {
|
|
const style = document.createElement("style");
|
|
style.textContent =
|
|
"#__vue-devtools-container__, .vue-devtools__anchor-btn, .vue-devtools__panel-content { display: none !important; visibility: hidden !important; pointer-events: none !important; }";
|
|
document.documentElement.appendChild(style);
|
|
localStorage.setItem("lastVersionCheck", String(Date.now()));
|
|
});
|
|
}
|
|
|
|
async function bootstrapAuthenticatedSuperuser(page) {
|
|
const token = "superuser-transfer-monitor-e2e-token";
|
|
await suppressVueDevtoolsOverlay(page);
|
|
await seedAuthenticatedState(page, token);
|
|
await mockApi(page, {
|
|
authenticated: true,
|
|
permissions: ["superuser", "user"],
|
|
loginToken: token,
|
|
});
|
|
}
|
|
|
|
function monitorPayload() {
|
|
return {
|
|
data: {
|
|
jobs: [
|
|
{
|
|
id: 9301,
|
|
status: "PROCESSING",
|
|
progress_percent: 45,
|
|
progress_message: "Exporting invoice lines",
|
|
details_summary: {
|
|
message: "Exporting invoice lines",
|
|
target: {
|
|
collected_invoice_id: 7001,
|
|
},
|
|
customer: {
|
|
customer_number: 42424242,
|
|
name: "Acme Fleet",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
id: 9302,
|
|
status: "FAILED",
|
|
progress_percent: 100,
|
|
error_message: "Missing e-conomic product",
|
|
details_summary: {
|
|
message: "Missing e-conomic product",
|
|
target: {
|
|
collected_invoice_id: 7002,
|
|
},
|
|
customer: {
|
|
customer_number: 52525252,
|
|
name: "Nordic Transport",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
id: 9303,
|
|
status: "COMPLETED",
|
|
progress_percent: 100,
|
|
progress_message: "Completed",
|
|
details_summary: {
|
|
message: "Completed",
|
|
target: {
|
|
collected_invoice_id: 7003,
|
|
},
|
|
customer: {
|
|
customer_number: 62626262,
|
|
name: "Finished Carrier",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
id: 9304,
|
|
status: "QUEUED",
|
|
progress_percent: 0,
|
|
progress_message: "Queued",
|
|
details_summary: {
|
|
message: "Queued",
|
|
target: {
|
|
collected_invoice_id: 7004,
|
|
},
|
|
customer: {
|
|
customer_number: 72727272,
|
|
name: "Queued Carrier",
|
|
},
|
|
},
|
|
},
|
|
],
|
|
counts: {
|
|
queued: 1,
|
|
in_progress: 1,
|
|
failed: 1,
|
|
completed: 1,
|
|
total: 4,
|
|
},
|
|
progress_percent: 61,
|
|
limit: 50,
|
|
},
|
|
meta: [],
|
|
includes: [],
|
|
};
|
|
}
|
|
|
|
function completedMonitorPayload() {
|
|
return {
|
|
data: {
|
|
jobs: [
|
|
{
|
|
id: 9401,
|
|
status: "COMPLETED",
|
|
progress_percent: 100,
|
|
progress_message: "Completed",
|
|
details_summary: {
|
|
message: "Completed",
|
|
target: {
|
|
collected_invoice_id: 7101,
|
|
},
|
|
customer: {
|
|
customer_number: 81818181,
|
|
name: "Green Carrier",
|
|
},
|
|
},
|
|
},
|
|
],
|
|
counts: {
|
|
queued: 0,
|
|
in_progress: 0,
|
|
failed: 0,
|
|
completed: 1,
|
|
total: 1,
|
|
},
|
|
progress_percent: 100,
|
|
limit: 50,
|
|
},
|
|
meta: [],
|
|
includes: [],
|
|
};
|
|
}
|
|
|
|
test.describe("Invoice transfer monitor header", () => {
|
|
test("shows progress dropdown and clears terminal jobs", async ({ page }) => {
|
|
let dismissedJobId: number | null = null;
|
|
let clearedTerminal = false;
|
|
|
|
await bootstrapAuthenticatedSuperuser(page);
|
|
|
|
await page.route("**/collected-invoices/economic/queue**", async (route) => {
|
|
const request = route.request();
|
|
const url = request.url();
|
|
|
|
if (request.method() === "GET" && matchesApiPath(url, QUEUE_MONITOR_PATH)) {
|
|
await route.fulfill(json(monitorPayload()));
|
|
return;
|
|
}
|
|
|
|
if (request.method() === "POST" && matchesApiPath(url, QUEUE_DISMISS_PATH)) {
|
|
const payload = request.postDataJSON() as { job_id?: number };
|
|
dismissedJobId = payload.job_id ?? null;
|
|
await route.fulfill(json({ data: { message: "cleared" } }));
|
|
return;
|
|
}
|
|
|
|
if (request.method() === "POST" && matchesApiPath(url, QUEUE_DISMISS_TERMINAL_PATH)) {
|
|
clearedTerminal = true;
|
|
await route.fulfill(json({ data: { dismissed_count: 2 } }));
|
|
return;
|
|
}
|
|
|
|
if (request.method() === "GET" && matchesApiPath(url, QUEUE_LIST_PATH)) {
|
|
await route.fulfill(
|
|
json({
|
|
data: {
|
|
items: [],
|
|
count: 0,
|
|
total: 0,
|
|
limit: 50,
|
|
offset: 0,
|
|
has_more: false,
|
|
},
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
await route.fallback();
|
|
});
|
|
|
|
await page.goto("/superuser/invoices?activeTab=queue");
|
|
|
|
const monitor = page.getByTestId("invoice-transfer-monitor");
|
|
await expect(monitor).toBeVisible({ timeout: 15_000 });
|
|
const monitorButton = page.getByTestId("invoice-transfer-monitor-button");
|
|
await expect(monitorButton).toContainText("Overførsler");
|
|
await expect(monitorButton).toContainText("I kø 1");
|
|
await expect(monitorButton).toContainText("Fejlet 1");
|
|
await expect(monitorButton).toHaveClass(/has-failed-transfers/);
|
|
await expect(monitorButton.locator(".queue-monitor-progress > span")).toHaveCSS(
|
|
"background-color",
|
|
"rgb(239, 68, 68)"
|
|
);
|
|
|
|
const monitorBox = await monitor.boundingBox();
|
|
const userProfiles = page.getByRole("link", { name: /Jeppe|E2E|profile|profil/i });
|
|
if ((await userProfiles.count()) > 0) {
|
|
const userBox = await userProfiles.last().boundingBox();
|
|
expect(monitorBox?.x ?? 0).toBeLessThan(userBox?.x ?? Number.POSITIVE_INFINITY);
|
|
}
|
|
|
|
await monitorButton.click();
|
|
const monitorMenu = page.getByTestId("invoice-transfer-monitor-menu");
|
|
await expect(monitorMenu).toBeVisible();
|
|
await expect(monitorMenu).toHaveClass(/has-failed-transfers/);
|
|
await expect(monitorMenu.locator(".dropdown-content")).toHaveCSS("border-left-width", "2px");
|
|
await expect(page.getByTestId("invoice-transfer-monitor-job")).toHaveCount(4);
|
|
await expect(page.getByText("Faktura #7002")).toBeVisible();
|
|
await expect(page.getByText("Nordic Transport - 52525252")).toBeVisible();
|
|
await expect(page.getByText("Missing e-conomic product")).toBeVisible();
|
|
|
|
await page.getByTestId("invoice-transfer-monitor-clear-one").first().click();
|
|
await expect.poll(() => dismissedJobId).toBe(9302);
|
|
|
|
await page.getByTestId("invoice-transfer-monitor-clear-all").click();
|
|
await expect.poll(() => clearedTerminal).toBe(true);
|
|
});
|
|
|
|
test("shows a full green progress bar when every visible transfer completed successfully", async ({ page }) => {
|
|
await bootstrapAuthenticatedSuperuser(page);
|
|
|
|
await page.route("**/collected-invoices/economic/queue**", async (route) => {
|
|
const request = route.request();
|
|
const url = request.url();
|
|
|
|
if (request.method() === "GET" && matchesApiPath(url, QUEUE_MONITOR_PATH)) {
|
|
await route.fulfill(json(completedMonitorPayload()));
|
|
return;
|
|
}
|
|
|
|
if (request.method() === "GET" && matchesApiPath(url, QUEUE_LIST_PATH)) {
|
|
await route.fulfill(
|
|
json({
|
|
data: {
|
|
items: [],
|
|
count: 0,
|
|
total: 0,
|
|
limit: 50,
|
|
offset: 0,
|
|
has_more: false,
|
|
},
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
await route.fallback();
|
|
});
|
|
|
|
await page.goto("/superuser/invoices?activeTab=queue");
|
|
|
|
const monitorButton = page.getByTestId("invoice-transfer-monitor-button");
|
|
await expect(monitorButton).toBeVisible({ timeout: 15_000 });
|
|
await expect(monitorButton).toContainText("Fuldført 1");
|
|
const progressFill = monitorButton.locator(".queue-monitor-progress > span");
|
|
await expect(monitorButton.locator(".queue-monitor-progress")).toHaveClass(/is-successful-complete/);
|
|
await expect(progressFill).toHaveCSS("background-color", "rgb(34, 197, 94)");
|
|
await expect(progressFill).toHaveCSS("width", /[1-9]\d{2}(\.\d+)?px/);
|
|
});
|
|
});
|