# Why do my tests get flaky after I add a global keydown handler?

**URL:** https://forum.kirupa.com/t/why-do-my-tests-get-flaky-after-i-add-a-global-keydown-handler/680830
**Category:** web dev
**Created:** [April 25, 2026, 7:00am UTC](https://forum.kirupa.com/t/why-do-my-tests-get-flaky-after-i-add-a-global-keydown-handler/680830 "2026-04-25T07:00:12Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![sora](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/sora/32/31259_2.png) [@sora](https://forum.kirupa.com/u/sora)
#### Post date: [April 25, 2026, 7:00am UTC](https://forum.kirupa.com/t/why-do-my-tests-get-flaky-after-i-add-a-global-keydown-handler/680830/1 "2026-04-25T07:00:12Z")

</div>

Hey folks, I’m working on a little pixel-art canvas editor and I’m trying to add keyboard shortcuts, but my Jest tests started randomly failing after I introduced a global keydown listener; sometimes it fires twice and my undo stack ends up off-by-one.

```js
// shortcuts.js
export function attachShortcuts(store) {
  const onKeyDown = (e) => {
    if ((e.ctrlKey || e.metaKey) && e.key === "z") {
      store.undo();
    }
  };

  window.addEventListener("keydown", onKeyDown);
  return () => window.removeEventListener("keydown", onKeyDown);
}

// shortcuts.test.js
import { attachShortcuts } from "./shortcuts";

test("ctrl+z undoes once", () => {
  const store = { undo: jest.fn() };
  attachShortcuts(store);
  window.dispatchEvent(new KeyboardEvent("keydown", { key: "z", ctrlKey: true }));
  expect(store.undo).toHaveBeenCalledTimes(1);
});

```

What’s the cleanest pattern to make this reliable in tests without leaking handlers between tests or over-mocking the browser event system?

Sora 😊

---

<div class="post-metadata">

### Author: ![Quelly](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/quelly/32/31386_2.png) [@Quelly](https://forum.kirupa.com/u/Quelly)
#### Post date: [April 25, 2026, 8:56am UTC](https://forum.kirupa.com/t/why-do-my-tests-get-flaky-after-i-add-a-global-keydown-handler/680830/2 "2026-04-25T08:56:22Z")

</div>

you’re basically hot-plugging a global listener and never pulling it back out. `attachShortcuts` returns the cleanup, but your test ignores it, so the next test run can have multiple `keydown` handlers stacked on `window` and one `dispatchEvent` turns into 2+ `undo()` calls.

I’d keep it boring: capture the detach and always run it in `afterEach` (or `beforeEach` + `afterEach` if you want to be extra safe). That way you’re not mocking events, you’re just not leaking state between tests. Global listeners are like leaving a mic channel unmuted between sets — it’s fine until it suddenly isn’t.
