Run the browser-dependent unit tests in a DOM-capable test environment
Motivation
Many unit tests — the map-engine adapters (Leaflet and deck.gl), the
map-engine registry, and the panel manager — do not actually run. Every one of
these specs errors while loading, before a single assertion executes, so the
suite reports them as failures and they provide zero protection today even
though the tests are written and look comprehensive (well over 200 cases).
This was invisible for a long time because the test job failed earlier, during
dependency install, and never reached the tests at all. Now that install is
fixed, the test step runs and surfaces this second, pre-existing layer of
breakage. The same specs fail on a developer's machine and in CI, so npm test
is red for everyone and a green-looking suite would be misleading.
The root cause is environmental, not a product bug: these specs exercise code
that expects a browser (a window, a document, browser element types), but the
unit suite runs in a plain Node process with no browser environment. CI compounds
it by running on an older Node than the project officially supports.
How it should work
- Running the unit suite — locally and in CI — executes all unit specs to
completion, with no load/import errors.
- The browser-dependent specs (map-engine adapters including deck.gl, the engine
registry, and the panel manager) pass.
- CI runs the unit suite on the Node version the project officially supports.
- A developer can run the unit suite, and a green result honestly means the
covered code works — the browser-dependent tests are actually enforced, not
silently skipped.
- The end-to-end suite is unaffected and continues to run as before.
Done when
Out of scope
- Writing new tests or changing what the existing tests assert — this is purely
about making the already-written tests run.
- Any rework of the end-to-end suite.
- The separate lean "served as a live server" gating gap (the deferred two-axis
/ capability-table work) — unrelated to the test environment.
Draft implementation plan — written as of 42b9e0a on 2026-06-16. Rough guide; re-verify against latest code.
Current behavior
Unit specs run through Playwright's test runner (playwright test tests/unit) in
a Node worker with no DOM. Nine specs fail at import:
tests/unit/LeafletAdapter.spec.js
tests/unit/deckGLAdapter.spec.js
tests/unit/deckGLHelpers.spec.js
tests/unit/mapEngineRegistry.spec.js
tests/unit/panelManager/panelManager.{layout,queries,registration,stateManagement,toolManagement}.spec.js
Two stacked causes:
- No DOM at import. These specs import browser-coupled modules (the Leaflet/
deck.gl adapters; PanelManager_ → TimeControl) that read window / screen
/ HTMLAnchorElement at module-load time. The repo's existing "shim window
in beforeEach" pattern is too late — the failure happens during import.
- Node can't
require() ESM. Those modules transitively require()
ESM-only packages (@mapbox/tiny-sdf via deck.gl, d3-time-format via
TimeControl). CI runs Node 18 (.github/workflows/playwright-tests.yml,
node-version: "18"), which throws ERR_REQUIRE_ESM — even though AGENTS.md
states the project requires Node 20+.
The split (verified by running locally on Node 22 vs CI on Node 18):
deckGLHelpers fails only on the ESM-require issue — it passes once Node is
20+. The other eight need a DOM regardless of Node version.
Where the change lands & rough plan
Move the unit specs to a DOM-capable runner instead of trying to bolt a DOM onto
Playwright's runner. Vitest with environment: 'jsdom' is verified to work
on a throwaway probe: deckGLAdapter's 28 tests all pass under it (no live WebGL
is needed — the adapter tests drive _viewState and the layer registry), and
panelManager.layout clears the window/ESM blockers under jsdom.
Rough steps:
- Add
vitest + jsdom as dev dependencies.
- Add a
vitest.config with test.environment = 'jsdom' covering tests/unit.
- Swap the unit specs' test import from
@playwright/test to vitest (the
test/expect APIs are compatible, so only the import line changes).
- Add a small Vitest setup file to stub the few remaining browser globals — the
probe showed panelManager still needs one (a Tooltip-providing library
referenced at import); identify and stub those.
- Keep Playwright for
tests/e2e; point the CI "unit" step at Vitest.
- Bump the CI workflow Node from 18 → 20.
⚠️ Gotcha: do not try to give Playwright's own runner a DOM via
NODE_OPTIONS=--require <jsdom-setup>. It triggers
ERR_METHOD_NOT_IMPLEMENTED: resolveSync — Playwright's ESM loader conflicts
with require()-ing ESM under a preload. A separate runner (Vitest) is the
path; patching Playwright is a dead end.
⚠️ Gotcha: the specs import .ts source files directly, so the runner must
transpile TypeScript on the fly. Vitest does this natively; a plain Jest setup
would need extra config.
References
.github/workflows/playwright-tests.yml — node-version: "18", npx playwright test tests/unit
playwright.config.js — current unit+e2e config
tests/unit/panelManager/testHelpers.js — existing (too-late) window shim pattern
src/essence/Basics/Layers_/LayerConstructors.js — let L = window.L at module load (one of the import-time window triggers)
Run the browser-dependent unit tests in a DOM-capable test environment
Motivation
Many unit tests — the map-engine adapters (Leaflet and deck.gl), the
map-engine registry, and the panel manager — do not actually run. Every one of
these specs errors while loading, before a single assertion executes, so the
suite reports them as failures and they provide zero protection today even
though the tests are written and look comprehensive (well over 200 cases).
This was invisible for a long time because the test job failed earlier, during
dependency install, and never reached the tests at all. Now that install is
fixed, the test step runs and surfaces this second, pre-existing layer of
breakage. The same specs fail on a developer's machine and in CI, so
npm testis red for everyone and a green-looking suite would be misleading.
The root cause is environmental, not a product bug: these specs exercise code
that expects a browser (a
window, a document, browser element types), but theunit suite runs in a plain Node process with no browser environment. CI compounds
it by running on an older Node than the project officially supports.
How it should work
completion, with no load/import errors.
registry, and the panel manager) pass.
covered code works — the browser-dependent tests are actually enforced, not
silently skipped.
Done when
locally and in CI.
engine registry, panel manager) execute.
Out of scope
about making the already-written tests run.
/ capability-table work) — unrelated to the test environment.
Draft implementation plan — written as of 42b9e0a on 2026-06-16. Rough guide; re-verify against latest code.
Current behavior
Unit specs run through Playwright's test runner (
playwright test tests/unit) ina Node worker with no DOM. Nine specs fail at import:
tests/unit/LeafletAdapter.spec.jstests/unit/deckGLAdapter.spec.jstests/unit/deckGLHelpers.spec.jstests/unit/mapEngineRegistry.spec.jstests/unit/panelManager/panelManager.{layout,queries,registration,stateManagement,toolManagement}.spec.jsTwo stacked causes:
deck.gl adapters;
PanelManager_→TimeControl) that readwindow/screen/
HTMLAnchorElementat module-load time. The repo's existing "shimwindowin
beforeEach" pattern is too late — the failure happens duringimport.require()ESM. Those modules transitivelyrequire()ESM-only packages (
@mapbox/tiny-sdfvia deck.gl,d3-time-formatviaTimeControl). CI runs Node 18 (.github/workflows/playwright-tests.yml,node-version: "18"), which throwsERR_REQUIRE_ESM— even though AGENTS.mdstates the project requires Node 20+.
The split (verified by running locally on Node 22 vs CI on Node 18):
deckGLHelpersfails only on the ESM-require issue — it passes once Node is20+. The other eight need a DOM regardless of Node version.
Where the change lands & rough plan
Move the unit specs to a DOM-capable runner instead of trying to bolt a DOM onto
Playwright's runner. Vitest with
environment: 'jsdom'is verified to workon a throwaway probe:
deckGLAdapter's 28 tests all pass under it (no live WebGLis needed — the adapter tests drive
_viewStateand the layer registry), andpanelManager.layoutclears thewindow/ESM blockers under jsdom.Rough steps:
vitest+jsdomas dev dependencies.vitest.configwithtest.environment = 'jsdom'coveringtests/unit.@playwright/testtovitest(thetest/expectAPIs are compatible, so only the import line changes).probe showed
panelManagerstill needs one (aTooltip-providing libraryreferenced at import); identify and stub those.
tests/e2e; point the CI "unit" step at Vitest.References
.github/workflows/playwright-tests.yml—node-version: "18",npx playwright test tests/unitplaywright.config.js— current unit+e2e configtests/unit/panelManager/testHelpers.js— existing (too-late)windowshim patternsrc/essence/Basics/Layers_/LayerConstructors.js—let L = window.Lat module load (one of the import-timewindowtriggers)