262 lines
8.3 KiB
TypeScript
262 lines
8.3 KiB
TypeScript
import { expect, Page, Locator } from '@playwright/test';
|
|
|
|
/**
|
|
* Custom Playwright assertions for E2E tests
|
|
* Provides domain-specific matchers for inventory operations
|
|
*/
|
|
|
|
/**
|
|
* Assert that an inventory item is visible with expected data
|
|
*/
|
|
export async function assertItemVisible(
|
|
page: Page,
|
|
itemName: string,
|
|
expectedData?: { quantity?: number; category?: string }
|
|
): Promise<void> {
|
|
const itemRow = page.locator(`[data-testid="item-row"][data-item-name="${itemName}"]`);
|
|
await expect(itemRow).toBeVisible();
|
|
|
|
if (expectedData?.quantity !== undefined) {
|
|
const quantityCell = itemRow.locator('[data-testid="quantity-cell"]');
|
|
await expect(quantityCell).toContainText(expectedData.quantity.toString());
|
|
}
|
|
|
|
if (expectedData?.category !== undefined) {
|
|
const categoryCell = itemRow.locator('[data-testid="category-cell"]');
|
|
await expect(categoryCell).toContainText(expectedData.category);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Assert that a barcode scan was successful
|
|
*/
|
|
export async function assertScanSuccess(
|
|
page: Page,
|
|
expectedItemName: string,
|
|
expectedQuantityChange: number
|
|
): Promise<void> {
|
|
// Check for success toast notification
|
|
const successToast = page.locator('[data-testid="toast-success"]');
|
|
await expect(successToast).toBeVisible({ timeout: 3000 });
|
|
|
|
// Verify item quantity was updated
|
|
const itemRow = page.locator(`[data-testid="item-row"][data-item-name="${expectedItemName}"]`);
|
|
await expect(itemRow).toBeVisible();
|
|
}
|
|
|
|
/**
|
|
* Assert that login form is displayed
|
|
*/
|
|
export async function assertLoginFormVisible(page: Page): Promise<void> {
|
|
const loginForm = page.locator('[data-testid="login-form"]');
|
|
await expect(loginForm).toBeVisible();
|
|
|
|
const usernameInput = page.locator('[data-testid="username-input"]');
|
|
const passwordInput = page.locator('[data-testid="password-input"]');
|
|
const submitButton = page.locator('[data-testid="login-submit"]');
|
|
|
|
await expect(usernameInput).toBeVisible();
|
|
await expect(passwordInput).toBeVisible();
|
|
await expect(submitButton).toBeVisible();
|
|
}
|
|
|
|
/**
|
|
* Assert that user is authenticated (on inventory page)
|
|
*/
|
|
export async function assertUserAuthenticated(page: Page, baseUrl: string = 'http://localhost'): Promise<void> {
|
|
// Check URL is on an authenticated page
|
|
await expect(page).toHaveURL(/inventory|dashboard|scanner/);
|
|
|
|
// Verify logout button is visible
|
|
const logoutButton = page.locator('[data-testid="logout-button"]');
|
|
await expect(logoutButton).toBeVisible();
|
|
}
|
|
|
|
/**
|
|
* Assert that admin dashboard is visible
|
|
*/
|
|
export async function assertAdminDashboardVisible(page: Page): Promise<void> {
|
|
const adminOverlay = page.locator('[data-testid="admin-overlay"]');
|
|
await expect(adminOverlay).toBeVisible();
|
|
|
|
// Check for tabs
|
|
const identityTab = page.locator('[data-testid="admin-tab-identity"]');
|
|
const databaseTab = page.locator('[data-testid="admin-tab-database"]');
|
|
|
|
await expect(identityTab).toBeVisible();
|
|
await expect(databaseTab).toBeVisible();
|
|
}
|
|
|
|
/**
|
|
* Assert that stock adjustment form is visible
|
|
*/
|
|
export async function assertStockAdjustmentVisible(page: Page, itemName: string): Promise<void> {
|
|
const adjustmentForm = page.locator('[data-testid="stock-adjustment-form"]');
|
|
await expect(adjustmentForm).toBeVisible();
|
|
|
|
const itemNameDisplay = page.locator(`[data-testid="adjustment-item-name"]`);
|
|
await expect(itemNameDisplay).toContainText(itemName);
|
|
|
|
const quantityInput = page.locator('[data-testid="adjustment-quantity-input"]');
|
|
await expect(quantityInput).toBeVisible();
|
|
}
|
|
|
|
/**
|
|
* Assert that AI extraction is in progress
|
|
*/
|
|
export async function assertAiExtractionInProgress(page: Page): Promise<void> {
|
|
const extractionOverlay = page.locator('[data-testid="ai-extraction-overlay"]');
|
|
await expect(extractionOverlay).toBeVisible();
|
|
|
|
const loadingSpinner = page.locator('[data-testid="extraction-loading"]');
|
|
await expect(loadingSpinner).toBeVisible();
|
|
}
|
|
|
|
/**
|
|
* Assert that AI extraction results are displayed
|
|
*/
|
|
export async function assertAiExtractionResults(
|
|
page: Page,
|
|
expectedFields: { name?: string; partNumber?: string; quantity?: string }
|
|
): Promise<void> {
|
|
const resultsForm = page.locator('[data-testid="extraction-results-form"]');
|
|
await expect(resultsForm).toBeVisible();
|
|
|
|
if (expectedFields.name) {
|
|
const nameInput = resultsForm.locator('[data-testid="extracted-name"]');
|
|
await expect(nameInput).toHaveValue(expectedFields.name);
|
|
}
|
|
|
|
if (expectedFields.partNumber) {
|
|
const pnInput = resultsForm.locator('[data-testid="extracted-part-number"]');
|
|
await expect(pnInput).toHaveValue(expectedFields.partNumber);
|
|
}
|
|
|
|
if (expectedFields.quantity) {
|
|
const quantityInput = resultsForm.locator('[data-testid="extracted-quantity"]');
|
|
await expect(quantityInput).toHaveValue(expectedFields.quantity);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Assert that offline sync is pending
|
|
*/
|
|
export async function assertOfflineSyncPending(page: Page): Promise<void> {
|
|
const syncIndicator = page.locator('[data-testid="offline-sync-indicator"]');
|
|
await expect(syncIndicator).toBeVisible();
|
|
|
|
const pendingBadge = page.locator('[data-testid="sync-pending-badge"]');
|
|
await expect(pendingBadge).toBeVisible();
|
|
}
|
|
|
|
/**
|
|
* Assert that offline sync completed
|
|
*/
|
|
export async function assertOfflineSyncComplete(page: Page): Promise<void> {
|
|
const syncIndicator = page.locator('[data-testid="offline-sync-indicator"]');
|
|
await expect(syncIndicator).not.toBeVisible({ timeout: 10000 });
|
|
|
|
const successBadge = page.locator('[data-testid="sync-success-badge"]');
|
|
await expect(successBadge).toBeVisible();
|
|
}
|
|
|
|
/**
|
|
* Assert that error message is displayed
|
|
*/
|
|
export async function assertErrorMessage(page: Page, errorText?: string): Promise<void> {
|
|
const errorToast = page.locator('[data-testid="toast-error"]');
|
|
await expect(errorToast).toBeVisible();
|
|
|
|
if (errorText) {
|
|
await expect(errorToast).toContainText(errorText);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Assert that category list is visible
|
|
*/
|
|
export async function assertCategoryListVisible(page: Page): Promise<void> {
|
|
const categoryList = page.locator('[data-testid="category-list"]');
|
|
await expect(categoryList).toBeVisible();
|
|
|
|
const categoryItems = page.locator('[data-testid="category-item"]');
|
|
const count = await categoryItems.count();
|
|
expect(count).toBeGreaterThan(0);
|
|
}
|
|
|
|
/**
|
|
* Assert that scanner interface is ready
|
|
*/
|
|
export async function assertScannerReady(page: Page): Promise<void> {
|
|
const scannerContainer = page.locator('[data-testid="scanner-container"]');
|
|
await expect(scannerContainer).toBeVisible();
|
|
|
|
const cameraView = page.locator('[data-testid="camera-view"]');
|
|
await expect(cameraView).toBeVisible();
|
|
|
|
const scanInput = page.locator('[data-testid="scan-input"]');
|
|
await expect(scanInput).toBeVisible();
|
|
}
|
|
|
|
/**
|
|
* Assert that item creation form is visible
|
|
*/
|
|
export async function assertItemCreationFormVisible(page: Page): Promise<void> {
|
|
const createForm = page.locator('[data-testid="create-item-form"]');
|
|
await expect(createForm).toBeVisible();
|
|
|
|
const nameInput = page.locator('[data-testid="item-name-input"]');
|
|
const categorySelect = page.locator('[data-testid="item-category-select"]');
|
|
const submitButton = page.locator('[data-testid="item-create-submit"]');
|
|
|
|
await expect(nameInput).toBeVisible();
|
|
await expect(categorySelect).toBeVisible();
|
|
await expect(submitButton).toBeVisible();
|
|
}
|
|
|
|
/**
|
|
* Assert element count matches expected
|
|
*/
|
|
export async function assertElementCount(
|
|
page: Page,
|
|
selector: string,
|
|
expectedCount: number
|
|
): Promise<void> {
|
|
const elements = page.locator(selector);
|
|
const count = await elements.count();
|
|
expect(count).toBe(expectedCount);
|
|
}
|
|
|
|
/**
|
|
* Assert element is disabled
|
|
*/
|
|
export async function assertElementDisabled(locator: Locator): Promise<void> {
|
|
await expect(locator).toBeDisabled();
|
|
}
|
|
|
|
/**
|
|
* Assert element is enabled
|
|
*/
|
|
export async function assertElementEnabled(locator: Locator): Promise<void> {
|
|
await expect(locator).toBeEnabled();
|
|
}
|
|
|
|
/**
|
|
* Assert modal is open
|
|
*/
|
|
export async function assertModalOpen(page: Page, modalId: string): Promise<void> {
|
|
const modal = page.locator(`[data-testid="${modalId}"]`);
|
|
await expect(modal).toBeVisible();
|
|
|
|
const backdrop = page.locator('[data-testid="modal-backdrop"]');
|
|
await expect(backdrop).toBeVisible();
|
|
}
|
|
|
|
/**
|
|
* Assert modal is closed
|
|
*/
|
|
export async function assertModalClosed(page: Page, modalId: string): Promise<void> {
|
|
const modal = page.locator(`[data-testid="${modalId}"]`);
|
|
await expect(modal).not.toBeVisible();
|
|
}
|