From 71ee529d354613edb356ae4b07d58fb261db539d Mon Sep 17 00:00:00 2001 From: hided62 Date: Sat, 29 Aug 2026 03:31:00 +0000 Subject: [PATCH] =?UTF-8?q?fix(game-ui):=20=EC=B2=9C=ED=86=B5=EA=B5=AD=20?= =?UTF-8?q?=EB=B2=A0=ED=8C=85=20=EA=B8=88=EC=95=A1=20=EC=B4=88=EC=95=88?= =?UTF-8?q?=EC=9D=84=20=EC=9C=A0=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/game-frontend/e2e/nationBetting.spec.ts | 117 ++++++++++++++++++ app/game-frontend/e2e/playwright.config.mjs | 1 + app/game-frontend/package.json | 1 + .../src/views/NationBettingView.vue | 1 - 4 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 app/game-frontend/e2e/nationBetting.spec.ts diff --git a/app/game-frontend/e2e/nationBetting.spec.ts b/app/game-frontend/e2e/nationBetting.spec.ts new file mode 100644 index 00000000..1ed10487 --- /dev/null +++ b/app/game-frontend/e2e/nationBetting.spec.ts @@ -0,0 +1,117 @@ +import { expect, test, type Page, type Route } from '@playwright/test'; + +import { gameProfile, gameTrpcRoute } from './gameTestPaths.js'; + +const response = (data: unknown) => ({ result: { data } }); +const errorResponse = (path: string) => ({ + error: { + message: `Unhandled fixture operation: ${path}`, + code: -32000, + data: { code: 'INTERNAL_SERVER_ERROR', httpStatus: 500, path }, + }, +}); +const operationNames = (route: Route): string[] => { + const url = new URL(route.request().url()); + return decodeURIComponent(url.pathname.slice(url.pathname.lastIndexOf('/trpc/') + 6)).split(','); +}; + +const bettingList = { + bettingList: { + 1: { + id: 1, + type: 'nation', + name: '첫 번째 천통국 베팅', + finished: false, + selectCnt: 1, + isExclusive: true, + reqInheritancePoint: false, + openYearMonth: 2400, + closeYearMonth: 2411, + winner: null, + totalAmount: 0, + }, + 2: { + id: 2, + type: 'nation', + name: '두 번째 천통국 베팅', + finished: false, + selectCnt: 1, + isExclusive: true, + reqInheritancePoint: false, + openYearMonth: 2400, + closeYearMonth: 2411, + winner: null, + totalAmount: 0, + }, + }, + year: 200, + month: 1, +}; + +const bettingDetail = (id: number) => ({ + bettingInfo: { + ...bettingList.bettingList[id as 1 | 2], + candidates: [ + { title: '위', info: '조조' }, + { title: '촉', info: '유비' }, + { title: '오', info: '손권' }, + ], + }, + bettingDetail: [], + myBetting: [], + remainPoint: 5_000, + year: 200, + month: 1, +}); + +const installFixture = async (page: Page) => { + await page.addInitScript((profile) => { + localStorage.setItem('sammo-game-token', 'ga_nation_betting_playwright'); + localStorage.setItem('sammo-game-profile', profile); + }, gameProfile); + + let detailId = 2; + await page.route(gameTrpcRoute, async (route) => { + const results = operationNames(route).map((operation) => { + if (operation === 'auth.status') return response({ ok: true }); + if (operation === 'lobby.info') return response({ myGeneral: { id: 7, name: '유비' } }); + if (operation === 'join.getConfig') return response({}); + if (operation === 'betting.getList') return response(bettingList); + if (operation === 'betting.getDetail') { + detailId = detailId === 2 ? 1 : 2; + return response(bettingDetail(detailId)); + } + if (operation === 'betting.bet') return response({ result: true }); + return errorResponse(operation); + }); + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(results), + }); + }); +}; + +test('keeps the nation-betting amount while changing candidates, submitting, and opening another bet', async ({ + page, +}, testInfo) => { + await installFixture(page); + await page.setViewportSize({ width: 500, height: 844 }); + await page.goto('nation-betting'); + + await page.getByRole('button', { name: /두 번째 천통국 베팅/u }).click(); + const amount = page.getByRole('spinbutton', { name: '베팅 금액' }); + await amount.fill('100'); + await page.getByRole('button', { name: /위 조조/u }).click(); + await expect(amount).toHaveValue('100'); + await page.getByRole('button', { name: /촉 유비/u }).click(); + await expect(amount).toHaveValue('100'); + + await page.getByRole('button', { name: '베팅', exact: true }).click(); + await expect(page.getByTestId('game-toast')).toContainText('베팅했습니다'); + await expect(amount).toHaveValue('100'); + + await page.getByRole('button', { name: /첫 번째 천통국 베팅/u }).click(); + await expect(amount).toHaveValue('100'); + await page.screenshot({ path: testInfo.outputPath('nation-betting-amount-retained.png'), fullPage: true }); +}); diff --git a/app/game-frontend/e2e/playwright.config.mjs b/app/game-frontend/e2e/playwright.config.mjs index 3d2b8fa4..4bdef13d 100644 --- a/app/game-frontend/e2e/playwright.config.mjs +++ b/app/game-frontend/e2e/playwright.config.mjs @@ -33,6 +33,7 @@ export default defineConfig({ 'nationGeneralSecret.spec.ts', 'npcPolicy.spec.ts', 'auction.spec.ts', + 'nationBetting.spec.ts', 'tournamentBracket.spec.ts', 'battleSimulator.spec.ts', 'battleSimulatorRef.spec.ts', diff --git a/app/game-frontend/package.json b/app/game-frontend/package.json index 1e912344..8e851b51 100644 --- a/app/game-frontend/package.json +++ b/app/game-frontend/package.json @@ -18,6 +18,7 @@ "test:e2e:board": "playwright test board.spec.ts --config e2e/playwright.config.mjs", "test:e2e:directories": "playwright test directoryLists.spec.ts --config e2e/playwright.config.mjs", "test:e2e:auction": "playwright test auction.spec.ts --config e2e/playwright.config.mjs", + "test:e2e:nation-betting": "playwright test nationBetting.spec.ts --config e2e/playwright.config.mjs", "test:e2e:tournament-bracket": "playwright test tournamentBracket.spec.ts --config e2e/playwright.config.mjs", "test:e2e:battle-simulator": "playwright test battleSimulator.spec.ts --config e2e/playwright.config.mjs", "test:e2e:join-live": "playwright test --config e2e/joinGeneral.live.playwright.config.mjs --tsconfig e2e/playwright.live.tsconfig.json", diff --git a/app/game-frontend/src/views/NationBettingView.vue b/app/game-frontend/src/views/NationBettingView.vue index 5bff5945..c44727bd 100644 --- a/app/game-frontend/src/views/NationBettingView.vue +++ b/app/game-frontend/src/views/NationBettingView.vue @@ -274,7 +274,6 @@ const loadDetail = async (bettingId: number, resetSelection = true) => { detail.value = await bettingApi.getDetail.query({ bettingId }); if (resetSelection) { selectedCandidates.value = []; - amount.value = 0; } } catch (error) { errorMessage.value = getErrorMessage(error);