The tea shop's till runs in a browser, and staff need to know when the connection drops, because orders can't be sent. Build App: a <p role="status"> that says Online or Offline.
The answer comes from navigator.onLine. The browser fires an online or offline event on window when it changes. Treat the events only as a sign that something changed, and read navigator.onLine for the answer.
Use useSyncExternalStore. Subscribe to both events once, not again on every render, and stop listening when App leaves the page.
In the tests, the connection is faked by changing what navigator.onLine returns and then firing the event on window.
<App />
// renders, while the connection is down:
<p role="status">Offline</p>
Object.defineProperty(navigator, "onLine", { configurable: true, get: () => true });
render(<App />);
expect(screen.getByRole("status").textContent).toBe("Online");
Object.defineProperty(navigator, "onLine", { configurable: true, get: () => false });
render(<App />);
expect(screen.getByRole("status").textContent).toBe("Offline");
let online = true;
Object.defineProperty(navigator, "onLine", { configurable: true, get: () => online });
render(<App />);
online = false;
fireEvent(window, new Event("offline"));
expect(screen.getByRole("status").textContent).toBe("Offline");
let online = false;
Object.defineProperty(navigator, "onLine", { configurable: true, get: () => online });
render(<App />);
online = true;
fireEvent(window, new Event("online"));
expect(screen.getByRole("status").textContent).toBe("Online");
online = false;
fireEvent(window, new Event("offline"));
expect(screen.getByRole("status").textContent).toBe("Offline");
let online = false;
Object.defineProperty(navigator, "onLine", { configurable: true, get: () => online });
render(<App />);
fireEvent(window, new Event("online"));
expect(screen.getByRole("status").textContent).toBe("Offline");
const added = [];
const add = window.addEventListener;
window.addEventListener = function (type, ...rest) {
added.push(type);
return add.call(this, type, ...rest);
};
const { rerender } = render(<App />);
rerender(<App />);
rerender(<App />);
rerender(<App />);
expect(added.filter((type) => type === "online")).toHaveLength(1);
expect(added.filter((type) => type === "offline")).toHaveLength(1);
const live = { online: 0, offline: 0 };
const add = window.addEventListener;
const remove = window.removeEventListener;
window.addEventListener = function (type, ...rest) {
if (type in live) live[type]++;
return add.call(this, type, ...rest);
};
window.removeEventListener = function (type, ...rest) {
if (type in live) live[type]--;
return remove.call(this, type, ...rest);
};
const { unmount } = render(<App />);
expect(live).toEqual({ online: 1, offline: 1 });
unmount();
expect(live).toEqual({ online: 0, offline: 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 Online status. 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.