import { chromium } from 'playwright' import fs from 'node:fs/promises' import path from 'node:path' import process from 'node:process' const baseUrl = 'http://127.0.0.1:5173' const chromePath = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe' const rootDir = process.cwd() const runtimeDir = path.join(rootDir, '.tmp', 'manual-four-players', String(Date.now())) const players = [ { username: 'pwtest04', loginId: '13812345681', password: 'play123', owner: true }, { username: 'pwtest01', loginId: '13812345678', password: 'play123', owner: false }, { username: 'pwtest02', loginId: '13812345679', password: 'play123', owner: false }, { username: 'pwtest03', loginId: '13812345680', password: 'play123', owner: false }, ] function log(message) { console.log(`[setup] ${message}`) } async function launchPlayer(player) { const profileDir = path.join(runtimeDir, player.username) await fs.mkdir(profileDir, { recursive: true }) log(`launch browser for ${player.username}`) const context = await chromium.launchPersistentContext(profileDir, { headless: false, executablePath: chromePath, args: ['--no-first-run', '--no-default-browser-check'], viewport: { width: 1400, height: 960 }, }) let page = context.pages()[0] if (!page) { page = await context.newPage() } await page.goto(`${baseUrl}/login`, { waitUntil: 'domcontentloaded' }) return { ...player, context, page, profileDir } } async function login(page, player) { log(`login ${player.username}`) await page.goto(`${baseUrl}/login`, { waitUntil: 'domcontentloaded' }) await page.getByRole('textbox', { name: '登录ID' }).fill(player.loginId) await page.getByRole('textbox', { name: '密码' }).fill(player.password) const submitButton = page.locator('form').getByRole('button', { name: '登录' }) await Promise.all([ page.waitForURL('**/hall', { timeout: 15000 }), submitButton.click(), ]) await page.getByRole('heading', { name: '麻将游戏大厅' }).waitFor({ timeout: 15000 }) log(`logged in ${player.username}`) } async function createRoom(page) { const roomName = `manual-${Date.now()}` log(`create room ${roomName}`) await page.getByRole('button', { name: '创建房间' }).click() await page.getByRole('textbox', { name: '房间名' }).fill(roomName) await page.getByRole('button', { name: '创建', exact: true }).click() const roomText = await page.getByText(/房间ID:/).textContent() const roomId = roomText?.replace('房间ID:', '').trim() if (!roomId) { throw new Error('Failed to read room id') } await Promise.all([ page.waitForURL(`**/game/chengdu/${roomId}*`, { timeout: 15000 }), page.getByRole('button', { name: '进入房间' }).click(), ]) log(`owner entered room ${roomId}`) return { roomId, roomName } } async function joinRoom(page, roomId, username) { log(`join room ${roomId} as ${username}`) await page.goto(`${baseUrl}/hall`, { waitUntil: 'domcontentloaded' }) await page.getByRole('textbox', { name: '输入 room_id' }).fill(roomId) await Promise.all([ page.waitForURL(`**/game/chengdu/${roomId}*`, { timeout: 15000 }), page.getByRole('button', { name: '加入' }).click(), ]) log(`joined room ${roomId} as ${username}`) } async function snapshotPage(session) { const bodyText = ((await session.page.locator('body').textContent()) ?? '').replace(/\s+/g, ' ').trim() return { username: session.username, loginId: session.loginId, url: session.page.url(), started: bodyText.includes('对局中') || bodyText.includes('牌局进行中'), bodyPreview: bodyText.slice(0, 240), } } async function main() { await fs.mkdir(runtimeDir, { recursive: true }) log(`runtimeDir ${runtimeDir}`) const sessions = [] for (const player of players) { sessions.push(await launchPlayer(player)) } try { for (const session of sessions) { await login(session.page, session) } const owner = sessions.find((session) => session.owner) if (!owner) { throw new Error('Owner session missing') } const { roomId } = await createRoom(owner.page) log(`room ready ${roomId}`) for (const session of sessions) { if (!session.owner) { await joinRoom(session.page, roomId, session.username) } } await new Promise((resolve) => setTimeout(resolve, 8000)) const playersSnapshot = [] for (const session of sessions) { await session.page.bringToFront() await new Promise((resolve) => setTimeout(resolve, 2000)) let snapshot = await snapshotPage(session) if (!snapshot.started) { log(`focus retry for ${session.username}`) await session.page.bringToFront() await new Promise((resolve) => setTimeout(resolve, 3000)) snapshot = await snapshotPage(session) } playersSnapshot.push(snapshot) } console.log(JSON.stringify({ roomId, roomUrl: `${baseUrl}/game/chengdu/${roomId}`, players: playersSnapshot, }, null, 2)) if (process.env.KEEP_ALIVE === '1') { log('setup finished; keeping browsers alive for manual testing') await new Promise(() => {}) } for (const session of sessions) { await session.context.close() } } catch (error) { console.error(error) if (process.env.KEEP_ALIVE !== '1') { for (const session of sessions) { try { await session.context.close() } catch {} } } throw error } } await main()