The tea shop's counter has a small light panel for children to play with while their parents order. Build GridLights, the default export, with no props: a 3 by 3 grid of light cells with an empty space in the middle, so 8 cells in all.
Each cell is a button with the accessible name Row 1, column 1 through Row 3, column 3 (use aria-label), skipping Row 2, column 2, which is just an empty space. A lit cell has aria-pressed="true", an unlit one aria-pressed="false". Show lit cells in a different colour too (the tests check aria-pressed, not the colour).
Clicking an unlit cell lights it. Clicking a lit cell does nothing: it stays lit. The lights stay on until all 8 are lit.
Then they turn off one at a time, in the reverse of the order they were lit: the last one lit goes off 300 ms after it was clicked, the one lit before it 300 ms after that, and so on, until all are off. While they're turning off, every cell is disabled. Once the last one is off, the cells work again and you can play another round.
If the grid leaves the page while the lights are turning off, stop: leave no timer running.
<button aria-label="Row 1, column 1" aria-pressed="true"></button>
<button aria-label="Row 1, column 2" aria-pressed="false"></button>
<button aria-label="Row 1, column 3" aria-pressed="false"></button>
<button aria-label="Row 2, column 1" aria-pressed="false"></button>
<span></span>
<button aria-label="Row 2, column 3" aria-pressed="false"></button>
...
render(<App />);
const buttons = screen.getAllByRole("button");
expect(buttons.length).toBe(8);
for (const button of buttons) {
expect(button).toHaveAttribute("aria-pressed", "false");
expect(button).toBeEnabled();
}
expect(screen.queryByRole("button", { name: "Row 2, column 2" })).not.toBeInTheDocument();
expect(screen.getByRole("button", { name: "Row 2, column 3" })).toBeInTheDocument();
const cell = (row, column) => screen.getByRole("button", { name: "Row " + row + ", column " + column });
render(<App />);
await user.click(cell(1, 1));
expect(cell(1, 1)).toHaveAttribute("aria-pressed", "true");
expect(cell(1, 2)).toHaveAttribute("aria-pressed", "false");
await user.click(cell(3, 2));
expect(cell(3, 2)).toHaveAttribute("aria-pressed", "true");
const cell = (row, column) => screen.getByRole("button", { name: "Row " + row + ", column " + column });
render(<App />);
await user.click(cell(1, 1));
await user.click(cell(1, 1));
expect(cell(1, 1)).toHaveAttribute("aria-pressed", "true");
const cell = (row, column) => screen.getByRole("button", { name: "Row " + row + ", column " + column });
const clock = useFakeTimers();
render(<App />);
const seven = [[1, 1], [1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]];
for (const [row, column] of seven) await user.click(cell(row, column));
await clock.advance(5000);
for (const [row, column] of seven) expect(cell(row, column)).toHaveAttribute("aria-pressed", "true");
expect(cell(3, 3)).toHaveAttribute("aria-pressed", "false");
const cell = (row, column) => screen.getByRole("button", { name: "Row " + row + ", column " + column });
const clock = useFakeTimers();
render(<App />);
const order = [[3, 3], [1, 1], [2, 1], [1, 3], [3, 2], [1, 2], [2, 3], [3, 1]];
for (const [row, column] of order) await user.click(cell(row, column));
await clock.advance(299);
for (const [row, column] of order) expect(cell(row, column)).toHaveAttribute("aria-pressed", "true");
await clock.advance(1);
for (let off = 1; off <= 8; off++) {
order.forEach(([row, column], index) => {
expect(cell(row, column)).toHaveAttribute("aria-pressed", index < 8 - off ? "true" : "false");
});
if (off < 8) await clock.advance(300);
}
const cell = (row, column) => screen.getByRole("button", { name: "Row " + row + ", column " + column });
const clock = useFakeTimers();
render(<App />);
const order = [[1, 1], [1, 2], [1, 3], [2, 3], [3, 3], [3, 2], [3, 1], [2, 1]];
for (const [row, column] of order) await user.click(cell(row, column));
for (const button of screen.getAllByRole("button")) expect(button).toBeDisabled();
await clock.advance(300);
expect(cell(2, 1)).toHaveAttribute("aria-pressed", "false");
expect(cell(2, 1)).toBeDisabled();
await user.click(cell(2, 1));
expect(cell(2, 1)).toHaveAttribute("aria-pressed", "false");
await clock.advance(300);
expect(cell(3, 1)).toHaveAttribute("aria-pressed", "false");
expect(cell(2, 1)).toHaveAttribute("aria-pressed", "false");
const cell = (row, column) => screen.getByRole("button", { name: "Row " + row + ", column " + column });
const clock = useFakeTimers();
render(<App />);
const order = [[1, 1], [1, 2], [1, 3], [2, 3], [3, 3], [3, 2], [3, 1], [2, 1]];
for (const [row, column] of order) await user.click(cell(row, column));
await clock.advance(2400);
for (const button of screen.getAllByRole("button")) {
expect(button).toHaveAttribute("aria-pressed", "false");
expect(button).toBeEnabled();
}
await user.click(cell(2, 3));
await clock.advance(1000);
expect(cell(2, 3)).toHaveAttribute("aria-pressed", "true");
for (const [row, column] of order) await user.click(cell(row, column));
await clock.advance(300);
expect(cell(2, 1)).toHaveAttribute("aria-pressed", "false");
expect(cell(2, 3)).toHaveAttribute("aria-pressed", "true");
const cell = (row, column) => screen.getByRole("button", { name: "Row " + row + ", column " + column });
const clock = useFakeTimers();
const { unmount } = render(<App />);
for (const [row, column] of [[1, 1], [1, 2], [1, 3], [2, 3], [3, 3], [3, 2], [3, 1], [2, 1]]) {
await user.click(cell(row, column));
}
await clock.advance(600);
unmount();
expect(clock.pending()).toBe(0);
Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.
Ctrl + Enter runs the tests (⌘ + Enter on a Mac).
I'm here to help with Grid lights. I give hints, never the solution, so you get to solve it yourself. Ask for a hint, select code to ask about it, or press Ask Tuto why on a failing test.
Your first 3 answers need no account. for free to keep asking.