Merge pull request 'Test/sw header more narrow' (#39) from test/sw-header-more-narrow into main
Deploy Storybook / deploy (push) Successful in 1m21s

Reviewed-on: #39
This commit was merged in pull request #39.
This commit is contained in:
shkim4 committed 2026-11-11 09:40:57 +09:00
commit cda60840d8
1 file changed
+28 -11
+28 -11
View File
@@ -51,11 +51,26 @@ await goto('sw-header--overview')
const docButton = page.locator('.hm-sw-header__document-button').first() const docButton = page.locator('.hm-sw-header__document-button').first()
await stableOnHover('Header file name', docButton, docButton.locator('.hm-sw-header__document-name')) await stableOnHover('Header file name', docButton, docButton.locator('.hm-sw-header__document-name'))
// SWHeader More (narrow): fields moved into the More menu are still SWHeader fields (400). // SWHeader More (narrow): fields moved into the More menu are still SWHeader fields (400).
await goto('sw-header--responsive-more') // Only below 760px does the header move fields into More (sw.css `@container hm-sw-header (max-width: 759.98px)`: 선/문자/치수
const narrow = page.locator('.hm-sw-header').filter({ visible: true }).nth(2) // 스타일, 속성Bar / 속성창, 색상; 인쇄 / 팝업 가이드 only below 640). From 760px the More button is hidden and the 화면 너비 Story
// rows stop at 760, so the 760 frame is narrowed to 700px, the way the Viewer More check below narrows its header.
const narrowHeaderMore = async () => {
await goto('sw-header--responsive-more')
const frame = page.locator('[data-frame-width="760"]')
await frame.evaluate(e => { e.style.maxWidth = '700px' }); await page.waitForTimeout(200)
return frame.locator('.hm-sw-header')
}
const narrow = await narrowHeaderMore()
const narrowWidth = await narrow.evaluate(e => Math.round(e.getBoundingClientRect().width))
const moreTrigger = narrow.locator('.hm-sw-header__more-trigger') const moreTrigger = narrow.locator('.hm-sw-header__more-trigger')
if (await moreTrigger.count()) { await moreTrigger.click(); await page.waitForTimeout(200) } check('Header More: the 700px header shows the More button', narrowWidth === 700 && await moreTrigger.isVisible(), { narrowWidth })
const moreValues = await styles('.hm-sw-header__field-value') const movedOut = await narrow.locator('.hm-sw-header__fields > :is([data-tier="aux"], [data-menu="color"])').evaluateAll(list => list.map(e => getComputedStyle(e).display))
check('Header More: 선/문자/치수 스타일 and 색상 leave the 700px header', movedOut.length === 4 && movedOut.every(d => d === 'none'), movedOut)
await moreTrigger.click(); await page.waitForTimeout(200)
const moreLabels = (await styles('[data-frame-width="760"] .hm-sw-header__more-item > span:first-child')).map(s => s.text)
const wantMore = ['색상', '선스타일', '문자스타일', '치수스타일', '속성Bar', '속성창']
check('Header More: the menu lists 색상 · 선/문자/치수 스타일 · 속성Bar · 속성창, not 인쇄 / 팝업 가이드 (below 640 only)', wantMore.every(w => moreLabels.includes(w)) && !moreLabels.includes('인쇄') && !moreLabels.includes('팝업 가이드'), moreLabels)
const moreValues = await styles('[data-frame-width="760"] :is(.hm-sw-header__field-value, .hm-sw-header__more-value)')
check('Header More: values shown with the More menu open stay 400 (none turn Bold)', moreValues.length > 0 && moreValues.every(v => v.weight === '400'), moreValues.filter(v => v.weight !== '400')) check('Header More: values shown with the More menu open stay 400 (none turn Bold)', moreValues.length > 0 && moreValues.every(v => v.weight === '400'), moreValues.filter(v => v.weight !== '400'))
await page.keyboard.press('Escape') await page.keyboard.press('Escape')
// Composed Controls: standalone menu fields (outside SWHeader) are Bold; labels and the font sample unchanged. // Composed Controls: standalone menu fields (outside SWHeader) are Bold; labels and the font sample unchanged.
@@ -118,9 +133,8 @@ await page.screenshot({ path: path.join(out, 'footer.png'), clip: { x: 0, y: 940
// SWHeader file-name button), 레이어 · 설정 · 속성 and Model / Layout; the two menus follow the SWHeader rules, measured // SWHeader file-name button), 레이어 · 설정 · 속성 and Model / Layout; the two menus follow the SWHeader rules, measured
// on SWHeader itself below and compared row by row. // on SWHeader itself below and compared row by row.
const typo = s => ({ weight: s.weight, size: s.size, family: s.family, outline: s.outline }) const typo = s => ({ weight: s.weight, size: s.size, family: s.family, outline: s.outline })
// SWHeader references: the responsive `...` menu rows and the file-name list rows. // SWHeader references: the responsive `...` menu rows (the same 700px header: More shows only below 760) and the file-name list rows.
await goto('sw-header--responsive-more') const refTrigger = (await narrowHeaderMore()).locator('.hm-sw-header__more-trigger')
const refTrigger = page.locator('.hm-sw-header__more-trigger').filter({ visible: true }).first()
await refTrigger.click(); await page.waitForTimeout(200) await refTrigger.click(); await page.waitForTimeout(200)
const refMore = await styles('.hm-sw-header__more-menu .hm-sw-header__more-item > span:first-child') const refMore = await styles('.hm-sw-header__more-menu .hm-sw-header__more-item > span:first-child')
check('SWHeader ... menu rows (reference): Regular 400 without outline', refMore.length > 0 && refMore.every(r => r.weight === '400' && r.outline === 'none'), refMore) check('SWHeader ... menu rows (reference): Regular 400 without outline', refMore.length > 0 && refMore.every(r => r.weight === '400' && r.outline === 'none'), refMore)
@@ -172,7 +186,9 @@ await stableOnHover('Viewer 레이어', lab.locator('xpath=ancestor::button[1]')
const tab = vh.locator('.hm-sw-viewer-header__tab', { hasText: 'Layout' }).first() const tab = vh.locator('.hm-sw-viewer-header__tab', { hasText: 'Layout' }).first()
await stableOnHover('Viewer Layout tab', tab, tab) await stableOnHover('Viewer Layout tab', tab, tab)
// More stays: narrow header shows the More button, it opens and lists the moved items. // More stays: narrow header shows the More button, it opens and lists the moved items.
await vh.evaluate(e => { e.style.width = '700px' }) // 2026-10-26 (cabd2f6): the viewer header keeps every menu down to 520px (measured steps) and moves items into More only
// below that, so the header is narrowed to 400px as in viewer.browser.mjs (the 520 row narrowed to 400).
await vh.evaluate(e => { e.style.width = '400px' })
const more = vh.getByRole('button', { name: /추가 도구/ }) const more = vh.getByRole('button', { name: /추가 도구/ })
// 2026-10-20: the header re-measures through a ResizeObserver; wait for More instead of a fixed 200ms (the check below // 2026-10-20: the header re-measures through a ResizeObserver; wait for More instead of a fixed 200ms (the check below
// still fails when it never appears). The fixed wait failed intermittently on the same build. // still fails when it never appears). The fixed wait failed intermittently on the same build.
@@ -203,10 +219,11 @@ const rowBefore = await rowGeo()
await stableOnHover('Recent file name', row, row.locator('.hm-sw-recent-files__name')) await stableOnHover('Recent file name', row, row.locator('.hm-sw-recent-files__name'))
await row.hover(); await page.waitForTimeout(250) await row.hover(); await page.waitForTimeout(250)
const preview = await page.locator('.hm-sw-recent-files__preview').evaluate(p => { const t = p.querySelector('.hm-sw-recent-files__preview-title'), c = getComputedStyle(t), b = p.getBoundingClientRect(), body = p.querySelector('.hm-sw-recent-files__preview-body').getBoundingClientRect() const preview = await page.locator('.hm-sw-recent-files__preview').evaluate(p => { const t = p.querySelector('.hm-sw-recent-files__preview-title'), c = getComputedStyle(t), b = p.getBoundingClientRect(), body = p.querySelector('.hm-sw-recent-files__preview-body').getBoundingClientRect()
return { title: t.textContent, weight: c.fontWeight, size: c.fontSize, color: c.color, outline: c.textShadow.split(', rgb')[0], titleW: t.getBoundingClientRect().width, overflow: c.textOverflow, w: b.width, h: b.height, bodyH: body.height, bodyEmpty: p.querySelector('.hm-sw-recent-files__preview-body').childElementCount === 0 && !p.querySelector('.hm-sw-recent-files__preview-body').textContent } }) return { title: t.textContent, weight: c.fontWeight, size: c.fontSize, color: c.color, outline: c.textShadow.split(', rgb')[0], titleW: t.getBoundingClientRect().width, overflow: c.textOverflow, w: b.width, h: b.height, bodyH: body.height, bodyContent: [...p.querySelector('.hm-sw-recent-files__preview-body').children].map(e => `${e.tagName.toLowerCase()}.${e.getAttribute('class')}`), bodyImages: p.querySelectorAll('.hm-sw-recent-files__preview-body img').length } })
report.preview = preview report.preview = preview
// 2026-10-21 (user decision): the preview frame stays on hover; its 243px body is empty (no image / thumbnail). // 2026-10-21 (user decision): the preview frame stays on hover; its 243px body shows only the red no-preview sign
check('Recent preview: title 14px 700 + 1.3px outline, width 294 with ellipsis, empty body 243px', preview.bodyEmpty && preview.weight === '700' && preview.size === '14px' && preview.outline === OUTLINE_14 && preview.titleW === 294 && preview.overflow === 'ellipsis' && preview.bodyH === 243, preview) // (DESIGN_RULES 최근파일 패널), never an image / thumbnail.
check('Recent preview: title 14px 700 + 1.3px outline, width 294 with ellipsis, body 243px with only the no-preview sign', JSON.stringify(preview.bodyContent) === '["svg.hm-sw-recent-files__preview-none"]' && preview.bodyImages === 0 && preview.weight === '700' && preview.size === '14px' && preview.outline === OUTLINE_14 && preview.titleW === 294 && preview.overflow === 'ellipsis' && preview.bodyH === 243, preview)
await page.screenshot({ path: path.join(out, 'recent-files.png'), clip: { x: 0, y: 0, width: 1100, height: 900 } }) await page.screenshot({ path: path.join(out, 'recent-files.png'), clip: { x: 0, y: 0, width: 1100, height: 900 } })
check('Recent files: rows keep 50px and their text widths', rowBefore === await rowGeo() && rowBefore.startsWith('50,'), rowBefore) check('Recent files: rows keep 50px and their text widths', rowBefore === await rowGeo() && rowBefore.startsWith('50,'), rowBefore)
await row.press('Enter').catch(() => {}) await row.press('Enter').catch(() => {})