import { test, expect } from '@playwright/test'; import * as auth from '../fixtures/auth'; import * as assertions from '../utils/assertions'; import * as helpers from '../utils/helpers'; import { LOCAL_USERS, TEST_ITEMS } from '../fixtures/test-data'; test.describe('Scan and Adjust Workflow', () => { const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; test.beforeEach(async ({ page }) => { // Navigate to app and login await page.goto(BASE_URL); await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); await assertions.assertUserAuthenticated(page, BASE_URL); // Navigate to scanner page await page.goto(`${BASE_URL}/scanner`); await assertions.assertScannerReady(page); }); test('should display scanner interface with camera view', async ({ page }) => { await assertions.assertScannerReady(page); // Verify camera controls const zoomButton = page.locator('[data-testid="zoom-control"]'); const cameraIndicator = page.locator('[data-testid="camera-indicator"]'); await expect(zoomButton).toBeVisible(); await expect(cameraIndicator).toBeVisible(); }); test('should display scan input field', async ({ page }) => { const scanInput = page.locator('[data-testid="scan-input"]'); await expect(scanInput).toBeVisible(); await expect(scanInput).toBeFocused(); }); test('should handle barcode scan and match to inventory item', async ({ page }) => { // Simulate barcode scan by entering barcode in input const scanInput = page.locator('[data-testid="scan-input"]'); // Enter first test item's barcode await scanInput.fill(TEST_ITEMS[0].barcode); await scanInput.press('Enter'); // Should show stock adjustment form await assertions.assertStockAdjustmentVisible(page, TEST_ITEMS[0].name); // Verify item details are shown const itemName = page.locator('[data-testid="adjustment-item-name"]'); await expect(itemName).toContainText(TEST_ITEMS[0].name); }); test('should default to check-in operation', async ({ page }) => { const scanInput = page.locator('[data-testid="scan-input"]'); await scanInput.fill(TEST_ITEMS[0].barcode); await scanInput.press('Enter'); // Check-in radio should be selected const checkInRadio = page.locator('[data-testid="operation-checkin"]'); await expect(checkInRadio).toBeChecked(); }); test('should allow switching between check-in and check-out', async ({ page }) => { const scanInput = page.locator('[data-testid="scan-input"]'); await scanInput.fill(TEST_ITEMS[0].barcode); await scanInput.press('Enter'); // Switch to check-out const checkOutRadio = page.locator('[data-testid="operation-checkout"]'); await checkOutRadio.click(); await expect(checkOutRadio).toBeChecked(); // Switch back to check-in const checkInRadio = page.locator('[data-testid="operation-checkin"]'); await checkInRadio.click(); await expect(checkInRadio).toBeChecked(); }); test('should allow quantity adjustment', async ({ page }) => { const scanInput = page.locator('[data-testid="scan-input"]'); await scanInput.fill(TEST_ITEMS[0].barcode); await scanInput.press('Enter'); // Change quantity const quantityInput = page.locator('[data-testid="adjustment-quantity-input"]'); await quantityInput.fill('10'); // Verify value changed const value = await helpers.getInputValue(page, '[data-testid="adjustment-quantity-input"]'); expect(value).toBe('10'); }); test('should reject invalid quantities', async ({ page }) => { const scanInput = page.locator('[data-testid="scan-input"]'); await scanInput.fill(TEST_ITEMS[0].barcode); await scanInput.press('Enter'); // Try invalid quantity const quantityInput = page.locator('[data-testid="adjustment-quantity-input"]'); await quantityInput.fill('-5'); // Submit should be disabled or show error const submitButton = page.locator('[data-testid="adjustment-submit"]'); if (await submitButton.isEnabled()) { await submitButton.click(); const errorToast = page.locator('[data-testid="toast-error"]'); await expect(errorToast).toBeVisible({ timeout: 3000 }); } }); test('should submit stock adjustment successfully', async ({ page }) => { const scanInput = page.locator('[data-testid="scan-input"]'); await scanInput.fill(TEST_ITEMS[0].barcode); await scanInput.press('Enter'); // Set quantity const quantityInput = page.locator('[data-testid="adjustment-quantity-input"]'); await quantityInput.fill('5'); // Submit const submitButton = page.locator('[data-testid="adjustment-submit"]'); await submitButton.click(); // Should show success message const successToast = page.locator('[data-testid="toast-success"]'); await expect(successToast).toBeVisible({ timeout: 5000 }); }); test('should close adjustment form after successful submission', async ({ page }) => { const scanInput = page.locator('[data-testid="scan-input"]'); await scanInput.fill(TEST_ITEMS[0].barcode); await scanInput.press('Enter'); const quantityInput = page.locator('[data-testid="adjustment-quantity-input"]'); await quantityInput.fill('5'); const submitButton = page.locator('[data-testid="adjustment-submit"]'); await submitButton.click(); // Wait for success and form to close const adjustmentForm = page.locator('[data-testid="stock-adjustment-form"]'); await expect(adjustmentForm).not.toBeVisible({ timeout: 5000 }); // Scanner input should be focused again const scanner = page.locator('[data-testid="scan-input"]'); await expect(scanner).toBeFocused(); }); test('should handle unknown barcode', async ({ page }) => { const scanInput = page.locator('[data-testid="scan-input"]'); await scanInput.fill('999999999'); await scanInput.press('Enter'); // Should show error or create new item dialog const errorOrDialog = page.locator( '[data-testid="toast-error"], [data-testid="new-item-dialog"]' ); await expect(errorOrDialog).toBeVisible({ timeout: 3000 }); }); test('should support multiple consecutive scans', async ({ page }) => { const scanInput = page.locator('[data-testid="scan-input"]'); // First scan await scanInput.fill(TEST_ITEMS[0].barcode); await scanInput.press('Enter'); let adjustmentForm = page.locator('[data-testid="stock-adjustment-form"]'); await expect(adjustmentForm).toBeVisible(); // Complete first adjustment const quantityInput = page.locator('[data-testid="adjustment-quantity-input"]'); await quantityInput.fill('5'); const submitButton = page.locator('[data-testid="adjustment-submit"]'); await submitButton.click(); // Wait for form to close await expect(adjustmentForm).not.toBeVisible({ timeout: 5000 }); // Second scan await scanInput.fill(TEST_ITEMS[1].barcode); await scanInput.press('Enter'); // Second adjustment form should appear adjustmentForm = page.locator('[data-testid="stock-adjustment-form"]'); await expect(adjustmentForm).toBeVisible(); }); test('should display item quantity history', async ({ page }) => { const scanInput = page.locator('[data-testid="scan-input"]'); await scanInput.fill(TEST_ITEMS[0].barcode); await scanInput.press('Enter'); // Check if history is displayed const historySection = page.locator('[data-testid="adjustment-history"]'); if (await historySection.isVisible()) { const historyItems = page.locator('[data-testid="history-item"]'); expect(await historyItems.count()).toBeGreaterThan(0); } }); test('should allow canceling adjustment', async ({ page }) => { const scanInput = page.locator('[data-testid="scan-input"]'); await scanInput.fill(TEST_ITEMS[0].barcode); await scanInput.press('Enter'); // Click cancel button const cancelButton = page.locator('[data-testid="adjustment-cancel"]'); if (await cancelButton.isVisible()) { await cancelButton.click(); // Form should close const adjustmentForm = page.locator('[data-testid="stock-adjustment-form"]'); await expect(adjustmentForm).not.toBeVisible(); } }); test('should display current inventory count', async ({ page }) => { const scanInput = page.locator('[data-testid="scan-input"]'); await scanInput.fill(TEST_ITEMS[0].barcode); await scanInput.press('Enter'); // Current quantity should be displayed const currentQuantity = page.locator('[data-testid="current-quantity"]'); await expect(currentQuantity).toBeVisible(); const quantityText = await currentQuantity.textContent(); expect(quantityText).toMatch(/\d+/); }); test('should show category in item details', async ({ page }) => { const scanInput = page.locator('[data-testid="scan-input"]'); await scanInput.fill(TEST_ITEMS[0].barcode); await scanInput.press('Enter'); const categoryDisplay = page.locator('[data-testid="item-category"]'); if (await categoryDisplay.isVisible()) { const categoryText = await categoryDisplay.textContent(); expect(categoryText).toContain(TEST_ITEMS[0].category); } }); test('should clear scan input after successful operation', async ({ page }) => { const scanInput = page.locator('[data-testid="scan-input"]'); await scanInput.fill(TEST_ITEMS[0].barcode); await scanInput.press('Enter'); const quantityInput = page.locator('[data-testid="adjustment-quantity-input"]'); await quantityInput.fill('5'); const submitButton = page.locator('[data-testid="adjustment-submit"]'); await submitButton.click(); // Wait for form to close and input to clear await expect(scanInput).toHaveValue('', { timeout: 5000 }); }); });