Version 2.0.0: Animation fixes, timing improvements, and E2E test suite
Animation fixes: - Fix held card positioning bug (was appearing at bottom of page) - Fix discard pile blank/white flash on turn transitions - Fix blank card at round end by skipping animations during round_over/game_over - Set card content before triggering flip animation to prevent flash - Center suit symbol on 10 cards Timing improvements: - Reduce post-discard delay from 700ms to 500ms - Reduce post-swap delay from 1800ms to 1000ms - Speed up swap flip animation from 1150ms to 550ms - Reduce CPU initial thinking delay from 150-250ms to 80-150ms - Pause now happens after swap completes (showing result) instead of before E2E test suite: - Add Playwright-based test bot that plays full games - State parser extracts game state from DOM for validation - AI brain ports decision logic for automated play - Freeze detector monitors for UI hangs - Visual validator checks CSS states - Full game, stress, and visual test specs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
71
tests/e2e/utils/timing.ts
Normal file
71
tests/e2e/utils/timing.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Animation timing constants from animation-queue.js
|
||||
* Used to wait for animations to complete before asserting state
|
||||
*/
|
||||
export const TIMING = {
|
||||
// Core animation durations (from CSS/animation-queue.js)
|
||||
flipDuration: 540,
|
||||
moveDuration: 270,
|
||||
pauseAfterFlip: 144,
|
||||
pauseAfterDiscard: 550,
|
||||
pauseBeforeNewCard: 150,
|
||||
pauseAfterSwapComplete: 400,
|
||||
pauseBetweenAnimations: 90,
|
||||
|
||||
// Derived waits for test actions
|
||||
get flipComplete() {
|
||||
return this.flipDuration + this.pauseAfterFlip + 100;
|
||||
},
|
||||
get swapComplete() {
|
||||
return this.flipDuration + this.pauseAfterFlip + this.moveDuration +
|
||||
this.pauseAfterDiscard + this.pauseBeforeNewCard +
|
||||
this.moveDuration + this.pauseAfterSwapComplete + 200;
|
||||
},
|
||||
get drawComplete() {
|
||||
return this.moveDuration + this.pauseBeforeNewCard + 100;
|
||||
},
|
||||
|
||||
// Safety margins for network/processing
|
||||
networkBuffer: 200,
|
||||
safetyMargin: 300,
|
||||
|
||||
// Longer waits
|
||||
turnTransition: 500,
|
||||
cpuThinkingMin: 400,
|
||||
cpuThinkingMax: 1200,
|
||||
roundOverDelay: 1000,
|
||||
};
|
||||
|
||||
/**
|
||||
* Wait for animation queue to drain
|
||||
*/
|
||||
export async function waitForAnimations(page: import('@playwright/test').Page, timeout = 5000): Promise<void> {
|
||||
await page.waitForFunction(
|
||||
() => {
|
||||
const game = (window as any).game;
|
||||
if (!game?.animationQueue) return true;
|
||||
return !game.animationQueue.isAnimating();
|
||||
},
|
||||
{ timeout }
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for WebSocket to be ready
|
||||
*/
|
||||
export async function waitForWebSocket(page: import('@playwright/test').Page, timeout = 5000): Promise<void> {
|
||||
await page.waitForFunction(
|
||||
() => {
|
||||
const game = (window as any).game;
|
||||
return game?.ws?.readyState === WebSocket.OPEN;
|
||||
},
|
||||
{ timeout }
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait a fixed time plus safety margin
|
||||
*/
|
||||
export function safeWait(duration: number): number {
|
||||
return duration + TIMING.safetyMargin;
|
||||
}
|
||||
Reference in New Issue
Block a user