This commit is contained in:
2026-03-24 15:25:40 +08:00
parent 292a4181ce
commit 58fe43607a
7 changed files with 757 additions and 9 deletions

View File

@@ -0,0 +1,183 @@
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.getByText(`用户名:${player.username}`).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')
}
return { roomId, roomName }
}
async function ownerEnterRoom(page, roomId) {
log(`owner enter room ${roomId}`)
await Promise.all([
page.waitForURL(`**/game/chengdu/${roomId}*`, { timeout: 15000 }),
page.getByRole('button', { name: '进入房间' }).click(),
])
log(`owner entered room ${roomId}`)
}
async function ownerStartGame(page) {
log('owner start game')
const startButton = page.getByRole('button', { name: '开始游戏' })
await startButton.waitFor({ timeout: 15000 })
await startButton.click()
log('owner clicked start game')
}
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 ownerEnterRoom(owner.page, roomId)
await new Promise((resolve) => setTimeout(resolve, 3000))
await ownerStartGame(owner.page)
await new Promise((resolve) => setTimeout(resolve, 8000))
const playersSnapshot = []
for (const session of sessions) {
let snapshot = await snapshotPage(session)
if (!snapshot.started) {
log(`reload game page for ${session.username}`)
await session.page.reload({ waitUntil: 'domcontentloaded' })
await new Promise((resolve) => setTimeout(resolve, 3000))
snapshot = await snapshotPage(session)
}
playersSnapshot.push(snapshot)
await session.page.bringToFront()
}
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()