Skip to content

Commit b02b39c

Browse files
authored
Refactor wipe inventory E2E playwright tests
2 parents e4aa38b + b290175 commit b02b39c

File tree

1 file changed

+161
-108
lines changed

1 file changed

+161
-108
lines changed
Lines changed: 161 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,182 @@
1+
import type { Page } from "@playwright/test";
12
import { expect, test } from "@playwright/test";
23

3-
test.describe("Wipe Inventory E2E Test", () => {
4-
test.beforeEach(async ({ page }) => {
5-
// Login as demo user (owner with permissions)
6-
await page.goto("/");
7-
await page.fill("input[type='text']", "[email protected]");
8-
await page.fill("input[type='password']", "demo");
9-
await page.click("button[type='submit']");
10-
await expect(page).toHaveURL("/home");
4+
const STATUS_ROUTE = "**/api/v1/status";
5+
const WIPE_ROUTE = "**/api/v1/actions/wipe-inventory";
6+
7+
const buildStatusResponse = (demo: boolean) => ({
8+
allowRegistration: true,
9+
build: { buildTime: new Date().toISOString(), commit: "test", version: "v0.0.0" },
10+
demo,
11+
health: true,
12+
labelPrinting: false,
13+
latest: { date: new Date().toISOString(), version: "v0.0.0" },
14+
message: "",
15+
oidc: { allowLocal: true, autoRedirect: false, buttonText: "", enabled: false },
16+
title: "Homebox",
17+
versions: [],
18+
});
19+
20+
async function mockStatus(page: Page, demo: boolean) {
21+
await page.route(STATUS_ROUTE, route => {
22+
route.fulfill({
23+
status: 200,
24+
contentType: "application/json",
25+
body: JSON.stringify(buildStatusResponse(demo)),
26+
});
27+
});
28+
}
29+
30+
async function login(page: Page, email = "[email protected]", password = "demo") {
31+
await page.goto("/home");
32+
await expect(page).toHaveURL("/");
33+
await page.fill("input[type='text']", email);
34+
await page.fill("input[type='password']", password);
35+
await page.click("button[type='submit']");
36+
await expect(page).toHaveURL("/home");
37+
}
38+
39+
async function openWipeInventory(page: Page) {
40+
await page.goto("/tools");
41+
await page.waitForLoadState("networkidle");
42+
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
43+
44+
const wipeButton = page.getByRole("button", { name: "Wipe Inventory" }).last();
45+
await expect(wipeButton).toBeVisible();
46+
await wipeButton.click();
47+
}
48+
49+
test.describe("Wipe Inventory", () => {
50+
test("shows demo mode warning without wipe options", async ({ page }) => {
51+
await mockStatus(page, true);
52+
await login(page);
53+
await openWipeInventory(page);
54+
55+
await expect(
56+
page.getByText(
57+
"Inventory, labels, locations and maintenance records cannot be wiped whilst Homebox is in demo mode.",
58+
{ exact: false }
59+
)
60+
).toBeVisible();
61+
62+
await expect(page.locator("input#wipe-labels-checkbox")).toHaveCount(0);
63+
await expect(page.locator("input#wipe-locations-checkbox")).toHaveCount(0);
64+
await expect(page.locator("input#wipe-maintenance-checkbox")).toHaveCount(0);
1165
});
1266

13-
test("should open wipe inventory dialog with all options", async ({ page }) => {
14-
// Navigate to Tools page
15-
await page.goto("/tools");
16-
await page.waitForLoadState("networkidle");
67+
test.describe("production mode", () => {
68+
test.beforeEach(async ({ page }) => {
69+
await mockStatus(page, false);
70+
await login(page);
71+
});
1772

18-
// Scroll to the bottom where wipe inventory is located
19-
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
20-
await page.waitForTimeout(500);
73+
test("renders wipe options and submits all flags", async ({ page }) => {
74+
await page.route(WIPE_ROUTE, route => {
75+
route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ completed: 0 }) });
76+
});
2177

22-
// Find and click the Wipe Inventory button
23-
const wipeButton = page.locator("button", { hasText: "Wipe Inventory" }).last();
24-
await expect(wipeButton).toBeVisible();
25-
await wipeButton.click();
78+
await openWipeInventory(page);
79+
await expect(page.getByText("Wipe Inventory").first()).toBeVisible();
2680

27-
// Wait for dialog to appear
28-
await page.waitForTimeout(1000);
81+
const labels = page.locator("input#wipe-labels-checkbox");
82+
const locations = page.locator("input#wipe-locations-checkbox");
83+
const maintenance = page.locator("input#wipe-maintenance-checkbox");
2984

30-
// Verify dialog title is visible
31-
await expect(page.locator("text=Wipe Inventory").first()).toBeVisible();
85+
await expect(labels).toBeVisible();
86+
await expect(locations).toBeVisible();
87+
await expect(maintenance).toBeVisible();
3288

33-
// Verify all checkboxes are present
34-
await expect(page.locator("input#wipe-labels-checkbox")).toBeVisible();
35-
await expect(page.locator("input#wipe-locations-checkbox")).toBeVisible();
36-
await expect(page.locator("input#wipe-maintenance-checkbox")).toBeVisible();
89+
await labels.check();
90+
await locations.check();
91+
await maintenance.check();
3792

38-
// Verify labels for checkboxes
39-
await expect(page.locator("label[for='wipe-labels-checkbox']")).toBeVisible();
40-
await expect(page.locator("label[for='wipe-locations-checkbox']")).toBeVisible();
41-
await expect(page.locator("label[for='wipe-maintenance-checkbox']")).toBeVisible();
93+
const requestPromise = page.waitForRequest(WIPE_ROUTE);
94+
await page.getByRole("button", { name: "Confirm" }).last().click();
95+
const request = await requestPromise;
4296

43-
// Verify both Cancel and Confirm buttons are present
44-
await expect(page.locator("button", { hasText: "Cancel" })).toBeVisible();
45-
const confirmButton = page.locator("button", { hasText: "Confirm" });
46-
await expect(confirmButton).toBeVisible();
97+
expect(request.postDataJSON()).toEqual({
98+
wipeLabels: true,
99+
wipeLocations: true,
100+
wipeMaintenance: true,
101+
});
47102

48-
// Take screenshot of the modal
49-
await page.screenshot({
50-
path: "/tmp/playwright-logs/wipe-inventory-modal-initial.png",
51-
});
52-
console.log("✅ Screenshot saved: wipe-inventory-modal-initial.png");
53-
54-
// Check all three options
55-
await page.check("input#wipe-labels-checkbox");
56-
await page.check("input#wipe-locations-checkbox");
57-
await page.check("input#wipe-maintenance-checkbox");
58-
await page.waitForTimeout(500);
59-
60-
// Verify checkboxes are checked
61-
await expect(page.locator("input#wipe-labels-checkbox")).toBeChecked();
62-
await expect(page.locator("input#wipe-locations-checkbox")).toBeChecked();
63-
await expect(page.locator("input#wipe-maintenance-checkbox")).toBeChecked();
64-
65-
// Take screenshot with all options checked
66-
await page.screenshot({
67-
path: "/tmp/playwright-logs/wipe-inventory-modal-options-checked.png",
103+
await expect(page.locator("[role='status']").first()).toBeVisible();
68104
});
69-
console.log("✅ Screenshot saved: wipe-inventory-modal-options-checked.png");
70105

71-
// Click Confirm button
72-
await confirmButton.click();
73-
await page.waitForTimeout(2000);
106+
test("blocks wipe attempts from non-owners", async ({ page }) => {
107+
await page.route(WIPE_ROUTE, route => {
108+
route.fulfill({
109+
status: 403,
110+
contentType: "application/json",
111+
body: JSON.stringify({ message: "forbidden" }),
112+
});
113+
});
74114

75-
// Wait for the dialog to close (verify button is no longer visible)
76-
await expect(confirmButton).not.toBeVisible({ timeout: 5000 });
115+
await openWipeInventory(page);
77116

78-
// Check for success toast notification
79-
// The toast should contain text about items being deleted
80-
const toastLocator = page.locator("[role='status'], [class*='toast'], [class*='sonner']");
81-
await expect(toastLocator.first()).toBeVisible({ timeout: 10000 });
117+
const requestPromise = page.waitForRequest(WIPE_ROUTE);
118+
await page.getByRole("button", { name: "Confirm" }).last().click();
119+
await requestPromise;
82120

83-
// Take screenshot of the page after confirmation
84-
await page.screenshot({
85-
path: "/tmp/playwright-logs/after-wipe-confirmation.png",
86-
fullPage: true,
121+
await expect(page.getByText("Failed to wipe inventory.")).toBeVisible();
87122
});
88-
console.log("✅ Screenshot saved: after-wipe-confirmation.png");
89-
90-
console.log("✅ Test completed successfully!");
91-
console.log("✅ Wipe Inventory dialog opened correctly");
92-
console.log("✅ All three options (labels, locations, maintenance) are available");
93-
console.log("✅ Confirm button triggers the action");
94-
console.log("✅ Dialog closes after confirmation");
95-
});
96123

97-
test("should cancel wipe inventory operation", async ({ page }) => {
98-
// Navigate to Tools page
99-
await page.goto("/tools");
100-
await page.waitForLoadState("networkidle");
101-
102-
// Scroll to wipe inventory section
103-
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
104-
await page.waitForTimeout(500);
105-
106-
// Click Wipe Inventory button
107-
const wipeButton = page.locator("button", { hasText: "Wipe Inventory" }).last();
108-
await wipeButton.click();
109-
await page.waitForTimeout(1000);
110-
111-
// Verify dialog is open
112-
await expect(page.locator("text=Wipe Inventory").first()).toBeVisible();
113-
114-
// Click Cancel button
115-
const cancelButton = page.locator("button", { hasText: "Cancel" });
116-
await cancelButton.click();
117-
await page.waitForTimeout(1000);
118-
119-
// Verify dialog is closed
120-
await expect(page.locator("text=Wipe Inventory").first()).not.toBeVisible({ timeout: 5000 });
121-
122-
// Take screenshot after cancel
123-
await page.screenshot({
124-
path: "/tmp/playwright-logs/after-cancel.png",
125-
});
126-
console.log("✅ Screenshot saved: after-cancel.png");
127-
console.log("✅ Cancel button works correctly");
124+
const checkboxCases = [
125+
{
126+
name: "labels only",
127+
selection: { labels: true, locations: false, maintenance: false },
128+
},
129+
{
130+
name: "locations only",
131+
selection: { labels: false, locations: true, maintenance: false },
132+
},
133+
{
134+
name: "maintenance only",
135+
selection: { labels: false, locations: false, maintenance: true },
136+
},
137+
];
138+
139+
for (const scenario of checkboxCases) {
140+
test(`submits correct flags when ${scenario.name} is selected`, async ({ page }) => {
141+
await page.route(WIPE_ROUTE, route => {
142+
route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ completed: 0 }) });
143+
});
144+
145+
await openWipeInventory(page);
146+
await expect(page.getByText("Wipe Inventory").first()).toBeVisible();
147+
148+
const labels = page.locator("input#wipe-labels-checkbox");
149+
const locations = page.locator("input#wipe-locations-checkbox");
150+
const maintenance = page.locator("input#wipe-maintenance-checkbox");
151+
152+
if (scenario.selection.labels) {
153+
await labels.check();
154+
} else {
155+
await labels.uncheck();
156+
}
157+
158+
if (scenario.selection.locations) {
159+
await locations.check();
160+
} else {
161+
await locations.uncheck();
162+
}
163+
164+
if (scenario.selection.maintenance) {
165+
await maintenance.check();
166+
} else {
167+
await maintenance.uncheck();
168+
}
169+
170+
const requestPromise = page.waitForRequest(WIPE_ROUTE);
171+
await page.getByRole("button", { name: "Confirm" }).last().click();
172+
const request = await requestPromise;
173+
174+
expect(request.postDataJSON()).toEqual({
175+
wipeLabels: scenario.selection.labels,
176+
wipeLocations: scenario.selection.locations,
177+
wipeMaintenance: scenario.selection.maintenance,
178+
});
179+
});
180+
}
128181
});
129182
});

0 commit comments

Comments
 (0)