fix(gateway): 모바일 계정 버튼 행을 정리
일반 사용자는 두 버튼을 한 행에 유지하고 관리자 링크는 모바일에서 전체폭 둘째 행으로 분리한다. 500px과 더 좁은 viewport의 Chromium 좌표 및 상호작용 회귀를 추가한다.
This commit is contained in:
@@ -240,6 +240,112 @@ test('desktop administrator sidebar follows the navbar away and then sticks to t
|
||||
await writeFile(testInfo.outputPath('admin-sidebar-scroll-geometry.json'), JSON.stringify(measurements, null, 2));
|
||||
});
|
||||
|
||||
test('keeps mobile account actions on clean rows for users and administrators', async ({ browser }, testInfo) => {
|
||||
const measureAccountActions = async (page: Page) => {
|
||||
const actions = page.locator('.account-actions');
|
||||
await expect(actions).toBeVisible();
|
||||
return actions.evaluate((element) => {
|
||||
const rect = (target: Element) => {
|
||||
const value = target.getBoundingClientRect();
|
||||
return {
|
||||
top: value.top,
|
||||
right: value.right,
|
||||
bottom: value.bottom,
|
||||
left: value.left,
|
||||
width: value.width,
|
||||
height: value.height,
|
||||
};
|
||||
};
|
||||
const items = Array.from(element.children).map((child) => ({
|
||||
...rect(child),
|
||||
clientWidth: (child as HTMLElement).clientWidth,
|
||||
scrollWidth: (child as HTMLElement).scrollWidth,
|
||||
whiteSpace: getComputedStyle(child).whiteSpace,
|
||||
}));
|
||||
return {
|
||||
container: rect(element),
|
||||
documentWidth: document.documentElement.scrollWidth,
|
||||
viewportWidth: window.innerWidth,
|
||||
items,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const userContext = await browser.newContext({ viewport: { width: 500, height: 900 } });
|
||||
const userPage = await userContext.newPage();
|
||||
await installGatewayFixture(userPage, []);
|
||||
await userPage.goto('lobby');
|
||||
const userGeometry = await measureAccountActions(userPage);
|
||||
expect(userGeometry.documentWidth).toBe(userGeometry.viewportWidth);
|
||||
expect(userGeometry.items).toHaveLength(2);
|
||||
expect(userGeometry.items[0]?.top).toBeCloseTo(userGeometry.items[1]?.top ?? 0, 0);
|
||||
expect(userGeometry.items[0]?.bottom).toBeCloseTo(userGeometry.items[1]?.bottom ?? 0, 0);
|
||||
expect(userGeometry.items[0]?.width).toBeCloseTo(userGeometry.items[1]?.width ?? 0, 0);
|
||||
expect(userGeometry.items.every(({ scrollWidth, clientWidth }) => scrollWidth <= clientWidth)).toBe(true);
|
||||
await userPage.screenshot({ path: testInfo.outputPath('gateway-account-actions-user-500px.png'), fullPage: true });
|
||||
await userContext.close();
|
||||
|
||||
const adminContext = await browser.newContext({ viewport: { width: 500, height: 900 } });
|
||||
const adminPage = await adminContext.newPage();
|
||||
await installGatewayFixture(adminPage, ['superuser']);
|
||||
await adminPage.goto('lobby');
|
||||
const adminGeometry = await measureAccountActions(adminPage);
|
||||
expect(adminGeometry.documentWidth).toBe(adminGeometry.viewportWidth);
|
||||
expect(adminGeometry.items).toHaveLength(3);
|
||||
const [account, logout, admin] = adminGeometry.items;
|
||||
expect(account?.top).toBeCloseTo(logout?.top ?? 0, 0);
|
||||
expect(account?.bottom).toBeCloseTo(logout?.bottom ?? 0, 0);
|
||||
expect(account?.width).toBeCloseTo(logout?.width ?? 0, 0);
|
||||
expect(admin?.top).toBeCloseTo((logout?.bottom ?? 0) + 16, 0);
|
||||
expect(admin?.left).toBeCloseTo(account?.left ?? 0, 0);
|
||||
expect(admin?.right).toBeCloseTo(logout?.right ?? 0, 0);
|
||||
expect(adminGeometry.items.every(({ scrollWidth, clientWidth }) => scrollWidth <= clientWidth)).toBe(true);
|
||||
expect(account?.whiteSpace).toBe('nowrap');
|
||||
expect(admin?.whiteSpace).toBe('nowrap');
|
||||
|
||||
const adminLink = adminPage.getByRole('link', { name: '관리자 페이지' });
|
||||
const baseBackground = await adminLink.evaluate((element) => getComputedStyle(element).backgroundColor);
|
||||
await adminLink.hover();
|
||||
await expect.poll(() => adminLink.evaluate((element) => getComputedStyle(element).backgroundColor)).not.toBe(
|
||||
baseBackground
|
||||
);
|
||||
await adminLink.focus();
|
||||
await expect(adminLink).toBeFocused();
|
||||
await adminPage.screenshot({ path: testInfo.outputPath('gateway-account-actions-admin-500px.png'), fullPage: true });
|
||||
|
||||
await adminPage.setViewportSize({ width: 390, height: 844 });
|
||||
const adminNarrowGeometry = await measureAccountActions(adminPage);
|
||||
expect(adminNarrowGeometry.documentWidth).toBe(adminNarrowGeometry.viewportWidth);
|
||||
expect(adminNarrowGeometry.items[0]?.top).toBeCloseTo(adminNarrowGeometry.items[1]?.top ?? 0, 0);
|
||||
expect(adminNarrowGeometry.items[2]?.top).toBeCloseTo(
|
||||
(adminNarrowGeometry.items[1]?.bottom ?? 0) + 16,
|
||||
0
|
||||
);
|
||||
expect(adminNarrowGeometry.items.every(({ scrollWidth, clientWidth }) => scrollWidth <= clientWidth)).toBe(true);
|
||||
await adminPage.screenshot({ path: testInfo.outputPath('gateway-account-actions-admin-390px.png'), fullPage: true });
|
||||
|
||||
await adminPage.setViewportSize({ width: 360, height: 800 });
|
||||
const adminSmallGeometry = await measureAccountActions(adminPage);
|
||||
expect(adminSmallGeometry.documentWidth).toBe(adminSmallGeometry.viewportWidth);
|
||||
expect(adminSmallGeometry.items[1]?.top).toBeCloseTo((adminSmallGeometry.items[0]?.bottom ?? 0) + 16, 0);
|
||||
expect(adminSmallGeometry.items[2]?.top).toBeCloseTo((adminSmallGeometry.items[1]?.bottom ?? 0) + 16, 0);
|
||||
expect(adminSmallGeometry.items.every(({ scrollWidth, clientWidth }) => scrollWidth <= clientWidth)).toBe(true);
|
||||
await writeFile(
|
||||
testInfo.outputPath('gateway-account-actions-geometry.json'),
|
||||
JSON.stringify(
|
||||
{
|
||||
user: userGeometry,
|
||||
admin: adminGeometry,
|
||||
adminNarrow: adminNarrowGeometry,
|
||||
adminSmall: adminSmallGeometry,
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
await adminContext.close();
|
||||
});
|
||||
|
||||
test('legacy server operations URL keeps query parameters and redirects to the server list', async ({ page }) => {
|
||||
await installGatewayFixture(page, ['superuser']);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user