favorites, favorites-filter, sold-filter, orders and pending-publish. Five more copies of "register a customer" and three more of the hardcoded base URL go with them. Two locators that were hiding real knowledge are now named. `gridCell` is the item's whole antd column rather than its card, needed because the SOLD ribbon renders outside the card — three specs reached for `.ant-col` directly to get at it. And `chooseAvailability` goes through the title attribute because antd's Segmented hides the real radio behind a styled label, so the input is found by role and cannot be clicked; that fact was written out twice in comments and is now written once in code. The favorite control is located page-wide rather than within a card. The storefront paginates as items accumulate and the control is named for its item anyway, so scoping to a card bought nothing and broke whenever the card was on another page. favorites-filter keeps its local `favorite()` helper. It is genuinely local — decline the opt-in, wait for the fading modal to stop intercepting pointer events, confirm the heart flipped — and belongs to that file's subject rather than to the storefront. It now takes page objects as parameters instead of reaching for locators itself, which is what a spec-level helper should look like. Two specs still drive the registration form rather than taking the `customer` fixture, and deliberately. Both are about a signed-out visitor being interrupted mid-action — favoriting an item, or switching on the favorites filter — and the claim is that the thing they asked for survives the interruption. Replacing the interruption with an API call would delete the test. Verified: favorites 6/6, favorites-filter 7/7, sold-filter 6/6, orders and pending-publish 8/8. Notably favorites-filter's "keeps showing a favorite after it sells" passes, which had been failing on a strict-mode violation from two items sharing a name across runs. Refs #137
60 lines
2.0 KiB
TypeScript
60 lines
2.0 KiB
TypeScript
import { Locator, Page } from '@playwright/test';
|
|
|
|
/**
|
|
* The admin inventory tab: the item table and the form that adds to it.
|
|
*
|
|
* Rows are located by the item's name rather than by index. The table is shared
|
|
* with every other run's items and is paginated and sortable, so an index means
|
|
* a different row depending on what else exists.
|
|
*/
|
|
export class AdminInventory {
|
|
readonly addItemButton: Locator;
|
|
readonly name: Locator;
|
|
readonly price: Locator;
|
|
readonly category: Locator;
|
|
readonly saveButton: Locator;
|
|
|
|
constructor(private readonly page: Page) {
|
|
this.addItemButton = page.getByRole('button', { name: 'Add Item' });
|
|
this.name = page.getByLabel('Name');
|
|
this.price = page.getByLabel('Price (USD)');
|
|
this.category = page.getByLabel('Category', { exact: true });
|
|
this.saveButton = page.getByRole('button', { name: 'Save', exact: true });
|
|
}
|
|
|
|
row(itemName: string): Locator {
|
|
return this.page.getByRole('row').filter({ hasText: itemName });
|
|
}
|
|
|
|
/** The status chip in an item's row — PENDING, AVAILABLE, RESERVED, SOLD. */
|
|
status(itemName: string, status: string): Locator {
|
|
return this.row(itemName).getByText(status);
|
|
}
|
|
|
|
publishButton(itemName: string): Locator {
|
|
return this.row(itemName).getByRole('button', { name: 'Publish' });
|
|
}
|
|
|
|
unpublishButton(itemName: string): Locator {
|
|
return this.row(itemName).getByRole('button', { name: 'Unpublish' });
|
|
}
|
|
|
|
/**
|
|
* The preview drawer, opened by clicking an item's name.
|
|
*
|
|
* It renders the item as the storefront card will, which is the question an
|
|
* admin is asking of a pending item — a customer never sees the pending state.
|
|
*/
|
|
previewDrawer(itemName: string): Locator {
|
|
return this.page.getByRole('dialog', { name: `Preview: ${itemName}` });
|
|
}
|
|
|
|
async openPreview(itemName: string): Promise<void> {
|
|
await this.page.getByRole('button', { name: itemName }).click();
|
|
}
|
|
|
|
async openItemForm(): Promise<void> {
|
|
await this.addItemButton.click();
|
|
}
|
|
}
|