test(sw): align legacy storybook suites and add header composition fixture

- dropdown-consolidation, storybook-cleanup-stage1, detail-buttons, property-panel-comparison: assert their recorded
  state and accept today only the approved later Story changes (storybook-inventory.mjs helpers).
- header-composition.browser.mjs + fixtures/header-composition.tsx: the removed Composition Story presets, hidden
  controls, invalid menuOrder / hiddenControls and live changes, on a test-only page using the public API only.
- storybook-unused-removal: header comment lists which older scripts run on current Stories again.
This commit is contained in:
shkim4 committed 2026-10-21 06:08:23 +09:00
1 parent 1e05eaf1de
commit b50e95c325
8 files changed
+375 -66

No files matched your search

@@ -5,8 +5,9 @@ import { execFileSync } from 'node:child_process'
import path from 'node:path'
import http from 'node:http'
import { parse } from '@babel/parser'
import { retiredDropdownIds, swStoryEntries, retainedInventory, inventorySignature } from './storybook-inventory.mjs'
import { retiredDropdownIds, swStoryEntries, retainedInventory, inventorySignature, laterRetiredHeaderIds, headerInventoryIssues, withApprovedEntryChanges, approvedAddedStoryIds, movedToPopupIds, headerSourceIssues, approvedMainCommit, integratedChangedFiles } from './storybook-inventory.mjs'
import { loadPlaywright } from './playwright-runtime.mjs'
import { sourceChanges, unapprovedChanges } from './source-changes.mjs'
const out = path.resolve(process.argv[2] ?? 'docs/sw/storybook-dropdown-page-qa')
await mkdir(out, { recursive: true })
@@ -20,12 +21,29 @@ const previousSW = swStoryEntries(previous)
report.menuCorrectionBaseCommit = '9482d45f340981c4b4ad6537cb678bf4afcdc681'
await writeFile(path.join(out, 'after-full-index.json'), JSON.stringify(after, null, 2) + '\n')
await writeFile(path.join(out, 'story-inventory.json'), JSON.stringify({ before: beforeSW, after: afterSW, removed: beforeSW.filter(e => retiredDropdownIds.includes(e.id)) }, null, 2) + '\n')
check('28 -> 24 SW Stories, exactly four approved Dropdown retirements', beforeSW.length === 28 && afterSW.length === 24 &&
JSON.stringify(inventorySignature(retainedInventory(beforeSW))) === JSON.stringify(inventorySignature(afterSW)))
// 2026-10-20 (test alignment): each inventory and source check asserts the consolidation on its recorded state (the
// index of the c705a1f smoke run and the c705a1f source, read from Git) and, for today, only the approved later
// changes listed in storybook-inventory.mjs. The browser checks below run unchanged on the current Storybook.
report.consolidationCommit = 'c705a1fc59fe8ecbce663bf4601638fde43553a1'
const git = (...args) => execFileSync('git', args, { encoding: 'utf8', maxBuffer: 1 << 26 })
const recorded = JSON.parse(git('show', `${report.consolidationCommit}:docs/sw/storybook-dropdown-page-qa/smoke/after-full-index.json`))
const recordedSW = swStoryEntries(recorded)
const signature = list => JSON.stringify(inventorySignature(list))
const now = headerInventoryIssues(beforeSW, after)
check('28 -> 24 SW Stories, exactly four approved Dropdown retirements (recorded at c705a1f); now only approved later changes', beforeSW.length === 28 && recordedSW.length === 24 &&
signature(retainedInventory(beforeSW)) === signature(recordedSW) && now.ok, { recorded: recordedSW.length, ...now })
check('Dropdown is one Story directly under Header with original ID, no Dropdown folder', afterSW.filter(e => e.name === 'Dropdown').length === 1 && after.entries['sw-header--composed-controls']?.title === 'SW/Header' && !afterSW.some(e => e.title.startsWith('SW/Header/')))
check('menu correction keeps all 24 IDs; only composed Story name/title change', previousSW.length === 24 && afterSW.length === 24 && JSON.stringify(inventorySignature(retainedInventory(previousSW))) === JSON.stringify(inventorySignature(afterSW)) && JSON.stringify(previousSW.filter(e => e.id !== 'sw-header--composed-controls')) === JSON.stringify(afterSW.filter(e => e.id !== 'sw-header--composed-controls')))
const otherRetained = list => list.filter(e => e.id !== 'sw-header--composed-controls')
const keptNow = otherRetained(previousSW).filter(e => !laterRetiredHeaderIds.includes(e.id))
check('menu correction keeps all 24 IDs; only composed Story name/title change (recorded at c705a1f); the other entries now differ only by approved changes',
previousSW.length === 24 && recordedSW.length === 24 && signature(retainedInventory(previousSW)) === signature(recordedSW) && JSON.stringify(otherRetained(previousSW)) === JSON.stringify(otherRetained(recordedSW)) &&
JSON.stringify(keptNow.map(withApprovedEntryChanges)) === JSON.stringify(keptNow.map(e => after.entries[e.id])), keptNow.filter(e => JSON.stringify(withApprovedEntryChanges(e)) !== JSON.stringify(after.entries[e.id])).map(e => e.id))
const nonSW = index => Object.values(index.entries).filter(e => !e.title.startsWith('SW/Header'))
check('all non-SW index entries identical', JSON.stringify(nonSW(before)) === JSON.stringify(nonSW(after)))
// Today: entries outside SW keep their values and order; SW entries outside SW/Header are exactly the approved additions and the Popup move.
const outsideSW = index => JSON.stringify(Object.values(index.entries).filter(e => !e.id.startsWith('sw-')))
const otherSW = { actual: nonSW(after).filter(e => e.id.startsWith('sw-')).map(e => e.id).sort(), expected: [...approvedAddedStoryIds.filter(id => !id.startsWith('sw-header--')), ...movedToPopupIds].sort() }
check('all non-SW index entries identical (recorded at c705a1f and now); other SW titles hold only approved additions and the Popup move', JSON.stringify(nonSW(before)) === JSON.stringify(nonSW(recorded)) &&
outsideSW(before) === outsideSW(after) && JSON.stringify(otherSW.actual) === JSON.stringify(otherSW.expected), otherSW)
const sourcePath = 'src/sw/sw-header.stories.tsx'
const original = execFileSync('git', ['show', `${report.baseCommit}:${sourcePath}`], { encoding: 'utf8' }).replaceAll('\r\n', '\n')
const source = (await readFile(sourcePath, 'utf8')).replaceAll('\r\n', '\n')
@@ -35,9 +53,19 @@ const declarations = text => Object.fromEntries(parse(text, { sourceType: 'modul
}))
const oldDeclarations = declarations(original), currentDeclarations = declarations(source)
const removed = ['LayerDropdown', 'ColorDropdown', 'LineStyleDropdown', 'TextDimensionStyleDropdown', 'ComposedControls', 'IconMatrix', 'ICON_LAYERS', 'NARROW_LAYER_WIDTHS', 'MENU_BUTTON_HOVER']
check('all retained declarations identical outside imports, meta and ComposedDemo', Object.entries(oldDeclarations).filter(([key]) => ![...removed, 'ImportDeclaration', 'meta', 'ComposedDemo'].includes(key)).every(([key, value]) => currentDeclarations[key] === value))
const ignored = [...removed, 'ImportDeclaration', 'meta', 'ComposedDemo']
const declarationsAt = commit => declarations(git('show', `${commit}:${sourcePath}`).replaceAll('\r\n', '\n'))
const consolidated = declarationsAt(report.consolidationCommit)
const sinceConsolidation = headerSourceIssues([...new Set([...Object.keys(consolidated), ...Object.keys(currentDeclarations)])].filter(key => !ignored.includes(key)), consolidated, currentDeclarations, declarationsAt)
check('all retained declarations identical outside imports, meta and ComposedDemo (at c705a1f); later changes only by approved commits at their approved content',
Object.entries(oldDeclarations).filter(([key]) => !ignored.includes(key)).every(([key, value]) => consolidated[key] === value) && sinceConsolidation.length === 0, sinceConsolidation)
const untouched = ['packages/sw/src', 'packages/sw/ai', 'packages/sw/package.json', 'src/sw/sw-header-overview.tsx', 'src/sw/sw-stories.css', 'src/sw/assets', '.storybook']
check('runtime, API, AI template, Overview, existing CSS/assets and Storybook configuration untouched', !execFileSync('git', ['diff', report.baseCommit, '--', ...untouched], { encoding: 'utf8' }))
// Today the same paths may differ from the approved main merge only in the integrated-improvement files (as in overview.browser.mjs).
// Untracked new files count as changes (source-changes.mjs).
const sourceDiff = { consolidation: git('diff', '--name-only', report.baseCommit, report.consolidationCommit, '--', ...untouched).trim(),
unapproved: unapprovedChanges(approvedMainCommit, untouched, integratedChangedFiles),
sinceBaseline: sourceChanges(report.baseCommit, untouched).length }
check('runtime, API, AI template, Overview, existing CSS/assets and Storybook configuration untouched by the consolidation; unchanged since the approved main merge', sourceDiff.consolidation === '' && sourceDiff.unapproved.length === 0, sourceDiff)
const root = path.resolve('storybook-static'), mime = { '.html': 'text/html', '.js': 'text/javascript', '.css': 'text/css', '.json': 'application/json', '.svg': 'image/svg+xml', '.ttf': 'font/ttf', '.png': 'image/png' }
const server = http.createServer(async (req, res) => {