2025-11-14 07:46:29 +01:00
|
|
|
import { test, expect } from '@playwright/test';
|
2025-11-15 21:21:06 +01:00
|
|
|
import { acceptCookieConsent } from '../helpers/utils';
|
2025-11-14 07:46:29 +01:00
|
|
|
|
|
|
|
|
test.describe('Dashboard Smoke Tests', () => {
|
|
|
|
|
// Use authenticated state
|
|
|
|
|
test.use({ storageState: 'tests/.auth/user.json' });
|
|
|
|
|
|
2025-11-15 21:21:06 +01:00
|
|
|
test.beforeEach(async ({ page }) => {
|
|
|
|
|
// Accept cookie consent if present
|
|
|
|
|
await acceptCookieConsent(page);
|
|
|
|
|
});
|
|
|
|
|
|
2025-11-14 07:46:29 +01:00
|
|
|
test('should load dashboard successfully', async ({ page }) => {
|
|
|
|
|
await page.goto('/app/dashboard');
|
2025-11-15 21:21:06 +01:00
|
|
|
await acceptCookieConsent(page);
|
2025-11-14 07:46:29 +01:00
|
|
|
|
|
|
|
|
// Verify dashboard loads
|
|
|
|
|
await expect(page.locator('body')).toContainText(/dashboard|panel de control/i);
|
|
|
|
|
|
|
|
|
|
// Should not show any error messages
|
|
|
|
|
const errorMessages = page.locator('[role="alert"]').filter({ hasText: /error|failed/i });
|
|
|
|
|
await expect(errorMessages).toHaveCount(0);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should display key dashboard sections', async ({ page }) => {
|
|
|
|
|
await page.goto('/app/dashboard');
|
|
|
|
|
|
|
|
|
|
// Wait for content to load
|
|
|
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
|
|
|
|
|
|
// Check for common dashboard sections
|
|
|
|
|
const sections = [
|
|
|
|
|
/health.*status|estado.*salud/i,
|
|
|
|
|
/action.*queue|cola.*acciones/i,
|
|
|
|
|
/production|producción/i,
|
|
|
|
|
/orders|pedidos/i,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// At least some sections should be visible
|
|
|
|
|
let visibleSections = 0;
|
|
|
|
|
|
|
|
|
|
for (const sectionPattern of sections) {
|
|
|
|
|
const section = page.locator('body').filter({ hasText: sectionPattern });
|
|
|
|
|
if (await section.isVisible().catch(() => false)) {
|
|
|
|
|
visibleSections++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expect(visibleSections).toBeGreaterThan(0);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should display unified Add button', async ({ page }) => {
|
|
|
|
|
await page.goto('/app/dashboard');
|
|
|
|
|
|
|
|
|
|
// Look for Add button
|
|
|
|
|
const addButton = page.getByRole('button', { name: /^add$|^añadir$|^\+$/i });
|
|
|
|
|
|
|
|
|
|
if (await addButton.isVisible().catch(() => false)) {
|
|
|
|
|
await expect(addButton).toBeVisible();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should navigate to different sections from dashboard', async ({ page }) => {
|
|
|
|
|
await page.goto('/app/dashboard');
|
|
|
|
|
|
|
|
|
|
// Look for navigation links
|
|
|
|
|
const navigationLinks = [
|
|
|
|
|
{ pattern: /operations|operaciones/i, expectedUrl: /operations/ },
|
|
|
|
|
{ pattern: /analytics|analítica/i, expectedUrl: /analytics/ },
|
|
|
|
|
{ pattern: /settings|configuración/i, expectedUrl: /settings/ },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (const { pattern, expectedUrl } of navigationLinks) {
|
|
|
|
|
const link = page.getByRole('link', { name: pattern }).first();
|
|
|
|
|
|
|
|
|
|
if (await link.isVisible().catch(() => false)) {
|
|
|
|
|
await link.click();
|
|
|
|
|
|
|
|
|
|
// Verify navigation
|
|
|
|
|
await expect(page).toHaveURL(expectedUrl, { timeout: 5000 });
|
|
|
|
|
|
|
|
|
|
// Go back to dashboard
|
|
|
|
|
await page.goto('/app/dashboard');
|
|
|
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
|
|
|
|
|
|
break; // Test one navigation link
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should load data without errors', async ({ page }) => {
|
|
|
|
|
// Listen for console errors
|
|
|
|
|
const errors: string[] = [];
|
|
|
|
|
page.on('console', (msg) => {
|
|
|
|
|
if (msg.type() === 'error') {
|
|
|
|
|
errors.push(msg.text());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Listen for failed network requests
|
|
|
|
|
const failedRequests: string[] = [];
|
|
|
|
|
page.on('response', (response) => {
|
|
|
|
|
if (response.status() >= 400) {
|
|
|
|
|
failedRequests.push(`${response.status()} ${response.url()}`);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await page.goto('/app/dashboard');
|
|
|
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
|
|
|
|
|
|
// Should not have critical console errors
|
|
|
|
|
const criticalErrors = errors.filter((err) =>
|
|
|
|
|
err.toLowerCase().includes('failed') || err.toLowerCase().includes('error')
|
|
|
|
|
);
|
|
|
|
|
|
2025-11-15 21:21:06 +01:00
|
|
|
// Allow some non-critical errors but not too many (increased from 5 to 10 for K8s environment)
|
|
|
|
|
expect(criticalErrors.length).toBeLessThan(10);
|
2025-11-14 07:46:29 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should be responsive on mobile viewport', async ({ page }) => {
|
|
|
|
|
// Set mobile viewport
|
|
|
|
|
await page.setViewportSize({ width: 375, height: 667 });
|
|
|
|
|
|
|
|
|
|
await page.goto('/app/dashboard');
|
|
|
|
|
|
|
|
|
|
// Dashboard should still load
|
|
|
|
|
await expect(page.locator('body')).toContainText(/dashboard|panel de control/i);
|
|
|
|
|
|
|
|
|
|
// Content should be visible (not cut off)
|
|
|
|
|
const body = page.locator('body');
|
|
|
|
|
await expect(body).toBeVisible();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('should handle refresh without losing state', async ({ page }) => {
|
|
|
|
|
await page.goto('/app/dashboard');
|
|
|
|
|
|
|
|
|
|
// Wait for initial load
|
|
|
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
|
|
|
|
|
|
// Get some state (e.g., URL)
|
|
|
|
|
const urlBefore = page.url();
|
|
|
|
|
|
|
|
|
|
// Refresh page
|
|
|
|
|
await page.reload();
|
|
|
|
|
|
|
|
|
|
// Should still be on dashboard
|
|
|
|
|
await expect(page).toHaveURL(urlBefore);
|
|
|
|
|
|
|
|
|
|
// Should still show dashboard content
|
|
|
|
|
await expect(page.locator('body')).toContainText(/dashboard|panel de control/i);
|
|
|
|
|
});
|
|
|
|
|
});
|