|
| 1 | +import { test, expect } from '@playwright/test'; |
| 2 | + |
| 3 | +/** |
| 4 | + * Docs site smoke tests. |
| 5 | + * |
| 6 | + * These tests run against the production build of the docs site (Next.js) |
| 7 | + * and verify that documentation pages render without client-side errors. |
| 8 | + * This catches issues like: |
| 9 | + * - Missing React context providers (e.g. SchemaRendererProvider) |
| 10 | + * - Broken component demos that throw during hydration |
| 11 | + * - Non-array `.map()` crashes in component renderers |
| 12 | + * - Failed asset loading (JS/CSS bundles returning 404) |
| 13 | + */ |
| 14 | + |
| 15 | +const DOCS_BASE = process.env.DOCS_BASE_URL || 'http://localhost:3000'; |
| 16 | + |
| 17 | +/** Representative pages across all documentation categories */ |
| 18 | +const SMOKE_PAGES = [ |
| 19 | + '/docs', |
| 20 | + // Components |
| 21 | + '/docs/components/form/button', |
| 22 | + '/docs/components/layout/card', |
| 23 | + '/docs/components/layout/tabs', |
| 24 | + '/docs/components/feedback/alert', |
| 25 | + '/docs/components/complex/data-table', |
| 26 | + '/docs/components/complex/resizable', |
| 27 | + '/docs/components/data-display/list', |
| 28 | + // Fields |
| 29 | + '/docs/fields/text', |
| 30 | + '/docs/fields/select', |
| 31 | + // Core |
| 32 | + '/docs/core/schema-renderer', |
| 33 | + '/docs/core/form-renderer', |
| 34 | + // Plugins (these require SchemaRendererProvider) |
| 35 | + '/docs/plugins/plugin-grid', |
| 36 | + '/docs/plugins/plugin-kanban', |
| 37 | + '/docs/plugins/plugin-view', |
| 38 | + '/docs/plugins/plugin-charts', |
| 39 | + '/docs/plugins/plugin-timeline', |
| 40 | + // Blocks |
| 41 | + '/docs/blocks/dashboard', |
| 42 | + '/docs/blocks/marketing', |
| 43 | +]; |
| 44 | + |
| 45 | +test.describe('Docs Site – Smoke', () => { |
| 46 | + for (const path of SMOKE_PAGES) { |
| 47 | + test(`${path} should load without client-side errors`, async ({ page }) => { |
| 48 | + const errors: string[] = []; |
| 49 | + |
| 50 | + page.on('pageerror', (err) => { |
| 51 | + errors.push(err.message); |
| 52 | + }); |
| 53 | + |
| 54 | + const response = await page.goto(`${DOCS_BASE}${path}`, { |
| 55 | + waitUntil: 'domcontentloaded', |
| 56 | + timeout: 30_000, |
| 57 | + }); |
| 58 | + |
| 59 | + // Page must return a successful HTTP status |
| 60 | + expect(response?.status(), `${path} returned HTTP ${response?.status()}`).toBeLessThan(400); |
| 61 | + |
| 62 | + // Wait for hydration |
| 63 | + await page.waitForTimeout(2000); |
| 64 | + |
| 65 | + // Must not have thrown uncaught JS exceptions |
| 66 | + expect(errors, `Uncaught JS errors on ${path}:\n${errors.join('\n')}`).toEqual([]); |
| 67 | + |
| 68 | + // Must not show the Next.js error overlay |
| 69 | + const bodyText = await page.locator('body').innerText(); |
| 70 | + expect(bodyText).not.toContain('Application error'); |
| 71 | + expect(bodyText).not.toContain('client-side exception'); |
| 72 | + }); |
| 73 | + } |
| 74 | + |
| 75 | + test('should load all JS/CSS bundles without 404s', async ({ page }) => { |
| 76 | + const failedAssets: string[] = []; |
| 77 | + |
| 78 | + page.on('response', (resp) => { |
| 79 | + const url = resp.url(); |
| 80 | + if ((url.endsWith('.js') || url.endsWith('.css')) && resp.status() >= 400) { |
| 81 | + failedAssets.push(`${resp.status()} ${url}`); |
| 82 | + } |
| 83 | + }); |
| 84 | + |
| 85 | + await page.goto(`${DOCS_BASE}/docs`, { waitUntil: 'networkidle', timeout: 30_000 }); |
| 86 | + expect(failedAssets, 'Critical assets returned HTTP errors').toEqual([]); |
| 87 | + }); |
| 88 | +}); |
0 commit comments