merge: 모바일 패널 CSS 감사와 기본값 문구 반영
This commit is contained in:
@@ -1271,7 +1271,7 @@ test('내 정보&설정의 지난 플레이는 기본 탐색과 분리되어 오
|
||||
}
|
||||
});
|
||||
|
||||
test('내 정보&설정에서 모바일 메인 패널을 드래그하거나 버튼으로 재정렬하고 Ref 순서로 복원한다', async ({ page }) => {
|
||||
test('내 정보&설정에서 모바일 메인 패널을 드래그하거나 버튼으로 재정렬하고 기본 순서로 복원한다', async ({ page }) => {
|
||||
const state: FixtureState = { permission: 'head', myset: 3, settingMutations: [], accessPages: [] };
|
||||
await install(page, state);
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
@@ -1334,7 +1334,7 @@ test('내 정보&설정에서 모바일 메인 패널을 드래그하거나 버
|
||||
.toEqual(['messages', 'commands', 'nation-menu', 'nation', 'general', 'map', 'city', 'records', 'global-menu']);
|
||||
|
||||
await page.getByRole('button', { name: '순서 바꾸기', exact: true }).click();
|
||||
await dialog.getByRole('button', { name: 'Ref 초깃값' }).click();
|
||||
await dialog.getByRole('button', { name: '기본값', exact: true }).click();
|
||||
await expect.poll(readOrder).toEqual(defaultOrder);
|
||||
await dialog.getByRole('button', { name: '적용', exact: true }).click();
|
||||
await expect
|
||||
|
||||
@@ -792,6 +792,103 @@ const gridColumnCount = async (page: Page, selector: string) =>
|
||||
.first()
|
||||
.evaluate((element) => getComputedStyle(element).gridTemplateColumns.split(' ').length);
|
||||
|
||||
const setMobilePanelOrder = async (page: Page, order: readonly string[]) => {
|
||||
await page.evaluate((nextOrder) => {
|
||||
localStorage.setItem('sam.mobileMainPanelOrder.v1', JSON.stringify(nextOrder));
|
||||
document.dispatchEvent(new CustomEvent('sam-mobile-main-panel-order-changed'));
|
||||
}, order);
|
||||
};
|
||||
|
||||
const inspectMobilePanelLayout = async (page: Page) =>
|
||||
page.locator('.layout-mobile').evaluate((container) => {
|
||||
const containerStyle = getComputedStyle(container);
|
||||
const panels = [...container.querySelectorAll<HTMLElement>(':scope > [data-mobile-panel-id]')].map(
|
||||
(element, domIndex) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const style = getComputedStyle(element);
|
||||
const content = element.firstElementChild as HTMLElement | null;
|
||||
const contentStyle = content ? getComputedStyle(content) : null;
|
||||
return {
|
||||
id: element.dataset.mobilePanelId ?? '',
|
||||
domIndex,
|
||||
top: rect.top,
|
||||
bottom: rect.bottom,
|
||||
left: rect.left,
|
||||
right: rect.right,
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
display: style.display,
|
||||
position: style.position,
|
||||
inset: [style.top, style.right, style.bottom, style.left],
|
||||
order: style.order,
|
||||
transform: style.transform,
|
||||
float: style.cssFloat,
|
||||
gridRow: `${style.gridRowStart} / ${style.gridRowEnd}`,
|
||||
gridColumn: `${style.gridColumnStart} / ${style.gridColumnEnd}`,
|
||||
marginTop: style.marginTop,
|
||||
marginBottom: style.marginBottom,
|
||||
content: contentStyle
|
||||
? {
|
||||
position: contentStyle.position,
|
||||
order: contentStyle.order,
|
||||
transform: contentStyle.transform,
|
||||
marginTop: contentStyle.marginTop,
|
||||
marginBottom: contentStyle.marginBottom,
|
||||
height: contentStyle.height,
|
||||
}
|
||||
: null,
|
||||
};
|
||||
}
|
||||
);
|
||||
return {
|
||||
container: {
|
||||
display: containerStyle.display,
|
||||
flexDirection: containerStyle.flexDirection,
|
||||
position: containerStyle.position,
|
||||
transform: containerStyle.transform,
|
||||
},
|
||||
panels,
|
||||
visualOrder: [...panels]
|
||||
.sort((left, right) => left.top - right.top || left.left - right.left)
|
||||
.map(({ id }) => id),
|
||||
};
|
||||
});
|
||||
|
||||
const expectMobilePanelVisualOrder = async (page: Page, expectedOrder: readonly string[]) => {
|
||||
await expect
|
||||
.poll(() =>
|
||||
page
|
||||
.locator('.layout-mobile > [data-mobile-panel-id]')
|
||||
.evaluateAll((elements) => elements.map((element) => element.getAttribute('data-mobile-panel-id')))
|
||||
)
|
||||
.toEqual(expectedOrder);
|
||||
const audit = await inspectMobilePanelLayout(page);
|
||||
expect(audit.container).toEqual({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'static',
|
||||
transform: 'none',
|
||||
});
|
||||
expect(audit.panels.map(({ id }) => id)).toEqual(expectedOrder);
|
||||
expect(audit.visualOrder).toEqual(expectedOrder);
|
||||
expect(audit.panels.every(({ left, right, width }) => left >= 0 && right <= 500 && width === 500)).toBe(true);
|
||||
expect(
|
||||
audit.panels.every((panel, index) => index === 0 || panel.top >= audit.panels[index - 1]!.bottom)
|
||||
).toBe(true);
|
||||
for (const panel of audit.panels) {
|
||||
expect(panel.display, `${panel.id}: display`).not.toBe('none');
|
||||
expect(['static', 'relative'], `${panel.id}: position`).toContain(panel.position);
|
||||
expect(
|
||||
panel.inset.every((value) => value === 'auto' || value === '0px'),
|
||||
`${panel.id}: inset ${panel.inset.join(' ')}`
|
||||
).toBe(true);
|
||||
expect(panel.order, `${panel.id}: order`).toBe('0');
|
||||
expect(panel.transform, `${panel.id}: transform`).toBe('none');
|
||||
expect(panel.float, `${panel.id}: float`).toBe('none');
|
||||
}
|
||||
return audit;
|
||||
};
|
||||
|
||||
const raisedButtonState = async (target: Locator) =>
|
||||
target.evaluate((element) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
@@ -2213,49 +2310,45 @@ test('the 939/940 boundary switches to the Ref-style 500px single document', asy
|
||||
]) {
|
||||
await expect(page.locator(selector)).toBeVisible();
|
||||
}
|
||||
const readMobilePanelOrder = () =>
|
||||
page
|
||||
.locator('.layout-mobile > [data-mobile-panel-id]')
|
||||
.evaluateAll((elements) => elements.map((element) => element.getAttribute('data-mobile-panel-id')));
|
||||
await expect
|
||||
.poll(readMobilePanelOrder)
|
||||
.toEqual(['commands', 'nation-menu', 'nation', 'general', 'city', 'map', 'records', 'global-menu', 'messages']);
|
||||
await page.evaluate(() => {
|
||||
localStorage.setItem(
|
||||
'sam.mobileMainPanelOrder.v1',
|
||||
JSON.stringify([
|
||||
'messages',
|
||||
'map',
|
||||
'commands',
|
||||
'nation-menu',
|
||||
'nation',
|
||||
'general',
|
||||
'city',
|
||||
'records',
|
||||
'global-menu',
|
||||
])
|
||||
const defaultOrder = [
|
||||
'commands',
|
||||
'nation-menu',
|
||||
'nation',
|
||||
'general',
|
||||
'city',
|
||||
'map',
|
||||
'records',
|
||||
'global-menu',
|
||||
'messages',
|
||||
];
|
||||
const customOrder = [
|
||||
'messages',
|
||||
'map',
|
||||
'commands',
|
||||
'nation-menu',
|
||||
'nation',
|
||||
'general',
|
||||
'city',
|
||||
'records',
|
||||
'global-menu',
|
||||
];
|
||||
const reverseOrder = [...defaultOrder].reverse();
|
||||
const mobilePanelAudits = {
|
||||
default: await expectMobilePanelVisualOrder(page, defaultOrder),
|
||||
custom: null as Awaited<ReturnType<typeof inspectMobilePanelLayout>> | null,
|
||||
reverse: null as Awaited<ReturnType<typeof inspectMobilePanelLayout>> | null,
|
||||
};
|
||||
await setMobilePanelOrder(page, customOrder);
|
||||
mobilePanelAudits.custom = await expectMobilePanelVisualOrder(page, customOrder);
|
||||
await setMobilePanelOrder(page, reverseOrder);
|
||||
mobilePanelAudits.reverse = await expectMobilePanelVisualOrder(page, reverseOrder);
|
||||
if (artifactRoot) {
|
||||
await mkdir(artifactRoot, { recursive: true });
|
||||
await writeFile(
|
||||
resolve(artifactRoot, `${basePath.slice(1)}-mobile-panel-css-order-audit.json`),
|
||||
`${JSON.stringify(mobilePanelAudits, null, 2)}\n`
|
||||
);
|
||||
document.dispatchEvent(new CustomEvent('sam-mobile-main-panel-order-changed'));
|
||||
});
|
||||
await expect
|
||||
.poll(readMobilePanelOrder)
|
||||
.toEqual(['messages', 'map', 'commands', 'nation-menu', 'nation', 'general', 'city', 'records', 'global-menu']);
|
||||
const customPanelGeometry = await page.locator('.layout-mobile > [data-mobile-panel-id]').evaluateAll((elements) =>
|
||||
elements.map((element) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
return {
|
||||
id: element.getAttribute('data-mobile-panel-id'),
|
||||
top: rect.top,
|
||||
bottom: rect.bottom,
|
||||
left: rect.left,
|
||||
right: rect.right,
|
||||
};
|
||||
})
|
||||
);
|
||||
expect(customPanelGeometry.every(({ left, right }) => left >= 0 && right <= 500)).toBe(true);
|
||||
expect(
|
||||
customPanelGeometry.every((panel, index) => index === 0 || panel.top >= customPanelGeometry[index - 1]!.bottom)
|
||||
).toBe(true);
|
||||
}
|
||||
await persistArtifact(page, `${basePath.slice(1)}-mobile-500`);
|
||||
});
|
||||
|
||||
@@ -2556,6 +2649,27 @@ test('real mobile devices initially fit the complete 500px game canvas', async (
|
||||
expect(mainGeometry.documentScrollWidth).toBeLessThanOrEqual(mainGeometry.innerWidth);
|
||||
expect(mainGeometry.canvas).toEqual({ left: 0, right: 500, width: 500 });
|
||||
expect(mainGeometry.canvas.right).toBeLessThanOrEqual((mainGeometry.visualViewportWidth ?? 0) + 0.01);
|
||||
let physicalPanelOrderAudit: unknown = null;
|
||||
if (deviceWidth === 390) {
|
||||
const defaultOrder = [
|
||||
'commands',
|
||||
'nation-menu',
|
||||
'nation',
|
||||
'general',
|
||||
'city',
|
||||
'map',
|
||||
'records',
|
||||
'global-menu',
|
||||
'messages',
|
||||
];
|
||||
const reverseOrder = [...defaultOrder].reverse();
|
||||
const defaultAudit = await expectMobilePanelVisualOrder(mobilePage, defaultOrder);
|
||||
await setMobilePanelOrder(mobilePage, reverseOrder);
|
||||
const reverseAudit = await expectMobilePanelVisualOrder(mobilePage, reverseOrder);
|
||||
physicalPanelOrderAudit = { default: defaultAudit, reverse: reverseAudit };
|
||||
await setMobilePanelOrder(mobilePage, defaultOrder);
|
||||
await expectMobilePanelVisualOrder(mobilePage, defaultOrder);
|
||||
}
|
||||
if (artifactRoot) {
|
||||
await mkdir(artifactRoot, { recursive: true });
|
||||
await mobilePage.screenshot({
|
||||
@@ -2599,7 +2713,11 @@ test('real mobile devices initially fit the complete 500px game canvas', async (
|
||||
}
|
||||
}
|
||||
|
||||
measurements[String(deviceWidth)] = { main: mainGeometry, routes: routeGeometry };
|
||||
measurements[String(deviceWidth)] = {
|
||||
main: mainGeometry,
|
||||
mobilePanelOrder: physicalPanelOrderAudit,
|
||||
routes: routeGeometry,
|
||||
};
|
||||
await context.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -743,7 +743,7 @@ onMounted(() => {
|
||||
</li>
|
||||
</ol>
|
||||
<div class="mobile-layout-dialog__actions">
|
||||
<button type="button" @click="resetMobileLayoutOrder">Ref 초깃값</button>
|
||||
<button type="button" @click="resetMobileLayoutOrder">기본값</button>
|
||||
<form method="dialog"><button type="submit">취소</button></form>
|
||||
<button class="mobile-layout-apply" type="button" @click="applyMobileLayoutOrder">적용</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user