import { chromium } from 'playwright'; import fs from 'fs'; import path from 'path'; console.log("Script started"); /** Ignore Storybook manager/addon requests; only count app and API failures. */ function isAppRelevantFailure(url) { try { const pathname = new URL(url).pathname; if (pathname.startsWith('/sb-manager/') || pathname.startsWith('/sb-addons/')) return false; if (pathname === '/index.json' || pathname === '/project.json') return false; return true; } catch { return true; } } async function audit() { console.log("Entering audit function"); let browser; try { console.log("Launching browser..."); browser = await chromium.launch({ headless: true }); console.log("Browser launched"); } catch (e) { console.error("Failed to launch browser:", e); process.exit(1); } const page = await browser.newPage(); const storybookStaticPath = path.resolve(process.cwd(), 'storybook-static/index.json'); console.log(`Reading index from ${storybookStaticPath}`); let stories = []; try { if (!fs.existsSync(storybookStaticPath)) { throw new Error(`File not found: ${storybookStaticPath}`); } const indexJson = JSON.parse(fs.readFileSync(storybookStaticPath, 'utf8')); stories = Object.values(indexJson.entries).map(e => e.id); } catch (e) { console.error(`Failed to read local index.json: ${e.message}`); process.exit(1); } console.log(`Found ${stories.length} stories.`); const report = { metadata: { timestamp: new Date().toISOString(), totalStories: stories.length, storiesWithErrors: 0, totalErrors: 0 }, failures: {} }; for (const [index, storyId] of stories.entries()) { const storyUrl = `http://localhost:6007/iframe.html?id=${storyId}&viewMode=story`; // Structured error collection const storyDetails = { console: [], pageErrors: [], network: [], navigation: null }; // Capture console messages (all types, but we flag errors) page.on('console', msg => { if (msg.type() === 'error' || msg.type() === 'warning') { const location = msg.location(); storyDetails.console.push({ type: msg.type(), text: msg.text(), location: `${location.url}:${location.lineNumber}:${location.columnNumber}` }); } }); // Capture page crashes/exceptions page.on('pageerror', err => { storyDetails.pageErrors.push({ message: err.message, stack: err.stack }); }); // Capture network failures (exclude Storybook internal sb-manager/sb-addons) // Ignore net::ERR_ABORTED on iframe/document - often navigation-induced, not app bug page.on('requestfailed', request => { const url = request.url(); if (!isAppRelevantFailure(url)) return; const failure = request.failure(); const errorText = failure ? failure.errorText : 'Unknown network error'; if (errorText === 'net::ERR_ABORTED' && /\/iframe\.html$|\/iframe$/.test(new URL(url).pathname || '')) return; storyDetails.network.push({ url, method: request.method(), errorText }); }); try { await page.goto(storyUrl, { waitUntil: 'domcontentloaded', timeout: 5000 }); // Small wait to catch immediate render errors await page.waitForTimeout(100); } catch (e) { storyDetails.navigation = { message: e.message, stack: e.stack }; } page.removeAllListeners('console'); page.removeAllListeners('pageerror'); page.removeAllListeners('requestfailed'); // Check if there were any errors const errorCount = storyDetails.console.filter(c => c.type === 'error').length + storyDetails.pageErrors.length + storyDetails.network.length + (storyDetails.navigation ? 1 : 0); if (errorCount > 0) { console.log(`[FAIL] ${storyId}: ${errorCount} errors`); report.failures[storyId] = storyDetails; report.metadata.storiesWithErrors++; report.metadata.totalErrors += errorCount; } if (index % 50 === 0) { console.log(`Processed ${index}/${stories.length}...`); } } console.log(`Audit complete.`); console.log(`Stories with errors: ${report.metadata.storiesWithErrors}`); console.log(`Total errors captured: ${report.metadata.totalErrors}`); const outputPath = path.resolve(process.cwd(), 'storybook_audit_detailed.json'); fs.writeFileSync(outputPath, JSON.stringify(report, null, 2)); console.log(`Detailed report saved to: ${outputPath}`); await browser.close(); if (report.metadata.storiesWithErrors > 0 || report.metadata.totalErrors > 0) { process.exit(1); } } audit().catch(e => { console.error("Top level error:", e); process.exit(1); });