/** * Holdem — 3 人 all-in 摊牌 E2E(联机,真实 UI + server + engine)。 * 多人 all-in 之后:公共牌应发完、亮牌、显示比大小结果。 */ import { test, expect, type Browser, type Page, type BrowserContext } from '@playwright/test'; interface Seat { ctx: BrowserContext; page: Page; pid: string; } async function authUser(suffix: string): Promise<{ token: string; username: string }> { const uname = `hj${suffix}${Math.floor(Math.random() * 1e6)}`.slice(0, 18); const pwd = 'pw123456'; const base = process.env.TTS_API_BASE ?? 'http://localhost:8000'; const reg = await fetch(`${base}/api/auth/register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: uname, password: pwd }), }); if (reg.ok) { const j = (await reg.json()) as { token: string; username: string }; return { token: j.token, username: j.username }; } const login = await fetch(`${base}/api/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: uname, password: pwd }), }); const j = (await login.json()) as { token: string; username: string }; return { token: j.token, username: j.username }; } async function newSeat(browser: Browser, pid: string, auth: { token: string; username: string }): Promise { const ctx = await browser.newContext(); const page = await ctx.newPage(); await page.addInitScript( ([token, username]) => { localStorage.setItem('tts-like.token', token); localStorage.setItem('tts-like.username', username); }, [auth.token, auth.username] as [string, string], ); await page.goto('/'); await page.getByTestId('game-select').selectOption('holdem'); await page.getByTestId('mode-online').click(); await expect(page.getByTestId('lobby-room-list')).toBeVisible({ timeout: 15_000 }); return { ctx, page, pid }; } test('3人 all-in → 三个客户端都看到完整公共牌 + 亮牌 + 结果', async ({ browser }) => { const auths = [await authUser('a'), await authUser('b'), await authUser('c')]; const seats = [ await newSeat(browser, '0', auths[0]!), await newSeat(browser, '1', auths[1]!), await newSeat(browser, '2', auths[2]!), ]; // P0 创建 3 座房间,起始筹码 100 await seats[0]!.page.getByTestId('lobby-create-seats').selectOption('3'); await seats[0]!.page.getByTestId('lobby-create-startingStack').fill('100'); await seats[0]!.page.getByTestId('lobby-create-room').click(); await expect(seats[0]!.page.getByTestId('holdem-board')).toBeVisible({ timeout: 15_000 }); // 读 P0 "在房间" 显示的 matchID(避免误加入旧房间) const roomText = await seats[0]!.page.getByTestId('lobby-current-room').innerText(); const mid = roomText.match(/在房间\s+(\S+)\s+作为/)?.[1] ?? ''; // P1 / P2 加入 P0 的房间 for (const seat of seats.slice(1)) { await expect(async () => { await seat.page.getByTestId('lobby-refresh').click(); const joinBtn = seat.page.getByTestId(`lobby-join-${seat.pid}-${mid}`); expect(await joinBtn.count()).toBeGreaterThan(0); }).toPass({ timeout: 15_000 }); await seat.page.getByTestId(`lobby-join-${seat.pid}-${mid}`).click(); await expect(seat.page.getByTestId('holdem-board')).toBeVisible({ timeout: 15_000 }); } // 开始 await expect(async () => { const startBtn = seats[0]!.page.getByTestId('holdem-start'); await expect(startBtn).toBeEnabled({ timeout: 2_000 }); await startBtn.click(); }).toPass({ timeout: 20_000 }); // button=0, SB=1, BB=2, UTG=0。等 P0 的行动条。 await expect(seats[0]!.page.getByTestId('holdem-btn-allin')).toBeVisible({ timeout: 15_000 }); await seats[0]!.page.getByTestId('holdem-btn-allin').click(); // P0 全下 100 // P1 call 全下 await expect(seats[1]!.page.getByTestId('holdem-btn-call')).toBeVisible({ timeout: 15_000 }); await seats[1]!.page.getByTestId('holdem-btn-call').click(); // P2 call 全下 await expect(seats[2]!.page.getByTestId('holdem-btn-call')).toBeVisible({ timeout: 15_000 }); await seats[2]!.page.getByTestId('holdem-btn-call').click(); // 三个客户端都应看到:5 张公共牌 + 6 张亮出的底牌 + 日志含"赢得" for (const seat of seats) { await expect(async () => { const cards = seat.page.locator('[data-testid^="holdem-board-card-"]'); expect(await cards.count()).toBe(5); }).toPass({ timeout: 15_000 }); await expect(async () => { const holes = seat.page.locator('[data-testid^="holdem-hole-"]'); expect(await holes.count()).toBe(6); }).toPass({ timeout: 5_000 }); await expect(async () => { const log = await seat.page.getByTestId('holdem-log').innerText(); expect(log).toContain('赢得'); }).toPass({ timeout: 5_000 }); } console.log('matchID:', mid); });