diff --git a/app/game-frontend/e2e/mainNavigation.spec.ts b/app/game-frontend/e2e/mainNavigation.spec.ts index 0a2e49e3..d722f64b 100644 --- a/app/game-frontend/e2e/mainNavigation.spec.ts +++ b/app/game-frontend/e2e/mainNavigation.spec.ts @@ -34,6 +34,8 @@ type NavigationFixture = { largeCommandTable?: boolean; currentYear?: number; currentMonth?: number; + scenarioTitle?: string; + latestVote?: { id: number; title: string; hasVoted: boolean } | null; globalRecords?: Array<{ id: number; text: string }>; generalRecords?: Array<{ id: number; text: string }>; worldHistory?: Array<{ id: number; text: string }>; @@ -309,6 +311,7 @@ const installFixture = async (page: Page, state: NavigationFixture) => { year: state.currentYear ?? 185, month: state.currentMonth ?? 1, turnTerm: 10, + scenarioTitle: state.scenarioTitle ?? '', }); } if (operation === 'dashboard.getContextBundleDelta') { @@ -421,7 +424,10 @@ const installFixture = async (page: Page, state: NavigationFixture) => { onlineGenerals: '메뉴검증장수', nationNotice: '

국가 방침

', lastExecuted: null, - latestVote: { id: 9, title: '메뉴 설문', hasVoted: false }, + latestVote: + state.latestVote === undefined + ? { id: 9, title: '메뉴 설문', hasVoted: false } + : state.latestVote, }); } if (operation === 'board.getAccess') { @@ -576,6 +582,7 @@ test('desktop menus preserve ref columns, prefix-safe routes, and controlled dro nationLevel: 3, stage: 1, npcMode: 1, + scenarioTitle: '메인 화면 검증 시나리오', generalMeCalls: 0, operations: [], }; @@ -589,6 +596,45 @@ test('desktop menus preserve ref columns, prefix-safe routes, and controlled dro await expect(page.locator('.main-mobile-bottom')).toBeHidden(); await expect(page.locator('.layout-desktop')).toBeVisible(); await expect(page.locator('.layout-mobile')).toHaveCount(0); + await expect(page.getByRole('heading', { name: '메인 화면 검증 시나리오', exact: true })).toHaveCount(1); + await expect(page.locator('.game-shell__subtitle')).toHaveText('185년 1월 · 턴 10분'); + await expect(page.locator('.game-shell__subtitle')).not.toContainText('메인 화면 검증 시나리오'); + await expect(page.locator('.tournament-status')).toHaveText('토너먼트: 참가 모집중'); + await expect(page.locator('.vote-status')).toHaveText('설문: 메뉴 설문'); + const headerStatusGeometry = await page.locator('.main-page').evaluate((element) => { + const title = element.querySelector('.game-shell__title'); + const subtitle = element.querySelector('.game-shell__subtitle'); + const activity = element.querySelector('.activity-status'); + const tournament = element.querySelector('.tournament-status'); + const survey = element.querySelector('.vote-status'); + if (!title || !subtitle || !activity || !tournament || !survey) { + throw new Error('main header status geometry is incomplete'); + } + return { + title: title.getBoundingClientRect().toJSON(), + subtitle: subtitle.getBoundingClientRect().toJSON(), + activity: activity.getBoundingClientRect().toJSON(), + tournament: tournament.getBoundingClientRect().toJSON(), + survey: survey.getBoundingClientRect().toJSON(), + activityColumns: getComputedStyle(activity).gridTemplateColumns, + }; + }); + expect(headerStatusGeometry.subtitle.y).toBeGreaterThanOrEqual(headerStatusGeometry.title.bottom); + expect(headerStatusGeometry.activity.width).toBeCloseTo(666.67, 0); + expect(headerStatusGeometry.tournament.width).toBeCloseTo(333.33, 0); + expect(headerStatusGeometry.survey.width).toBeCloseTo(333.33, 0); + expect(headerStatusGeometry.activityColumns.split(' ')).toHaveLength(2); + const tournamentStatusLink = page.locator('.tournament-status a'); + const surveyStatusLink = page.locator('.vote-status a'); + await tournamentStatusLink.hover(); + await expect + .poll(() => tournamentStatusLink.evaluate((element) => getComputedStyle(element).cursor)) + .toBe('pointer'); + await surveyStatusLink.focus(); + await expect(surveyStatusLink).toBeFocused(); + await expect + .poll(() => surveyStatusLink.evaluate((element) => getComputedStyle(element).textDecorationLine)) + .toContain('underline'); const contentOrder = await page .locator('.record-zone, [data-menu-position="middle"], .desktop-message-panel, [data-menu-position="bottom"]') .evaluateAll((elements) => @@ -642,7 +688,7 @@ test('desktop menus preserve ref columns, prefix-safe routes, and controlled dro await expect(gameInfoButton).toBeFocused(); await gameInfoButton.click(); - await page.getByRole('heading', { name: '전장 현황' }).click(); + await page.getByRole('heading', { name: '메인 화면 검증 시나리오' }).click(); await expect(gameInfoButton).toHaveAttribute('aria-expanded', 'false'); await persistArtifact(page, `${basePath.slice(1)}-desktop-1200`); }); @@ -1121,6 +1167,8 @@ test('the 939/940 boundary switches to the Ref-style 500px single document', asy nationLevel: 3, stage: 6, npcMode: 1, + scenarioTitle: '모바일 검증 시나리오', + latestVote: null, generalMeCalls: 0, operations: [], }; @@ -1139,6 +1187,27 @@ test('the 939/940 boundary switches to the Ref-style 500px single document', asy await expect(page.locator('.main-mobile-bottom')).toBeVisible(); await page.setViewportSize({ width: 500, height: 900 }); + await expect(page.getByRole('heading', { name: '모바일 검증 시나리오', exact: true })).toHaveCount(1); + await expect(page.locator('.game-shell__subtitle')).toHaveText('185년 1월 · 턴 10분'); + await expect(page.locator('.tournament-status')).toHaveText('토너먼트: 베팅 진행중'); + await expect(page.locator('.vote-status')).toHaveText('설문: 진행 중인 설문 없음'); + const activityGeometry = await page.locator('.activity-status').evaluate((element) => { + const tournament = element.querySelector('.tournament-status'); + const survey = element.querySelector('.vote-status'); + if (!tournament || !survey) throw new Error('activity status is incomplete'); + return { + width: element.getBoundingClientRect().width, + tournamentWidth: tournament.getBoundingClientRect().width, + surveyWidth: survey.getBoundingClientRect().width, + columns: getComputedStyle(element).gridTemplateColumns, + }; + }); + expect(activityGeometry).toMatchObject({ + width: 500, + tournamentWidth: 250, + surveyWidth: 250, + columns: '250px 250px', + }); await expect .poll(() => page diff --git a/app/game-frontend/src/components/main/MainFrontStatus.vue b/app/game-frontend/src/components/main/MainFrontStatus.vue index 87b53a47..5731e4e1 100644 --- a/app/game-frontend/src/components/main/MainFrontStatus.vue +++ b/app/game-frontend/src/components/main/MainFrontStatus.vue @@ -1,5 +1,9 @@