merge: 최신 main을 profile 버전 안내에 통합한다
This commit is contained in:
@@ -22,6 +22,13 @@ const persistParityArtifact = async (page: Page, name: string, geometry: unknown
|
||||
]);
|
||||
};
|
||||
|
||||
const waitForVisualAssets = async (page: Page): Promise<void> => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.evaluate(async () => {
|
||||
await document.fonts.ready;
|
||||
});
|
||||
};
|
||||
|
||||
const readGeneralPanelImages = async (panel: Locator) =>
|
||||
panel.evaluate((element) =>
|
||||
[...element.querySelectorAll<HTMLElement>('.general-image')].map((image) => {
|
||||
@@ -77,6 +84,7 @@ type FixtureState = {
|
||||
joinConfig?: Record<string, unknown>;
|
||||
createGeneralInputs?: Array<Record<string, unknown>>;
|
||||
mainTraits?: { personal: string; specialDomestic: string; specialWar: string };
|
||||
mainTraitAges?: { specialDomestic: number; specialWar: number };
|
||||
richMyInfo?: boolean;
|
||||
hiddenSeedLogText?: string;
|
||||
recentRecords?: {
|
||||
@@ -130,6 +138,7 @@ const myGeneral = (state: FixtureState) => ({
|
||||
}
|
||||
: null,
|
||||
traits: state.mainTraits ?? { personal: '-', specialDomestic: '-', specialWar: '-' },
|
||||
traitAges: state.mainTraitAges ?? { specialDomestic: 31, specialWar: 31 },
|
||||
traitInfo: state.richMyInfo
|
||||
? {
|
||||
personal: '부상당할 확률이 감소합니다.',
|
||||
@@ -725,6 +734,47 @@ test('재야 메인은 국가 틀과 성격·특기 표기명을 Chromium에 표
|
||||
await persistParityArtifact(page, 'main-neutral-trait-display', geometry);
|
||||
});
|
||||
|
||||
test('메인 장수 정보는 없는 내정·전투 특기의 Ref 획득 나이를 Chromium에 표시한다', async ({ page }) => {
|
||||
const state: FixtureState = {
|
||||
permission: 'member',
|
||||
myset: 0,
|
||||
mainTraits: { personal: '안전', specialDomestic: '-', specialWar: '-' },
|
||||
mainTraitAges: { specialDomestic: 35, specialWar: 29 },
|
||||
settingMutations: [],
|
||||
accessPages: [],
|
||||
};
|
||||
await install(page, state);
|
||||
|
||||
for (const viewport of [
|
||||
{ width: 1000, height: 900 },
|
||||
{ width: 390, height: 844 },
|
||||
]) {
|
||||
await page.setViewportSize(viewport);
|
||||
await page.goto('');
|
||||
|
||||
const specialValue = page.locator('.general-card .special-value');
|
||||
await expect(specialValue).toHaveText(/35세\s*\/\s*31세/u);
|
||||
await expect(specialValue).toHaveAttribute('aria-label', '35세 / 31세');
|
||||
const geometry = await specialValue.evaluate((element) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const documentWidth = document.documentElement.scrollWidth;
|
||||
return {
|
||||
text: element.textContent?.replace(/\s+/gu, ' ').trim(),
|
||||
left: rect.left,
|
||||
right: rect.right,
|
||||
width: rect.width,
|
||||
documentWidth,
|
||||
viewportWidth: window.innerWidth,
|
||||
};
|
||||
});
|
||||
expect(geometry.width).toBeGreaterThan(0);
|
||||
expect(geometry.left).toBeGreaterThanOrEqual(0);
|
||||
expect(geometry.right).toBeLessThanOrEqual(geometry.documentWidth);
|
||||
expect(geometry.documentWidth).toBe(Math.max(viewport.width, 500));
|
||||
await persistParityArtifact(page, `main-speciality-age-${viewport.width}`, geometry);
|
||||
}
|
||||
});
|
||||
|
||||
test('메인 카드의 국가·수도·관직·계급·병종은 Ref 출력명으로 표시된다', async ({ page }) => {
|
||||
const state: FixtureState = {
|
||||
permission: 'head',
|
||||
@@ -1270,6 +1320,9 @@ test('내 정보&설정 keeps desktop density and becomes a 390px horizontal-ide
|
||||
await expect(page.locator('#container')).not.toContainText('che_');
|
||||
await expect(page.locator('.title-row')).toContainText('내 정 보');
|
||||
await expect(page.locator('#set_my_setting')).toBeVisible();
|
||||
await expect(page.getByRole('radiogroup', { name: '화면 폭 모드' })).toHaveCount(0);
|
||||
await expect(page.getByRole('button', { name: '순서 바꾸기', exact: true })).toHaveCount(0);
|
||||
await expect(page.locator('#custom_css')).toHaveCount(0);
|
||||
await expect(page.locator('.general-column [role="progressbar"]')).toHaveCount(14);
|
||||
await expect(page.locator('.general-column [aria-label*="1,275,975 (EX+)"]')).toHaveCount(5);
|
||||
await expect.poll(() => state.generalMeQueries).toBeGreaterThan(0);
|
||||
@@ -1290,7 +1343,6 @@ test('내 정보&설정 keeps desktop density and becomes a 390px horizontal-ide
|
||||
const settings = element.querySelector<HTMLElement>('.settings-column')!.getBoundingClientRect();
|
||||
const saveButton = element.querySelector<HTMLElement>('#set_my_setting')!;
|
||||
const save = saveButton.getBoundingClientRect();
|
||||
const customCss = element.querySelector<HTMLElement>('#custom_css')!.getBoundingClientRect();
|
||||
const columns = getComputedStyle(element.querySelector('.top-grid')!).gridTemplateColumns;
|
||||
return {
|
||||
width: rect.width,
|
||||
@@ -1302,8 +1354,6 @@ test('내 정보&설정 keeps desktop density and becomes a 390px horizontal-ide
|
||||
saveWidth: save.width,
|
||||
saveHeight: save.height,
|
||||
saveBackground: getComputedStyle(saveButton).backgroundColor,
|
||||
customCssWidth: customCss.width,
|
||||
customCssHeight: customCss.height,
|
||||
backgroundImage: getComputedStyle(element).backgroundImage,
|
||||
sectionBackgroundImage: getComputedStyle(element.querySelector('.section-title')!).backgroundImage,
|
||||
};
|
||||
@@ -1317,8 +1367,6 @@ test('내 정보&설정 keeps desktop density and becomes a 390px horizontal-ide
|
||||
expect(desktop.saveWidth).toBe(160);
|
||||
expect(desktop.saveHeight).toBe(30);
|
||||
expect(desktop.saveBackground).toBe('rgb(34, 85, 0)');
|
||||
expect(desktop.customCssWidth).toBe(420);
|
||||
expect(desktop.customCssHeight).toBe(150);
|
||||
expect(desktop.backgroundImage).toContain('back_walnut.jpg');
|
||||
expect(desktop.sectionBackgroundImage).toContain('back_green.jpg');
|
||||
await expectLumenButtonStates(page, page.locator('#set_my_setting'), 'rgb(34, 85, 0)');
|
||||
@@ -1583,11 +1631,68 @@ test('내 정보&설정의 지난 플레이는 기본 탐색과 분리되어 오
|
||||
}
|
||||
});
|
||||
|
||||
test('내 정보&설정에서 모바일 메인 패널을 드래그하거나 버튼으로 재정렬하고 기본 순서로 복원한다', async ({ page }) => {
|
||||
test('화면 설정에서 화면 폭과 개인 CSS를 저장하고 게임 설정 API는 호출하지 않는다', async ({ page }, testInfo) => {
|
||||
const state: FixtureState = { permission: 'head', myset: 3, settingMutations: [], accessPages: [] };
|
||||
await install(page, state);
|
||||
await page.setViewportSize({ width: 1000, height: 900 });
|
||||
await page.goto('my-settings');
|
||||
await waitForVisualAssets(page);
|
||||
|
||||
await expect(page.locator('.title-row')).toContainText('화 면 설 정');
|
||||
await expect(
|
||||
page.getByText('이 설정은 이 기기의 화면 표시만 바꾸며 게임 상태에는 영향을 주지 않습니다.')
|
||||
).toHaveCount(0);
|
||||
await expect(page.locator('#set_my_setting')).toHaveCount(0);
|
||||
await expect(page.locator('#custom_css')).toBeVisible();
|
||||
expect(state.settingMutations).toHaveLength(0);
|
||||
|
||||
const desktop = await page.locator('#interface-settings').evaluate((element) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const css = element.querySelector<HTMLTextAreaElement>('#custom_css')!.getBoundingClientRect();
|
||||
return {
|
||||
width: rect.width,
|
||||
columns: getComputedStyle(element.querySelector('.settings-grid')!).gridTemplateColumns,
|
||||
cssWidth: css.width,
|
||||
cssHeight: css.height,
|
||||
backgroundImage: getComputedStyle(element).backgroundImage,
|
||||
sectionBackgroundImage: getComputedStyle(element.querySelector('.section-title')!).backgroundImage,
|
||||
};
|
||||
});
|
||||
expect(desktop.width).toBe(1000);
|
||||
expect(desktop.columns.split(' ')).toHaveLength(2);
|
||||
expect(desktop.cssWidth).toBe(420);
|
||||
expect(desktop.cssHeight).toBe(150);
|
||||
expect(desktop.backgroundImage).toContain('back_walnut.jpg');
|
||||
expect(desktop.sectionBackgroundImage).toContain('back_green.jpg');
|
||||
await page.screenshot({ path: testInfo.outputPath('interface-settings-desktop.png'), fullPage: true });
|
||||
|
||||
await page.getByRole('radio', { name: '500px' }).check();
|
||||
await expect.poll(() => page.evaluate(() => localStorage.getItem('sam.screenMode'))).toBe('500px');
|
||||
await expect(page.locator('meta[name="viewport"]')).toHaveAttribute('content', 'width=500');
|
||||
|
||||
const cssText = '#interface-settings { --ui-settings-e2e: 23px; }';
|
||||
await page.getByLabel('개인용 CSS').fill(cssText);
|
||||
await expect(page.locator('.custom-css span')).toHaveText('(저장 중)');
|
||||
await expect.poll(() => page.evaluate(() => localStorage.getItem('sam_customCSS'))).toBe(cssText);
|
||||
await expect.poll(() => page.locator('#sammo-custom-css').textContent()).toBe(cssText);
|
||||
await page.reload();
|
||||
await expect.poll(() => page.locator('#sammo-custom-css').textContent()).toBe(cssText);
|
||||
expect(state.settingMutations).toHaveLength(0);
|
||||
|
||||
await page.getByLabel('개인용 CSS').fill('');
|
||||
await expect.poll(() => page.evaluate(() => localStorage.getItem('sam_customCSS'))).toBe('');
|
||||
await page.getByRole('radio', { name: '자동' }).check();
|
||||
await persistParityArtifact(page, 'core-interface-settings-desktop', desktop);
|
||||
});
|
||||
|
||||
test('화면 설정에서 모바일 메인 패널을 드래그하거나 버튼으로 재정렬하고 기본 순서로 복원한다', async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
const state: FixtureState = { permission: 'head', myset: 3, settingMutations: [], accessPages: [] };
|
||||
await install(page, state);
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await page.goto('my-page');
|
||||
await page.goto('my-settings');
|
||||
await waitForVisualAssets(page);
|
||||
|
||||
await page.getByRole('button', { name: '순서 바꾸기', exact: true }).click();
|
||||
const dialog = page.getByRole('dialog', { name: '모바일 레이아웃 순서 바꾸기' });
|
||||
@@ -1637,7 +1742,8 @@ test('내 정보&설정에서 모바일 메인 패널을 드래그하거나 버
|
||||
expect(dialogGeometry.firstItem?.height).toBeGreaterThanOrEqual(44);
|
||||
expect(dialogGeometry.moveButton?.width).toBeGreaterThanOrEqual(36);
|
||||
expect(dialogGeometry.documentWidth).toBe(390);
|
||||
await persistParityArtifact(page, 'core-my-page-mobile-layout-order-dialog', dialogGeometry);
|
||||
await dialog.screenshot({ path: testInfo.outputPath('interface-settings-mobile-layout-dialog.png') });
|
||||
await persistParityArtifact(page, 'core-interface-settings-mobile-layout-order-dialog', dialogGeometry);
|
||||
|
||||
await dialog.getByRole('button', { name: '적용', exact: true }).click();
|
||||
await expect(dialog).toBeHidden();
|
||||
@@ -1654,7 +1760,7 @@ test('내 정보&설정에서 모바일 메인 패널을 드래그하거나 버
|
||||
.toEqual(defaultOrder);
|
||||
});
|
||||
|
||||
test('실제 모바일 터치로 메인 패널 순서를 재정렬한다', async ({ browser }, testInfo) => {
|
||||
test('화면 설정에서 실제 모바일 터치로 메인 패널 순서를 재정렬한다', async ({ browser }, testInfo) => {
|
||||
const configuredBaseUrl = testInfo.project.use.baseURL;
|
||||
if (typeof configuredBaseUrl !== 'string') {
|
||||
throw new Error('Playwright baseURL is required for the mobile touch contract');
|
||||
@@ -1672,7 +1778,8 @@ test('실제 모바일 터치로 메인 패널 순서를 재정렬한다', async
|
||||
try {
|
||||
const state: FixtureState = { permission: 'head', myset: 3, settingMutations: [], accessPages: [] };
|
||||
await install(mobilePage, state);
|
||||
await mobilePage.goto('my-page');
|
||||
await mobilePage.goto('my-settings');
|
||||
await waitForVisualAssets(mobilePage);
|
||||
await mobilePage.getByRole('button', { name: '순서 바꾸기', exact: true }).click();
|
||||
|
||||
const dialog = mobilePage.getByRole('dialog', { name: '모바일 레이아웃 순서 바꾸기' });
|
||||
|
||||
@@ -29,6 +29,8 @@ type NavigationFixture = {
|
||||
permission: number;
|
||||
nationLevel: number;
|
||||
stage: number;
|
||||
tournamentType?: 0 | 1 | 2 | 3;
|
||||
tournamentWinnerId?: number;
|
||||
npcMode: number;
|
||||
generalMeCalls: number;
|
||||
operations: string[];
|
||||
@@ -758,7 +760,16 @@ const installFixture = async (page: Page, state: NavigationFixture) => {
|
||||
canSecret: state.permission >= 2,
|
||||
});
|
||||
}
|
||||
if (operation === 'tournament.getState') return response({ stage: state.stage });
|
||||
if (operation === 'tournament.getState') {
|
||||
if (state.stage === 0 && state.tournamentType === undefined && state.tournamentWinnerId === undefined) {
|
||||
return response(null);
|
||||
}
|
||||
return response({
|
||||
stage: state.stage,
|
||||
type: state.tournamentType ?? 0,
|
||||
winnerId: state.tournamentWinnerId,
|
||||
});
|
||||
}
|
||||
return response({ ok: true });
|
||||
});
|
||||
operations.forEach((operation, index) => {
|
||||
@@ -1260,7 +1271,27 @@ test('desktop menus preserve ref columns, prefix-safe routes, and controlled dro
|
||||
await expect(global.locator('[data-navigation-id="board-community"]')).toHaveAttribute('href', '/xe/community');
|
||||
await expect(global.locator('[data-navigation-id="official-chat"]')).toHaveAttribute('target', '_blank');
|
||||
await expect(global.locator('[data-navigation-id="survey"]')).toHaveClass(/highlight/);
|
||||
await expect(page.locator('.main-nation-menu [data-navigation-id="tournament"]')).toHaveClass(/highlight/);
|
||||
const nationMenu = page.locator('.main-nation-menu:visible');
|
||||
await expect(nationMenu.locator(':scope > *')).toHaveCount(20);
|
||||
const tournamentMain = nationMenu.locator('[data-navigation-id="tournament"]');
|
||||
const tournamentToggle = nationMenu.locator('[data-menu-id="tournament-betting"]');
|
||||
await expect(tournamentMain).toHaveClass(/highlight/);
|
||||
await expect(tournamentMain).toHaveAttribute('href', `${basePath}/tournament`);
|
||||
await expect(tournamentToggle).toHaveAttribute('aria-expanded', 'false');
|
||||
await expect(nationMenu.locator('[data-navigation-id="my-settings"]')).toHaveAttribute(
|
||||
'href',
|
||||
`${basePath}/my-settings`
|
||||
);
|
||||
await tournamentToggle.click();
|
||||
await expect(tournamentToggle).toHaveAttribute('aria-expanded', 'true');
|
||||
await expect(
|
||||
nationMenu.locator('#nation-menu-tournament-betting [data-navigation-id="tournament-menu"]')
|
||||
).toHaveText('토너먼트');
|
||||
await expect(nationMenu.locator('#nation-menu-tournament-betting [data-navigation-id="betting"]')).toHaveAttribute(
|
||||
'href',
|
||||
`${basePath}/betting`
|
||||
);
|
||||
await page.keyboard.press('Escape');
|
||||
|
||||
const gameInfoButton = global.locator('[data-menu-id="game-info"]');
|
||||
const bettingButton = global.locator('[data-navigation-id="nation-betting"]');
|
||||
@@ -1417,6 +1448,95 @@ test('shows the persisted official game index beside the scenario title without
|
||||
}
|
||||
});
|
||||
|
||||
test('tournament split main action follows recruitment, betting, finals, and tournament type on desktop and mobile', async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
const state: NavigationFixture = {
|
||||
officerLevel: 5,
|
||||
permission: 2,
|
||||
nationLevel: 3,
|
||||
stage: 1,
|
||||
tournamentType: 3,
|
||||
npcMode: 1,
|
||||
scenarioTitle: '토너먼트 동적 메뉴 검증 시나리오',
|
||||
generalMeCalls: 0,
|
||||
operations: [],
|
||||
};
|
||||
await installFixture(page, state);
|
||||
|
||||
const cases = [
|
||||
{ stage: 1, type: 3 as const, label: '설 전', route: '/tournament' },
|
||||
{ stage: 5, type: 2 as const, label: '일 기 토', route: '/tournament' },
|
||||
{ stage: 6, type: 2 as const, label: '베 팅 장', route: '/betting' },
|
||||
{ stage: 7, type: 2 as const, label: '일 기 토', route: '/tournament' },
|
||||
{ stage: 10, type: 3 as const, label: '설 전', route: '/tournament' },
|
||||
{ stage: 0, type: 3 as const, label: '설 전', route: '/tournament', winnerId: 17 },
|
||||
];
|
||||
|
||||
for (const viewport of [
|
||||
{ width: 1200, height: 900 },
|
||||
{ width: 500, height: 900 },
|
||||
]) {
|
||||
await page.setViewportSize(viewport);
|
||||
for (const lifecycle of cases) {
|
||||
state.stage = lifecycle.stage;
|
||||
state.tournamentType = lifecycle.type;
|
||||
state.tournamentWinnerId = lifecycle.winnerId;
|
||||
if (page.url() === 'about:blank') {
|
||||
await waitForMain(page);
|
||||
} else {
|
||||
await page.reload();
|
||||
await waitForMain(page);
|
||||
}
|
||||
|
||||
const nationMenu = page.locator('.main-nation-menu:visible');
|
||||
const main = nationMenu.locator('[data-navigation-id="tournament"]');
|
||||
await expect(main).toHaveText(lifecycle.label);
|
||||
await expect(main).toHaveAttribute('href', `${basePath}${lifecycle.route}`);
|
||||
await expect(main).toHaveClass(/highlight/);
|
||||
|
||||
const toggle = nationMenu.locator('[data-menu-id="tournament-betting"]');
|
||||
await toggle.click();
|
||||
const tournamentItem = nationMenu.locator(
|
||||
'#nation-menu-tournament-betting [data-navigation-id="tournament-menu"]'
|
||||
);
|
||||
const bettingItem = nationMenu.locator('#nation-menu-tournament-betting [data-navigation-id="betting"]');
|
||||
if (lifecycle.stage === 6) {
|
||||
await expect(tournamentItem).not.toHaveClass(/highlight/);
|
||||
await expect(bettingItem).toHaveClass(/highlight/);
|
||||
} else {
|
||||
await expect(tournamentItem).toHaveClass(/highlight/);
|
||||
await expect(bettingItem).not.toHaveClass(/highlight/);
|
||||
}
|
||||
await page.keyboard.press('Escape');
|
||||
|
||||
if (viewport.width === 500) {
|
||||
const nationTrigger = page.locator('[data-bottom-menu="nation"]');
|
||||
await nationTrigger.click();
|
||||
const mobileTournament = page.locator('#mobile-nation-menu [data-navigation-id="tournament-menu"]');
|
||||
const mobileBetting = page.locator('#mobile-nation-menu [data-navigation-id="betting"]');
|
||||
if (lifecycle.stage === 6) {
|
||||
await expect(mobileTournament).not.toHaveClass(/highlight/);
|
||||
await expect(mobileBetting).toHaveClass(/highlight/);
|
||||
} else {
|
||||
await expect(mobileTournament).toHaveClass(/highlight/);
|
||||
await expect(mobileBetting).not.toHaveClass(/highlight/);
|
||||
}
|
||||
await page.keyboard.press('Escape');
|
||||
}
|
||||
}
|
||||
|
||||
await page
|
||||
.locator('.main-nation-menu:visible [data-menu-id="tournament-betting"]')
|
||||
.locator('..')
|
||||
.screenshot({
|
||||
path: artifactRoot
|
||||
? resolve(artifactRoot, `tournament-dynamic-main-${viewport.width}.png`)
|
||||
: testInfo.outputPath(`tournament-dynamic-main-${viewport.width}.png`),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('shows game index zero for a profile whose first game starts at zero', async ({ page }) => {
|
||||
const state: NavigationFixture = {
|
||||
officerLevel: 5,
|
||||
@@ -1455,7 +1575,7 @@ test('nation split buttons keep square inner corners and a single divider in eve
|
||||
officerLevel: 5,
|
||||
permission: 2,
|
||||
nationLevel: 3,
|
||||
stage: 1,
|
||||
stage: 6,
|
||||
npcMode: 1,
|
||||
scenarioTitle: '분할 버튼 이음새 검증 시나리오',
|
||||
generalMeCalls: 0,
|
||||
@@ -1515,14 +1635,21 @@ test('nation split buttons keep square inner corners and a single divider in eve
|
||||
for (const width of [1200, 500]) {
|
||||
await page.setViewportSize({ width, height: 900 });
|
||||
await waitForMain(page);
|
||||
const nationSplit = page.locator('.main-nation-menu:visible .nation-menu-split').first();
|
||||
const pairs: Array<[string, Locator, Locator]> = [
|
||||
[
|
||||
'nation',
|
||||
nationSplit.locator('[data-navigation-id="auction-resource"]'),
|
||||
nationSplit.locator('[data-menu-id="auction"]'),
|
||||
'tournament',
|
||||
page.locator('.main-nation-menu:visible [data-navigation-id="tournament"]'),
|
||||
page.locator('.main-nation-menu:visible [data-menu-id="tournament-betting"]'),
|
||||
],
|
||||
[
|
||||
'auction',
|
||||
page.locator('.main-nation-menu:visible [data-navigation-id="auction-resource"]'),
|
||||
page.locator('.main-nation-menu:visible [data-menu-id="auction"]'),
|
||||
],
|
||||
];
|
||||
await expect(page.locator('.main-nation-menu:visible [data-navigation-id="tournament"]')).toHaveClass(
|
||||
/highlight/
|
||||
);
|
||||
|
||||
for (const [label, main, toggle] of pairs) {
|
||||
await expect(main).toBeVisible();
|
||||
@@ -3959,9 +4086,7 @@ for (const viewport of [
|
||||
await picker.getByLabel('장비 종류', { exact: true }).selectOption('weapon');
|
||||
const equipment = picker.getByLabel('장비', { exact: true });
|
||||
await equipment.selectOption('청룡언월도');
|
||||
const optionLabelBeforeRefresh = await equipment
|
||||
.locator('option[value="청룡언월도"]')
|
||||
.textContent();
|
||||
const optionLabelBeforeRefresh = await equipment.locator('option[value="청룡언월도"]').textContent();
|
||||
await equipment.evaluate((element) => {
|
||||
const select = element as HTMLSelectElement;
|
||||
const valueDescriptor = Object.getOwnPropertyDescriptor(HTMLSelectElement.prototype, 'value');
|
||||
@@ -4091,8 +4216,8 @@ test('keeps an Android Chromium native command select untouched while a turn sig
|
||||
await waitForMain(mobilePage);
|
||||
await expect
|
||||
.poll(() =>
|
||||
mobilePage.evaluate(
|
||||
() => (window as unknown as { __hasMainRealtime: () => boolean }).__hasMainRealtime()
|
||||
mobilePage.evaluate(() =>
|
||||
(window as unknown as { __hasMainRealtime: () => boolean }).__hasMainRealtime()
|
||||
)
|
||||
)
|
||||
.toBe(true);
|
||||
|
||||
@@ -693,6 +693,30 @@ test('tournament and betting pages expose same-row navigation tabs beside close'
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(390);
|
||||
});
|
||||
|
||||
test('tournament and betting close only their script-opened popup window', async ({ page }, testInfo) => {
|
||||
const baseURL = testInfo.project.use.baseURL;
|
||||
expect(typeof baseURL).toBe('string');
|
||||
await page.goto('about:blank');
|
||||
|
||||
for (const route of ['tournament', 'betting'] as const) {
|
||||
const popupPromise = page.waitForEvent('popup');
|
||||
await page.evaluate(() => window.open('about:blank', '_blank', 'noopener'));
|
||||
const popup = await popupPromise;
|
||||
await installFixture(popup, { tournamentStage: route === 'betting' ? 6 : 1 });
|
||||
await popup.goto(new URL(route, baseURL as string).href);
|
||||
|
||||
await expect(popup.getByRole('button', { name: '창 닫기' }).first()).toBeVisible();
|
||||
expect(await popup.evaluate(() => window.opener)).toBeNull();
|
||||
|
||||
const closed = popup.waitForEvent('close');
|
||||
await popup.getByRole('button', { name: '창 닫기' }).first().click();
|
||||
await closed;
|
||||
|
||||
expect(page.isClosed()).toBe(false);
|
||||
expect(page.url()).toBe('about:blank');
|
||||
}
|
||||
});
|
||||
|
||||
test('mobile betting rankings use tabs and keep dedicated icons beside general names', async ({ page }, testInfo) => {
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
const { placedBets } = await installFixture(page, { tournamentStage: 6 });
|
||||
|
||||
Reference in New Issue
Block a user