docs(storybook): make Expanded OrgChart a preview-only page
Deploy Storybook / deploy (push) Successful in 59s
Deploy Storybook / deploy (push) Successful in 59s
Remove the data, layout, interaction and employee-popup setting panels from the Expanded OrgChart Story. The chart now renders a fixed sample (7 companies x 20, TB, all expanded, collapse/zoom/pan on, Drag & Drop off, HM Dialog) right under the page title. Story ID, OrgChart packages and public API are unchanged. Align the Story browser checks (P7, P8, P9, P9.2-P9.5, geometry, popup parity, hierarchy, HM Story) with the preview: setting-only scenarios are removed, chart rendering, collapse, Zoom/Pan/Fit and HM Dialog checks run on the fixed state. Move/Drag & Drop coverage stays in the Vanilla Core checks (verify-p9-3-core, verify-p9-4-core). Verified: tsc, test:guard 94/94, node --check on 11 scripts, changed browser sections PASS. Pre-existing P7 story-menu, P8 Department long-name, P9 Expanded tb/runner failures remain separate issues. verify-p9-5-popup-parity was not run (needs the Vanilla example server).
This commit is contained in:
1 parent
4a54cfbeb2
commit
f4ddd5ac4b
14 files changed
+163
-1134
No files matched your search
@@ -83,11 +83,6 @@ const endpoint = m => m.cards.every(c => c.endpointError !== null && c.endpointE
|
||||
const border = m => m.cards.every(c => { const i = { top: 0, right: 1, left: 3 }[c.direction]; return i === undefined ? c.border.every(b => b === c.border[2]) : c.border[i] !== c.border[2] && c.border.every((b, j) => j === i || b === c.border[2]); });
|
||||
async function screenshot(name) { await page.screenshot({ path: path.join(output, name + '.png'), fullPage: true }); }
|
||||
async function setLayout(options) { await page.evaluate(options => window.handle.setAutoLayout(options), options); await ready(); }
|
||||
async function select(label, option) {
|
||||
await page.getByRole('combobox', { name: label, exact: true }).click();
|
||||
await page.getByRole('option', { name: option, exact: true }).click();
|
||||
await settle();
|
||||
}
|
||||
async function hmPopup(name) {
|
||||
const first = page.locator('.hm-orgchart-employee').first();
|
||||
const id = await first.getAttribute('data-employee-id');
|
||||
@@ -272,60 +267,17 @@ try {
|
||||
await screenshot('2100-hybrid');
|
||||
}
|
||||
if (run('story')) {
|
||||
// Expanded is preview-only (2026-10-22): the fixed 7 companies x 20 TB sample replaces the
|
||||
// removed data/scope/company/layout/Depth/popup settings scenarios.
|
||||
await page.goto((process.env.ORGCHART_STORY_ORIGIN ?? 'http://127.0.0.1:6056') + '/iframe.html?id=orgchart--expanded-org-chart&viewMode=story');
|
||||
await ready(20);
|
||||
check(await page.locator('.hm-orgchart-story-companies').first().getByRole('checkbox').count() === 7 && new Set((await measure()).nodes.map(n => n.company)).size === 7, 'Story total20: all seven company controls and rendered trees');
|
||||
for (const count of [100, 300]) {
|
||||
await select('전체 직원 수', `${count}명`);
|
||||
check(await page.locator('.hm-orgchart-employee').count() !== count, `Story total${count}: draft choice does not render before Apply`);
|
||||
await page.getByRole('button', { name: '데이터 적용', exact: true }).click(); await ready(count);
|
||||
check((await measure()).cards.length === count, `Story total${count}: actual selector applies count`);
|
||||
}
|
||||
await page.getByRole('button', { name: '선택 해제', exact: true }).click();
|
||||
await page.getByRole('checkbox', { name: '한맥기술', exact: true }).check();
|
||||
await select('데이터 범위', '회사별');
|
||||
for (const count of [20, 100, 300]) {
|
||||
await select('회사당 직원 수', `${count}명`);
|
||||
await page.getByRole('button', { name: '데이터 적용', exact: true }).click(); await ready(count);
|
||||
check((await measure()).cards.every(c => c.company === 'hanmac'), `Story per-company${count}: exact chosen roster`);
|
||||
}
|
||||
await page.getByRole('checkbox', { name: '삼안', exact: true }).check();
|
||||
await select('회사당 직원 수', '100명');
|
||||
await page.getByRole('button', { name: '데이터 적용', exact: true }).click(); await ready(200);
|
||||
check(new Set((await measure()).cards.map(c => c.company)).size === 2, 'Story two companies100: actual 200');
|
||||
for (const [label, type] of [['가로형 LR', 'lr'], ['혼합형 Hybrid', 'hybrid'], ['세로형 TB', 'tb']]) {
|
||||
await select('조직도 표시 유형', label); await ready(200);
|
||||
check((await measure()).layout === type, `Story layout ${type}: real screen switched`);
|
||||
await screenshot('story-' + type + '-200');
|
||||
}
|
||||
check(await page.getByRole('combobox', { name: '혼합형 시작 Depth', exact: true }).isDisabled(), 'Story Hybrid depth limited outside Hybrid');
|
||||
await select('조직도 표시 유형', '혼합형 Hybrid');
|
||||
for (const depth of [2, 3, 4]) { await select('혼합형 시작 Depth', `Depth ${depth}부터 세로 배치`); await ready(200); check(!overlap((await measure()).cards.map(c => c.box)), `Story HybridDepth${depth}: actual control applied safely`); }
|
||||
await ready(140);
|
||||
check(new Set((await measure()).nodes.map(n => n.company)).size === 7 && (await measure()).layout === 'tb', 'Story preview: seven companies in fixed TB');
|
||||
await hmPopup('Story HM');
|
||||
// Source/company disappearance closes the external popup safely.
|
||||
await page.locator('.hm-orgchart-employee').first().press('Enter'); await page.locator('[data-component="HMOrgChartEmployeeDialog"]').waitFor();
|
||||
await page.evaluate(() => {
|
||||
const overlay = document.querySelector('[data-component="HMOrgChartEmployeeDialog"]');
|
||||
// Escape to dismiss first; normal UI then commits an empty company view.
|
||||
overlay.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
||||
});
|
||||
await page.keyboard.press('Escape');
|
||||
await page.getByRole('button', { name: '선택 해제', exact: true }).click();
|
||||
await page.getByRole('button', { name: '데이터 적용', exact: true }).click(); await ready(0);
|
||||
check(await page.locator('[data-component="HMOrgChartEmployeeDialog"]').count() === 0 && await page.locator('.hm-orgchart-expanded-empty').count() === 1, 'Story empty selection safely clears view/popup');
|
||||
await page.getByRole('button', { name: '초기화', exact: true }).click(); await ready(20);
|
||||
await select('조직도 표시 유형', '세로형 TB');
|
||||
const rootId = (await measure()).nodes.find(n => !n.parent).id;
|
||||
const toggle = page.locator(`.hm-orgchart-expanded-toggle[data-organization-id="${rootId}"]`);
|
||||
await toggle.focus(); await toggle.press('Enter'); await ready(); const collapsed = await page.locator('.hm-orgchart-employee').count();
|
||||
await select('직원 정보 팝업', 'Core 기본 팝업'); await ready();
|
||||
check(await page.locator('.hm-orgchart-employee').count() === collapsed, 'Story popup ownership switch retains independent collapse');
|
||||
await page.locator('.hm-orgchart-employee').first().press('Enter'); await page.locator('dialog[open]').waitFor(); await page.keyboard.press('Escape');
|
||||
await select('직원 정보 팝업', '사용 안 함'); await ready();
|
||||
await page.locator('.hm-orgchart-employee').first().press('Enter'); await settle();
|
||||
check(await page.getByRole('dialog').count() === 0, 'Story popup none: no default or HM popup');
|
||||
await select('직원 정보 팝업', 'HMDesign Dialog'); await ready();
|
||||
await toggle.focus(); await toggle.press('Enter'); await ready(20);
|
||||
await toggle.focus(); await toggle.press('Enter'); await ready();
|
||||
check(await toggle.getAttribute('aria-expanded') === 'false' && await page.locator('.hm-orgchart-employee').count() < 140, 'Story preview: group collapse');
|
||||
await toggle.focus(); await toggle.press('Enter'); await ready(140);
|
||||
for (const width of [390, 768, 1280, 1440]) {
|
||||
await page.setViewportSize({ width, height: width === 390 ? 844 : 1100 }); await settle();
|
||||
await page.getByRole('button', { name: 'Fit to View', exact: true }).click(); await settle();
|
||||
@@ -334,16 +286,6 @@ try {
|
||||
measurements.push({ name: `Story ${width}px`, value: m });
|
||||
await screenshot('story-' + width);
|
||||
}
|
||||
await select('조직도 표시 유형', '가로형 LR');
|
||||
await select('초기 표시 Depth', '2Depth까지');
|
||||
await page.getByRole('button', { name: '전체 회사', exact: true }).click();
|
||||
await select('데이터 범위', '회사별'); await select('회사당 직원 수', '300명');
|
||||
check(await page.getByText(/대용량 2,100명 전환 예정/).count() === 1, 'Story2100: scale disclosed before data commit');
|
||||
await page.getByRole('button', { name: '데이터 적용', exact: true }).click(); await ready();
|
||||
check(await page.getByText(/실제 직원 합계 2,100명/).count() === 1 && (await measure()).nodes.every(n => n.depth < 2), 'Story2100: source count retained with independent initial-depth reduction');
|
||||
await screenshot('story-2100-depth2');
|
||||
await page.getByRole('button', { name: '초기화', exact: true }).click();
|
||||
await select('초기 표시 Depth', '전체 펼침'); await select('조직도 표시 유형', '세로형 TB'); await ready(20);
|
||||
check(await page.getByRole('alert').count() === 0, 'Story has no lifecycle error alert');
|
||||
}
|
||||
if (run('react')) {
|
||||
@@ -418,33 +360,14 @@ try {
|
||||
return { visible: r.left >= b.left && r.right <= b.right && r.top >= b.top && r.bottom <= b.bottom, scale: v.dataset.scale, scroll: [v.scrollLeft, v.scrollTop] };
|
||||
});
|
||||
check(focus.visible && focus.scale === '1' && focus.scroll.every(n => n === 0), 'Pan disabled: keyboard reveals offscreen card at unchanged Zoom with no hidden scroll', focus);
|
||||
// Actual new React/Story settings and changed content layout, without replaying all data scenarios.
|
||||
await page.goto((process.env.ORGCHART_STORY_ORIGIN ?? 'http://127.0.0.1:6056') + '/iframe.html?id=orgchart--expanded-org-chart&viewMode=story'); await ready(20);
|
||||
for (const [label, type] of [['세로형 TB', 'tb'], ['가로형 LR', 'lr'], ['혼합형 Hybrid', 'hybrid']]) {
|
||||
await select('조직도 표시 유형', label); await ready(20);
|
||||
await page.getByRole('checkbox', { name: '접기·펼치기 사용', exact: true }).uncheck();
|
||||
await page.getByRole('checkbox', { name: 'Zoom 사용', exact: true }).uncheck();
|
||||
await page.getByRole('checkbox', { name: 'Pan 사용', exact: true }).uncheck(); await ready(20);
|
||||
check(await page.locator('.hm-orgchart-expanded-toggle').first().isDisabled() && await page.getByRole('button', { name: '확대', exact: true }).isDisabled() && await page.locator('.hm-orgchart-viewport').getAttribute('data-pan-enabled') === 'false', `Story ${type}: all independent checkboxes control actual Core`);
|
||||
await hmPopup('Final ' + type);
|
||||
await page.getByRole('checkbox', { name: '접기·펼치기 사용', exact: true }).check();
|
||||
await page.getByRole('checkbox', { name: 'Zoom 사용', exact: true }).check();
|
||||
await page.getByRole('checkbox', { name: 'Pan 사용', exact: true }).check(); await ready(20);
|
||||
}
|
||||
await select('직원 정보 팝업', '사용 안 함'); await ready(20);
|
||||
check(await page.locator('.hm-orgchart-employee[role="button"]').count() === 0 && await page.locator('.hm-orgchart-employee[tabindex="0"]').count() === 0, 'Story popup none: no false actionable card semantics');
|
||||
await select('직원 정보 팝업', 'HMDesign Dialog'); await ready(20);
|
||||
// Expanded is preview-only (2026-10-22): its collapse/Zoom/Pan checkboxes and popup selector were removed.
|
||||
await page.goto((process.env.ORGCHART_STORY_ORIGIN ?? 'http://127.0.0.1:6056') + '/iframe.html?id=orgchart--expanded-org-chart&viewMode=story'); await ready(140);
|
||||
await hmPopup('Final tb');
|
||||
}
|
||||
if (run('options') || run('options-tail')) {
|
||||
if (run('options-tail')) {
|
||||
await page.goto((process.env.ORGCHART_STORY_ORIGIN ?? 'http://127.0.0.1:6056') + '/iframe.html?id=orgchart--expanded-org-chart&viewMode=story'); await ready(20);
|
||||
await page.goto((process.env.ORGCHART_STORY_ORIGIN ?? 'http://127.0.0.1:6056') + '/iframe.html?id=orgchart--expanded-org-chart&viewMode=story'); await ready(140);
|
||||
}
|
||||
await select('조직도 표시 유형', '세로형 TB');
|
||||
await select('특정 그룹 세로 배치', '한맥기술 · 가상 조직'); await ready(20);
|
||||
check(await page.locator('[data-group-hybrid="true"]').count() === 1, 'Story per-group Hybrid: real applied local branch');
|
||||
await select('조직도 표시 유형', '가로형 LR'); await ready(20);
|
||||
check(await page.getByRole('combobox', { name: '특정 그룹 세로 배치', exact: true }).isDisabled(), 'Story per-group Hybrid: incompatible LR selection disabled and cleared');
|
||||
await select('조직도 표시 유형', '세로형 TB');
|
||||
for (const width of [390, 768, 1280, 1440]) {
|
||||
await page.setViewportSize({ width, height: width === 390 ? 844 : 1100 }); await settle();
|
||||
await page.getByRole('button', { name: 'Fit to View', exact: true }).click(); await settle(); const m = await measure();
|
||||
@@ -523,7 +446,7 @@ try {
|
||||
}
|
||||
if (run('dialog-narrow')) {
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await page.goto((process.env.ORGCHART_STORY_ORIGIN ?? 'http://127.0.0.1:6056') + '/iframe.html?id=orgchart--expanded-org-chart&viewMode=story'); await ready(20);
|
||||
await page.goto((process.env.ORGCHART_STORY_ORIGIN ?? 'http://127.0.0.1:6056') + '/iframe.html?id=orgchart--expanded-org-chart&viewMode=story'); await ready(140);
|
||||
await page.locator('.hm-orgchart-employee').first().press('Enter'); const d = page.locator('[data-component="HMOrgChartEmployeeDialog"]'); await d.waitFor(); await settle();
|
||||
const bounds = await d.evaluate(d => {
|
||||
const r = d.getBoundingClientRect();
|
||||
|
||||
Reference in new issue
Block a user