Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
146 commits
Select commit Hold shift + click to select a range
9109505
RFC: Migrate from tape to vitest
chrisgervang Jan 27, 2026
659c49f
RFC: Add multi-environment architecture and expanded implementation plan
chrisgervang Jan 27, 2026
ee46a47
RFC: Add @deck.gl/test-utils deprecation timeline
chrisgervang Jan 27, 2026
04b8519
chore(test): add vitest infrastructure
chrisgervang Jan 28, 2026
718a052
chore(test): add tape-to-vitest migration script
chrisgervang Jan 28, 2026
4949e46
chore(test): convert test files from tape to vitest
chrisgervang Jan 28, 2026
d632932
chore(test): add TODO for typed array equality tester removal
chrisgervang Jan 28, 2026
541f0c1
chore(test): remove obsolete gpu-grid-layer test
chrisgervang Jan 28, 2026
3b187e2
chore(test): convert spy.called to vitest toHaveBeenCalled()
chrisgervang Jan 29, 2026
fd05149
chore: ignore yarn engine checks for vitest dependencies
chrisgervang Jan 29, 2026
8c1954a
chore(test): remove unused describe imports from vitest conversions
chrisgervang Jan 29, 2026
47e1d61
chore: ignore vite.config.local.mjs in eslint
chrisgervang Jan 29, 2026
14d3c7c
chore(test): convert t.pass() to console.log() in vitest migration
chrisgervang Jan 29, 2026
f14ccae
chore(test): handle test.skip and test.only in vitest migration
chrisgervang Jan 29, 2026
9e75ff6
fix(test): preserve assertion message in assert callback conversion
chrisgervang Jan 29, 2026
c2955bb
chore(test): handle expression body arrow functions in migration
chrisgervang Jan 29, 2026
2f77513
fix(ci): install Playwright browsers and use headless project
chrisgervang Jan 29, 2026
c8eef73
fix(test): exclude tests that were not in original CI suite
chrisgervang Jan 29, 2026
cfffba1
chore(test): restructure test commands with vitest projects
chrisgervang Jan 30, 2026
b0280a0
docs(rfc): update vitest migration RFC with implementation details
chrisgervang Jan 30, 2026
84ff56c
fix(test): convert makeSpy to vi.spyOn for browser compatibility
chrisgervang Jan 30, 2026
4a35838
fix(test): convert spy.restore/reset to mockRestore/mockReset
chrisgervang Jan 30, 2026
f2402ce
fix(test): convert spy.called to toHaveBeenCalled matcher
chrisgervang Jan 30, 2026
e95ae27
fix(test): handle nested t.test() conversion in migration script
chrisgervang Jan 30, 2026
d616d74
fix(test): address diff comment issues
chrisgervang Jan 30, 2026
cc69f73
chore(test): add manual fix skip list to migration script
chrisgervang Jan 30, 2026
6161023
fix(test): convert spy.callCount to toHaveBeenCalledTimes
chrisgervang Jan 30, 2026
fd9930c
fix(test): pass message to expect assertions for better error messages
chrisgervang Jan 30, 2026
8fce5f5
fix(test): convert spy.callCount to toHaveBeenCalledTimes in terrain …
chrisgervang Jan 30, 2026
4766b53
chore(test): exclude tests that were commented out on master
chrisgervang Jan 30, 2026
7054272
feat(test): add browser commands for vitest test runner
chrisgervang Jan 30, 2026
a9edc69
feat(test): add interaction and render test specs for vitest
chrisgervang Jan 30, 2026
b1e947f
docs: update CONTRIBUTING and RFC with vitest migration progress
chrisgervang Jan 30, 2026
a4ffad0
chore(deps): add image comparison dependencies for vitest
chrisgervang Jan 30, 2026
facc654
fix(scripts): remove unused fullCall variable in migration script
chrisgervang Jan 30, 2026
354485a
fix(test): add await detection for testLayerAsync and exclude failing…
chrisgervang Jan 30, 2026
a14cd26
fix(test): rename jupyter-widget utility file to not have .spec suffix
chrisgervang Jan 30, 2026
ed053cc
fix(test-utils): use mockRestore instead of mockClear for spy cleanup
chrisgervang Jan 30, 2026
cea4d17
chore(test): reduce verbose logging and use TAP for CI
chrisgervang Feb 1, 2026
8bcb3ee
RFC: Migrate from tape to vitest
chrisgervang Jan 27, 2026
d44d9d5
RFC: Add multi-environment architecture and expanded implementation plan
chrisgervang Jan 27, 2026
237a9f6
RFC: Add @deck.gl/test-utils deprecation timeline
chrisgervang Jan 27, 2026
7750fed
RFC: Update CLI commands and finalize Phase 4 discovery outcome
chrisgervang Jan 30, 2026
a30500c
fix(test-utils): enable es2022 for top-level await support
chrisgervang Feb 2, 2026
5e4683f
chore: merge chr/tape-to-vitest into chr/vitest-setup
chrisgervang Feb 2, 2026
d5a9bbf
feat(test-utils): add backward compatibility for tape/probe.gl users
chrisgervang Feb 2, 2026
c711bb8
fix(vitest): pre-bundle dependencies to prevent CI flakiness
chrisgervang Feb 2, 2026
6c04566
ci: split test steps for better visibility
chrisgervang Feb 3, 2026
ad34130
ci: use npx for vitest commands
chrisgervang Feb 3, 2026
16b3e9d
fix(test-utils): make spy framework initialization lazy
chrisgervang Feb 4, 2026
305668e
fix(test-utils): enable test-utils import in Node with NullDevice fal…
chrisgervang Feb 4, 2026
beb5176
feat(test-utils): add Injectable Spy API for framework-agnostic testing
chrisgervang Feb 4, 2026
ae7e43f
RFC: Migrate from tape to vitest
chrisgervang Jan 27, 2026
b4d166d
RFC: Add multi-environment architecture and expanded implementation plan
chrisgervang Jan 27, 2026
8c8ed22
RFC: Add @deck.gl/test-utils deprecation timeline
chrisgervang Jan 27, 2026
ec43806
RFC: Update CLI commands and finalize Phase 4 discovery outcome
chrisgervang Jan 30, 2026
bb7a6a5
RFC: Add injectable spy API, Phase 5 outcome, and Phase 7
chrisgervang Feb 4, 2026
5443914
Merge branch 'origin/chr/tape-to-vitest' into chr/vitest-setup
chrisgervang Feb 4, 2026
e8aa70c
chore(test): add createSpy to all testLayer calls (migration script o…
chrisgervang Feb 4, 2026
2ab06f0
chore(test): separate render tests into dedicated vitest project
chrisgervang Feb 5, 2026
a6acf0c
chore(test): fix test-render script and add separate entry points
chrisgervang Feb 5, 2026
4f7be42
chore(test-utils): add vi.spyOn default to vitest entry point
chrisgervang Feb 5, 2026
1f8ff88
chore(test): update migration script to use @deck.gl/test-utils/vitest
chrisgervang Feb 5, 2026
5002217
chore(test): migrate unit tests to @deck.gl/test-utils/vitest
chrisgervang Feb 5, 2026
329e6cc
chore(test): update core-layers.node.spec.ts to use vitest entry
chrisgervang Feb 5, 2026
8250c0f
chore(test): remove old tape/probe.gl test entry points
chrisgervang Feb 5, 2026
f067e09
chore(test): convert interaction tests to native vitest browser mode
chrisgervang Feb 6, 2026
de68ae4
chore(test): include interaction tests in headless project
chrisgervang Feb 6, 2026
875b0c4
chore(test): convert render tests to native vitest with test.each
chrisgervang Feb 6, 2026
c406bc3
chore(test): fix render test layer loading and use tap reporter
chrisgervang Feb 6, 2026
0eb3d30
chore(test): add views, effects, and useDevicePixels support to rende…
chrisgervang Feb 6, 2026
c84c896
chore(test): fix render test timeouts with absolute URLs and new Deck…
chrisgervang Feb 6, 2026
959390b
chore(test): add skip support for render tests and skip timeout tests
chrisgervang Feb 7, 2026
4b88f59
RFC: Migrate from tape to vitest
chrisgervang Jan 27, 2026
16437f1
RFC: Add multi-environment architecture and expanded implementation plan
chrisgervang Jan 27, 2026
4579dfb
RFC: Add @deck.gl/test-utils deprecation timeline
chrisgervang Jan 27, 2026
f860847
RFC: Update CLI commands and finalize Phase 4 discovery outcome
chrisgervang Jan 30, 2026
7119e0f
RFC: Add injectable spy API, Phase 5 outcome, and Phase 7
chrisgervang Feb 4, 2026
0a646af
Merge remote-tracking branch 'origin/chr/tape-to-vitest' into chr/vit…
chrisgervang Feb 7, 2026
f8a9a0b
fix(test): fix collision-filter-effect test expectation
chrisgervang Feb 7, 2026
d127bda
fix(test-utils): make @probe.gl/test-utils a required peer dependency
chrisgervang Feb 7, 2026
ac1293a
fix(test): use mockClear instead of mockReset for spy.reset conversion
chrisgervang Feb 7, 2026
119252b
chore(test): use @deck.gl/test-utils/vitest entry point for all spec …
chrisgervang Feb 7, 2026
0c3fa68
fix(test): correctly convert t.throws regex matchers to toThrow()
chrisgervang Feb 7, 2026
972be68
chore(test): add tap-spec formatter for prettier test output
chrisgervang Feb 16, 2026
2b7bf5e
chore(ci): upload render test failure images as artifacts
chrisgervang Feb 16, 2026
394fe75
chore(test): update golden images for mvt-layer and post-process-effects
chrisgervang Feb 27, 2026
6becbcd
RFC: Migrate from tape to vitest
chrisgervang Jan 27, 2026
d2f2f23
RFC: Add multi-environment architecture and expanded implementation plan
chrisgervang Jan 27, 2026
8a60964
RFC: Add @deck.gl/test-utils deprecation timeline
chrisgervang Jan 27, 2026
c8e9bd9
RFC: Update CLI commands and finalize Phase 4 discovery outcome
chrisgervang Jan 30, 2026
ed2dece
RFC: Add injectable spy API, Phase 5 outcome, and Phase 7
chrisgervang Feb 4, 2026
a999c4b
Merge branch 'chr/tape-to-vitest' into chr/vitest-setup
chrisgervang Feb 27, 2026
2763739
chore(test): restore coverage TODO and run migration script
chrisgervang Feb 27, 2026
754737e
fix(test): add dblclick support to browser emulateInput command
chrisgervang Feb 27, 2026
907474f
chore(test): replace tap-spec with vitest default reporter
chrisgervang Feb 27, 2026
6b9de2f
fix(test): improve modifier key handling for dblclick events
chrisgervang Feb 27, 2026
33ec6d6
RFC: Migrate from tape to vitest
chrisgervang Jan 27, 2026
7437439
RFC: Add multi-environment architecture and expanded implementation plan
chrisgervang Jan 27, 2026
1121bc5
RFC: Add @deck.gl/test-utils deprecation timeline
chrisgervang Jan 27, 2026
1bcda33
RFC: Update CLI commands and finalize Phase 4 discovery outcome
chrisgervang Jan 30, 2026
d2c9f78
RFC: Add injectable spy API, Phase 5 outcome, and Phase 7
chrisgervang Feb 4, 2026
b2970ad
refactor(test): split render tests into individual spec files
chrisgervang Feb 27, 2026
3ab80db
fix(test): fix timeline render tests by reusing Deck instance
chrisgervang Feb 27, 2026
fe58fe9
fix(test): unskip scatterplot-transition-3 and transition-4 tests
chrisgervang Feb 27, 2026
7f083a7
revert(test): restore original arc-lnglat and gridcell-lnglat golden …
chrisgervang Feb 27, 2026
d81014e
Merge branch 'origin/chr/tape-to-vitest' into chr/vitest-setup
chrisgervang Feb 27, 2026
8619d9f
chore: remove --ignore-engines and add playwright postinstall
chrisgervang Feb 27, 2026
39e5275
feat(test): upgrade vitest from 2.x to 4.x
chrisgervang Feb 27, 2026
3cc0944
fix(test): disable isolation and file parallelism for browser tests
chrisgervang Feb 27, 2026
5fdc63a
fix(test): configure viewport via playwright contextOptions for vites…
chrisgervang Mar 2, 2026
fb0c44a
fix(test): exclude flaky tests that fail with isolate: false in CI
chrisgervang Mar 2, 2026
411746c
chore(ci): simplify CI workflow and re-enable coverage
chrisgervang Mar 2, 2026
df2f530
fix(test-utils): update vitest peer dependency to ^4.0.18
chrisgervang Mar 2, 2026
5a537d4
fix(test-utils): mark @probe.gl/test-utils peer dependency as optional
chrisgervang Mar 2, 2026
66d9959
feat(scripts): add jscodeshift-based tape-to-vitest codemod
chrisgervang Mar 3, 2026
ec78fd2
fix(scripts): improve tape-to-vitest codemod transform
chrisgervang Mar 3, 2026
a752446
fix(test): correctly pass expected error to toThrow() assertions
chrisgervang Mar 3, 2026
9f43b37
docs(test): add comprehensive TEST-STATUS.md and fix test scripts
chrisgervang Mar 4, 2026
35a33c7
fix(scripts): detect 3-arg t.ok pattern as equality assertion
chrisgervang Mar 4, 2026
03b09b9
fix(test): re-enable mvt-layer tests after await fix
chrisgervang Mar 4, 2026
4bd8dea
docs(test): update TEST-STATUS.md after mvt-layer fix
chrisgervang Mar 4, 2026
02d1726
fix(test-utils): require @probe.gl/test-utils peer dependency
chrisgervang Mar 4, 2026
82f9dcb
fix(test-utils): add @probe.gl/test-utils to root devDependencies
chrisgervang Mar 4, 2026
05614bf
refactor(test): DRY up screenshot logic in deck-test-utils
chrisgervang Mar 4, 2026
51b411d
chore(test-utils): remove completed TODO comment
chrisgervang Mar 4, 2026
701afe0
Merge branch 'master' into chr/vitest-setup
chrisgervang Mar 4, 2026
fe8ea26
refactor(test-utils): Add resetSpy callback and extract shared utilities
chrisgervang Mar 5, 2026
ce9016e
fix(test-utils): Remove unused imports from setup-gl.ts
chrisgervang Mar 5, 2026
9584d2e
fix(test-utils): Add async cleanup to prevent luma.gl unhandled rejec…
chrisgervang Mar 5, 2026
0eb0a50
fix(test): Re-enable carto-raster-tile tests and document excluded tests
chrisgervang Mar 5, 2026
93bde3e
fix(test): Exclude render tests from browser project and fix vitest d…
chrisgervang Mar 6, 2026
3131d3a
fix(codemod): Use vitest entry point for utility file fixture
chrisgervang Mar 6, 2026
e70e2a3
refactor(test): Use import.meta.dirname for modern Node.js
chrisgervang Mar 6, 2026
79bc238
chore: Merge master into chr/vitest-setup
chrisgervang Mar 9, 2026
e2add2c
Merge branch 'master' into chr/vitest-setup
ibgreen Mar 28, 2026
01efe7c
rebase-cleanup
ibgreen Mar 28, 2026
c6d7b1b
fixes
ibgreen Mar 28, 2026
7eb0a2f
tape-compat
ibgreen Mar 28, 2026
b5eb8bd
Enabled skipped test cases and files
ibgreen Mar 28, 2026
6eccf27
partial-test-restore
ibgreen Mar 28, 2026
f5fb11f
fixes
ibgreen Mar 28, 2026
b03f384
fixes
ibgreen Mar 28, 2026
8535d8d
wip
ibgreen Mar 28, 2026
632f5a7
fix
ibgreen Mar 28, 2026
2625a74
disable
ibgreen Mar 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ mapbox-gl.js
.docusaurus
examples/layer-browser/
test/apps/
bindings/
bindings/
# TODO: Remove once eslint-plugin-import supports vite 5.x (vitest brings vite 5.x, master uses 4.x)
examples/vite.config.local.mjs
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ dist/
node_modules/
coverage/
test/**/*-failed.png
test/**/__screenshots__/
.nyc_output/
.reify-cache/

Expand Down
1 change: 1 addition & 0 deletions .yarnrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--ignore-engines true
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Engine checks disabled for all installs

Medium Severity

Adding --ignore-engines true disables dependency engine validation globally. This allows unsupported Node versions to install vitest and related tooling, then fail later at runtime instead of failing fast during install, which makes setup and CI/local behavior inconsistent and harder to diagnose.

Fix in Cursor Fix in Web

377 changes: 377 additions & 0 deletions dev-docs/RFCs/proposals/vitest-migration-rfc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,377 @@
# RFC: Migrate from Tape to Vitest

- **Author**: Chris Gervang
- **Date**: January 2026
- **Status**: Draft

## Overview

This RFC proposes migrating deck.gl's test infrastructure from **tape** (assertion framework) + **ocular-test** (test runner from @vis.gl/dev-tools) to **vitest** (which serves as both runner and assertion library).

The migration aims to:
- Modernize the test infrastructure with a widely-adopted, actively maintained framework
- Improve developer experience with better error messages, watch mode, and IDE integration
- Reduce complexity by consolidating runner and assertions into a single tool
- Maintain the same CLI commands for backwards compatibility

## Background

### Current Architecture

```
ocular-test (runner from @vis.gl/dev-tools)
├── Vite (dev server for browser tests)
├── BrowserTestDriver (@probe.gl/test-utils)
├── c8 (coverage)
└── tape (assertions via tape-promise/tape)
```

**Entry points:**
- `test/node.ts` - Minimal smoke test (only `imports-spec` + `core-layers.spec`)
- `test/browser.ts` - **Comprehensive** - runs ALL tests (`./modules` + `./render` + `./interaction`)

**Important architectural note:** The previous design intentionally ran all tests in the browser (source of truth for a WebGL library), with Node serving only as a smoke test.

**Current test commands:**
- `yarn test` - runs `ocular-test`
- `yarn test-fast` - runs `ocular-lint && ocular-test node`
- `yarn cover` - runs `ocular-test cover`

### Pain Points

1. **Fragmented tooling**: Test runner (ocular-test), assertions (tape), coverage (c8) are separate tools
2. **Tape is minimalist**: Limited error messages, no built-in mocking, requires wrappers like tape-promise
3. **Custom infrastructure**: BrowserTestDriver requires custom hooks (`window.browserTestDriver_finish`)
4. **Developer experience**: No watch mode, no IDE integration for running individual tests

## Proposal

Replace ocular-test and tape with vitest:

```
vitest (runner + assertions)
├── Vite (built-in - same foundation as ocular-test)
├── Playwright (browser mode - replaces BrowserTestDriver)
├── v8 coverage (built-in)
└── expect() assertions (replaces tape)
```

### Why Vitest?

1. **Built on Vite**: Same bundler that ocular-test uses, ensuring compatibility
2. **All-in-one**: Runner, assertions, mocking, coverage in a single package
3. **Modern DX**: Watch mode, parallel execution, better error messages
4. **Industry standard**: Widely adopted, well-documented, actively maintained
5. **TypeScript-first**: Native TypeScript support without additional configuration

### Multi-Environment Architecture

We adopt a **hybrid approach** using vitest workspaces:
- **Browser runs ALL tests** (source of truth for correctness)
- **Node runs pure unit tests** (fast feedback during development)

This preserves the previous design philosophy where browser tests are comprehensive, while adding fast local iteration via Node.

**File naming convention:**
| Pattern | Description |
|---------|-------------|
| `*.spec.ts` | Default - runs in both environments |
| `*.browser.spec.ts` | Browser-only (WebGL, real DOM, etc.) |

**Vitest workspace configuration:**
```typescript
// vitest.config.ts
export default defineConfig({
test: {
projects: [
{
test: {
name: 'node',
environment: 'node',
include: ['test/modules/**/*.spec.ts'],
exclude: ['test/modules/**/*.browser.spec.ts'],
setupFiles: ['./test/setup/vitest-node-setup.ts']
}
},
{
test: {
name: 'browser',
include: ['test/modules/**/*.spec.ts'], // ALL tests
browser: {
enabled: true,
provider: playwright(),
instances: [{browser: 'chromium'}]
}
}
},
{
test: {
name: 'headless',
include: ['test/modules/**/*.spec.ts'], // ALL tests
browser: {
enabled: true,
headless: true,
provider: playwright(),
instances: [{browser: 'chromium'}]
}
}
}
]
}
});
```

**CLI commands:**
```json
{
"test": "vitest run",
"test-node": "vitest run --project node",
"test-browser": "vitest run --project browser",
"test-headless": "vitest run --project headless"
}
```

### Why Playwright Instead of Puppeteer?

Vitest browser mode only supports **Playwright** or WebdriverIO as providers - Puppeteer is not an option. This is actually beneficial:
- Playwright has better parallel execution
- Native TypeScript support
- More robust browser automation APIs
- Better cross-browser testing support

The existing Puppeteer usage (via `@probe.gl/test-utils` BrowserTestDriver) will be replaced with Playwright's native APIs.

### API Changes

**Test file changes:**

```typescript
// Before (tape)
import test from 'tape-promise/tape';

test('color#parseColor', t => {
const result = parseColor([127, 128, 129]);
t.deepEqual(result, [127, 128, 129, 255], 'expected result');
t.end();
});

// After (vitest)
import {test, expect} from 'vitest';

test('color#parseColor', () => {
const result = parseColor([127, 128, 129]);
expect(result).toEqual([127, 128, 129, 255]);
});
```

**Assertion mapping:**

| tape | vitest |
|------|--------|
| `t.ok(value)` | `expect(value).toBeTruthy()` |
| `t.notOk(value)` | `expect(value).toBeFalsy()` |
| `t.equal(a, b)` / `t.is(a, b)` | `expect(a).toBe(b)` |
| `t.deepEqual(a, b)` | `expect(a).toEqual(b)` |
| `t.throws(fn)` | `expect(fn).toThrow()` |
| `t.end()` | (not needed) |

### CLI Compatibility

Commands remain the same:

```json
{
"scripts": {
"test": "vitest run",
"test-fast": "ocular-lint && vitest run",
"cover": "vitest run --coverage"
}
}
```

`yarn test ci` continues to work - vitest auto-detects CI environments.

### @deck.gl/test-utils Updates

The `@deck.gl/test-utils` module uses `makeSpy` from `@probe.gl/test-utils`. This will be replaced with vitest's built-in `vi.spyOn`:

```typescript
// Before
import {makeSpy} from '@probe.gl/test-utils';
const spy = makeSpy(Object.getPrototypeOf(layer), 'updateState');

// After
import {vi} from 'vitest';
const spy = vi.spyOn(Object.getPrototypeOf(layer), 'updateState');
```

## Implementation Plan

### Phase 1: Infrastructure Setup

**1.1 Install dependencies:**
```bash
yarn add -D @vitest/browser @vitest/browser-playwright playwright
```

**Node 18 Compatibility:** Confirmed - Vitest 2.1.9 requires `^18.0.0 || >=20.0.0`, Playwright requires `>=18`.

**1.2 Update `vitest.config.ts`** with workspace projects (see Multi-Environment Architecture above)

**1.3 Create setup files:**
- `test/setup/vitest-node-setup.ts` - JSDOM polyfills (from current `test/node.ts`)
- `test/setup/vitest-browser-setup.ts` - Minimal (browser provides DOM)

**1.4 Add npm scripts** for each environment

### Phase 2: Update @deck.gl/test-utils
- Replace `makeSpy` with `vi.spyOn`
- Add vitest as peer dependency

### Phase 3: Migrate Test Files (~185 files)
- Convert tape imports to vitest
- Transform assertions
- Remove `t.end()` calls
- Update callback patterns (`onError: t.notOk` → `onError: (err) => expect(err).toBeFalsy()`)

### Phase 4: Discovery - Run Node Tests and Identify Browser Dependencies

The hybrid approach serves as a **discovery mechanism**:

1. Run `yarn test-node` and observe failures
2. Failures reveal browser-only dependencies:
- WebGL/GPU operations (`@luma.gl/*`)
- Real DOM APIs not in JSDOM
- Browser-specific APIs (fetch quirks, Web Workers)
- Dependencies that check `typeof window`
- Canvas 2D context beyond JSDOM's mock

**Decision point after discovery:**
- **Few failures (~10-20%)** → Keep hybrid, rename failures to `.browser.spec.ts`
- **Many failures (~50%+)** → Fall back to browser-only approach

### Phase 5: Migrate Snapshot & Interaction Tests

**Current state:**
- **35 test files** in `test/render/` with **150 golden images**
- **3 test files** in `test/interaction/`
- Both use tape + probe.gl's `BrowserTestDriver` (Puppeteer)
- `SnapshotTestRunner` uses `window.browserTestDriver_captureAndDiffScreen`
- `InteractionTestRunner` uses `window.browserTestDriver_emulateInput`

**5.1 Convert to vitest syntax:**
- Replace `import test from 'tape'` with `import {test, expect} from 'vitest'`
- Update assertion syntax

**5.2 Update SnapshotTestRunner for Playwright:**
- Replace `browserTestDriver_captureAndDiffScreen` with Playwright's `page.screenshot()`
- Use `@vitest/browser`'s page context
- Keep golden image comparison logic

**5.3 Update InteractionTestRunner for Playwright:**
- Replace `browserTestDriver_emulateInput` with Playwright APIs:
- `page.mouse.move()`, `page.mouse.click()`, `page.keyboard.press()`

**5.4 Add to browser project:**
```typescript
{
name: 'browser',
include: [
'test/modules/**/*.spec.ts',
'test/render/**/*.spec.ts', // Add render tests
'test/interaction/**/*.spec.ts' // Add interaction tests
]
}
```

**Files to modify:**
- `modules/test-utils/src/snapshot-test-runner.ts`
- `modules/test-utils/src/interaction-test-runner.ts`
- `test/render/index.js` → `test/render/index.spec.ts`
- `test/interaction/index.js` → `test/interaction/index.spec.ts`

### Phase 6: Cleanup
- Remove `tap-spec`, `tape-catch` dependencies
- Remove test entry points from `.ocularrc.js`
- Delete `test/node.ts`, `test/browser.ts`, `.nycrc`

## Scope

- ~185 test files in `test/modules/`
- ~2800 assertions to convert
- 1 test utility module (`@deck.gl/test-utils`)
- 35 render test files with 150 golden images
- 3 interaction test files

## Verification

1. `yarn test-node` - runs unit tests in Node (fast feedback)
2. `yarn test-browser` - runs ALL tests in Chromium (unit + render + interaction)
3. `yarn test-headless` - runs ALL tests headlessly (CI)
4. **Render tests**: Golden image comparison passes for all 150 images
5. **Interaction tests**: Controller/picking tests pass

## Risks and Mitigations

| Risk | Mitigation |
|------|------------|
| Browser tests may behave differently | Vitest browser mode uses Playwright, similar to current Puppeteer-based setup |
| Coverage format changes | Vitest v8 provider outputs lcov format, same as current setup |
| Breaking changes for external consumers of test-utils | Add vitest as peer dependency, document migration |
| Many tests fail in Node environment | Discovery phase allows fallback to browser-only approach (Option A) |
| Puppeteer → Playwright migration breaks snapshot comparison | Vitest requires Playwright; will need to regenerate golden images if pixel differences occur |
| CI takes longer (running tests twice) | Node tests are fast; browser failures are the blocking check |

## Alternatives Considered

### Keep ocular-test, only replace tape assertions
- **Rejected**: Would require custom integration between ocular-test's BrowserTestDriver and vitest assertions
- Vitest is designed to be both runner and assertion library

### Migrate to Jest
- **Rejected**: Jest has slower startup, less Vite integration
- Vitest is faster and shares the same Vite foundation as ocular-test

## Open Questions

1. Should we convert test file structure to use `describe`/`it` blocks, or keep flat `test()` calls?
2. ~~Should browser tests run in CI by default, or remain opt-in?~~ **Resolved:** Browser tests are the source of truth and should run in CI by default.
3. ~~Timeline for deprecating tape support in `@deck.gl/test-utils`?~~ **Resolved:** See deprecation timeline below.
4. After Phase 4 discovery: What percentage of tests fail in Node? This determines whether to keep hybrid approach or fall back to browser-only.

## @deck.gl/test-utils Deprecation Timeline

**Goal:** Allow external consumers time to migrate while moving the ecosystem forward.

**Note:** `@deck.gl/test-utils` is published on npm with ~10k monthly downloads (~1% of core). While primarily intended for internal use, external consumers exist and deserve a migration path.

| Phase | Version | Timeline | Changes |
|-------|---------|----------|---------|
| **Compatibility** | 9.3.x | Next minor release | Add vitest as peer dependency alongside `@probe.gl/test-utils`. Both tape and vitest patterns work. |
| **Deprecation Warning** | 9.4.x | +1 minor release | Console warnings for tape-based patterns (`makeSpy`, `assert: t.ok`). Documentation updated with vitest examples. |
| **Removal** | 10.0.0 | Next major release | Remove tape/probe.gl support. `vi.spyOn` replaces `makeSpy`. Callbacks use vitest `expect()`. |

**Migration guide for external consumers:**

```typescript
// Before (tape)
import {testLayer} from '@deck.gl/test-utils';
import test from 'tape';

testLayer({assert: test.ok, onError: test.fail});

// After (vitest)
import {testLayer} from '@deck.gl/test-utils';
import {expect} from 'vitest';

testLayer({
assert: (condition, message) => expect(condition, message).toBeTruthy(),
onError: (error) => { throw error; }
});
```

## References

- [Vitest Documentation](https://vitest.dev/)
- [Vitest Browser Mode](https://vitest.dev/guide/browser/)
- [ocular-test source](https://github.com/visgl/dev-tools/blob/master/modules/dev-tools/src/test.ts)
Loading
Loading