feat: integrate latest HMDesign design system updates
This commit is contained in:
1 parent
99faec189e
commit
1c4e0bb9a1
209 files changed
+8845
-552
No files matched your search
@@ -0,0 +1,84 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { createRequire } from 'node:module';
|
||||
const require = createRequire(process.env.HM_PLAYWRIGHT_DIR ? path.join(process.env.HM_PLAYWRIGHT_DIR, 'package.json') : import.meta.url);
|
||||
const { chromium } = require('playwright');
|
||||
const browser = await chromium.launch({ headless: true, ...(process.env.HM_CHROME_PATH ? { executablePath: process.env.HM_CHROME_PATH } : {}) });
|
||||
const out = '_local/quality-20261010';
|
||||
const results = [];
|
||||
const selected = process.argv.slice(2);
|
||||
const base = 'http://127.0.0.1:6322';
|
||||
const task = async (name, fn) => { if (selected.length && !selected.includes(name)) return; try { const evidence = await fn(); results.push({ name, status: 'PASS', evidence }); } catch (e) { results.push({ name, status: 'FAIL', error: e.message }); } console.log(JSON.stringify(results.at(-1))); };
|
||||
const assert = (ok, message) => { if (!ok) throw Error(message); };
|
||||
try {
|
||||
for (const [name, route] of [['APP', '/'], ['PUBLISHER', '/publisher/'], ['DASHBOARD', '/dashboard/'], ['RECRUIT', '/recruit/']]) {
|
||||
await task(`${name}_RESPONSIVE_RUNTIME`, async () => {
|
||||
const evidence = [];
|
||||
for (const width of [390, 768, 1280, 1440]) {
|
||||
const page = await browser.newPage({ viewport: { width, height: 900 } });
|
||||
const errors = [];
|
||||
page.on('pageerror', e => errors.push(e.message));
|
||||
await page.goto(base + route, { waitUntil: 'networkidle' });
|
||||
await page.locator('#root [data-slot]:visible').first().waitFor();
|
||||
const result = await page.evaluate(() => {
|
||||
const frame = document.querySelector('[data-slot="dashboard-layout"]');
|
||||
const scroll = document.querySelector('[data-slot="dashboard-scroll"]');
|
||||
return { overflow: document.documentElement.scrollWidth > innerWidth + 1, hmElements: document.querySelectorAll('[data-slot]').length, frameWidth: frame?.getBoundingClientRect().width, headerHeight: document.querySelector('[data-slot="dashboard-header"]')?.getBoundingClientRect().height, internalOverflow: scroll ? scroll.scrollWidth > scroll.clientWidth : null };
|
||||
});
|
||||
await page.screenshot({ path: `${out}/existing-${name}-${width}.png`, fullPage: true });
|
||||
await page.close();
|
||||
assert(!result.overflow && !errors.length, `${width}: overflow / browser errors ${JSON.stringify(errors)}`);
|
||||
if (result.frameWidth) assert(result.frameWidth >= 960 && result.headerHeight === 48, 'Dashboard geometry');
|
||||
evidence.push({ width, ...result, errors });
|
||||
}
|
||||
return evidence;
|
||||
});
|
||||
}
|
||||
await task('FILTERBAR_REFERENCE_USAGE', async () => {
|
||||
const page = await browser.newPage();
|
||||
await page.goto(`${base}/storybook/iframe.html?id=patterns-data-filter-bar--all&viewMode=story`, { waitUntil: 'networkidle' });
|
||||
const status = page.getByRole('status');
|
||||
await page.getByRole('searchbox', { name: '검색어' }).fill('김');
|
||||
assert((await status.innerText()).includes('입력한 조건 1개 · 조회 적용 조건 0개'), 'draft / applied distinction');
|
||||
await page.getByRole('button', { name: '조회', exact: true }).click(); assert((await status.innerText()).includes('조회 적용 조건 1개'), 'reference query');
|
||||
await page.getByRole('button', { name: '초기화', exact: true }).click(); assert((await status.innerText()).includes('입력한 조건 0개 · 조회 적용 조건 0개'), 'reference reset');
|
||||
const evidence = [];
|
||||
for (const width of [390, 768, 1280, 1440]) {
|
||||
await page.setViewportSize({ width, height: 900 });
|
||||
const metrics = await page.locator('[data-slot="filter-bar"]').evaluate(e => ({ layout: e.dataset.layout, gap: getComputedStyle(e).gap, justify: getComputedStyle(e).justifyContent, wrap: getComputedStyle(e).flexWrap }));
|
||||
assert(metrics.layout === 'list-extended' && metrics.gap === '8px' && metrics.wrap === 'wrap' && metrics.justify === 'flex-start', 'FilterBar composition');
|
||||
await page.screenshot({ path: `${out}/filter-reference-${width}.png`, fullPage: true }); evidence.push({ width, ...metrics });
|
||||
}
|
||||
await page.close(); return evidence;
|
||||
});
|
||||
await task('THEME_DESIGNER', async () => {
|
||||
const page = await browser.newPage();
|
||||
await page.goto(`${base}/storybook/iframe.html?id=theme-designer-playground--live-verification&viewMode=story`, { waitUntil: 'networkidle' });
|
||||
await page.waitForFunction(() => /^(PASS|FAIL)/.test(document.querySelector('[data-testid="designer-result"]')?.textContent ?? ''), { timeout: 20000 });
|
||||
const text = await page.locator('[data-testid="designer-result"]').innerText(); assert(text.startsWith('PASS'), text);
|
||||
await page.close(); return { text };
|
||||
});
|
||||
await task('THEME_JSON_LOADER', async () => {
|
||||
const page = await browser.newPage();
|
||||
await page.goto(`${base}/storybook/iframe.html?id=theme-designer-playground--editor&viewMode=story`, { waitUntil: 'networkidle' });
|
||||
await page.getByRole('button', { name: 'Load Service Example JSON', exact: true }).click();
|
||||
await page.waitForFunction(() => document.querySelector('[aria-label="Primary / Brand HEX"]')?.value !== '#123328');
|
||||
const changed = await page.getByRole('textbox', { name: 'Primary / Brand HEX', exact: true }).inputValue();
|
||||
await page.getByRole('button', { name: 'Load Default JSON', exact: true }).click();
|
||||
await page.waitForFunction(() => document.querySelector('[aria-label="Primary / Brand HEX"]')?.value === '#123328');
|
||||
await page.close(); return { servicePrimary: changed, defaultPrimary: '#123328' };
|
||||
});
|
||||
await task('RUNTIME_THEME_KEYBOARD', async () => {
|
||||
const page = await browser.newPage();
|
||||
await page.goto(`${base}/storybook/iframe.html?id=theme-runtime-contract--verification&viewMode=story`, { waitUntil: 'networkidle' });
|
||||
await page.waitForFunction(() => /^(PASS|FAIL)/.test(document.querySelector('[data-testid="result"]')?.textContent ?? ''), { timeout: 20000 });
|
||||
const auto = await page.locator('[data-testid="result"]').innerText(); assert(auto.startsWith('PASS'), auto);
|
||||
const run = page.getByRole('button', { name: 'Run verification', exact: true });
|
||||
await run.focus(); await page.keyboard.press('Tab'); await page.keyboard.press('Shift+Tab'); await page.keyboard.press('Enter');
|
||||
await page.waitForFunction(() => /^(PASS|FAIL)/.test(document.querySelector('[data-testid="result"]')?.textContent ?? '') && document.querySelector('[data-testid="result"]')?.dataset.running !== 'true', { timeout: 20000 });
|
||||
const keyboard = await page.locator('[data-testid="result"]').innerText(); assert(keyboard.startsWith('PASS') && !keyboard.includes('KEYBOARD_FOCUS: NOT VERIFIED'), keyboard);
|
||||
await page.close(); return { auto, keyboard };
|
||||
});
|
||||
} finally { await browser.close(); }
|
||||
fs.writeFileSync(`${out}/${selected.length ? 'reference-' + selected.join('-') : 'reference-runtime'}.json`, JSON.stringify(results, null, 2));
|
||||
if (results.some(r => r.status === 'FAIL')) process.exitCode = 1;
|
||||
Reference in new issue
Block a user