Skip to content

Commit f0ec83e

Browse files
Copilotpethers
andauthored
fix: use useLayoutEffect for test event listener to prevent Cypress race condition
Root cause: useEffect registers the test:targetClick listener after the browser paints, creating a race where Cypress finds the target-sphere DOM element and dispatches events before the listener is ready. Fix: switch to useLayoutEffect (runs before paint) so the listener is always registered by the time any Cypress test can dispatch events. Also add cy.wait(100) after event dispatch in screenshots.cy.ts, consistent with the pattern in gameplay.cy.ts, to give React time to process state updates. Agent-Logs-Url: https://github.com/Hack23/game/sessions/cc45c339-eb55-475b-8b72-29b9fab0ce47 Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
1 parent a18c1f6 commit f0ec83e

2 files changed

Lines changed: 9 additions & 3 deletions

File tree

cypress/e2e/screenshots.cy.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ describe("Game Visual Documentation", () => {
6060
win.dispatchEvent(new CustomEvent('test:targetClick'));
6161
win.dispatchEvent(new CustomEvent('test:targetClick'));
6262
});
63-
63+
64+
// Wait for React to process the state updates (consistent with gameplay.cy.ts pattern)
65+
cy.wait(100);
66+
6467
// Verify score updated
6568
cy.get("[data-testid=score-value]").should("not.contain", "0");
6669

src/App.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Canvas } from "@react-three/fiber";
2-
import { useRef, useState, useCallback, useEffect } from "react";
2+
import { useRef, useState, useCallback, useEffect, useLayoutEffect } from "react";
33
import type { JSX } from "react";
44
import { useGameState } from "./hooks/useGameState";
55
import { useAudioManager } from "./hooks/useAudioManager";
@@ -96,7 +96,10 @@ function App(): JSX.Element {
9696
const gameStateRef = useRef(gameState);
9797
gameStateRef.current = gameState;
9898

99-
useEffect(() => {
99+
// useLayoutEffect (not useEffect) ensures the listener is registered synchronously
100+
// before the browser paints, preventing a race where Cypress finds the target-sphere
101+
// in the DOM before the test event listener is ready to receive events.
102+
useLayoutEffect(() => {
100103
const handleTestTargetClick = (): void => {
101104
const gs = gameStateRef.current;
102105
if (gs.isPlaying && gs.timeLeft > 0 && gs.targets.length > 0) {

0 commit comments

Comments
 (0)