Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions examples/typescript-jest/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ const cols = 4;
const App = ({ className }: Props) => {
const [difficulty, setDifficulty] = useState<Difficulty>(Difficulty.EASY);

const { score, incrementScore, activeTile, timeRemaining } = useGameManager(
rows,
cols,
difficulty,
);
const {
score,
incrementScore,
activeTile,
timeRemaining,
isPaused,
toggleTimer,
} = useGameManager(rows, cols, difficulty);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is not covered by any tests.


return (
<main className={className}>
Expand All @@ -31,14 +34,19 @@ const App = ({ className }: Props) => {
timeRemaining={timeRemaining}
difficulty={difficulty}
setDifficulty={setDifficulty}
isPaused={isPaused}
toggleTimer={toggleTimer}
/>
<Board
rows={rows}
cols={cols}
onTilePressed={(row: number, col: number) =>
row === activeTile?.row && col === activeTile?.col && incrementScore()
!isPaused &&

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of these branches are covered by tests.

row === activeTile?.row &&
col === activeTile?.col &&
incrementScore()
}
activeTile={activeTile}
activeTile={!isPaused ? activeTile : undefined}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of these branches are covered by tests.

timeRemaining={timeRemaining}
/>
</main>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
interface Props {
onClick: () => void;
isPaused: boolean;
}

export const PauseButton = ({ onClick, isPaused }: Props) => (
<button onClick={onClick}>{isPaused ? "Resume" : "Pause"}</button>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { fireEvent, render, screen } from "@testing-library/react";
import { PauseButton } from "../PauseButton.tsx";

describe("PauseButton", () => {
it("should render a pause button when not paused", () => {
render(<PauseButton onClick={jest.fn()} isPaused={false} />);

const button = screen.getByRole("button");
expect(button).toHaveTextContent("Pause");
});

it("should render a resume button when paused", () => {
render(<PauseButton onClick={jest.fn()} isPaused={true} />);

const button = screen.getByRole("button");
expect(button).toHaveTextContent("Resume");
});

it("should pause game when toggled", () => {
const onClick = jest.fn();

render(<PauseButton onClick={onClick} isPaused={false} />);

const button = screen.getByRole("button");
fireEvent.click(button);
fireEvent.click(button);

expect(onClick).toHaveBeenCalledTimes(2);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { PauseButton } from "./PauseButton.tsx";
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { DifficultySelector } from "../DifficultySelector";
import { Difficulty } from "../../hooks/useGameManager.ts";
import { PauseButton } from "../PauseButton";

interface Props {
className?: string;
score: number;
timeRemaining: number;
difficulty: Difficulty;
setDifficulty: (difficulty: Difficulty) => void;
isPaused: boolean;
toggleTimer: () => void;
}

export const StatsCard = ({
Expand All @@ -15,6 +18,8 @@ export const StatsCard = ({
timeRemaining,
difficulty,
setDifficulty,
isPaused,
toggleTimer,
}: Props) => (
<aside className={className}>
<div>
Expand All @@ -24,7 +29,7 @@ export const StatsCard = ({
setDifficulty={setDifficulty}
difficulty={difficulty}
/>
<PauseButton onClick={toggleTimer} isPaused={isPaused} />
</div>
<div></div>
</aside>
);
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ describe("StatsCard", () => {
difficulty={Difficulty.HARD}
timeRemaining={1000}
setDifficulty={() => {}}
isPaused
toggleTimer={() => {}}
/>,
);

Expand All @@ -23,6 +25,8 @@ describe("StatsCard", () => {
difficulty={Difficulty.HARD}
timeRemaining={1000}
setDifficulty={() => {}}
isPaused
toggleTimer={() => {}}
/>,
);

Expand All @@ -36,6 +40,8 @@ describe("StatsCard", () => {
difficulty={Difficulty.HARD}
timeRemaining={1000}
setDifficulty={() => {}}
isPaused
toggleTimer={() => {}}
/>,
);

Expand Down
16 changes: 14 additions & 2 deletions examples/typescript-jest/src/hooks/useGameManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export type GameManager = {
incrementScore: () => void;
activeTile?: ActiveTile;
timeRemaining: number;
isPaused: boolean;
toggleTimer: () => void;
};

export type ActiveTile = { row: number; col: number };
Expand Down Expand Up @@ -40,12 +42,22 @@ export const useGameManager = (
resetTimer();
};

const { timeRemaining, resetTimer } = useTimer(nextTile, tileDuration);
const { timeRemaining, resetTimer, isPaused, toggleTimer } = useTimer(
nextTile,
tileDuration,
);

const incrementScore = () => {
setScore((prev) => prev + 1);
nextTile();
};

return { score, incrementScore, timeRemaining, activeTile };
return {
score,
incrementScore,
timeRemaining,
activeTile,
isPaused,
toggleTimer,
};
};
16 changes: 14 additions & 2 deletions examples/typescript-jest/src/hooks/useTimer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import { useCallback, useEffect, useState } from "react";
*/
export const useTimer = (onFinish: () => void, time: number = 4000) => {
const [timeRemaining, setTimeRemaining] = useState(time);
const [isPaused, setIsPaused] = useState(false);

const toggleTimer = useCallback(
() => setIsPaused((prev) => !prev),
[setIsPaused],
);

const resetTimer = useCallback(
() => setTimeRemaining(time),
Expand All @@ -13,18 +19,24 @@ export const useTimer = (onFinish: () => void, time: number = 4000) => {

useEffect(() => {
const timer = setInterval(() => {
if (isPaused) {
// Don't decrement the time remaining if the timer is paused.
return;
}

setTimeRemaining((prev) => prev - 1);
}, 1);

if (timeRemaining <= 0) {
// The timers elapsed, so we call the onFinish callback and reset the timer.
onFinish();
resetTimer();
}

return () => {
clearInterval(timer);
};
}, [timeRemaining, onFinish, resetTimer, setTimeRemaining]);
}, [timeRemaining, onFinish, resetTimer, setTimeRemaining, isPaused]);

return { timeRemaining, resetTimer };
return { timeRemaining, resetTimer, isPaused, toggleTimer };
};