b34b0dd7d6
Validators (Pushes and Pull Requests) / UI & Storage Validation (pull_request) Failing after 12s
Validators (Pushes and Pull Requests) / Database & Schema Validation (pull_request) Successful in 13s
Validators (Pushes and Pull Requests) / Core Validators & Database Setup (pull_request) Failing after 28s
Validators (Pushes and Pull Requests) / WBS & Audit Validations (pull_request) Has been skipped
Validators (Pushes and Pull Requests) / .NET Contracts (pull_request) Has been skipped
Validators (Pushes and Pull Requests) / Calibration & Performance (pull_request) Has been skipped
Validators (Pushes and Pull Requests) / Operational Report & Decision Packet (pull_request) Has been skipped
Validators (Pushes and Pull Requests) / CI Workflow Lint (pull_request) Failing after 10s
Validators (Pushes and Pull Requests) / Security & Secrets (pull_request) Successful in 12s
Validators (Pushes and Pull Requests) / Notify PR Results (pull_request) Successful in 2s
Frontend CI Pipeline / ci-frontend-8-steps (pull_request) Failing after 2m50s
259 lines
7.8 KiB
TypeScript
259 lines
7.8 KiB
TypeScript
/**
|
|
* E2E Tests: Complete Order-to-Inventory Flow
|
|
* Tests the full business flow from order creation to inventory update
|
|
*
|
|
* Run: npm run test:e2e
|
|
*/
|
|
|
|
import { test, expect } from '@playwright/test'
|
|
|
|
test.describe('OMS·WMS·ERP Complete Flow', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
// Navigate to application
|
|
await page.goto('http://localhost:5173')
|
|
|
|
// Wait for app to load
|
|
await page.waitForLoadState('networkidle')
|
|
})
|
|
|
|
test('orders page loads with navigation', async ({ page }) => {
|
|
// Find navigation to orders
|
|
const ordersNav = page.getByRole('link', { name: /orders/i })
|
|
await expect(ordersNav).toBeVisible()
|
|
|
|
// Click and verify page loads
|
|
await ordersNav.click()
|
|
await page.waitForURL('**/orders**')
|
|
await expect(page).toHaveTitle(/.*orders.*/i)
|
|
})
|
|
|
|
test('inventory page loads with navigation', async ({ page }) => {
|
|
const inventoryNav = page.getByRole('link', { name: /inventory/i })
|
|
await expect(inventoryNav).toBeVisible()
|
|
|
|
await inventoryNav.click()
|
|
await page.waitForURL('**/inventory**')
|
|
await expect(page).toHaveTitle(/.*inventory.*/i)
|
|
})
|
|
|
|
test('products page loads with navigation', async ({ page }) => {
|
|
const productsNav = page.getByRole('link', { name: /products/i })
|
|
await expect(productsNav).toBeVisible()
|
|
|
|
await productsNav.click()
|
|
await page.waitForURL('**/products**')
|
|
await expect(page).toHaveTitle(/.*products.*/i)
|
|
})
|
|
|
|
test('responsive navigation on mobile', async ({ page }) => {
|
|
// Set mobile viewport
|
|
await page.setViewportSize({ width: 375, height: 667 })
|
|
|
|
// Look for mobile menu toggle
|
|
const menuToggle = page.getByRole('button', { name: /menu|toggle/i })
|
|
if (await menuToggle.isVisible()) {
|
|
await menuToggle.click()
|
|
await expect(page.getByRole('navigation')).toBeVisible()
|
|
}
|
|
})
|
|
|
|
test('orders page displays data', async ({ page }) => {
|
|
await page.goto('http://localhost:5173/orders')
|
|
await page.waitForLoadState('networkidle')
|
|
|
|
// Wait for table to load
|
|
const table = page.locator('table')
|
|
if (await table.isVisible({ timeout: 5000 }).catch(() => false)) {
|
|
const rows = await page.locator('tbody tr').count()
|
|
// Should have at least mock data
|
|
expect(rows).toBeGreaterThan(0)
|
|
}
|
|
})
|
|
|
|
test('inventory page displays data', async ({ page }) => {
|
|
await page.goto('http://localhost:5173/inventory')
|
|
await page.waitForLoadState('networkidle')
|
|
|
|
const content = page.locator('main, [role="main"]')
|
|
await expect(content).toBeVisible()
|
|
})
|
|
|
|
test('products page displays data', async ({ page }) => {
|
|
await page.goto('http://localhost:5173/products')
|
|
await page.waitForLoadState('networkidle')
|
|
|
|
const content = page.locator('main, [role="main"]')
|
|
await expect(content).toBeVisible()
|
|
})
|
|
|
|
test('buttons are accessible and interactive', async ({ page }) => {
|
|
await page.goto('http://localhost:5173/orders')
|
|
await page.waitForLoadState('networkidle')
|
|
|
|
// Look for action buttons
|
|
const buttons = page.getByRole('button')
|
|
const count = await buttons.count()
|
|
|
|
if (count > 0) {
|
|
const firstButton = buttons.first()
|
|
await expect(firstButton).toBeEnabled()
|
|
}
|
|
})
|
|
|
|
test('forms have proper validation', async ({ page }) => {
|
|
// Navigate to create order (if form exists)
|
|
await page.goto('http://localhost:5173/orders')
|
|
|
|
// Look for create button or form
|
|
const createButton = page.getByRole('button', { name: /create|new|add/i })
|
|
if (await createButton.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
await createButton.click()
|
|
|
|
// Look for form inputs
|
|
const inputs = page.locator('input')
|
|
const inputCount = await inputs.count()
|
|
|
|
if (inputCount > 0) {
|
|
// Verify inputs are interactive
|
|
const firstInput = inputs.first()
|
|
await expect(firstInput).toBeFocusable()
|
|
}
|
|
}
|
|
})
|
|
|
|
test('error handling shows user-friendly messages', async ({ page }) => {
|
|
// This test would require a specific error scenario
|
|
// For now, verify that error states don't break the UI
|
|
|
|
await page.goto('http://localhost:5173/orders')
|
|
await page.waitForLoadState('networkidle')
|
|
|
|
// Verify page content is visible even if API might fail
|
|
const mainContent = page.locator('main, [role="main"]')
|
|
await expect(mainContent).toBeVisible()
|
|
})
|
|
|
|
test('page navigation history works', async ({ page }) => {
|
|
// Start at home
|
|
await page.goto('http://localhost:5173')
|
|
|
|
// Navigate to orders
|
|
await page.getByRole('link', { name: /orders/i }).click()
|
|
await page.waitForURL('**/orders**')
|
|
|
|
// Navigate to products
|
|
await page.getByRole('link', { name: /products/i }).click()
|
|
await page.waitForURL('**/products**')
|
|
|
|
// Go back
|
|
await page.goBack()
|
|
await page.waitForURL('**/orders**')
|
|
|
|
// Go forward
|
|
await page.goForward()
|
|
await page.waitForURL('**/products**')
|
|
})
|
|
|
|
test('accessibility: keyboard navigation', async ({ page }) => {
|
|
await page.goto('http://localhost:5173')
|
|
|
|
// Tab through navigation
|
|
await page.keyboard.press('Tab')
|
|
const focusedElement = await page.evaluate(() => {
|
|
return document.activeElement?.tagName
|
|
})
|
|
|
|
// Should focus on an interactive element
|
|
expect(['A', 'BUTTON', 'INPUT', 'SELECT']).toContain(focusedElement)
|
|
})
|
|
|
|
test('accessibility: color contrast', async ({ page }) => {
|
|
await page.goto('http://localhost:5173/orders')
|
|
await page.waitForLoadState('networkidle')
|
|
|
|
// Run axe accessibility audit
|
|
const { injectAxe, checkA11y } = require('axe-playwright')
|
|
|
|
await injectAxe(page)
|
|
await checkA11y(page, null, {
|
|
detailedReport: true,
|
|
detailedReportOptions: {
|
|
html: true
|
|
}
|
|
})
|
|
})
|
|
})
|
|
|
|
test.describe('Order Management Flow', () => {
|
|
test('create order workflow', async ({ page }) => {
|
|
await page.goto('http://localhost:5173/orders')
|
|
await page.waitForLoadState('networkidle')
|
|
|
|
// Look for create order button
|
|
const createBtn = page.getByRole('button', { name: /create|new|add/i })
|
|
|
|
if (await createBtn.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
await createBtn.click()
|
|
|
|
// Verify modal or form appears
|
|
const form = page.locator('form')
|
|
if (await form.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
// Fill in sample data
|
|
const inputs = form.locator('input, select')
|
|
const inputCount = await inputs.count()
|
|
|
|
expect(inputCount).toBeGreaterThan(0)
|
|
}
|
|
}
|
|
})
|
|
|
|
test('view order details', async ({ page }) => {
|
|
await page.goto('http://localhost:5173/orders')
|
|
await page.waitForLoadState('networkidle')
|
|
|
|
// Find first order row
|
|
const firstRow = page.locator('tbody tr').first()
|
|
if (await firstRow.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
await firstRow.click()
|
|
|
|
// Verify details view loads
|
|
await page.waitForLoadState('networkidle')
|
|
const details = page.locator('[data-test="order-details"], .order-details')
|
|
if (await details.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
expect(details).toBeVisible()
|
|
}
|
|
}
|
|
})
|
|
})
|
|
|
|
test.describe('Performance Checks', () => {
|
|
test('page loads in acceptable time', async ({ page }) => {
|
|
const startTime = Date.now()
|
|
|
|
await page.goto('http://localhost:5173/orders', {
|
|
waitUntil: 'networkidle'
|
|
})
|
|
|
|
const loadTime = Date.now() - startTime
|
|
|
|
// Should load within 3 seconds (including network delays)
|
|
expect(loadTime).toBeLessThan(3000)
|
|
})
|
|
|
|
test('no console errors on navigation', async ({ page }) => {
|
|
const errors: string[] = []
|
|
|
|
page.on('console', (msg) => {
|
|
if (msg.type() === 'error') {
|
|
errors.push(msg.text())
|
|
}
|
|
})
|
|
|
|
await page.goto('http://localhost:5173')
|
|
await page.getByRole('link', { name: /orders/i }).click()
|
|
await page.waitForLoadState('networkidle')
|
|
|
|
expect(errors).toHaveLength(0)
|
|
})
|
|
})
|