From 4e4c195c796e433947dfddafc7ca1a2987d16716 Mon Sep 17 00:00:00 2001 From: EJClaw Date: Thu, 8 Oct 2026 10:23:14 +0900 Subject: [PATCH] =?UTF-8?q?=EB=8B=A4=EC=8B=9C=EB=B3=B4=EA=B8=B0:=20?= =?UTF-8?q?=EB=8C=80=EA=B5=AD=20=EC=A4=91=20=EB=8B=B5=EC=9D=84=20=EB=B0=9B?= =?UTF-8?q?=EB=8D=98=20=EC=B0=BD(=EB=AC=B4=EB=A5=B4=EA=B8=B0=C2=B7?= =?UTF-8?q?=EB=AC=B4=EC=8A=B9=EB=B6=80=20=EC=9A=94=EC=B2=AD,=20=EB=B1=85!?= =?UTF-8?q?=20=EC=84=A0=ED=83=9D=20=EC=B0=BD)=EC=9D=B4=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=EC=9D=84=20=EB=8D=AE=EC=A7=80=20=EC=95=8A=EA=B2=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 다시보기는 게임의 Side/Board를 읽기 전용으로 그리는데, 그 장면의 요청 창(Sheet, 뱅! 모달)도 함께 떠서 화면 전체를 덮고 클릭을 막았음(읽기 전용 영역이라 수락/거절도 안 됨). .replay-readonly 안의 창은 숨김 - e2e(replay): 오목 중 무르기 요청→거절을 넣고, 폰 다시보기에서 그 장면에 창이 없고 [다음]이 되는지 확인 Co-Authored-By: Claude Opus 5.5 --- apps/web/src/styles/global.css | 5 +++++ e2e/replay.e2e.ts | 21 +++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/apps/web/src/styles/global.css b/apps/web/src/styles/global.css index 057101c..87a061d 100644 --- a/apps/web/src/styles/global.css +++ b/apps/web/src/styles/global.css @@ -1010,6 +1010,11 @@ button.header-user { .replay-readonly { display: contents; } +/* Prompts that waited on a live player (무르기·무승부 요청, 뱅! 선택 창…) can't be answered in a replay: don't let them cover the screen. */ +.replay-readonly .sheet-backdrop, +.replay-readonly .bg-modal-back { + display: none; +} .replay-readonly button, .replay-readonly [role='button'], .replay-readonly svg { diff --git a/e2e/replay.e2e.ts b/e2e/replay.e2e.ts index f070b28..9155dca 100644 --- a/e2e/replay.e2e.ts +++ b/e2e/replay.e2e.ts @@ -2,6 +2,7 @@ * E2E (docs/09 §8): game record replay. * 1) 오목 to the end with two browsers (PC + phone), open 다시 보기 from the result sheet and from 내 정보, * step through it (buttons, slider, keyboard, play) and check the board changes. + * A asks to take back a move once and B declines: B's replay must not show that request as a sheet over the screen. * 2) 원카드 (hidden hands): each player's replay shows only their own cards. * Run: E2E_PORT=4532 bun e2e/replay.e2e.ts (needs apps/web/dist built) */ @@ -102,6 +103,14 @@ try { for (let i = 0; i < 4; i++) { await a.getByText('내 차례예요').waitFor(); await tapCell(a, 5 + i, 7, false); + if (i === 3) { + // A asks to take the 4th stone back; B declines (the replay keeps that moment). + await waitStones(b, 7); + await a.getByRole('button', { name: /↩ 무르기/ }).click(); + await b.getByText('상대가 1수 무르기를 요청했어요').waitFor(); + await b.getByRole('button', { name: '거절' }).tap(); + await a.getByText('상대의 답을 기다리는 중…').waitFor({ state: 'detached' }); + } await b.getByText('내 차례예요').waitFor(); await tapCell(b, 5 + i, 3, true); } @@ -117,7 +126,7 @@ try { await a.waitForURL(/\/replay\/[0-9A-Z]{26}$/); replayUrl = a.url(); await a.getByText('게임을 시작했어요.').waitFor(); - expectEq((await count(a)).replace(/\s+/g, ' '), '시작 / 전체 9번', 'count at start'); + expectEq((await count(a)).replace(/\s+/g, ' '), '시작 / 전체 11번', 'count at start'); await waitStones(a, 0); await a.getByRole('button', { name: '다음' }).click(); await waitStones(a, 1); @@ -137,7 +146,7 @@ try { await step('A(PC): 슬라이더 · 방향키 · 재생/멈춤 · 판은 눌러도 그대로', async () => { await a.getByLabel('몇 번째 장면인지 고르기').fill('4'); await waitStones(a, 4); - expectEq((await count(a)).replace(/\s+/g, ' '), '4번째 / 전체 9번', 'count after slider'); + expectEq((await count(a)).replace(/\s+/g, ' '), '4번째 / 전체 11번', 'count after slider'); await a.locator('body').click({ position: { x: 5, y: 300 } }); await a.keyboard.press('ArrowRight'); await waitStones(a, 5); @@ -174,6 +183,14 @@ try { await waitStones(b, 2); await b.getByText('내가 움직였어요.').waitFor(); await b.screenshot({ path: join(SHOTS, 'replay-3-omok-phone.png') }); + // The moment A asked to take a move back: no "수락/거절" sheet covering the screen, the controls still work. + await b.getByLabel('몇 번째 장면인지 고르기').fill('8'); + await waitStones(b, 7); + expectEq((await count(b)).replace(/\s+/g, ' '), '8번째 / 전체 11번', 'count at the undo request'); + if (await b.getByRole('dialog').count()) throw new Error('the undo request sheet shows in the replay'); + await b.screenshot({ path: join(SHOTS, 'replay-3b-undo-request-phone.png') }); + await b.getByRole('button', { name: '다음' }).tap(); + expectEq((await count(b)).replace(/\s+/g, ' '), '9번째 / 전체 11번', 'count after 다음 at the undo request'); await b.getByRole('button', { name: '끝으로' }).tap(); await waitStones(b, 9); });