Skip to content

Run the browser-dependent unit tests in a DOM-capable test environment #148

Description

@CarsonDavis

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

  • The unit suite runs every unit spec without import/load errors, both
    locally and in CI.
  • The previously non-running specs (map-engine adapters incl. deck.gl,
    engine registry, panel manager) execute.
  • CI runs the unit suite on the project's supported Node version (20+).
  • A failing unit test fails the CI check (the suite is actually gating again).
  • The end-to-end test suite still runs and is unchanged in behavior.

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:

  1. 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.
  2. 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.ymlnode-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.jslet L = window.L at module load (one of the import-time window triggers)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions