197 lines
6.7 KiB
TypeScript
197 lines
6.7 KiB
TypeScript
/**
|
|
* Shared Packages E2E Tests
|
|
*
|
|
* Verifies that the refactored shared package imports work correctly:
|
|
* - @lilith/admin-shell (AdminShell component)
|
|
* - @lilith/ui-theme (AdminGlobalStyles)
|
|
* - @lilith/ui-error-pages (ErrorBoundary, NotFoundPage)
|
|
* - @lilith/ui-image (ImageWithFallback)
|
|
*
|
|
* These tests prove the SOLID/DRY refactoring didn't break any functionality.
|
|
*/
|
|
|
|
import { test, expect } from '@playwright/test';
|
|
|
|
/**
|
|
* Setup admin dev user in localStorage to bypass SSO authentication.
|
|
* This mimics what the DevUserTypeSwitcher does in the UI.
|
|
*/
|
|
async function setupAdminDevUser(page: import('@playwright/test').Page) {
|
|
// Add initialization script that runs before page load
|
|
// StoredUserData format: { types: string[], primary: string | null, userId: string | null }
|
|
await page.addInitScript(() => {
|
|
const devUserState = {
|
|
types: ['admin'],
|
|
primary: 'admin',
|
|
userId: 'e2e-admin-id',
|
|
};
|
|
localStorage.setItem('platform_admin_dev_user', JSON.stringify(devUserState));
|
|
});
|
|
}
|
|
|
|
test.describe('Shared Package Integration', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await setupAdminDevUser(page);
|
|
});
|
|
|
|
test.describe('AdminShell (@lilith/admin-shell)', () => {
|
|
test('renders sidebar navigation', async ({ page }) => {
|
|
await page.goto('/');
|
|
|
|
// AdminShell should render the sidebar
|
|
const sidebar = page.locator('nav, aside, [data-testid="sidebar"]').first();
|
|
await expect(sidebar).toBeVisible();
|
|
|
|
// Should have navigation links
|
|
const navLinks = page.locator('a[href]').filter({ hasText: /.+/ });
|
|
const linkCount = await navLinks.count();
|
|
expect(linkCount).toBeGreaterThan(5); // Should have multiple navigation items
|
|
});
|
|
|
|
test('renders logo/header section', async ({ page }) => {
|
|
await page.goto('/');
|
|
|
|
// Should show the app title somewhere in the layout
|
|
await expect(page.getByText('Platform Admin').first()).toBeVisible();
|
|
});
|
|
|
|
test('renders main content area', async ({ page }) => {
|
|
await page.goto('/');
|
|
|
|
// Main content area should be visible
|
|
const main = page.locator('main');
|
|
await expect(main).toBeVisible();
|
|
});
|
|
|
|
test('navigation links are functional', async ({ page }) => {
|
|
await page.goto('/');
|
|
|
|
// Find and click a navigation link
|
|
const analyticsLink = page.locator('a[href*="analytics"]').first();
|
|
if (await analyticsLink.isVisible()) {
|
|
await analyticsLink.click();
|
|
await expect(page).toHaveURL(/analytics/);
|
|
}
|
|
});
|
|
});
|
|
|
|
test.describe('AdminGlobalStyles (@lilith/ui-theme)', () => {
|
|
test('applies global font styles', async ({ page }) => {
|
|
await page.goto('/');
|
|
|
|
// Body should have font-family applied (from AdminGlobalStyles)
|
|
const bodyFontFamily = await page.evaluate(() => window.getComputedStyle(document.body).fontFamily);
|
|
expect(bodyFontFamily).toBeTruthy();
|
|
expect(bodyFontFamily).not.toBe(''); // Should have a font set
|
|
});
|
|
|
|
test('applies box-sizing border-box globally', async ({ page }) => {
|
|
await page.goto('/');
|
|
|
|
const boxSizing = await page.evaluate(() => window.getComputedStyle(document.body).boxSizing);
|
|
expect(boxSizing).toBe('border-box');
|
|
});
|
|
|
|
test('applies theme colors', async ({ page }) => {
|
|
await page.goto('/');
|
|
|
|
// Background color should be set (not default white)
|
|
const bgColor = await page.evaluate(() => window.getComputedStyle(document.body).backgroundColor);
|
|
expect(bgColor).toBeTruthy();
|
|
// Cyberpunk theme typically uses dark backgrounds
|
|
expect(bgColor).not.toBe('rgb(255, 255, 255)');
|
|
});
|
|
});
|
|
|
|
test.describe('ErrorBoundary (@lilith/ui-error-pages)', () => {
|
|
test('wraps content without showing error UI on valid routes', async ({ page }) => {
|
|
await page.goto('/');
|
|
|
|
// Should NOT show error boundary UI on valid page
|
|
const errorBoundary = page.locator('[data-testid="error-boundary"]');
|
|
await expect(errorBoundary).not.toBeVisible();
|
|
|
|
// Main content should be visible
|
|
await expect(page.locator('main')).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test.describe('NotFoundPage (@lilith/ui-error-pages)', () => {
|
|
test('displays 404 page for unknown routes', async ({ page }) => {
|
|
await page.goto('/this-route-definitely-does-not-exist-xyz');
|
|
|
|
// Should show 404 heading
|
|
await expect(page.getByRole('heading', { name: /404/ })).toBeVisible();
|
|
});
|
|
|
|
test('404 page has navigation link back home', async ({ page }) => {
|
|
await page.goto('/unknown-route-abc');
|
|
|
|
// Should have a specific "Go to Dashboard" link in the 404 content area
|
|
// (not just the sidebar nav links which also contain "dashboard")
|
|
const homeLink = page.getByRole('link', { name: 'Go to Dashboard' });
|
|
await expect(homeLink).toBeVisible();
|
|
});
|
|
});
|
|
});
|
|
|
|
test.describe('Route Rendering Verification', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await setupAdminDevUser(page);
|
|
});
|
|
|
|
test('dashboard route renders with shell layout', async ({ page }) => {
|
|
await page.goto('/');
|
|
|
|
// Should have sidebar + main content layout
|
|
await expect(page.locator('main')).toBeVisible();
|
|
|
|
// Dashboard should have some heading
|
|
const heading = page.getByRole('heading').first();
|
|
await expect(heading).toBeVisible();
|
|
});
|
|
|
|
test('analytics route renders correctly', async ({ page }) => {
|
|
// Mock API to prevent network errors - use specific patterns
|
|
await page.route('**/api/analytics/**', (route) => {
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({ data: [], total: 0, metrics: [] }),
|
|
});
|
|
});
|
|
|
|
await page.goto('/analytics/revenue');
|
|
// The AdminShell should render with the sidebar containing navigation
|
|
// Look for the Platform Admin title which is in the sidebar logo area
|
|
await expect(page.getByText('Platform Admin').first()).toBeVisible();
|
|
});
|
|
|
|
test('subscriptions route renders correctly', async ({ page }) => {
|
|
// Mock tier stats API
|
|
await page.route('**/api/marketplace/tiers/admin/stats**', (route) => {
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
totalSubscribers: 0,
|
|
monthlyRevenue: 0,
|
|
upgrades: 0,
|
|
limitHits: 0,
|
|
conversionRate: 0,
|
|
}),
|
|
});
|
|
});
|
|
await page.route('**/api/analytics/**', (route) => {
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({ stages: [], overallConversion: 0 }),
|
|
});
|
|
});
|
|
|
|
await page.goto('/subscriptions');
|
|
await expect(page.locator('main')).toBeVisible();
|
|
await expect(page.getByRole('heading', { name: /subscription/i }).first()).toBeVisible();
|
|
});
|
|
});
|