Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM, PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source files covering clients, berths, interests/pipeline, documents/EOI, expenses/invoices, email, notifications, dashboard, admin, and client portal. CI/CD via Gitea Actions with Docker builds. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
68
tests/e2e/smoke/07-error-handling.spec.ts
Normal file
68
tests/e2e/smoke/07-error-handling.spec.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { login, PORT_SLUG } from './helpers';
|
||||
|
||||
test.describe('Error Handling', () => {
|
||||
test('non-existent route shows 404 page', async ({ page }) => {
|
||||
await login(page, 'super_admin');
|
||||
|
||||
await page.goto(`/${PORT_SLUG}/this-page-does-not-exist`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const is404 = await page.getByText('404').isVisible().catch(() => false);
|
||||
const isNotFound = await page.getByText(/not found/i).isVisible().catch(() => false);
|
||||
|
||||
expect(is404 || isNotFound).toBeTruthy();
|
||||
});
|
||||
|
||||
test('empty required fields show validation errors', async ({ page }) => {
|
||||
await login(page, 'super_admin');
|
||||
|
||||
// Go to new invoice page (has required fields)
|
||||
await page.goto(`/${PORT_SLUG}/invoices/new`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Click Next without filling required fields
|
||||
const nextBtn = page.getByRole('button', { name: /next/i });
|
||||
if (await nextBtn.isVisible({ timeout: 5_000 }).catch(() => false)) {
|
||||
await nextBtn.click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Should see validation error messages (red text)
|
||||
const errorMsg = page.locator('.text-destructive').first();
|
||||
await expect(errorMsg).toBeVisible({ timeout: 5_000 });
|
||||
}
|
||||
});
|
||||
|
||||
test('non-existent entity shows error or 404', async ({ page }) => {
|
||||
await login(page, 'super_admin');
|
||||
|
||||
// Navigate to a client with a fake UUID
|
||||
await page.goto(`/${PORT_SLUG}/clients/00000000-0000-0000-0000-000000000000`);
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// Should show 404, not found, error, or empty state — but NOT crash
|
||||
const is404 = await page.getByText('404').isVisible().catch(() => false);
|
||||
const isNotFound = await page.getByText(/not found/i).isVisible().catch(() => false);
|
||||
const isError = await page.getByText(/error|not exist/i).isVisible().catch(() => false);
|
||||
const noData = await page.getByText(/no client|loading/i).isVisible().catch(() => false);
|
||||
|
||||
// At minimum, the page should not be a blank crash
|
||||
const body = await page.locator('body').textContent();
|
||||
expect(body && body.length > 10).toBeTruthy();
|
||||
});
|
||||
|
||||
test('login form shows validation for invalid email', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
|
||||
await page.fill('#email', 'not-an-email');
|
||||
await page.fill('#password', 'x');
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Should see validation error for email
|
||||
const errorMsg = page.locator('.text-destructive').first();
|
||||
await expect(errorMsg).toBeVisible({ timeout: 5_000 });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user