#!/usr/bin/env python3 """ 斗地主 Headless 浏览器测试 - 最终版 简化流程,专注验证AI对战功能 """ import asyncio import sys import os sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from playwright.async_api import async_playwright SERVER_URL = "http://129.211.173.87:8900" async def run_test(): print("=" * 70) print(" 🎮 斗地主 Headless 测试 - 三方对战") print("=" * 70) async with async_playwright() as p: browser = await p.chromium.launch(headless=True) page = await browser.new_page(viewport={'width': 1280, 'height': 900}) try: # 访问并连接 await page.goto(f"{SERVER_URL}/test_client.html") await asyncio.sleep(1) print("\n📡 连接服务器...") await page.fill('input[placeholder*="服务器地址"]', SERVER_URL) # 设置监听 await page.evaluate(""" window.testLog = []; window.currentGame = null; window.myPlayerId = null; const waitSocket = setInterval(() => { if (typeof socket !== 'undefined') { clearInterval(waitSocket); socket.on('connect', () => { window.myPlayerId = socket.id; }); socket.on('room_created', (data) => { window.testLog.push('ROOM:' + data.room.code); window.roomData = data.room; }); socket.on('game_started', (data) => { window.testLog.push('GAME_STARTED'); window.currentGame = data.room.game; }); socket.on('state_update', (data) => { const action = data.action; const pid = data.player_id ? data.player_id.slice(0,8) : 'N/A'; const name = data.game_state?.players?.[data.player_id]?.name || pid; window.testLog.push(`ACTION:${name}:${action}`); window.currentGame = data.game_state; }); socket.on('game_ended', (data) => { window.testLog.push('ENDED:' + data.winner); }); } }, 100); """) await page.click('button:has-text("连接")') await asyncio.sleep(1) # 创建房间 await page.fill('input[placeholder*="玩家名称"]', 'Headless玩家') await page.evaluate(""" socket.emit('create_room', { game_type: 'doudizhu', player_name: 'Headless玩家', ai_config: {ai_count: 2, ai_types: ['rule', 'deepseek']} }); """) await asyncio.sleep(2) # 获取房间信息 room_data = await page.evaluate("() => window.roomData") my_id = await page.evaluate("() => window.myPlayerId") if not room_data: print("❌ 房间创建失败") return print(f"✅ 房间: {room_data.get('code')}") players = room_data.get('players', []) if isinstance(players, dict): players = list(players.values()) for p in players: icon = "🤖" if p.get('is_ai') else "👤" pid = p.get('id', 'N/A') print(f" {icon} {p.get('name')} ({pid[:8]})") print(f" 我的ID: {my_id[:8] if my_id else 'N/A'}") # 准备并开始 print("\n🚀 开始游戏...") await page.click('button:has-text("准备")') await asyncio.sleep(0.5) await page.click('button:has-text("开始游戏")') await asyncio.sleep(2) print("\n🎲 游戏进行中...") print("-" * 50) turn_count = 0 game_ended = False for i in range(100): # 100秒 # 获取日志 logs = await page.evaluate("() => { const l = window.testLog; window.testLog = []; return l; }") for log in logs: if log.startswith("ACTION:"): parts = log.split(":") if len(parts) >= 3: turn_count += 1 print(f"{turn_count:2d}. {parts[1][:10]}: {parts[2]}") elif log.startswith("ENDED:"): print(f"\n🏆 游戏结束! 获胜者: {log[6:14]}") game_ended = True if game_ended: break # 检查当前回合并执行动作 game = await page.evaluate("() => window.currentGame") if game: current = game.get('current_turn_player_id') or game.get('current_turn') doudizhu = game.get('doudizhu', {}) phase = doudizhu.get('phase', '') if current == my_id: if phase == 'calling': print(" -> Headless叫地主") await page.evaluate("socket.emit('game_action', {action:'call',data:{want:true}})") await asyncio.sleep(1) elif phase == 'playing': # 简单策略:尝试出牌,失败就pass print(" -> Headless出牌") await page.evaluate(""" const cards = window.currentGame?.player_cards?.[socket.id] || []; if (cards.length > 0) { socket.emit('game_action', {action:'play',data:{card_ids:[cards[0].id]}}); } else { socket.emit('game_action', {action:'pass',data:{}}); } """) await asyncio.sleep(1) await asyncio.sleep(0.5) if not game_ended: print(f"\n⏱️ 超时 - 进行了 {turn_count} 步") await page.screenshot(path='/tmp/doudizhu_final.png', full_page=True) print(f"\n📸 截图: /tmp/doudizhu_final.png") await browser.close() print("\n✅ 测试完成!") except Exception as e: print(f"\n❌ 错误: {e}") import traceback traceback.print_exc() await browser.close() if __name__ == '__main__': asyncio.run(run_test())