diff --git a/app/game-frontend/e2e/inGameInfo.spec.ts b/app/game-frontend/e2e/inGameInfo.spec.ts index c859f953..d7786d6e 100644 --- a/app/game-frontend/e2e/inGameInfo.spec.ts +++ b/app/game-frontend/e2e/inGameInfo.spec.ts @@ -742,24 +742,19 @@ test('global-info renders the ref nation summary columns beside the map', async const titleTextBackground = await mapTitle.evaluate((element) => getComputedStyle(element).backgroundImage); expect(titleTextBackground).toContain('ad.gif'); expect(titleTextBackground).toContain('spring.gif'); - await mapTitle.hover(); const titleTooltip = page.locator('.map-title-tooltip'); - await expect(titleTooltip).toBeVisible(); - await expect(titleTooltip).toContainText('기술등급 제한 : 5등급 (205년 해제)'); + await expect(titleTooltip).toHaveCount(0); const titleGeometry = await page.locator('.map-top').evaluate((element) => { const band = element.getBoundingClientRect(); const title = element.querySelector('.map-title')?.getBoundingClientRect(); - const tooltip = element.querySelector('.map-title-tooltip')?.getBoundingClientRect(); return { band: { width: band.width, height: band.height }, title: title ? { width: title.width, height: title.height } : null, - tooltip: tooltip ? { width: tooltip.width, height: tooltip.height } : null, }; }); expect(titleGeometry).toEqual({ band: { width: 700, height: 20 }, title: { width: 160, height: 20 }, - tooltip: { width: 220, height: 28 }, }); if (artifactRoot) { await mkdir(artifactRoot, { recursive: true }); @@ -938,19 +933,14 @@ test('global-info renders the ref nation summary columns beside the map', async expect(mobileGeometry.map?.width).toBe(500); expect(mobileGeometry.summary?.width).toBe(500); expect(mobileGeometry.summary?.y).toBe(mobileGeometry.map?.bottom); - await mapTitle.hover(); - await expect(titleTooltip).toBeVisible(); const mobileTitleGeometry = await page.locator('.map-top').evaluate((element) => { const band = element.getBoundingClientRect(); - const tooltip = element.querySelector('.map-title-tooltip')?.getBoundingClientRect(); return { band: { width: band.width, height: band.height }, - tooltip: tooltip ? { x: tooltip.x, width: tooltip.width } : null, documentWidth: document.documentElement.scrollWidth, }; }); expect(mobileTitleGeometry.band).toEqual({ width: 500, height: 20 }); - expect(mobileTitleGeometry.tooltip?.width).toBe(220); expect(mobileTitleGeometry.documentWidth).toBe(500); await hoveredCastle.hover(); await expect(cityTooltip).toBeVisible(); @@ -964,17 +954,17 @@ test('global-info renders the ref nation summary columns beside the map', async } }); -test('map title keeps the ref early-game restriction boundary and color', async ({ page }) => { +test('non-main map title keeps the ref early-game color without the main-only restriction tooltip', async ({ + page, +}) => { await install(page, 'member', 100, 2, { ...map, startYear: 198 }); await page.setViewportSize({ width: 1200, height: 900 }); await go(page, 'global-info'); const mapTitle = page.locator('.map-title'); await expect(mapTitle).toHaveCSS('color', 'rgb(255, 255, 0)'); - await mapTitle.hover(); - await expect(page.locator('.map-title-tooltip')).toHaveText( - '초반제한 기간 : 0년 12개월 (201년)기술등급 제한 : 1등급 (203년 해제)' - ); + await expect(mapTitle).not.toHaveAttribute('tabindex'); + await expect(page.locator('.map-title-tooltip')).toHaveCount(0); }); test('global-info diplomacy height follows the active nation count', async ({ page }) => { diff --git a/app/game-frontend/e2e/mainNavigation.spec.ts b/app/game-frontend/e2e/mainNavigation.spec.ts index 568d06c9..6fdbc52d 100644 --- a/app/game-frontend/e2e/mainNavigation.spec.ts +++ b/app/game-frontend/e2e/mainNavigation.spec.ts @@ -3415,6 +3415,84 @@ test('main layout and map use the same mobile/desktop boundary', async ({ page } await page.screenshot({ path: testInfo.outputPath('screen-mode-mobile-939.png'), fullPage: true }); }); +test('main map year exposes the Ref restriction and technology limit on desktop and mobile', async ({ + page, +}, testInfo) => { + const state: NavigationFixture = { + officerLevel: 5, + permission: 2, + nationLevel: 3, + stage: 6, + npcMode: 1, + currentYear: 182, + currentMonth: 1, + generalMeCalls: 0, + operations: [], + validMapImages: true, + }; + await installFixture(page, state); + await page.setViewportSize({ width: 1200, height: 900 }); + await waitForMain(page); + + const assertTitleTooltip = async (layout: 'desktop' | 'mobile') => { + const mapPanel = page.locator(`.layout-${layout} [data-main-target="map"]`); + const title = mapPanel.locator('.map-title'); + const tooltip = mapPanel.getByRole('tooltip'); + await expect(title).toHaveText(/182年 1月/u); + await expect(title).toHaveCSS('color', 'rgb(255, 255, 0)'); + await expect(title).toHaveAttribute('tabindex', '0'); + await expect(tooltip).toBeHidden(); + await title.hover(); + await expect(tooltip).toBeVisible(); + await expect(tooltip).toHaveText('초반제한 기간 : 0년 12개월 (183년)기술등급 제한 : 1등급 (185년 해제)'); + const geometry = await mapPanel.evaluate((panel) => { + const panelRect = panel.getBoundingClientRect(); + const titleRect = panel.querySelector('.map-title')?.getBoundingClientRect(); + const tooltipRect = panel.querySelector('.map-title-tooltip')?.getBoundingClientRect(); + const titleStyle = titleRect ? getComputedStyle(panel.querySelector('.map-title')!) : null; + return { + panelOverflow: getComputedStyle(panel).overflow, + title: titleRect ? { top: titleRect.top, width: titleRect.width, height: titleRect.height } : null, + tooltip: tooltipRect + ? { top: tooltipRect.top, bottom: tooltipRect.bottom, width: tooltipRect.width } + : null, + textDecorationLine: titleStyle?.textDecorationLine ?? null, + viewportWidth: document.documentElement.scrollWidth, + panelLeft: panelRect.left, + panelRight: panelRect.right, + }; + }); + expect(geometry.panelOverflow).toBe('visible'); + expect(geometry.title?.width).toBe(160); + expect(geometry.title?.height).toBe(20); + expect(geometry.tooltip?.width).toBe(220); + expect(geometry.tooltip?.bottom).toBeLessThanOrEqual(geometry.title?.top ?? 0); + expect(geometry.textDecorationLine).toBe('none'); + return geometry; + }; + + const desktopGeometry = await assertTitleTooltip('desktop'); + await testInfo.attach('main-map-year-tooltip-desktop.png', { + body: await page.screenshot({ fullPage: false }), + contentType: 'image/png', + }); + + await page.setViewportSize({ width: 500, height: 900 }); + await expect(page.locator('.layout-mobile')).toBeVisible(); + const mobileGeometry = await assertTitleTooltip('mobile'); + expect(mobileGeometry.viewportWidth).toBe(500); + await page.locator('.layout-mobile [data-main-target="map"] .map-title').focus(); + await expect(page.locator('.layout-mobile [data-main-target="map"] .map-title-tooltip')).toBeVisible(); + await testInfo.attach('main-map-year-tooltip-mobile.png', { + body: await page.screenshot({ fullPage: false }), + contentType: 'image/png', + }); + await testInfo.attach('main-map-year-tooltip-geometry.json', { + body: Buffer.from(`${JSON.stringify({ desktop: desktopGeometry, mobile: mobileGeometry }, null, 2)}\n`), + contentType: 'application/json', + }); +}); + test('the 939/940 boundary switches to the Ref-style 500px single document', async ({ page }) => { const state: NavigationFixture = { officerLevel: 5, diff --git a/app/game-frontend/src/components/main/MapViewer.vue b/app/game-frontend/src/components/main/MapViewer.vue index 200962c4..32be5f5b 100644 --- a/app/game-frontend/src/components/main/MapViewer.vue +++ b/app/game-frontend/src/components/main/MapViewer.vue @@ -75,6 +75,7 @@ const props = withDefaults( fitContainer?: boolean; showCurrentCityMarker?: boolean; showSelectionBorder?: boolean; + showTitleTooltip?: boolean; readonly?: boolean; }>(), { @@ -82,6 +83,7 @@ const props = withDefaults( detailMode: undefined, selectedCityId: undefined, showSelectionBorder: true, + showTitleTooltip: false, } ); @@ -152,6 +154,7 @@ const mapControls = ref(null); const tooltipElement = ref(null); const mapOptionsOpen = ref(false); const mapOptionsMenuId = `map-options-${useId()}`; +const mapTitleTooltipId = `map-title-tooltip-${useId()}`; const { width: mapBodyWidth } = useElementSize(mapBody); const { elementX, elementY } = useMouseInElement(mapArea); @@ -630,9 +633,14 @@ const selectCity = (cityId: number) => {