Files
mahjong-web/scripts/open-four-players.mjs
2026-03-24 15:25:40 +08:00

184 lines
5.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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()