mirror of
https://github.com/GoodStartLabs/AI_Diplomacy.git
synced 2026-04-22 16:49:15 +00:00
WIP: Majority converted to event queue, continuing to work on others.
The bottom newsbar still needs conversion, as do numerous other pieces, but we're working our way there. Attempting adding some tests with Claude, but they aren't functioning yet, making them effectively useless. Continuing to iterate.
This commit is contained in:
parent
2b52a9cbf9
commit
a929bf5ee6
9 changed files with 611 additions and 32 deletions
178
ai_animation/tests/e2e/message-flow-verification.spec.ts
Normal file
178
ai_animation/tests/e2e/message-flow-verification.spec.ts
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
import { test, expect, Page } from '@playwright/test';
|
||||
import { waitForGameReady, getCurrentPhaseName, enableInstantMode, getAllChatMessages, waitForMessagesToComplete } from './test-helpers';
|
||||
|
||||
interface MessageRecord {
|
||||
content: string;
|
||||
chatWindow: string;
|
||||
phase: string;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets expected messages for current power from the browser's game data
|
||||
*/
|
||||
async function getExpectedMessagesFromBrowser(page: Page): Promise<Array<{
|
||||
sender: string;
|
||||
recipient: string;
|
||||
message: string;
|
||||
phase: string;
|
||||
}>> {
|
||||
return await page.evaluate(() => {
|
||||
const gameData = window.gameState?.gameData;
|
||||
const currentPower = window.gameState?.currentPower;
|
||||
|
||||
if (!gameData || !currentPower) return [];
|
||||
|
||||
const relevantMessages: Array<{
|
||||
sender: string;
|
||||
recipient: string;
|
||||
message: string;
|
||||
phase: string;
|
||||
}> = [];
|
||||
|
||||
gameData.phases.forEach((phase: any) => {
|
||||
if (phase.messages) {
|
||||
phase.messages.forEach((msg: any) => {
|
||||
// Apply same filtering logic as updateChatWindows()
|
||||
if (msg.sender === currentPower ||
|
||||
msg.recipient === currentPower ||
|
||||
msg.recipient === 'GLOBAL') {
|
||||
relevantMessages.push({
|
||||
sender: msg.sender,
|
||||
recipient: msg.recipient,
|
||||
message: msg.message,
|
||||
phase: phase.name
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return relevantMessages;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
test.describe('Message Flow Verification', () => {
|
||||
test('should verify basic message system functionality', async ({ page }) => {
|
||||
// This test verifies the message system works and doesn't get stuck
|
||||
await page.goto('http://localhost:5173');
|
||||
await waitForGameReady(page);
|
||||
|
||||
// Enable instant mode for faster testing
|
||||
await enableInstantMode(page);
|
||||
|
||||
// Verify game state is accessible
|
||||
const gameState = await page.evaluate(() => ({
|
||||
hasGameData: !!window.gameState?.gameData,
|
||||
currentPower: window.gameState?.currentPower,
|
||||
phaseIndex: window.gameState?.phaseIndex,
|
||||
hasEventQueue: !!window.gameState?.eventQueue
|
||||
}));
|
||||
|
||||
expect(gameState.hasGameData).toBe(true);
|
||||
expect(gameState.currentPower).toBeTruthy();
|
||||
expect(gameState.hasEventQueue).toBe(true);
|
||||
|
||||
console.log(`Game loaded with current power: ${gameState.currentPower}`);
|
||||
|
||||
// Start playback for a short time to verify message system works
|
||||
await page.click('#play-btn');
|
||||
|
||||
// Monitor for basic functionality over 10 seconds
|
||||
let messageAnimationDetected = false;
|
||||
let eventQueueActive = false;
|
||||
|
||||
for (let i = 0; i < 100; i++) { // 10 seconds in 100ms intervals
|
||||
const status = await page.evaluate(() => ({
|
||||
isAnimating: window.gameState?.messagesPlaying || false,
|
||||
hasEvents: window.gameState?.eventQueue?.pendingEvents?.length > 0 || false,
|
||||
phase: document.querySelector('#phase-display')?.textContent?.replace('Era: ', '') || ''
|
||||
}));
|
||||
|
||||
if (status.isAnimating) {
|
||||
messageAnimationDetected = true;
|
||||
}
|
||||
|
||||
if (status.hasEvents) {
|
||||
eventQueueActive = true;
|
||||
}
|
||||
|
||||
// If we've detected both, we can finish early
|
||||
if (messageAnimationDetected && eventQueueActive) {
|
||||
break;
|
||||
}
|
||||
|
||||
await page.waitForTimeout(100);
|
||||
}
|
||||
|
||||
// Stop playback
|
||||
await page.click('#play-btn');
|
||||
|
||||
// Verify basic functionality was detected
|
||||
console.log(`Message animation detected: ${messageAnimationDetected}`);
|
||||
console.log(`Event queue active: ${eventQueueActive}`);
|
||||
|
||||
// At minimum, the event queue should be active (even if no messages in first phase)
|
||||
expect(eventQueueActive).toBe(true);
|
||||
|
||||
console.log('✅ Basic message system functionality verified');
|
||||
});
|
||||
|
||||
test('should verify no simultaneous message animations', async ({ page }) => {
|
||||
await page.goto('http://localhost:5173');
|
||||
await waitForGameReady(page);
|
||||
|
||||
// Enable instant mode for faster testing
|
||||
await enableInstantMode(page);
|
||||
|
||||
let simultaneousAnimationDetected = false;
|
||||
let animationCount = 0;
|
||||
|
||||
// Start playback
|
||||
await page.click('#play-btn');
|
||||
|
||||
// Monitor animation state for overlaps
|
||||
for (let i = 0; i < 100; i++) { // 10 seconds
|
||||
const animationStatus = await page.evaluate(() => {
|
||||
// Check if multiple animation systems are active simultaneously
|
||||
const messagesPlaying = window.gameState?.messagesPlaying || false;
|
||||
const chatMessages = document.querySelectorAll('.chat-message');
|
||||
const recentlyAdded = Array.from(chatMessages).filter(msg => {
|
||||
const timeStamp = msg.dataset.timestamp;
|
||||
return timeStamp && (Date.now() - parseInt(timeStamp)) < 500; // Added in last 500ms
|
||||
});
|
||||
|
||||
return {
|
||||
messagesPlaying,
|
||||
messageCount: chatMessages.length,
|
||||
recentMessages: recentlyAdded.length
|
||||
};
|
||||
});
|
||||
|
||||
if (animationStatus.messagesPlaying) {
|
||||
animationCount++;
|
||||
|
||||
// Check if too many messages appear simultaneously (could indicate race condition)
|
||||
if (animationStatus.recentMessages > 3) {
|
||||
simultaneousAnimationDetected = true;
|
||||
console.warn(`Potential simultaneous animation: ${animationStatus.recentMessages} recent messages`);
|
||||
}
|
||||
}
|
||||
|
||||
await page.waitForTimeout(100);
|
||||
}
|
||||
|
||||
// Stop playback
|
||||
await page.click('#play-btn');
|
||||
|
||||
console.log(`Animation cycles detected: ${animationCount}`);
|
||||
console.log(`Simultaneous animations detected: ${simultaneousAnimationDetected}`);
|
||||
|
||||
// We should see some animations but no simultaneous ones
|
||||
expect(simultaneousAnimationDetected).toBe(false);
|
||||
|
||||
console.log('✅ No simultaneous message animations detected');
|
||||
});
|
||||
});
|
||||
|
|
@ -283,3 +283,149 @@ export async function advanceGameManually(
|
|||
|
||||
return false; // Didn't reach victory
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to wait for messages to complete animating in current phase
|
||||
*/
|
||||
export async function waitForMessagesToComplete(page: Page, timeoutMs = 10000): Promise<void> {
|
||||
const startTime = Date.now();
|
||||
|
||||
while (Date.now() - startTime < timeoutMs) {
|
||||
const isAnimating = await page.evaluate(() => window.gameState?.messagesPlaying || false);
|
||||
|
||||
if (!isAnimating) {
|
||||
return; // Messages completed
|
||||
}
|
||||
|
||||
await page.waitForTimeout(100);
|
||||
}
|
||||
|
||||
throw new Error('Timeout waiting for messages to complete animation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get current power that the player is assigned
|
||||
*/
|
||||
export async function getCurrentPower(page: Page): Promise<string | null> {
|
||||
try {
|
||||
return await page.evaluate(() => window.gameState?.currentPower || null);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to count visible chat messages across all chat windows
|
||||
*/
|
||||
export async function countVisibleChatMessages(page: Page): Promise<number> {
|
||||
try {
|
||||
return await page.evaluate(() => {
|
||||
const chatMessages = document.querySelectorAll('.chat-message');
|
||||
return chatMessages.length;
|
||||
});
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get all chat messages with their metadata
|
||||
*/
|
||||
export async function getAllChatMessages(page: Page): Promise<Array<{
|
||||
content: string;
|
||||
chatWindow: string;
|
||||
phase: string;
|
||||
}>> {
|
||||
try {
|
||||
return await page.evaluate(() => {
|
||||
const messages: Array<{
|
||||
content: string;
|
||||
chatWindow: string;
|
||||
phase: string;
|
||||
}> = [];
|
||||
|
||||
const chatMessages = document.querySelectorAll('.chat-message');
|
||||
chatMessages.forEach(messageElement => {
|
||||
const chatWindow = messageElement.closest('.chat-window');
|
||||
const chatWindowId = chatWindow?.id || 'unknown';
|
||||
|
||||
// Extract message content (excluding sender label)
|
||||
const contentSpan = messageElement.querySelector('span:not([class*="power-"])');
|
||||
const timeDiv = messageElement.querySelector('.message-time');
|
||||
|
||||
if (contentSpan && timeDiv) {
|
||||
messages.push({
|
||||
content: contentSpan.textContent || '',
|
||||
chatWindow: chatWindowId,
|
||||
phase: timeDiv.textContent || ''
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return messages;
|
||||
});
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to enable instant mode for faster testing
|
||||
*/
|
||||
export async function enableInstantMode(page: Page): Promise<void> {
|
||||
await page.evaluate(() => {
|
||||
if (window.config) {
|
||||
window.config.setInstantMode(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to check if the event queue has any pending events
|
||||
*/
|
||||
export async function hasEventQueueEvents(page: Page): Promise<boolean> {
|
||||
try {
|
||||
return await page.evaluate(() => {
|
||||
return window.gameState?.eventQueue?.pendingEvents?.length > 0 || false;
|
||||
});
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to monitor message animation state continuously
|
||||
* Returns a function to call to get the animation history
|
||||
*/
|
||||
export async function startMessageAnimationMonitoring(page: Page): Promise<() => Promise<Array<{
|
||||
timestamp: number;
|
||||
isAnimating: boolean;
|
||||
phase: string;
|
||||
messageCount: number;
|
||||
}>>> {
|
||||
// Set up monitoring in the browser context
|
||||
await page.evaluate(() => {
|
||||
window.messageAnimationHistory = [];
|
||||
|
||||
const monitor = () => {
|
||||
const isAnimating = window.gameState?.messagesPlaying || false;
|
||||
const phase = document.querySelector('#phase-display')?.textContent?.replace('Era: ', '') || '';
|
||||
const messageCount = document.querySelectorAll('.chat-message').length;
|
||||
|
||||
window.messageAnimationHistory.push({
|
||||
timestamp: Date.now(),
|
||||
isAnimating,
|
||||
phase,
|
||||
messageCount
|
||||
});
|
||||
};
|
||||
|
||||
// Monitor every 50ms
|
||||
window.messageAnimationInterval = setInterval(monitor, 50);
|
||||
});
|
||||
|
||||
// Return function to get the history
|
||||
return async () => {
|
||||
return await page.evaluate(() => window.messageAnimationHistory || []);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue