Build a Tic-Tac-Toe Game - Build a Tic-Tac-Toe Game

Tell us what’s happening:

I have finished the user stories of the tic-tac-toe challenge in the new fullstack courses but can’t get the automated tests to pass.

  • My event handler returns immediately if an unavailable square is clicked and there is no state change/rerender yet test 8 fails.
  • There is a message in my component indicating the winner (or draw), yet tests 10 and 11 fail.
  • The event handler returns immediately if the game ended and there is no state change/rerender yet test 9 fails.
  • The state toggles the “active player” between X and O meaning that those symbols are entered alternately, yet test 7 fails.

I am used to sometimes rewriting correct code to see how the tests respond but with this challenge I really can’t tell what is actually tested. If the test condition is “no change”, there must be some deeper misalignment between my approach to the challenge an the assumptions by the tests. Taking a very close look at the example project also didn’t help.

  • Test 7: All subsequent clicks of a button.square element should alternate between displaying X and O within the element.
  • Test 8: Clicking on an already used button.square element should result in no change.
  • Test 9: Clicking on a button.square element after the game has ended should result in no change.
  • Test 10: The game should display a message indicating the winner to be X or O.
  • Test 11: The game should display a message indicating a draw.

I know there are other tic-tac-toe related posts but most of them are from other courses and I’m not having issues with the challenge itself, but with the validation, so I figured a new post in the forum is justified.

Your code so far

/* file: index.jsx */
const { useState } = React;

const winning_combinations = [
  [0,1,2],[3,4,5],[6,7,8],[0,3,6],
  [1,4,7],[2,5,8],[0,4,8],[2,4,6]];

export function Board() {
  const [state, setState] = useState({
    selections: Array(9).fill(null),
    activePlayer: "X"
  });
  const [msg, setMsg] = useState("");
  const HandleClick = (key) => {
    if (state.selections[key] || msg !== "") {
      return /* not a valid key or game ended */
    }
    setState(s => {
      const cp = [...s.selections];
      cp[key] = s.activePlayer;
      const draw = cp.every(x => x !== null);
      const winner = winning_combinations.some(
        combo => combo.every(
          key => cp[key] === s.activePlayer));
      if (winner) {
        setMsg("Winner: " + s.activePlayer);
      } else if (draw) {
        setMsg("It's a Draw");
      }
      return {
        activePlayer: s.activePlayer === "X" ? "O" : "X",
        selections: cp
      };
    })
  }
  const reset = () => {
    setState({
      selections: Array(9).fill(null),
      activePlayer: "X"
    });
    setMsg("");
  }
  return <>
    <h1>Tic Tac Toe</h1>
    <div className="msg status">{msg}</div>
    <div className="squares">
      {state.selections.map((x, i) =>
        <button className="square" onClick={
          () => HandleClick(i)} key={i}>{x}</button>
      )}
    </div>
    <button type="reset" id="reset"
      onClick={reset}>Reset</button>
  </>;
}
<!-- file: index.html -->
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>Tic-Tac-Toe</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.5/babel.min.js"></script>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      src="index.jsx"
    ></script>
    <link rel="stylesheet" href="styles.css" />
</head>

<body>
    <div id="root"></div>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      data-presets="react"
      data-type="module"
    >
      import { Board } from './index.jsx';
      ReactDOM.createRoot(document.getElementById('root')).render(<Board />);
    </script>
</body>

</html>
/* file: styles.css */
.squares {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  gap: 1rem;
  width: 11rem;
  height: 11rem;
}

.square {
  cursor: pointer;
  border-radius: 5px;
  border: 1px solid;
}

button:hover {
  outline: 2px solid orange;
}

body {
  background: #333;
  color: #ddd;
  font-family: Arial, sans-serif;
}

button[type="reset"] {
  width: 11rem;
  margin-top: 1rem;
  border-radius: 5px;
  padding: .5rem;
  font-size: 1.5rem;
}

.msg {
  margin-bottom: 1rem;
  font-size: 1.5rem;
}

Your browser information:

User Agent is: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36

Challenge Information:

Build a Tic-Tac-Toe Game - Build a Tic-Tac-Toe Game

1 Like

Edit: I just changed the state to also include the winner/draw message because calling setMsg() within setState() seemed like something that might trip up automated tests, but it didn’t help.

const [state, setState] = useState({
  selections: Array(9).fill(null),
  activePlayer: "X",
  msg: ""
});

test cases (7-11) seems to me are also covered! it could be a glitch, have you tried in other browsers? or tried after disabling any dark theme alike extensions?

happy coding :slight_smile:

2 Likes

Hi! I thought I was the only one facing this kind of test instability…

Yesterday, I spent a lot of time testing various implementations — all of which work fine manually. The game behaves as expected: turns alternate correctly, the board prevents moves after the game ends, and both win and draw conditions are displayed properly.

However, tests 7–11 keep failing regardless. I double-checked everything, but the results remain the same.

Just in case it’s useful, here’s my user agent:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36
Note: I’m on Windows 11, but the user-agent string still shows NT 10.0 (which is expected).

If there’s anything else I can provide to help debug this — let me know!

Thanks!

Thanks! I just tested on a different browser (firefox 139.0.1) and all the tests passed now. Now I feel a bit silly for trying so many different approaches yesterday :laughing:

2 Likes

Same here!
I was using Chrome (137.0.0.0) on Windows 11, and the last five tests were failing no matter what I tried — even though everything worked perfectly when tested manually.
Switched to Firefox 139.0 and… boom — all tests passed on the first try. :exploding_head:
Seems like there’s definitely some glitch with the test runner in Chromium-based browsers. Thanks for confirming!

dont be, more practices, various approaches means you are learning it as solidly as possible, kudos :clap:

happy coding :slight_smile: