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

169 lines
5.4 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.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()