fix: display main turn time in server timezone
This commit is contained in:
@@ -20,6 +20,7 @@ type NavigationFixture = {
|
|||||||
generalMeCalls: number;
|
generalMeCalls: number;
|
||||||
operations: string[];
|
operations: string[];
|
||||||
generalName?: string;
|
generalName?: string;
|
||||||
|
generalTurnTime?: string;
|
||||||
cityDefence?: number;
|
cityDefence?: number;
|
||||||
cityState?: number;
|
cityState?: number;
|
||||||
nationRate?: number;
|
nationRate?: number;
|
||||||
@@ -239,7 +240,7 @@ const generalContext = (state: NavigationFixture) => ({
|
|||||||
dex: [350, 100_000, 500_000, 1_000_000, 1_275_975],
|
dex: [350, 100_000, 500_000, 1_000_000, 1_275_975],
|
||||||
},
|
},
|
||||||
items: { horse: null, weapon: null, book: null, item: null },
|
items: { horse: null, weapon: null, book: null, item: null },
|
||||||
turnTime: '0185-01-01T00:00:00.000Z',
|
turnTime: state.generalTurnTime ?? '0185-01-01T00:00:00.000Z',
|
||||||
},
|
},
|
||||||
city: {
|
city: {
|
||||||
id: 1,
|
id: 1,
|
||||||
@@ -666,6 +667,66 @@ test('desktop menus preserve ref columns, prefix-safe routes, and controlled dro
|
|||||||
await persistArtifact(page, `${basePath.slice(1)}-desktop-1200`);
|
await persistArtifact(page, `${basePath.slice(1)}-desktop-1200`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('main general card renders the next turn in the Seoul server timezone', async ({ page }) => {
|
||||||
|
const state: NavigationFixture = {
|
||||||
|
officerLevel: 0,
|
||||||
|
permission: 0,
|
||||||
|
nationLevel: 0,
|
||||||
|
stage: 0,
|
||||||
|
npcMode: 1,
|
||||||
|
generalMeCalls: 0,
|
||||||
|
operations: [],
|
||||||
|
generalName: 'Administrator',
|
||||||
|
generalTurnTime: '2026-08-13T00:07:06.713Z',
|
||||||
|
currentYear: 179,
|
||||||
|
currentMonth: 8,
|
||||||
|
};
|
||||||
|
await installFixture(page, state);
|
||||||
|
await page.setViewportSize({ width: 1200, height: 900 });
|
||||||
|
await waitForMain(page);
|
||||||
|
|
||||||
|
const title = page.locator('[data-main-target="general"] .general-title').first();
|
||||||
|
await expect(title).toContainText('Administrator');
|
||||||
|
await expect(title).toContainText('다음 턴 09:07');
|
||||||
|
await expect(title).not.toContainText('00:07');
|
||||||
|
|
||||||
|
const desktopGeometry = await title.evaluate((element) => {
|
||||||
|
const rect = element.getBoundingClientRect();
|
||||||
|
const style = getComputedStyle(element);
|
||||||
|
return {
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height,
|
||||||
|
fontSize: style.fontSize,
|
||||||
|
lineHeight: style.lineHeight,
|
||||||
|
overflow: style.overflow,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
expect(desktopGeometry.width).toBeGreaterThan(0);
|
||||||
|
expect(desktopGeometry.height).toBeGreaterThan(0);
|
||||||
|
if (artifactRoot) {
|
||||||
|
const target = resolve(artifactRoot);
|
||||||
|
await mkdir(target, { recursive: true });
|
||||||
|
await Promise.all([
|
||||||
|
page.screenshot({ path: resolve(target, 'main-turn-time-seoul-desktop-1200.png'), fullPage: true }),
|
||||||
|
writeFile(
|
||||||
|
resolve(target, 'main-turn-time-seoul-desktop-1200.json'),
|
||||||
|
`${JSON.stringify(desktopGeometry, null, 2)}\n`
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
await page.setViewportSize({ width: 500, height: 900 });
|
||||||
|
const mobileTitle = page.locator('[data-main-target="general"] .general-title').first();
|
||||||
|
await expect(mobileTitle).toContainText('다음 턴 09:07');
|
||||||
|
expect(await mobileTitle.evaluate((element) => element.scrollWidth - element.clientWidth)).toBeLessThanOrEqual(0);
|
||||||
|
if (artifactRoot) {
|
||||||
|
await page.screenshot({
|
||||||
|
path: resolve(artifactRoot, 'main-turn-time-seoul-mobile-500.png'),
|
||||||
|
fullPage: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('pure NPC message senders are not rendered as reply targets', async ({ page }) => {
|
test('pure NPC message senders are not rendered as reply targets', async ({ page }) => {
|
||||||
const target = (generalId: number, generalName: string) => ({
|
const target = (generalId: number, generalName: string) => ({
|
||||||
generalId,
|
generalId,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import SkeletonLines from '../ui/SkeletonLines.vue';
|
import SkeletonLines from '../ui/SkeletonLines.vue';
|
||||||
import LegacyProgressBar from '../ui/LegacyProgressBar.vue';
|
import LegacyProgressBar from '../ui/LegacyProgressBar.vue';
|
||||||
|
import { formatSeoulHourMinute } from '../../utils/legacyDateTime';
|
||||||
import { legacyExperiencePercent, ratioPercent } from '../../utils/legacyProgress';
|
import { legacyExperiencePercent, ratioPercent } from '../../utils/legacyProgress';
|
||||||
|
|
||||||
interface GeneralStats {
|
interface GeneralStats {
|
||||||
@@ -80,7 +81,7 @@ const experiencePercent = computed(() =>
|
|||||||
<div class="general-title">
|
<div class="general-title">
|
||||||
{{ props.general.name }} · 관직 {{ props.general.officerLevel }} · {{ props.general.age ?? '-' }}세 ·
|
{{ props.general.name }} · 관직 {{ props.general.officerLevel }} · {{ props.general.age ?? '-' }}세 ·
|
||||||
다음 턴
|
다음 턴
|
||||||
{{ props.general.turnTime?.slice(11, 16) ?? '-' }}
|
{{ props.general.turnTime ? formatSeoulHourMinute(props.general.turnTime) : '-' }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="stat-progress-grid">
|
<div class="stat-progress-grid">
|
||||||
|
|||||||
@@ -20,3 +20,5 @@ export const formatSeoulDateTime = (value: string | Date): string => {
|
|||||||
koreaTime.getUTCSeconds()
|
koreaTime.getUTCSeconds()
|
||||||
)}`;
|
)}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const formatSeoulHourMinute = (value: string | Date): string => formatSeoulDateTime(value).slice(11, 16);
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import test from 'node:test';
|
||||||
|
|
||||||
|
import { formatSeoulDateTime, formatSeoulHourMinute } from '../src/utils/legacyDateTime.ts';
|
||||||
|
|
||||||
|
void test('formats API UTC timestamps in the server Seoul timezone', () => {
|
||||||
|
assert.equal(formatSeoulDateTime('2026-08-13T00:07:06.713Z'), '2026-08-13 09:07:06');
|
||||||
|
assert.equal(formatSeoulHourMinute('2026-08-13T00:07:06.713Z'), '09:07');
|
||||||
|
});
|
||||||
|
|
||||||
|
void test('keeps legacy timezone-less server timestamps unchanged', () => {
|
||||||
|
assert.equal(formatSeoulDateTime('2026-08-13 09:07:06'), '2026-08-13 09:07:06');
|
||||||
|
assert.equal(formatSeoulHourMinute('2026-08-13 09:07:06'), '09:07');
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user