@almadar/verify 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -147,13 +147,14 @@ declare function navigateWithRetry(page: Page, url: string, options?: {
147
147
  retries?: number;
148
148
  }): Promise<void>;
149
149
  /**
150
- * Wait for the runtime to load and render content.
151
- * The OrbitalPreview shows "Loading runtime..." then renders actual content.
150
+ * Wait for the runtime to load, render content, and expose the verification API.
151
+ * Polls for window.__orbitalVerification and confirms INIT completed.
152
+ * Falls back to a timeout if the API never appears (e.g., simple pages).
152
153
  *
153
154
  * @param page - Playwright page
154
- * @param waitMs - Time to wait for runtime to settle (default: 3000ms)
155
+ * @param timeoutMs - Maximum time to wait (default: 10000ms)
155
156
  */
156
- declare function waitForRuntime(page: Page, waitMs?: number): Promise<void>;
157
+ declare function waitForRuntime(page: Page, timeoutMs?: number): Promise<void>;
157
158
 
158
159
  /**
159
160
  * State bridge: read window.__orbitalVerification from a Playwright page.
package/dist/index.js CHANGED
@@ -33,7 +33,10 @@ var WARNING_NOISE_PATTERNS = [
33
33
  "DevTools",
34
34
  "React DevTools",
35
35
  "Download the React DevTools",
36
- "Warning: Each child in a list should have a unique"
36
+ "Warning: Each child in a list should have a unique",
37
+ "set is server-side only, ignored on client",
38
+ "persist is server-side only, ignored on client",
39
+ "callService is server-side only, ignored on client"
37
40
  ];
38
41
  function isNoiseError(text) {
39
42
  return ERROR_NOISE_PATTERNS.some((pattern) => text.includes(pattern));
@@ -100,8 +103,11 @@ async function takeScreenshot(page, outputPath, selector) {
100
103
  if (selector) {
101
104
  const element = await page.$(selector);
102
105
  if (element) {
103
- await element.screenshot({ path: outputPath });
104
- return outputPath;
106
+ try {
107
+ await element.screenshot({ path: outputPath });
108
+ return outputPath;
109
+ } catch {
110
+ }
105
111
  }
106
112
  }
107
113
  await page.screenshot({ path: outputPath, fullPage: false });
@@ -145,8 +151,20 @@ async function navigateWithRetry(page, url, options) {
145
151
  1e3
146
152
  );
147
153
  }
148
- async function waitForRuntime(page, waitMs = 3e3) {
149
- await page.waitForTimeout(waitMs);
154
+ async function waitForRuntime(page, timeoutMs = 1e4) {
155
+ const pollInterval = 200;
156
+ const deadline = Date.now() + timeoutMs;
157
+ while (Date.now() < deadline) {
158
+ const ready = await page.evaluate(() => {
159
+ const api = window.__orbitalVerification;
160
+ if (!api?.getSnapshot) return false;
161
+ const snap = api.getSnapshot();
162
+ return snap.transitions.length > 0;
163
+ }).catch(() => false);
164
+ if (ready) return;
165
+ await page.waitForTimeout(pollInterval);
166
+ }
167
+ await page.waitForTimeout(1e3);
150
168
  }
151
169
 
152
170
  // src/runtime/state-bridge.ts
@@ -241,7 +259,8 @@ async function inspectDOM(page, previewSelector = '[class*="livePreviewBox"], [c
241
259
  const preview = document.querySelector(selector);
242
260
  if (!preview) return result;
243
261
  const text = (preview.textContent ?? "").trim();
244
- result.isEmpty = text.length === 0;
262
+ const hasVisualElements = preview.querySelector("canvas, svg, video, img, iframe") !== null;
263
+ result.isEmpty = text.length === 0 && !hasVisualElements;
245
264
  const unknownMatch = text.match(/Unknown pattern:\s*\S+/g);
246
265
  if (unknownMatch) {
247
266
  result.unknownPatterns = unknownMatch;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/browser/launch.ts","../src/util/filter.ts","../src/browser/console.ts","../src/browser/screenshot.ts","../src/util/retry.ts","../src/browser/navigate.ts","../src/runtime/state-bridge.ts","../src/runtime/entity-inspector.ts","../src/analysis/dom-inspector.ts","../src/analysis/console-report.ts","../src/report/json-report.ts","../src/report/markdown-report.ts"],"names":["mkdirSync","dirname","writeFileSync"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Browser launch with shared defaults.\n *\n * @packageDocumentation\n */\n\nimport { chromium, type Browser, type BrowserContext } from 'playwright';\n\nexport interface LaunchOptions {\n headless?: boolean;\n viewport?: { width: number; height: number };\n timeout?: number;\n}\n\nconst DEFAULTS: Required<LaunchOptions> = {\n headless: true,\n viewport: { width: 1440, height: 900 },\n timeout: 30000,\n};\n\n/**\n * Launch a Chromium browser with shared defaults.\n * Returns both the browser and a context with the configured viewport.\n */\nexport async function launchBrowser(\n options?: LaunchOptions\n): Promise<{ browser: Browser; context: BrowserContext }> {\n const opts = { ...DEFAULTS, ...options };\n\n const browser = await chromium.launch({\n headless: opts.headless,\n });\n\n const context = await browser.newContext({\n viewport: opts.viewport,\n });\n\n context.setDefaultTimeout(opts.timeout);\n\n return { browser, context };\n}\n","/**\n * Noise filters for console messages.\n *\n * Shared across orbital-verify, runtime-verify, and playground-test\n * to exclude browser/webpack/DevTools noise from error reports.\n *\n * @packageDocumentation\n */\n\n/** Patterns that should be ignored from console errors */\nconst ERROR_NOISE_PATTERNS = [\n 'favicon.ico',\n 'net::ERR_',\n 'the server responded with a status of 404',\n 'Failed to load resource',\n 'ERR_CONNECTION_REFUSED',\n] as const;\n\n/** Patterns that should be ignored from console warnings */\nconst WARNING_NOISE_PATTERNS = [\n 'DevTools',\n 'React DevTools',\n 'Download the React DevTools',\n 'Warning: Each child in a list should have a unique',\n] as const;\n\n/** Check if a console error message is noise (should be ignored) */\nexport function isNoiseError(text: string): boolean {\n return ERROR_NOISE_PATTERNS.some((pattern) => text.includes(pattern));\n}\n\n/** Check if a console warning message is noise (should be ignored) */\nexport function isNoiseWarning(text: string): boolean {\n return WARNING_NOISE_PATTERNS.some((pattern) => text.includes(pattern));\n}\n","/**\n * Console message collector for Playwright pages.\n *\n * Collects console errors and warnings from a Playwright page,\n * filtering out noise (favicon, DevTools, net::ERR_, etc.).\n *\n * @packageDocumentation\n */\n\nimport type { Page, ConsoleMessage } from 'playwright';\nimport type { ConsoleEntry } from '../util/types.js';\nimport { isNoiseError, isNoiseWarning } from '../util/filter.js';\n\n/**\n * Collects and categorizes console messages from a Playwright page.\n *\n * Usage:\n * ```ts\n * const collector = new ConsoleCollector(page);\n * // ... navigate and interact ...\n * const { errors, warnings } = collector.getResults();\n * collector.dispose();\n * ```\n */\nexport class ConsoleCollector {\n private entries: ConsoleEntry[] = [];\n private uncaughtErrors: string[] = [];\n private page: Page;\n private consoleHandler: (msg: ConsoleMessage) => void;\n private errorHandler: (err: Error) => void;\n\n constructor(page: Page) {\n this.page = page;\n\n this.consoleHandler = (msg: ConsoleMessage) => {\n const text = msg.text();\n const timestamp = Date.now();\n\n if (msg.type() === 'error') {\n if (isNoiseError(text)) return;\n this.entries.push({ type: 'error', text, timestamp });\n } else if (msg.type() === 'warning') {\n if (isNoiseWarning(text)) return;\n this.entries.push({ type: 'warning', text, timestamp });\n } else {\n this.entries.push({ type: 'info', text, timestamp });\n }\n };\n\n this.errorHandler = (err: Error) => {\n this.uncaughtErrors.push(`Uncaught: ${err.message}`);\n this.entries.push({ type: 'error', text: `Uncaught: ${err.message}`, timestamp: Date.now() });\n };\n\n page.on('console', this.consoleHandler);\n page.on('pageerror', this.errorHandler);\n }\n\n /** Get all collected entries */\n getEntries(): ConsoleEntry[] {\n return [...this.entries];\n }\n\n /** Get categorized results */\n getResults(): { errors: string[]; warnings: string[]; uncaughtErrors: string[] } {\n return {\n errors: this.entries.filter((e) => e.type === 'error').map((e) => e.text),\n warnings: this.entries.filter((e) => e.type === 'warning').map((e) => e.text),\n uncaughtErrors: [...this.uncaughtErrors],\n };\n }\n\n /** Clear collected entries (useful between navigation steps) */\n clear(): void {\n this.entries = [];\n this.uncaughtErrors = [];\n }\n\n /** Remove event listeners from the page */\n dispose(): void {\n this.page.removeListener('console', this.consoleHandler);\n this.page.removeListener('pageerror', this.errorHandler);\n }\n}\n","/**\n * Screenshot capture utilities.\n *\n * @packageDocumentation\n */\n\nimport { mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { Page, ElementHandle } from 'playwright';\n\n/**\n * Capture a screenshot of a specific element or the full page.\n *\n * @param page - Playwright page\n * @param outputPath - File path for the screenshot\n * @param selector - Optional CSS selector to screenshot a specific element\n * @returns The actual path where the screenshot was saved, or null on failure\n */\nexport async function takeScreenshot(\n page: Page,\n outputPath: string,\n selector?: string\n): Promise<string | null> {\n try {\n mkdirSync(dirname(outputPath), { recursive: true });\n\n if (selector) {\n const element: ElementHandle | null = await page.$(selector);\n if (element) {\n await element.screenshot({ path: outputPath });\n return outputPath;\n }\n }\n\n // Fallback to page screenshot\n await page.screenshot({ path: outputPath, fullPage: false });\n return outputPath;\n } catch {\n return null;\n }\n}\n\n/** Sanitize a name for use as a filename */\nexport function safeFileName(name: string): string {\n return name.replace(/[^a-zA-Z0-9_-]/g, '_');\n}\n","/**\n * Retry utility with exponential backoff.\n *\n * @packageDocumentation\n */\n\n/**\n * Retry an async operation with exponential backoff.\n *\n * @param fn - Async function to retry\n * @param maxRetries - Maximum number of retries (default: 3)\n * @param baseDelayMs - Base delay in ms before first retry (default: 500)\n * @returns Result of the successful call\n * @throws Last error if all retries exhausted\n */\nexport async function retry<T>(\n fn: () => Promise<T>,\n maxRetries = 3,\n baseDelayMs = 500\n): Promise<T> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n if (attempt < maxRetries) {\n const delay = baseDelayMs * Math.pow(2, attempt);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n\n throw lastError;\n}\n","/**\n * Navigation utilities with retry and wait helpers.\n *\n * @packageDocumentation\n */\n\nimport type { Page } from 'playwright';\nimport { retry } from '../util/retry.js';\n\n/**\n * Navigate to a URL with retry on failure.\n *\n * @param page - Playwright page\n * @param url - URL to navigate to\n * @param options - Navigation options\n */\nexport async function navigateWithRetry(\n page: Page,\n url: string,\n options?: {\n waitUntil?: 'domcontentloaded' | 'load' | 'networkidle';\n timeout?: number;\n retries?: number;\n }\n): Promise<void> {\n const { waitUntil = 'domcontentloaded', timeout = 15000, retries = 2 } = options ?? {};\n\n await retry(\n async () => {\n const resp = await page.goto(url, { waitUntil, timeout });\n if (!resp || resp.status() >= 500) {\n throw new Error(`Navigation to ${url} failed with status ${resp?.status()}`);\n }\n },\n retries,\n 1000\n );\n}\n\n/**\n * Wait for the runtime to load and render content.\n * The OrbitalPreview shows \"Loading runtime...\" then renders actual content.\n *\n * @param page - Playwright page\n * @param waitMs - Time to wait for runtime to settle (default: 3000ms)\n */\nexport async function waitForRuntime(page: Page, waitMs = 3000): Promise<void> {\n await page.waitForTimeout(waitMs);\n}\n","/**\n * State bridge: read window.__orbitalVerification from a Playwright page.\n *\n * The OrbitalVerificationAPI is exposed by @almadar/ui's verificationRegistry.ts\n * on window.__orbitalVerification. This module provides typed access to it.\n *\n * @packageDocumentation\n */\n\nimport type { Page } from 'playwright';\nimport type { RuntimeState } from '../util/types.js';\n\n/** Shape of window.__orbitalVerification (subset used by verify tools) */\nexport interface OrbitalVerificationSnapshot {\n checks: Array<{\n id: string;\n label: string;\n status: 'pass' | 'fail' | 'pending' | 'warn';\n details?: string;\n }>;\n transitions: Array<{\n id: string;\n traitName: string;\n from: string;\n to: string;\n event: string;\n effects: Array<{ type: string; status: string; error?: string }>;\n }>;\n bridge: { connected: boolean } | null;\n summary: {\n totalChecks: number;\n passed: number;\n failed: number;\n warnings: number;\n pending: number;\n };\n}\n\n/**\n * Read the verification snapshot from the browser.\n * Returns null if the API is not available (runtime not loaded).\n */\nexport async function readVerificationSnapshot(\n page: Page\n): Promise<OrbitalVerificationSnapshot | null> {\n return page.evaluate(() => {\n const api = (window as unknown as Record<string, unknown>).__orbitalVerification as\n | { getSnapshot?: () => OrbitalVerificationSnapshot }\n | undefined;\n return api?.getSnapshot?.() ?? null;\n });\n}\n\n/**\n * Read trait states from the verification API.\n * Returns a map of trait name -> current state name.\n */\nexport async function readTraitStates(\n page: Page\n): Promise<Record<string, string>> {\n return page.evaluate(() => {\n const api = (window as unknown as Record<string, unknown>).__orbitalVerification as\n | { getTraitState?: (name: string) => { currentState: string } | null }\n | undefined;\n if (!api?.getTraitState) return {};\n\n // We can't enumerate trait names from the API directly, so\n // use the snapshot's transitions to discover trait names.\n const snapshotApi = api as unknown as { getSnapshot?: () => OrbitalVerificationSnapshot };\n const snapshot = snapshotApi.getSnapshot?.();\n if (!snapshot) return {};\n\n const result: Record<string, string> = {};\n const traitNames = new Set(snapshot.transitions.map((t) => t.traitName));\n for (const name of traitNames) {\n const state = api.getTraitState(name);\n if (state) result[name] = state.currentState;\n }\n return result;\n });\n}\n\n/**\n * Read the event log from the verification API.\n */\nexport async function readEventLog(\n page: Page\n): Promise<Array<{ event: string; listenerCount?: number }>> {\n return page.evaluate(() => {\n const api = (window as unknown as Record<string, unknown>).__orbitalVerification as\n | { eventLog?: Array<{ event: string; listenerCount?: number }> }\n | undefined;\n return api?.eventLog ?? [];\n });\n}\n\n/**\n * Build a RuntimeState from the verification snapshot.\n * Combines trait states, entity data, events, and guard results.\n */\nexport async function readRuntimeState(page: Page): Promise<RuntimeState | null> {\n const snapshot = await readVerificationSnapshot(page);\n if (!snapshot) return null;\n\n const traitStates = await readTraitStates(page);\n\n return {\n traits: Object.fromEntries(\n Object.entries(traitStates).map(([name, currentState]) => [\n name,\n { currentState, context: {} },\n ])\n ),\n entities: {}, // Entity data requires FetchedDataContext inspection\n events: snapshot.transitions.map((t) => t.event),\n guards: Object.fromEntries(\n snapshot.checks\n .filter((c) => c.id.startsWith('guard-'))\n .map((c) => [c.id, c.status === 'pass'])\n ),\n };\n}\n","/**\n * Entity data inspector.\n *\n * Extract entity data visibility from the DOM to verify that\n * mock data actually reached the rendered components.\n *\n * @packageDocumentation\n */\n\nimport type { Page } from 'playwright';\n\n/** Result of an entity data inspection */\nexport interface EntityInspection {\n /** Whether any entity data content was found in the DOM */\n hasContent: boolean;\n /** Number of entity-related DOM elements found */\n elementCount: number;\n /** Whether an \"empty state\" pattern is visible */\n showsEmptyState: boolean;\n /** Text content of the preview area (truncated) */\n previewText: string;\n}\n\n/**\n * Inspect the preview area for entity data content.\n * Checks for empty states, entity cards, table rows, etc.\n *\n * @param page - Playwright page\n * @param previewSelector - CSS selector for the preview area\n */\nexport async function inspectEntityData(\n page: Page,\n previewSelector = '[class*=\"livePreviewBox\"], [class*=\"opPreviewBox\"]'\n): Promise<EntityInspection> {\n return page.evaluate((selector) => {\n const preview = document.querySelector(selector);\n if (!preview) {\n return { hasContent: false, elementCount: 0, showsEmptyState: false, previewText: '' };\n }\n\n const text = (preview.textContent ?? '').trim();\n\n // Count entity-related elements\n const entityElements = preview.querySelectorAll(\n '[data-pattern], [data-entity], table tbody tr, [class*=\"card\"], [class*=\"Card\"]'\n );\n\n // Check for empty state indicators\n const emptyStateTexts = ['empty', 'no data', 'no items', 'nothing to show', 'no results'];\n const showsEmptyState = emptyStateTexts.some((t) =>\n text.toLowerCase().includes(t)\n );\n\n return {\n hasContent: text.length > 0 && entityElements.length > 0,\n elementCount: entityElements.length,\n showsEmptyState,\n previewText: text.substring(0, 500),\n };\n }, previewSelector);\n}\n","/**\n * DOM state extraction and inspection.\n *\n * Check for common error patterns in the rendered DOM:\n * \"Unknown pattern\", error boundaries, empty content, etc.\n *\n * @packageDocumentation\n */\n\nimport type { Page } from 'playwright';\n\n/** DOM inspection result */\nexport interface DOMInspection {\n /** Unknown pattern errors found in the DOM */\n unknownPatterns: string[];\n /** Whether an error boundary fallback is visible */\n hasErrorBoundary: boolean;\n /** Whether \"Objects are not valid as a React child\" appears */\n hasObjectRenderError: boolean;\n /** Whether the preview area is completely empty */\n isEmpty: boolean;\n /** Whether a preview error banner is visible */\n hasPreviewError: boolean;\n /** The preview error text, if any */\n previewErrorText: string;\n}\n\n/**\n * Inspect the DOM for common rendering errors.\n *\n * @param page - Playwright page\n * @param previewSelector - CSS selector for the preview area\n */\nexport async function inspectDOM(\n page: Page,\n previewSelector = '[class*=\"livePreviewBox\"], [class*=\"opPreviewBox\"]'\n): Promise<DOMInspection> {\n return page.evaluate((selector: string) => {\n const result: DOMInspection = {\n unknownPatterns: [],\n hasErrorBoundary: false,\n hasObjectRenderError: false,\n isEmpty: true,\n hasPreviewError: false,\n previewErrorText: '',\n };\n\n // Check for preview error banner\n const previewError = document.querySelector('[class*=\"previewError\"]');\n if (previewError) {\n result.hasPreviewError = true;\n result.previewErrorText = (previewError.textContent ?? '').trim();\n }\n\n // Check preview area content\n const preview = document.querySelector(selector);\n if (!preview) return result;\n\n const text = (preview.textContent ?? '').trim();\n result.isEmpty = text.length === 0;\n\n // Check for \"Unknown pattern: xxx\"\n const unknownMatch = text.match(/Unknown pattern:\\s*\\S+/g);\n if (unknownMatch) {\n result.unknownPatterns = unknownMatch;\n }\n\n // Check for React render error\n if (text.includes('Objects are not valid as a React child')) {\n result.hasObjectRenderError = true;\n }\n\n // Check for error boundary\n const errorBoundary = preview.querySelector('[class*=\"error-boundary\"], [class*=\"ErrorBoundary\"]');\n if (errorBoundary) {\n result.hasErrorBoundary = true;\n }\n\n return result;\n }, previewSelector);\n}\n","/**\n * Console message categorization and reporting.\n *\n * @packageDocumentation\n */\n\nimport type { ConsoleEntry } from '../util/types.js';\n\n/** Categorized console report */\nexport interface ConsoleReport {\n errorCount: number;\n warningCount: number;\n infoCount: number;\n errors: string[];\n warnings: string[];\n /** Unique error patterns (deduplicated by first 80 chars) */\n uniqueErrors: string[];\n}\n\n/**\n * Build a console report from collected entries.\n */\nexport function buildConsoleReport(entries: ConsoleEntry[]): ConsoleReport {\n const errors = entries.filter((e) => e.type === 'error').map((e) => e.text);\n const warnings = entries.filter((e) => e.type === 'warning').map((e) => e.text);\n const infoCount = entries.filter((e) => e.type === 'info').length;\n\n // Deduplicate errors by first 80 characters\n const seen = new Set<string>();\n const uniqueErrors: string[] = [];\n for (const err of errors) {\n const key = err.substring(0, 80);\n if (!seen.has(key)) {\n seen.add(key);\n uniqueErrors.push(err);\n }\n }\n\n return {\n errorCount: errors.length,\n warningCount: warnings.length,\n infoCount,\n errors,\n warnings,\n uniqueErrors,\n };\n}\n","/**\n * JSON report generation.\n *\n * @packageDocumentation\n */\n\nimport { writeFileSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { VerifyReport, VerifyResult } from '../util/types.js';\n\n/**\n * Build a JSON report from verification results.\n */\nexport function buildJsonReport(\n url: string,\n mode: 'playground' | 'app',\n results: VerifyResult[]\n): VerifyReport {\n const pass = results.filter((r) => r.status === 'pass').length;\n const error = results.filter((r) => r.status === 'error').length;\n const warning = results.filter((r) => r.status === 'warning').length;\n\n return {\n timestamp: new Date().toISOString(),\n url,\n mode,\n summary: { total: results.length, pass, error, warning },\n results,\n };\n}\n\n/**\n * Write a JSON report to disk.\n */\nexport function writeJsonReport(report: VerifyReport, outputPath: string): void {\n mkdirSync(dirname(outputPath), { recursive: true });\n writeFileSync(outputPath, JSON.stringify(report, null, 2));\n}\n","/**\n * Markdown report generation.\n *\n * @packageDocumentation\n */\n\nimport { writeFileSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { VerifyReport } from '../util/types.js';\n\n/**\n * Generate a markdown report from verification results.\n */\nexport function buildMarkdownReport(report: VerifyReport): string {\n const lines: string[] = [];\n\n lines.push(`# Verification Report`);\n lines.push('');\n lines.push(`- **Date**: ${report.timestamp}`);\n lines.push(`- **URL**: ${report.url}`);\n lines.push(`- **Mode**: ${report.mode}`);\n lines.push('');\n\n lines.push(`## Summary`);\n lines.push('');\n lines.push(`| Status | Count |`);\n lines.push(`|--------|-------|`);\n lines.push(`| PASS | ${report.summary.pass} |`);\n lines.push(`| WARN | ${report.summary.warning} |`);\n lines.push(`| ERROR | ${report.summary.error} |`);\n lines.push(`| **Total** | **${report.summary.total}** |`);\n lines.push('');\n\n // Error details\n const errors = report.results.filter((r) => r.status === 'error');\n if (errors.length > 0) {\n lines.push(`## Errors (${errors.length})`);\n lines.push('');\n for (const item of errors) {\n lines.push(`### ${item.name}`);\n for (const e of item.errors) {\n lines.push(`- ${e.substring(0, 200)}`);\n }\n lines.push('');\n }\n }\n\n // Warning details\n const warnings = report.results.filter((r) => r.status === 'warning');\n if (warnings.length > 0) {\n lines.push(`## Warnings (${warnings.length})`);\n lines.push('');\n for (const item of warnings) {\n lines.push(`### ${item.name}`);\n for (const w of item.warnings) {\n lines.push(`- ${w.substring(0, 200)}`);\n }\n lines.push('');\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Write a markdown report to disk.\n */\nexport function writeMarkdownReport(report: VerifyReport, outputPath: string): void {\n mkdirSync(dirname(outputPath), { recursive: true });\n writeFileSync(outputPath, buildMarkdownReport(report));\n}\n"]}
1
+ {"version":3,"sources":["../src/browser/launch.ts","../src/util/filter.ts","../src/browser/console.ts","../src/browser/screenshot.ts","../src/util/retry.ts","../src/browser/navigate.ts","../src/runtime/state-bridge.ts","../src/runtime/entity-inspector.ts","../src/analysis/dom-inspector.ts","../src/analysis/console-report.ts","../src/report/json-report.ts","../src/report/markdown-report.ts"],"names":["mkdirSync","dirname","writeFileSync"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Browser launch with shared defaults.\n *\n * @packageDocumentation\n */\n\nimport { chromium, type Browser, type BrowserContext } from 'playwright';\n\nexport interface LaunchOptions {\n headless?: boolean;\n viewport?: { width: number; height: number };\n timeout?: number;\n}\n\nconst DEFAULTS: Required<LaunchOptions> = {\n headless: true,\n viewport: { width: 1440, height: 900 },\n timeout: 30000,\n};\n\n/**\n * Launch a Chromium browser with shared defaults.\n * Returns both the browser and a context with the configured viewport.\n */\nexport async function launchBrowser(\n options?: LaunchOptions\n): Promise<{ browser: Browser; context: BrowserContext }> {\n const opts = { ...DEFAULTS, ...options };\n\n const browser = await chromium.launch({\n headless: opts.headless,\n });\n\n const context = await browser.newContext({\n viewport: opts.viewport,\n });\n\n context.setDefaultTimeout(opts.timeout);\n\n return { browser, context };\n}\n","/**\n * Noise filters for console messages.\n *\n * Shared across orbital-verify, runtime-verify, and playground-test\n * to exclude browser/webpack/DevTools noise from error reports.\n *\n * @packageDocumentation\n */\n\n/** Patterns that should be ignored from console errors */\nconst ERROR_NOISE_PATTERNS = [\n 'favicon.ico',\n 'net::ERR_',\n 'the server responded with a status of 404',\n 'Failed to load resource',\n 'ERR_CONNECTION_REFUSED',\n] as const;\n\n/** Patterns that should be ignored from console warnings */\nconst WARNING_NOISE_PATTERNS = [\n 'DevTools',\n 'React DevTools',\n 'Download the React DevTools',\n 'Warning: Each child in a list should have a unique',\n 'set is server-side only, ignored on client',\n 'persist is server-side only, ignored on client',\n 'callService is server-side only, ignored on client',\n] as const;\n\n/** Check if a console error message is noise (should be ignored) */\nexport function isNoiseError(text: string): boolean {\n return ERROR_NOISE_PATTERNS.some((pattern) => text.includes(pattern));\n}\n\n/** Check if a console warning message is noise (should be ignored) */\nexport function isNoiseWarning(text: string): boolean {\n return WARNING_NOISE_PATTERNS.some((pattern) => text.includes(pattern));\n}\n","/**\n * Console message collector for Playwright pages.\n *\n * Collects console errors and warnings from a Playwright page,\n * filtering out noise (favicon, DevTools, net::ERR_, etc.).\n *\n * @packageDocumentation\n */\n\nimport type { Page, ConsoleMessage } from 'playwright';\nimport type { ConsoleEntry } from '../util/types.js';\nimport { isNoiseError, isNoiseWarning } from '../util/filter.js';\n\n/**\n * Collects and categorizes console messages from a Playwright page.\n *\n * Usage:\n * ```ts\n * const collector = new ConsoleCollector(page);\n * // ... navigate and interact ...\n * const { errors, warnings } = collector.getResults();\n * collector.dispose();\n * ```\n */\nexport class ConsoleCollector {\n private entries: ConsoleEntry[] = [];\n private uncaughtErrors: string[] = [];\n private page: Page;\n private consoleHandler: (msg: ConsoleMessage) => void;\n private errorHandler: (err: Error) => void;\n\n constructor(page: Page) {\n this.page = page;\n\n this.consoleHandler = (msg: ConsoleMessage) => {\n const text = msg.text();\n const timestamp = Date.now();\n\n if (msg.type() === 'error') {\n if (isNoiseError(text)) return;\n this.entries.push({ type: 'error', text, timestamp });\n } else if (msg.type() === 'warning') {\n if (isNoiseWarning(text)) return;\n this.entries.push({ type: 'warning', text, timestamp });\n } else {\n this.entries.push({ type: 'info', text, timestamp });\n }\n };\n\n this.errorHandler = (err: Error) => {\n this.uncaughtErrors.push(`Uncaught: ${err.message}`);\n this.entries.push({ type: 'error', text: `Uncaught: ${err.message}`, timestamp: Date.now() });\n };\n\n page.on('console', this.consoleHandler);\n page.on('pageerror', this.errorHandler);\n }\n\n /** Get all collected entries */\n getEntries(): ConsoleEntry[] {\n return [...this.entries];\n }\n\n /** Get categorized results */\n getResults(): { errors: string[]; warnings: string[]; uncaughtErrors: string[] } {\n return {\n errors: this.entries.filter((e) => e.type === 'error').map((e) => e.text),\n warnings: this.entries.filter((e) => e.type === 'warning').map((e) => e.text),\n uncaughtErrors: [...this.uncaughtErrors],\n };\n }\n\n /** Clear collected entries (useful between navigation steps) */\n clear(): void {\n this.entries = [];\n this.uncaughtErrors = [];\n }\n\n /** Remove event listeners from the page */\n dispose(): void {\n this.page.removeListener('console', this.consoleHandler);\n this.page.removeListener('pageerror', this.errorHandler);\n }\n}\n","/**\n * Screenshot capture utilities.\n *\n * @packageDocumentation\n */\n\nimport { mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { Page, ElementHandle } from 'playwright';\n\n/**\n * Capture a screenshot of a specific element or the full page.\n *\n * @param page - Playwright page\n * @param outputPath - File path for the screenshot\n * @param selector - Optional CSS selector to screenshot a specific element\n * @returns The actual path where the screenshot was saved, or null on failure\n */\nexport async function takeScreenshot(\n page: Page,\n outputPath: string,\n selector?: string\n): Promise<string | null> {\n try {\n mkdirSync(dirname(outputPath), { recursive: true });\n\n if (selector) {\n const element: ElementHandle | null = await page.$(selector);\n if (element) {\n try {\n await element.screenshot({ path: outputPath });\n return outputPath;\n } catch {\n // Element screenshot failed (e.g., element detached or too large)\n // Fall through to page screenshot\n }\n }\n }\n\n // Fallback to page screenshot\n await page.screenshot({ path: outputPath, fullPage: false });\n return outputPath;\n } catch {\n return null;\n }\n}\n\n/** Sanitize a name for use as a filename */\nexport function safeFileName(name: string): string {\n return name.replace(/[^a-zA-Z0-9_-]/g, '_');\n}\n","/**\n * Retry utility with exponential backoff.\n *\n * @packageDocumentation\n */\n\n/**\n * Retry an async operation with exponential backoff.\n *\n * @param fn - Async function to retry\n * @param maxRetries - Maximum number of retries (default: 3)\n * @param baseDelayMs - Base delay in ms before first retry (default: 500)\n * @returns Result of the successful call\n * @throws Last error if all retries exhausted\n */\nexport async function retry<T>(\n fn: () => Promise<T>,\n maxRetries = 3,\n baseDelayMs = 500\n): Promise<T> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n if (attempt < maxRetries) {\n const delay = baseDelayMs * Math.pow(2, attempt);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n\n throw lastError;\n}\n","/**\n * Navigation utilities with retry and wait helpers.\n *\n * @packageDocumentation\n */\n\nimport type { Page } from 'playwright';\nimport { retry } from '../util/retry.js';\n\n/**\n * Navigate to a URL with retry on failure.\n *\n * @param page - Playwright page\n * @param url - URL to navigate to\n * @param options - Navigation options\n */\nexport async function navigateWithRetry(\n page: Page,\n url: string,\n options?: {\n waitUntil?: 'domcontentloaded' | 'load' | 'networkidle';\n timeout?: number;\n retries?: number;\n }\n): Promise<void> {\n const { waitUntil = 'domcontentloaded', timeout = 15000, retries = 2 } = options ?? {};\n\n await retry(\n async () => {\n const resp = await page.goto(url, { waitUntil, timeout });\n if (!resp || resp.status() >= 500) {\n throw new Error(`Navigation to ${url} failed with status ${resp?.status()}`);\n }\n },\n retries,\n 1000\n );\n}\n\n/**\n * Wait for the runtime to load, render content, and expose the verification API.\n * Polls for window.__orbitalVerification and confirms INIT completed.\n * Falls back to a timeout if the API never appears (e.g., simple pages).\n *\n * @param page - Playwright page\n * @param timeoutMs - Maximum time to wait (default: 10000ms)\n */\nexport async function waitForRuntime(page: Page, timeoutMs = 10000): Promise<void> {\n const pollInterval = 200;\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() < deadline) {\n const ready = await page.evaluate(() => {\n const api = (window as unknown as Record<string, unknown>).__orbitalVerification as\n { getSnapshot?: () => { transitions: unknown[] } } | undefined;\n if (!api?.getSnapshot) return false;\n const snap = api.getSnapshot();\n // Ready when at least one transition has been recorded (INIT fired)\n return snap.transitions.length > 0;\n }).catch(() => false);\n\n if (ready) return;\n await page.waitForTimeout(pollInterval);\n }\n\n // Fallback: API never appeared, wait a bit for basic rendering\n await page.waitForTimeout(1000);\n}\n","/**\n * State bridge: read window.__orbitalVerification from a Playwright page.\n *\n * The OrbitalVerificationAPI is exposed by @almadar/ui's verificationRegistry.ts\n * on window.__orbitalVerification. This module provides typed access to it.\n *\n * @packageDocumentation\n */\n\nimport type { Page } from 'playwright';\nimport type { RuntimeState } from '../util/types.js';\n\n/** Shape of window.__orbitalVerification (subset used by verify tools) */\nexport interface OrbitalVerificationSnapshot {\n checks: Array<{\n id: string;\n label: string;\n status: 'pass' | 'fail' | 'pending' | 'warn';\n details?: string;\n }>;\n transitions: Array<{\n id: string;\n traitName: string;\n from: string;\n to: string;\n event: string;\n effects: Array<{ type: string; status: string; error?: string }>;\n }>;\n bridge: { connected: boolean } | null;\n summary: {\n totalChecks: number;\n passed: number;\n failed: number;\n warnings: number;\n pending: number;\n };\n}\n\n/**\n * Read the verification snapshot from the browser.\n * Returns null if the API is not available (runtime not loaded).\n */\nexport async function readVerificationSnapshot(\n page: Page\n): Promise<OrbitalVerificationSnapshot | null> {\n return page.evaluate(() => {\n const api = (window as unknown as Record<string, unknown>).__orbitalVerification as\n | { getSnapshot?: () => OrbitalVerificationSnapshot }\n | undefined;\n return api?.getSnapshot?.() ?? null;\n });\n}\n\n/**\n * Read trait states from the verification API.\n * Returns a map of trait name -> current state name.\n */\nexport async function readTraitStates(\n page: Page\n): Promise<Record<string, string>> {\n return page.evaluate(() => {\n const api = (window as unknown as Record<string, unknown>).__orbitalVerification as\n | { getTraitState?: (name: string) => { currentState: string } | null }\n | undefined;\n if (!api?.getTraitState) return {};\n\n // We can't enumerate trait names from the API directly, so\n // use the snapshot's transitions to discover trait names.\n const snapshotApi = api as unknown as { getSnapshot?: () => OrbitalVerificationSnapshot };\n const snapshot = snapshotApi.getSnapshot?.();\n if (!snapshot) return {};\n\n const result: Record<string, string> = {};\n const traitNames = new Set(snapshot.transitions.map((t) => t.traitName));\n for (const name of traitNames) {\n const state = api.getTraitState(name);\n if (state) result[name] = state.currentState;\n }\n return result;\n });\n}\n\n/**\n * Read the event log from the verification API.\n */\nexport async function readEventLog(\n page: Page\n): Promise<Array<{ event: string; listenerCount?: number }>> {\n return page.evaluate(() => {\n const api = (window as unknown as Record<string, unknown>).__orbitalVerification as\n | { eventLog?: Array<{ event: string; listenerCount?: number }> }\n | undefined;\n return api?.eventLog ?? [];\n });\n}\n\n/**\n * Build a RuntimeState from the verification snapshot.\n * Combines trait states, entity data, events, and guard results.\n */\nexport async function readRuntimeState(page: Page): Promise<RuntimeState | null> {\n const snapshot = await readVerificationSnapshot(page);\n if (!snapshot) return null;\n\n const traitStates = await readTraitStates(page);\n\n return {\n traits: Object.fromEntries(\n Object.entries(traitStates).map(([name, currentState]) => [\n name,\n { currentState, context: {} },\n ])\n ),\n entities: {}, // Entity data requires FetchedDataContext inspection\n events: snapshot.transitions.map((t) => t.event),\n guards: Object.fromEntries(\n snapshot.checks\n .filter((c) => c.id.startsWith('guard-'))\n .map((c) => [c.id, c.status === 'pass'])\n ),\n };\n}\n","/**\n * Entity data inspector.\n *\n * Extract entity data visibility from the DOM to verify that\n * mock data actually reached the rendered components.\n *\n * @packageDocumentation\n */\n\nimport type { Page } from 'playwright';\n\n/** Result of an entity data inspection */\nexport interface EntityInspection {\n /** Whether any entity data content was found in the DOM */\n hasContent: boolean;\n /** Number of entity-related DOM elements found */\n elementCount: number;\n /** Whether an \"empty state\" pattern is visible */\n showsEmptyState: boolean;\n /** Text content of the preview area (truncated) */\n previewText: string;\n}\n\n/**\n * Inspect the preview area for entity data content.\n * Checks for empty states, entity cards, table rows, etc.\n *\n * @param page - Playwright page\n * @param previewSelector - CSS selector for the preview area\n */\nexport async function inspectEntityData(\n page: Page,\n previewSelector = '[class*=\"livePreviewBox\"], [class*=\"opPreviewBox\"]'\n): Promise<EntityInspection> {\n return page.evaluate((selector) => {\n const preview = document.querySelector(selector);\n if (!preview) {\n return { hasContent: false, elementCount: 0, showsEmptyState: false, previewText: '' };\n }\n\n const text = (preview.textContent ?? '').trim();\n\n // Count entity-related elements\n const entityElements = preview.querySelectorAll(\n '[data-pattern], [data-entity], table tbody tr, [class*=\"card\"], [class*=\"Card\"]'\n );\n\n // Check for empty state indicators\n const emptyStateTexts = ['empty', 'no data', 'no items', 'nothing to show', 'no results'];\n const showsEmptyState = emptyStateTexts.some((t) =>\n text.toLowerCase().includes(t)\n );\n\n return {\n hasContent: text.length > 0 && entityElements.length > 0,\n elementCount: entityElements.length,\n showsEmptyState,\n previewText: text.substring(0, 500),\n };\n }, previewSelector);\n}\n","/**\n * DOM state extraction and inspection.\n *\n * Check for common error patterns in the rendered DOM:\n * \"Unknown pattern\", error boundaries, empty content, etc.\n *\n * @packageDocumentation\n */\n\nimport type { Page } from 'playwright';\n\n/** DOM inspection result */\nexport interface DOMInspection {\n /** Unknown pattern errors found in the DOM */\n unknownPatterns: string[];\n /** Whether an error boundary fallback is visible */\n hasErrorBoundary: boolean;\n /** Whether \"Objects are not valid as a React child\" appears */\n hasObjectRenderError: boolean;\n /** Whether the preview area is completely empty */\n isEmpty: boolean;\n /** Whether a preview error banner is visible */\n hasPreviewError: boolean;\n /** The preview error text, if any */\n previewErrorText: string;\n}\n\n/**\n * Inspect the DOM for common rendering errors.\n *\n * @param page - Playwright page\n * @param previewSelector - CSS selector for the preview area\n */\nexport async function inspectDOM(\n page: Page,\n previewSelector = '[class*=\"livePreviewBox\"], [class*=\"opPreviewBox\"]'\n): Promise<DOMInspection> {\n return page.evaluate((selector: string) => {\n const result: DOMInspection = {\n unknownPatterns: [],\n hasErrorBoundary: false,\n hasObjectRenderError: false,\n isEmpty: true,\n hasPreviewError: false,\n previewErrorText: '',\n };\n\n // Check for preview error banner\n const previewError = document.querySelector('[class*=\"previewError\"]');\n if (previewError) {\n result.hasPreviewError = true;\n result.previewErrorText = (previewError.textContent ?? '').trim();\n }\n\n // Check preview area content\n const preview = document.querySelector(selector);\n if (!preview) return result;\n\n const text = (preview.textContent ?? '').trim();\n // Canvas/SVG/video/img elements have no textContent but are valid content\n const hasVisualElements = preview.querySelector('canvas, svg, video, img, iframe') !== null;\n result.isEmpty = text.length === 0 && !hasVisualElements;\n\n // Check for \"Unknown pattern: xxx\"\n const unknownMatch = text.match(/Unknown pattern:\\s*\\S+/g);\n if (unknownMatch) {\n result.unknownPatterns = unknownMatch;\n }\n\n // Check for React render error\n if (text.includes('Objects are not valid as a React child')) {\n result.hasObjectRenderError = true;\n }\n\n // Check for error boundary\n const errorBoundary = preview.querySelector('[class*=\"error-boundary\"], [class*=\"ErrorBoundary\"]');\n if (errorBoundary) {\n result.hasErrorBoundary = true;\n }\n\n return result;\n }, previewSelector);\n}\n","/**\n * Console message categorization and reporting.\n *\n * @packageDocumentation\n */\n\nimport type { ConsoleEntry } from '../util/types.js';\n\n/** Categorized console report */\nexport interface ConsoleReport {\n errorCount: number;\n warningCount: number;\n infoCount: number;\n errors: string[];\n warnings: string[];\n /** Unique error patterns (deduplicated by first 80 chars) */\n uniqueErrors: string[];\n}\n\n/**\n * Build a console report from collected entries.\n */\nexport function buildConsoleReport(entries: ConsoleEntry[]): ConsoleReport {\n const errors = entries.filter((e) => e.type === 'error').map((e) => e.text);\n const warnings = entries.filter((e) => e.type === 'warning').map((e) => e.text);\n const infoCount = entries.filter((e) => e.type === 'info').length;\n\n // Deduplicate errors by first 80 characters\n const seen = new Set<string>();\n const uniqueErrors: string[] = [];\n for (const err of errors) {\n const key = err.substring(0, 80);\n if (!seen.has(key)) {\n seen.add(key);\n uniqueErrors.push(err);\n }\n }\n\n return {\n errorCount: errors.length,\n warningCount: warnings.length,\n infoCount,\n errors,\n warnings,\n uniqueErrors,\n };\n}\n","/**\n * JSON report generation.\n *\n * @packageDocumentation\n */\n\nimport { writeFileSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { VerifyReport, VerifyResult } from '../util/types.js';\n\n/**\n * Build a JSON report from verification results.\n */\nexport function buildJsonReport(\n url: string,\n mode: 'playground' | 'app',\n results: VerifyResult[]\n): VerifyReport {\n const pass = results.filter((r) => r.status === 'pass').length;\n const error = results.filter((r) => r.status === 'error').length;\n const warning = results.filter((r) => r.status === 'warning').length;\n\n return {\n timestamp: new Date().toISOString(),\n url,\n mode,\n summary: { total: results.length, pass, error, warning },\n results,\n };\n}\n\n/**\n * Write a JSON report to disk.\n */\nexport function writeJsonReport(report: VerifyReport, outputPath: string): void {\n mkdirSync(dirname(outputPath), { recursive: true });\n writeFileSync(outputPath, JSON.stringify(report, null, 2));\n}\n","/**\n * Markdown report generation.\n *\n * @packageDocumentation\n */\n\nimport { writeFileSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { VerifyReport } from '../util/types.js';\n\n/**\n * Generate a markdown report from verification results.\n */\nexport function buildMarkdownReport(report: VerifyReport): string {\n const lines: string[] = [];\n\n lines.push(`# Verification Report`);\n lines.push('');\n lines.push(`- **Date**: ${report.timestamp}`);\n lines.push(`- **URL**: ${report.url}`);\n lines.push(`- **Mode**: ${report.mode}`);\n lines.push('');\n\n lines.push(`## Summary`);\n lines.push('');\n lines.push(`| Status | Count |`);\n lines.push(`|--------|-------|`);\n lines.push(`| PASS | ${report.summary.pass} |`);\n lines.push(`| WARN | ${report.summary.warning} |`);\n lines.push(`| ERROR | ${report.summary.error} |`);\n lines.push(`| **Total** | **${report.summary.total}** |`);\n lines.push('');\n\n // Error details\n const errors = report.results.filter((r) => r.status === 'error');\n if (errors.length > 0) {\n lines.push(`## Errors (${errors.length})`);\n lines.push('');\n for (const item of errors) {\n lines.push(`### ${item.name}`);\n for (const e of item.errors) {\n lines.push(`- ${e.substring(0, 200)}`);\n }\n lines.push('');\n }\n }\n\n // Warning details\n const warnings = report.results.filter((r) => r.status === 'warning');\n if (warnings.length > 0) {\n lines.push(`## Warnings (${warnings.length})`);\n lines.push('');\n for (const item of warnings) {\n lines.push(`### ${item.name}`);\n for (const w of item.warnings) {\n lines.push(`- ${w.substring(0, 200)}`);\n }\n lines.push('');\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Write a markdown report to disk.\n */\nexport function writeMarkdownReport(report: VerifyReport, outputPath: string): void {\n mkdirSync(dirname(outputPath), { recursive: true });\n writeFileSync(outputPath, buildMarkdownReport(report));\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/verify",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Shared Playwright verification utilities for Almadar runtime and compiled projects",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",