Files
tfm_ainventory/frontend/e2e/workflows/2-scan-adjust.spec.ts

258 lines
9.6 KiB
TypeScript

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:8917';
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 });
});
});