Deploy Storybook / deploy (push) Successful in 1m10s
Test-only approval commit after the34f02bfmain merge (sw-test-regression- baseline section 9); no protected path changes. - public-api.approved.json from the clean34f02bfbuild: 170 exports kept, only SWViewerHeader.d.ts changes (7 optional SWViewerHeaderProps). - approvedMainCommitb4e0771-> b320a8f; approvedHeaderDeclarations for the23d522cStory declarations; withApprovedOrder for the approved SW Header first position; storybook-simplification expects SW/Theme hidden. - Verification report: docs/sw/sw-viewer-storybook-merge-verification-2026-10-21.md
67 lines
6.5 KiB
JavaScript
67 lines
6.5 KiB
JavaScript
// 2026-10-20 SW Storybook simplification: sidebar order, hidden verification Stories, removed IDs, direct URL render of
|
||
// every SW Story and the moved Property Panel (SW/Popup, ID sw-header--property-panel-compare).
|
||
// Usage: build Storybook first, then node packages/sw/tests/storybook-simplification.browser.mjs [evidence-dir]
|
||
import { readFile, writeFile, mkdir } from 'node:fs/promises'
|
||
import path from 'node:path'
|
||
import http from 'node:http'
|
||
import { runtimeRequire } from './playwright-runtime.mjs'
|
||
const require = runtimeRequire()
|
||
const { chromium } = require('playwright')
|
||
const out = path.resolve(process.argv[2] ?? 'docs/sw/storybook-simplification-qa'); await mkdir(out, { recursive: true })
|
||
const root = path.resolve('storybook-static'), mime = { '.html': 'text/html', '.js': 'text/javascript', '.css': 'text/css', '.json': 'application/json', '.svg': 'image/svg+xml', '.png': 'image/png', '.ttf': 'font/ttf', '.woff2': 'font/woff2' }
|
||
const server = http.createServer(async (req, res) => { try { const p = new URL(req.url, 'http://localhost').pathname, file = path.resolve(root, '.' + decodeURIComponent(p === '/' ? '/index.html' : p)); res.setHeader('Content-Type', mime[path.extname(file)] ?? 'application/octet-stream'); res.end(await readFile(file)) } catch { res.writeHead(404).end() } })
|
||
await new Promise(r => server.listen(0, '127.0.0.1', r)); const base = `http://127.0.0.1:${server.address().port}`
|
||
const browser = await chromium.launch({ headless: true, executablePath: process.env.SW_CHROME_PATH ?? 'C:/Program Files/Google/Chrome/Application/chrome.exe' })
|
||
const checks = []; const check = (n, ok, d) => { checks.push({ n, ok, d }); console.log(ok ? 'PASS' : 'FAIL', n, ok ? '' : JSON.stringify(d)) }
|
||
const index = JSON.parse(await readFile(path.join(root, 'index.json'), 'utf8'))
|
||
const sw = Object.values(index.entries).filter(e => e.type === 'story' && e.title.startsWith('SW/'))
|
||
// 1. every SW story renders by direct URL without page errors
|
||
const page = await browser.newPage({ viewport: { width: 1920, height: 1000 } })
|
||
let errors = []; page.on('pageerror', e => errors.push(e.message)); page.on('console', m => { if (m.type() === 'error') errors.push(m.text()) })
|
||
const bad = []
|
||
for (const e of sw) {
|
||
errors = []
|
||
await page.goto(`${base}/iframe.html?id=${e.id}&viewMode=story`)
|
||
try { await page.locator('#storybook-root > *').first().waitFor({ timeout: 15000 }) } catch { bad.push([e.id, 'no root']) ; continue }
|
||
await page.waitForTimeout(150)
|
||
const err = await page.locator('.sb-show-errordisplay').count()
|
||
if (err || errors.length) bad.push([e.id, errors.slice(0, 2)])
|
||
}
|
||
check(`direct URL render: ${sw.length} SW Stories, no error display / page error`, bad.length === 0, bad)
|
||
// 2. removed IDs are gone
|
||
const removed = ['figma', 'capture-active', 'capture-outline', 'capture-recent', 'variants', 'recent-files'].map(id => `sw-header--home-menu-${id}`)
|
||
check('removed Home Menu IDs absent from index', removed.every(id => !index.entries[id]))
|
||
// 2026-10-20 Footer cleanup: retired Footer IDs are gone, the two main Footer Stories stay.
|
||
check('removed Footer IDs absent, full-footer / figma-variants kept', ['sw-footer--default', 'sw-footer--states'].every(id => !index.entries[id]) && ['sw-footer--full-footer', 'sw-footer--figma-variants'].every(id => index.entries[id]))
|
||
// 3. Property panel in Popup: four states
|
||
await page.goto(`${base}/iframe.html?id=sw-header--property-panel-compare&viewMode=story`)
|
||
await page.locator('[data-compare]').first().waitFor()
|
||
await page.waitForTimeout(300)
|
||
const cells = await page.locator('[data-compare]').evaluateAll(list => list.map(c => { const r = c.querySelector('.hm-sw-property').getBoundingClientRect(); return [c.dataset.compare, Math.round(r.width), Math.round(r.height)] }))
|
||
check('Popup › Property Panel: four states none/all/circle/expanded at 314 × 256/361/658/754', JSON.stringify(cells) === JSON.stringify([['none', 314, 256], ['all', 314, 361], ['circle', 314, 658], ['expanded', 314, 754]]), cells)
|
||
await page.screenshot({ path: path.join(out, 'popup-property-panel-compare.png'), fullPage: true })
|
||
// 4. manager sidebar
|
||
const m = await browser.newPage({ viewport: { width: 1600, height: 2400 } })
|
||
await m.goto(`${base}/?path=/story/sw-header--overview`)
|
||
await m.locator('[data-item-id="sw-header--overview"]').waitFor()
|
||
for (const c of ['sw-footer', 'sw-popup', 'sw-viewer', 'sw-theme']) { const b = m.locator(`[data-item-id="${c}"] > button[aria-expanded="false"]`); if (await b.count()) await b.click() }
|
||
await m.waitForTimeout(500)
|
||
const rows = await m.locator('#storybook-explorer-tree [data-item-id^="sw-"]').evaluateAll(list => list.map(e => [e.dataset.itemId, e.dataset.nodetype, e.textContent.replace('Skip to content', '').trim()]))
|
||
await writeFile(path.join(out, 'sidebar.json'), JSON.stringify(rows, null, 1))
|
||
const comps = rows.filter(r => r[1] === 'component').map(r => r[2])
|
||
// 2026-10-21 (user request): SW/Theme left the sidebar (verification tag); its Story keeps its ID and direct URL.
|
||
check('sidebar SW order Header → Footer → Popup → Viewer (Theme hidden)', JSON.stringify(comps) === JSON.stringify(['Header', 'Footer', 'Popup', 'Viewer']), comps)
|
||
const hidden = ['sw-header--window-move-motion', 'sw-header--k-guide', 'sw-footer--figma-variants', 'sw-header--detail-buttons', 'sw-header--home-menu-capture-default']
|
||
check('verification Stories not in sidebar', rows.every(r => !hidden.includes(r[0])), rows.filter(r => hidden.includes(r[0])))
|
||
const popupRows = await m.locator('#storybook-explorer-tree [data-item-id]').evaluateAll(list => list.map(e => e.dataset.itemId))
|
||
const pi = popupRows.indexOf('sw-popup')
|
||
check('Popup children order: Custom Content, Multiple Popups, Property Panel', JSON.stringify(popupRows.slice(pi + 1, pi + 4)) === JSON.stringify(['sw-popup--custom-content', 'sw-popup--multiple-popups', 'sw-header--property-panel-compare']), popupRows.slice(pi + 1, pi + 4))
|
||
const headerIds = rows.filter(r => r[0].startsWith('sw-header--')).map(r => r[0])
|
||
check('Property Panel listed once (under Popup only)', headerIds.filter(id => id === 'sw-header--property-panel-compare').length === 1)
|
||
await m.locator('[data-item-id="sw-header--property-panel-compare"]').click(); await m.waitForTimeout(800)
|
||
check('sidebar link opens moved Story with same ID', m.url().includes('sw-header--property-panel-compare'), m.url())
|
||
await m.screenshot({ path: path.join(out, 'sidebar.png'), clip: { x: 0, y: 0, width: 320, height: 2400 } })
|
||
await writeFile(path.join(out, 'result.json'), JSON.stringify(checks, null, 1))
|
||
console.log(checks.filter(c => c.ok).length + '/' + checks.length + ' PASS')
|
||
await browser.close(); server.close()
|