Stabilize parallel E2E slices
This commit is contained in:
@@ -123,7 +123,7 @@ Default worker allocation:
|
||||
```sh
|
||||
PLAYWRIGHT_PARALLEL_WORKERS_CHROMIUM=2
|
||||
PLAYWRIGHT_PARALLEL_WORKERS_FIREFOX=1
|
||||
PLAYWRIGHT_PARALLEL_WORKERS_WEBKIT=2
|
||||
PLAYWRIGHT_PARALLEL_WORKERS_WEBKIT=1
|
||||
```
|
||||
|
||||
Optional overrides:
|
||||
@@ -132,7 +132,7 @@ Optional overrides:
|
||||
PLAYWRIGHT_PARALLEL_BASE_PORT=5191
|
||||
PLAYWRIGHT_PARALLEL_WORKERS_CHROMIUM=2
|
||||
PLAYWRIGHT_PARALLEL_WORKERS_FIREFOX=1
|
||||
PLAYWRIGHT_PARALLEL_WORKERS_WEBKIT=2
|
||||
PLAYWRIGHT_PARALLEL_WORKERS_WEBKIT=1
|
||||
```
|
||||
|
||||
The runner fails fast if the combined worker count exceeds 5.
|
||||
|
||||
@@ -28,7 +28,7 @@ const groups = [
|
||||
{
|
||||
name: "webkit",
|
||||
projects: ["webkit-desktop", "webkit-tablet", "webkit-mobile"],
|
||||
defaultWorkers: 2,
|
||||
defaultWorkers: 1,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ const isBenignNavigationError = (error: unknown) => {
|
||||
return (
|
||||
message.includes("interrupted by another navigation") ||
|
||||
message.includes("ERR_ABORTED") ||
|
||||
message.includes("NS_BINDING_ABORTED") ||
|
||||
message.includes("Frame load interrupted")
|
||||
);
|
||||
};
|
||||
@@ -38,10 +39,6 @@ function fulfillJson(route: Route, body: unknown, status = 200) {
|
||||
});
|
||||
}
|
||||
|
||||
function getErrorMessage(error: unknown) {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
async function hasConnectivityIssue(page: Page) {
|
||||
return page
|
||||
.getByText(CONNECTIVITY_ISSUE_PATTERN)
|
||||
|
||||
@@ -57,6 +57,20 @@ async function prepareInvoiceDistributionPage(page, overrides = {}) {
|
||||
await primeSuperuserSession(page);
|
||||
}
|
||||
|
||||
async function gotoInvoiceDistribution(page, url) {
|
||||
for (let attempt = 0; attempt < 2; attempt += 1) {
|
||||
try {
|
||||
await page.goto(url);
|
||||
return;
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
if (attempt > 0 || !message.includes("WebKit encountered an internal error")) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test.describe("Invoice distribution smoke", () => {
|
||||
test("@smoke @pr overview loads and quick-open month action works", async ({ page }) => {
|
||||
const componentWarnings = [];
|
||||
@@ -68,7 +82,7 @@ test.describe("Invoice distribution smoke", () => {
|
||||
});
|
||||
|
||||
await prepareInvoiceDistributionPage(page);
|
||||
await page.goto("/superuser/invoices?activeTab=distribution");
|
||||
await gotoInvoiceDistribution(page, "/superuser/invoices?activeTab=distribution");
|
||||
|
||||
await expect(page.getByTestId("distribution-overview-page")).toBeVisible({ timeout: 15_000 });
|
||||
await expect(page.locator('[data-testid="distribution-overview-page"] h2').first()).toBeVisible();
|
||||
@@ -95,7 +109,8 @@ test.describe("Invoice distribution smoke", () => {
|
||||
|
||||
test("@smoke monthly tabs keep URL query-state in sync", async ({ page }) => {
|
||||
await prepareInvoiceDistributionPage(page);
|
||||
await page.goto(
|
||||
await gotoInvoiceDistribution(
|
||||
page,
|
||||
"/superuser/invoices/distribution/2026/3/customers?customerSearch=acme&customerSource=fixed_pricing&customerDepartment=Copenhagen&compareMode=line_by_line"
|
||||
);
|
||||
|
||||
@@ -118,7 +133,7 @@ test.describe("Invoice distribution smoke", () => {
|
||||
|
||||
test("@smoke compare flow shows progress and mismatch-first results", async ({ page }) => {
|
||||
await prepareInvoiceDistributionPage(page);
|
||||
await page.goto("/superuser/invoices/distribution/2026/3/compare?compareMode=line_by_line");
|
||||
await gotoInvoiceDistribution(page, "/superuser/invoices/distribution/2026/3/compare?compareMode=line_by_line");
|
||||
|
||||
await page.getByTestId("distribution-compare-submit").click();
|
||||
const compareTable = page.getByTestId("distribution-compare-table");
|
||||
@@ -139,7 +154,7 @@ test.describe("Invoice distribution smoke", () => {
|
||||
|
||||
test("@smoke mobile layout sanity keeps primary controls visible", async ({ page }) => {
|
||||
await prepareInvoiceDistributionPage(page);
|
||||
await page.goto("/superuser/invoices/distribution/2026/3/overview");
|
||||
await gotoInvoiceDistribution(page, "/superuser/invoices/distribution/2026/3/overview");
|
||||
|
||||
await expect(page.getByTestId("distribution-month-toolbar")).toBeVisible();
|
||||
await expect(page.getByTestId("distribution-month-prev")).toBeVisible();
|
||||
@@ -155,12 +170,12 @@ test.describe("Invoice distribution smoke", () => {
|
||||
invoiceDistributionForceCompareFallback: true,
|
||||
});
|
||||
|
||||
await page.goto("/superuser/invoices?activeTab=distribution");
|
||||
await gotoInvoiceDistribution(page, "/superuser/invoices?activeTab=distribution");
|
||||
await expect(page.locator(".message.is-warning").filter({ hasText: /v2/i }).first()).toBeVisible({
|
||||
timeout: 15_000,
|
||||
});
|
||||
|
||||
await page.goto("/superuser/invoices/distribution/2026/3/compare?compareMode=line_by_line");
|
||||
await gotoInvoiceDistribution(page, "/superuser/invoices/distribution/2026/3/compare?compareMode=line_by_line");
|
||||
await expect(page.locator(".message.is-warning").filter({ hasText: /v2/i }).first()).toBeVisible({
|
||||
timeout: 15_000,
|
||||
});
|
||||
|
||||
@@ -87,7 +87,7 @@ test("non-default release channel keeps the regular frontend and dynamic API run
|
||||
|
||||
expect(page.url()).toContain("/shared/passkey-safe-link");
|
||||
expect(page.url()).not.toContain("api-v2.truckwash.io");
|
||||
expect(runtimeRequests).toHaveLength(1);
|
||||
await expect.poll(() => runtimeRequests.length).toBe(1);
|
||||
const runtimeRequestUrl = new URL(runtimeRequests[0]);
|
||||
expect(["/api/release/runtime", "/master/api/release/runtime"]).toContain(runtimeRequestUrl.pathname);
|
||||
expect(runtimeRequestUrl.pathname).not.toBe("/canary/api/release/runtime");
|
||||
|
||||
@@ -120,6 +120,7 @@ function isBenignNavigationError(error) {
|
||||
return (
|
||||
message.includes("interrupted by another navigation") ||
|
||||
message.includes("ERR_ABORTED") ||
|
||||
message.includes("NS_BINDING_ABORTED") ||
|
||||
message.includes("Frame load interrupted")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ function isBenignNavigationError(error) {
|
||||
return (
|
||||
message.includes("interrupted by another navigation") ||
|
||||
message.includes("ERR_ABORTED") ||
|
||||
message.includes("NS_BINDING_ABORTED") ||
|
||||
message.includes("Frame load interrupted")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ test("[PAGES][User][/user/bookings] should display the title", async ({ page })
|
||||
});
|
||||
|
||||
test("[BOOKINGS][User][Mobile] should keep booking overview cards within the viewport", async ({ page }) => {
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
|
||||
await mockApi(page, {
|
||||
authenticated: true,
|
||||
sessionData: {
|
||||
@@ -42,7 +44,7 @@ test("[BOOKINGS][User][Mobile] should keep booking overview cards within the vie
|
||||
customer_number: 12345679,
|
||||
customer_name: "Pleno Logistics ApS",
|
||||
department: 12,
|
||||
datetime: "2026-05-28 08:30:00",
|
||||
datetime: `${today} 08:30:00`,
|
||||
reg_1: "AB12345",
|
||||
reg_2: "CD67890",
|
||||
reference: "Lang intern reference der tidligere pressede kortet ud over kanten",
|
||||
@@ -65,7 +67,7 @@ test("[BOOKINGS][User][Mobile] should keep booking overview cards within the vie
|
||||
customer_number: 12345679,
|
||||
customer_name: "Pleno Logistics ApS",
|
||||
department: 1,
|
||||
datetime: "2026-05-28 14:15:00",
|
||||
datetime: `${today} 14:15:00`,
|
||||
reg_1: "EF24680",
|
||||
reg_2: "",
|
||||
reference: "",
|
||||
|
||||
Reference in New Issue
Block a user