pelagia-portal/App/pelagia-portal/tests/e2e/admin-bordered-buttons.spec.ts
Hardik 26211e898d test(e2e): add comprehensive Playwright test suite for all recent features
Covers 21 user story groups extracted from the last 15+ feature commits:

- rebrand.spec.ts — PPMS branding on login page, sidebar, and tab title
- dashboard/po-status-badges.js — color-coded status badges for submitter & manager
- po-submit-button.spec.ts — Submit for Approval button visibility on DRAFT POs
- notification-bell.spec.ts — in-app bell icon, unread badge, and panel open
- export-gate.spec.ts — export buttons gated on MGR_APPROVED+ status; 403 on pre-approval
- payment-history.spec.ts — /payments/history accessible to ACCOUNTS; redirects others
- partial-receipt.spec.ts — per-item delivery tracking UI on paid POs
- vendor-auto-verify.spec.ts — vendor verification status visible in admin
- admin-bordered-buttons.spec.ts — Edit/Deactivate/Delete have border classes on admin pages
- profile.spec.ts — profile page loads for all roles; signature section for MANAGER/SUPERUSER
- inventory/items-tags.spec.ts — Cheapest/Closest tags and auto-sort by distance
- inventory/cart-icon.spec.ts — cart header icon with badge; item/vendor detail pages
- mobile/desktop-required.spec.ts — Desktop Required overlay for non-mobile roles + sign-out
- mobile/manager-approvals.spec.ts — mobile card layout; edit form hidden; action buttons visible
- mobile/accounts-payments.spec.ts — ACCOUNTS payments queue and buttons on mobile
- mobile/bottom-nav.spec.ts — Home/Approvals/Profile tabs for MANAGER; Home/Payments/Profile for ACCOUNTS
- approvals-edit-highlight.spec.ts — diff indicators on resubmitted POs

Also adds shared helpers/login.ts with USERS constants, login(), createDraftPo(),
and submitPo() — all using name-attribute selectors since PO form labels have no
htmlFor binding. Playwright config updated: workers capped at 2 locally (was
unlimited) to prevent auth concurrency failures, and retries set to 1 locally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 18:25:42 +05:30

128 lines
4.6 KiB
TypeScript

/**
* User stories covered: Feature 10 — Admin bordered buttons
* - On /admin/vendors, Edit and Delete buttons have visible borders (not plain text links)
* - Same checks apply to /admin/users, /admin/vessels, /admin/accounts, /admin/products
*
* The fix replaced text-link style buttons with bordered buttons. We check that action
* buttons in admin tables do NOT have link-only styling (no underline-only appearance)
* and DO have a border or background CSS class.
*
* Selector strategy: Admin action buttons are rendered by EditVendorButton, ConfirmDeleteButton.
* We look for <button> or <a> elements in the last table column that have class attributes
* containing "border" — this is the key indicator of the style fix.
*
* Created: 2026-05-17
*/
import { test, expect } from "@playwright/test";
import { login, USERS } from "./helpers/login";
/** Assert that action buttons in the last column of an admin table have border classes. */
async function assertBorderedButtons(
page: import("@playwright/test").Page,
url: string
): Promise<void> {
await page.goto(url);
await page.waitForLoadState("networkidle");
// Find all action cells in the last column of the table body
// The admin pages use a consistent table layout where the last <td> holds action buttons
const actionCells = page.locator("table tbody tr td:last-child");
const cellCount = await actionCells.count();
if (cellCount === 0) {
console.log(` No table rows found on ${url} — skipping button check`);
return;
}
// Get all buttons/links within the action cells
const actionButtons = actionCells.locator("button, a");
const btnCount = await actionButtons.count();
if (btnCount === 0) {
console.log(` No action buttons found on ${url}`);
return;
}
// Verify at least one button has border-related class (not a plain text link)
let foundBorderedButton = false;
for (let i = 0; i < Math.min(btnCount, 10); i++) {
const cls = (await actionButtons.nth(i).getAttribute("class")) ?? "";
if (
cls.includes("border") ||
cls.includes("bg-") ||
cls.includes("btn") ||
cls.includes("rounded")
) {
foundBorderedButton = true;
break;
}
}
expect(foundBorderedButton).toBeTruthy();
console.log(`✓ Bordered/styled action buttons found on ${url}`);
}
test.describe("Feature 10 — Admin bordered buttons", () => {
test("US-10a: /admin/vendors action buttons have border classes", async ({
page,
}) => {
await login(page, USERS.ADMIN);
await assertBorderedButtons(page, "/admin/vendors");
});
test("US-10a: /admin/users action buttons have border classes", async ({
page,
}) => {
await login(page, USERS.ADMIN);
await assertBorderedButtons(page, "/admin/users");
});
test("US-10a: /admin/vessels action buttons have border classes", async ({
page,
}) => {
await login(page, USERS.ADMIN);
await assertBorderedButtons(page, "/admin/vessels");
});
test("US-10a: /admin/accounts action buttons have border classes", async ({
page,
}) => {
await login(page, USERS.ADMIN);
await assertBorderedButtons(page, "/admin/accounts");
});
test("US-10a: /admin/products action buttons have border classes", async ({
page,
}) => {
await login(page, USERS.ADMIN);
await assertBorderedButtons(page, "/admin/products");
});
test("US-10a: /admin/vendors Edit button is visually distinct from plain text", async ({
page,
}) => {
await login(page, USERS.ADMIN);
await page.goto("/admin/vendors");
await page.waitForLoadState("networkidle");
// The EditVendorButton renders as a <button> with some visual styling
// After the fix it should have border or background — not just text color
const editBtns = page.locator("table tbody tr td:last-child button").first();
if (await editBtns.isVisible()) {
const cls = (await editBtns.getAttribute("class")) ?? "";
// Must NOT be an unstyled anchor-look-alike; must have border or bg
const hasVisualStyle =
cls.includes("border") || cls.includes("bg-") || cls.includes("rounded");
expect(hasVisualStyle).toBeTruthy();
console.log(`✓ Edit button class: ${cls.slice(0, 80)}...`);
} else {
// Vendors table might use <span> wrapping both buttons
const spanBtn = page.locator("table tbody tr td:last-child span button").first();
const spanCls = (await spanBtn.getAttribute("class")) ?? "";
expect(
spanCls.includes("border") || spanCls.includes("bg-") || spanCls.includes("rounded")
).toBeTruthy();
console.log(`✓ Vendor edit button has visual styling`);
}
});
});