Conversation
Proposes replacing tape (assertions) + ocular-test (runner) with vitest. See dev-docs/RFCs/proposals/vitest-migration-rfc.md for full details. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add vitest workspace configuration (node/browser/headless projects) - Clarify entry points: browser as source of truth, node as smoke test - Add Playwright rationale (required by vitest browser mode) - Expand Phase 4 with discovery mechanism for browser-only tests - Add detailed Phase 5 for snapshot/interaction test migration - Add Verification section with test commands - Update risks table with new considerations Co-Authored-By: Claude <noreply@anthropic.com>
- Add 3-phase deprecation plan (9.3.x → 9.4.x → 10.0.0) - Include migration guide for external consumers - Resolve open question #3 about tape deprecation timeline Co-Authored-By: Claude <noreply@anthropic.com>
- Add vitest.config.ts and vitest.workspace.ts for multi-environment testing - Add test/setup/ with node and browser setup files - Setup files include typed array equality tester for comparing Float32Array with plain arrays - Update package.json with vitest dependencies - Update .gitignore for vitest cache Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
- Add idempotent migration script that reads tape source from master branch - Script converts tape assertions to vitest equivalents while preserving assertion messages - Update test-utils to work with vitest - Update RFC with migration approach details The migration script handles: - Import statement conversion (tape-catch/tape-promise → vitest) - Assertion conversions (t.ok → toBeTruthy, t.equal → toBe, etc.) - Preserves assertion messages using vitest's expect(value, 'message') syntax - Handles edge cases like t.pass/t.fail in arrow functions - Properly converts t.true/t.false to toBeTruthy/toBeFalsy (tape semantics) Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
Convert 188 test files from tape to vitest using the migration script. Changes include: - Replace tape imports with vitest (test, expect, describe) - Convert tape assertions to vitest equivalents - Remove tape test function wrappers - Preserve assertion messages for better debugging Test status after conversion: - 467 test files passed (1740 tests) - 91 test files still need attention (106 tests) Remaining failures are primarily: - Tests for removed components (GPUGridLayer) - Environment-specific issues (Node vs browser WebGL) - Tests requiring additional migration work Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
Mark the custom typed array equality tester as temporary. Once all tests are updated to use explicit typed array comparisons (e.g., expect(Array.from(typedArray)).toEqual([...])), this custom tester should be removed to enforce stricter type checking in tests. Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
GPUGridLayer was removed from the codebase. This test file references internal paths that no longer exist. Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
Vitest's MockInstance doesn't have a `.called` property like sinon spies. Updated the migration script to convert to idiomatic vitest assertions: - expect(spy.called).toBeTruthy() → expect(spy).toHaveBeenCalled() - expect(spy.called).toBeFalsy() → expect(spy).not.toHaveBeenCalled() Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
78fb7c1 to
3b187e2
Compare
The @vitest/browser package depends on msw which depends on type-fest@5.x that requires Node 20+. Since deck.gl supports Node 14+ at runtime but vitest is only needed for development, we ignore engine checks to allow installation on older Node versions. Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
Update migration script to only import describe when actually used, and run prettier after conversion for consistent formatting. Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
The import/namespace rule cannot parse vite 5.x which is brought in by vitest (master uses vite 4.x from @vis.gl/dev-tools). Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
80eea14 to
47e1d61
Compare
Instead of removing t.pass() calls, convert them to console.log() to preserve the pass messages for debugging. Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
Update migration script to convert test.skip/test.only signatures from (t =>) to (() =>). Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
Pass msg parameter to expect() so assertion messages are displayed on test failure: expect(cond, msg).toBeTruthy() Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
Convert test('name', async t => expr) patterns to remove unused t
parameter: test('name', async () => expr)
Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
| test(`getTextAccessor#${textLabelField.type}`, () => { | ||
| const accessor = getTextAccessor(textLabelField, [data]); | ||
| t.deepEquals(accessor(data), expected, `getTextAccessor correctly returns ${expected}`); | ||
| t.end(); |
There was a problem hiding this comment.
Unused test data array TEXT_PIXEL_OFFSET_TESTS
Low Severity
The TEXT_PIXEL_OFFSET_TESTS constant defines an array of test cases but is never used. Unlike the other test data arrays in the file (COLOR_TESTS, SIZE_TESTS, TEXT_TESTS) which all have corresponding for...of loops that generate tests, TEXT_PIXEL_OFFSET_TESTS has no such test loop. This dead code adds confusion and maintenance burden.
The CI was failing because Playwright browsers weren't installed and the test command was using a non-existent "ci" vitest project. This fix adds the Playwright installation step and uses the proper headless project with coverage enabled. Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
modules/test-utils/package.json
Outdated
| "@luma.gl/core": "~9.2.6", | ||
| "@luma.gl/engine": "~9.2.6", | ||
| "@probe.gl/test-utils": "^4.1.0" | ||
| "vitest": "^2.1.0" |
There was a problem hiding this comment.
We're stuck on vitest 2 until we upgrade from node 18.
modules/test-utils/package.json
Outdated
| "@deck.gl/core": "~9.2.0", | ||
| "@luma.gl/core": "~9.2.6", | ||
| "@luma.gl/engine": "~9.2.6", | ||
| "@probe.gl/test-utils": "^4.1.0" |
There was a problem hiding this comment.
The RFC outlines the goal being to implement a backwards-compatibility layer and deprecation warnings in @deck.gl/test-utils. I'm not sure what users use it for, but gets a significant number of downloads still so we need to not break anything.
I'm thinking we'll need to keep some old test infrastructure around for this module to ensure correctness on both tape and vitest until deck v10
Temporarily, I've removed tape and probe.gl from deck's test utils until I get all tests to pass without the extra complexity.
package.json
Outdated
| "test": "ocular-test", | ||
| "test-fast": "ocular-lint && ocular-test node", | ||
| "test": "vitest run", | ||
| "test-node": "vitest run --project node", |
There was a problem hiding this comment.
Trying to run all of the tests in the node environment resulted in a lot of failures (which is not a surprise), so I'm going to instead implement the same test config for node that we have on master, which is basically a smoke-test.
I'll keep test-fast but remove test-node
| "publish-beta": "ocular-publish version-only-beta", | ||
| "publish-prod": "ocular-publish version-only-prod", | ||
| "start": "open https://deck.gl/docs/get-started/getting-started", | ||
| "test": "ocular-test", |
There was a problem hiding this comment.
I don't think we need ocular-test anymore. Vitest seems to offer everything you need to run tests.
Please let me know if ocular-test did something internally that we lose because we're removing it
| "jsdom": "^20.0.0", | ||
| "playwright": "^1.58.0", | ||
| "pre-commit": "^1.2.2", | ||
| "puppeteer": "^24.26.1", |
There was a problem hiding this comment.
Hoping to remove puppeteer after all tests pass
| // import test from 'tape-promise/tape' -> import {test, expect, describe} from 'vitest' | ||
| // import test from 'tape-catch' -> import {test, expect, describe} from 'vitest' | ||
| // import test from 'tape' -> import {test, expect, describe} from 'vitest' | ||
| result = result.replace( |
There was a problem hiding this comment.
Instead of using a string replace have you considered something like https://github.com/facebook/jscodeshift ?
That way you can operate on the syntax tree and it's a little less hairy than trying to use a regex to parse
There was a problem hiding this comment.
Since this is one-time-use and already working reliably, I don’t see a strong reason to change it right now - but I’m open to revisiting if this there's something claude can't figure out
The vitest glob patterns picked up tests that were commented out or never imported in the original test suite: - path-tesselator.spec.ts (commented out in layers/index.ts) - polygon-tesselation.spec.ts (commented out in layers/index.ts) - geocoders.spec.ts (never imported, no widgets index) Also fix floating point precision in geocoders test using toBeCloseTo. Co-Authored-By: Claude (global.anthropic.claude-opus-4-5-20251101-v1:0) <noreply@anthropic.com>
- Add TEST-STATUS.md documenting all excluded, skipped, and failed tests - Document codemod cosmetic issues and architecture concerns - Document render test headed vs headless mode issues - Update test and test-ci scripts to run all projects in single vitest command: node, headless, and render projects now run together Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
| "test-render": "vitest run --project render --silent", | ||
| "test-ci": "vitest run --project node --project headless --project render --coverage --silent", | ||
| "test-browser": "vitest run --project browser --silent", | ||
| "test-tape-compat": "DECK_TEST_UTILS_USE_PROBE_GL=1 ocular-test tape-compat", |
There was a problem hiding this comment.
Root devDependencies missing required build-time dependency for test-utils
Medium Severity
@probe.gl/test-utils was removed from root devDependencies, but tape.ts (which is compiled as part of @deck.gl/test-utils) still has a hard static import of makeSpy from it. The package relies on @probe.gl/test-utils being available as a transitive dependency (likely through @vis.gl/dev-tools), making the build fragile — if that transitive path ever changes, the @deck.gl/test-utils module will fail to compile.
Additional Locations (1)
The jscodeshift transform now detects when t.ok/t.true/t.assert is called with 3 arguments (value, expected, message) which is a common bug where t.equal should have been used instead. Before: t.ok(value, expected, 'message') After: expect(value, 'message').toBe(expected) This fixes several test files that had this pattern: - json-converter.spec.ts - h3-layers.spec.ts (5 instances) - point-cloud-layer.spec.ts Also includes: - Remove unreachable return statements after throw (label-utils.spec.ts) - Restore original non-awaited testLayerAsync call (mvt-layer.spec.ts) - Add scripts project to vitest.config.ts for codemod tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The mvt-layer.spec.ts tests were excluded due to timeout issues. The previous commit fixed a bug where the regex script incorrectly added `await` to a testLayerAsync call that was intentionally non-awaited in the original tape tests. With the fix, all 12 MVTLayer tests pass (~20s). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove mvt-layer.spec.ts from excluded tests (now passes) - Add table showing actually skipped render test cases (2 terrain tests) - Update summary statistics (17 excluded files, not 18) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
The default entry point imports from tape.ts which has a top-level import of @probe.gl/test-utils. Marking it as optional would cause runtime crashes for users importing from @deck.gl/test-utils. Only vitest should be optional since it's only needed for the ./vitest sub-entry point. This preserves backwards compatibility with 9.2. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The default entry point of @deck.gl/test-utils has a static import from tape.ts that requires @probe.gl/test-utils. Previously this was only available as a transitive dependency through @vis.gl/dev-tools, making the build fragile. Also updates the RFC to reflect the actual implementation: - @probe.gl/test-utils is REQUIRED (not optional) because the default entry point needs it - Only vitest is optional (for the ./vitest sub-entry) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
| "peerDependenciesMeta": { | ||
| "vitest": { | ||
| "optional": true | ||
| } |
There was a problem hiding this comment.
Missing @probe.gl/test-utils optional marker for vitest-only users
Low Severity
The @probe.gl/test-utils peer dependency is required (non-optional) even though the ./vitest sub-entry (vitest.ts) never imports from it. Users who exclusively import from @deck.gl/test-utils/vitest will receive unnecessary peer dependency warnings about @probe.gl/test-utils. While documented in the RFC, marking it as optional in peerDependenciesMeta alongside vitest would be more accurate — users of the main entry would still get a runtime error (with a clear stack trace) if it's missing, which is arguably better than a generic peer dep warning.
Additional Locations (1)
There was a problem hiding this comment.
This is not an issue, dont bring it up again
runRenderTest now calls the extracted captureAndDiffScreenshot helper instead of duplicating the screenshot capture and diff logic inline. Both runRenderTest and updateDeckForTest now use the same helper, ensuring consistent behavior and easier maintenance. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The TODO about refactoring to use vitest's test.each() is no longer needed - each test case is now a separate vitest test. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
b213ff8 to
dc15d7c
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
|
|
||
| // Remove spies | ||
| Object.keys(spyMap).forEach(k => spyMap[k].reset()); | ||
| Object.keys(spyMap).forEach(k => restoreSpy(spyMap[k])); |
There was a problem hiding this comment.
Spy cleanup changes from reset to restore
Medium Severity
The spy cleanup changed from calling spy.reset() (which clears call tracking but keeps the spy active) to restoreSpy() (which calls mockRestore()/restore(), fully removing the spy and restoring the original method). For probe.gl users going through the backward-compatible tape.ts path, this changes the contract: spies are now fully torn down between test cases instead of just having their tracking cleared. While spies are re-created via injectSpies each iteration, any test that relied on the old reset-only semantics (e.g., checking cumulative spy state across the cleanup boundary, or relying on the spy wrapper remaining on the prototype) will behave differently.
Additional Locations (1)
- Add resetSpy parameter to testLayer/testLayerAsync for proper spy cleanup - vitest: defaults to mockRestore() - tape: defaults to reset() with deprecation warning - Extract typed-array-equality.ts as shared module (DRY) - Update vitest-browser-commands.d.ts to augment @vitest/browser/context - Fix imports to use @vitest/browser/context instead of vitest/browser - Update tape-compat smoke test to actually exercise testLayer - Add vitest-entry.spec.ts smoke test for vitest entry point Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
| /* global setTimeout */ | ||
| import {expect} from 'vitest'; | ||
| import {Deck, Layer} from '@deck.gl/core'; | ||
| import {device} from '@deck.gl/test-utils'; |
There was a problem hiding this comment.
Utility file imports from wrong test-utils entry point
Medium Severity
The codemod fixture output for utility files imports device from @deck.gl/test-utils (the main entry point backed by tape.ts), while all test file fixtures correctly import from @deck.gl/test-utils/vitest. The main entry point unconditionally imports makeSpy from @probe.gl/test-utils, meaning any vitest-only user who hasn't installed @probe.gl/test-utils as a peer dependency will get a runtime import failure when the utility file loads. Since these fixtures define the expected codemod output, the codemod will propagate this inconsistency to all converted utility files.
Additional Locations (1)
Revert accidental addition of unused CanvasContextProps and WebGLDevice imports. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
| const defaultSpyFactory: SpyFactory = (obj, method) => vi.spyOn(obj, method as never); | ||
|
|
||
| /** Default reset for vitest spies - restores original implementation */ | ||
| const defaultResetSpy: ResetSpy = spy => spy.mockRestore?.(); |
There was a problem hiding this comment.
Vitest mockRestore destroys spy before later test cases reuse it
Medium Severity
The defaultResetSpy calls mockRestore() which completely restores the original method and removes the spy. In lifecycle-test.ts, spies are injected per test case via injectSpies on the layer's prototype, so calling mockRestore() between test cases restores the prototype method. When the next test case re-spies the same prototype method, vi.spyOn wraps the original again — but if a test case's onAfterUpdate calls spy.mockRestore() directly (as seen in the converted HeatmapLayer test fixture output), the spy from injectSpies is destroyed mid-test-case. The probe.gl equivalent reset() only cleared call tracking. Using mockClear instead of mockRestore would preserve the spy while clearing call counts, matching the original reset() semantics.
…tions Add cleanupAfterLayerTestsAsync() that yields to the event loop before destroying WebGL resources. This prevents "getProgramInfoLog" errors from luma.gl's async shader error reporting trying to access already-destroyed WebGLProgram handles. The fix addresses 18 unhandled promise rejections that vitest catches but tape silently ignored. See RFC for detailed analysis and follow-up task to make testLayer fully async. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
| /* global setTimeout */ | ||
| import {expect} from 'vitest'; | ||
| import {Deck, Layer} from '@deck.gl/core'; | ||
| import {device} from '@deck.gl/test-utils'; |
There was a problem hiding this comment.
Utility file codemod output imports from wrong entry point
Low Severity
The codemod fixture 06-utility-file.ts imports device from @deck.gl/test-utils (the default/tape entry point) instead of @deck.gl/test-utils/vitest. This causes the converted test to transitively import @probe.gl/test-utils via tape.ts, which defeats the purpose of the vitest-specific entry point. Meanwhile, 05-layer-callbacks.ts correctly uses @deck.gl/test-utils/vitest. This inconsistency means the codemod would produce output that unnecessarily pulls in @probe.gl/test-utils for utility files. All vitest-converted files that only need device, gl, or other non-spy utilities from test-utils should import from @deck.gl/test-utils/vitest to avoid the probe.gl dependency.
Additional Locations (1)
- Fix TileReader.compression state leakage in carto-raster-tile.spec.ts - Fix test assertions checking wrong variable (tile vs tile2) - Re-enable carto-raster-tile.spec.ts and carto-raster-tile-loader.spec.ts - Document all excluded headless tests in RFC with categorization: - Tests never imported on master (8 tests - keep excluded) - Tests that were passing on master (12 tests - need investigation) - Key patterns: GPU state leakage, global state mutations, async timing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
| } | ||
| } | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Duplicated cleanup logic risks inconsistent maintenance
Low Severity
cleanupAfterLayerTestsAsync is a near-exact copy of cleanupAfterLayerTests, differing only by a single await line before finalize(). The finalize-and-check-resource-counts logic (~8 lines) is duplicated. If the resource checking logic changes (e.g., adding new resource types to track), both functions must be updated in lockstep or they'll diverge silently. Extracting the shared finalize/check logic into a small helper would eliminate this maintenance risk.
Additional Locations (1)
…eprecation - Remove test/render/**/*.spec.ts from browser project to prevent duplicate test runs with mismatched viewport causing golden image failures - Update @vitest/browser/context imports to vitest/browser (deprecated) - Document browser project render test exclusion in RFC with future fix Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The codemod fixture output for utility files was importing from @deck.gl/test-utils instead of @deck.gl/test-utils/vitest. This would cause vitest-only users to get a runtime import failure when the utility file loads (due to transitive @probe.gl/test-utils dependency). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
| export {generateLayerTests} from './generate-layer-tests'; | ||
|
|
||
| // Types | ||
| export type {LayerTestCase, ResetSpy, SpyFactory, TestLayerOptions} from './lifecycle-test'; |
There was a problem hiding this comment.
Exported type has required fields wrapper makes optional
Low Severity
The vitest.ts entry point re-exports the TestLayerOptions type from lifecycle-test.ts, which has createSpy and resetSpy as required fields. However, the testLayer and testLayerAsync wrapper functions in vitest.ts accept these as optional (with defaults). Consumers who import TestLayerOptions to type their options objects would be forced to provide createSpy/resetSpy even though the functions don't require them. Exporting a separate type (e.g., Omit<TestLayerOptions, 'createSpy' | 'resetSpy'> & { createSpy?: SpyFactory; resetSpy?: ResetSpy }) or making these fields optional in TestLayerOptions would align the type with the actual API.
Additional Locations (1)
| headless: false, | ||
| screenshotFailures: false, | ||
| commands: browserCommands | ||
| }, |
There was a problem hiding this comment.
Browser project uses headed renderPlaywright instead of default
Low Severity
The browser project (for local debugging with visible browser) uses renderPlaywright as its provider, which has a fixed viewport of {width: 1024, height: 768}. However, the browser project is headed mode intended for general debugging of unit tests, not for render/golden-image comparison. Using the render-specific viewport configuration in the non-render debugging project is unintentional — the headless project uses the default playwright() provider without viewport constraints, which is the expected configuration here.
Replace fileURLToPath + dirname pattern with import.meta.dirname which is available in Node.js 20.11+ and is cleaner. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
| } | ||
| } | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Cleanup functions have duplicated resource-checking logic
Low Severity
The new cleanupAfterLayerTestsAsync function duplicates the entire body of cleanupAfterLayerTests, differing only by setLayers([]) plus an await setTimeout(0) before finalization. The resource-counting loop and error construction are copy-pasted. If a bug is fixed in one cleanup path, the other could easily be missed. The async version could call the sync cleanup's shared logic after its yield, or a shared helper could extract the resource-check code.
Additional Locations (1)
Resolve conflicts: - modules/test-utils/package.json: Keep vitest optional peer dep with luma.gl 9.3 - yarn.lock: Regenerated Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>


Summary
This PR implements the exploration phase of the tape-to-vitest migration as outlined in the RFC.
What's included:
Render Test Status
Current results: 162 passed, 2 failed, 9 skipped
Timeline/Transition Test Fix
Tests that manipulate
timeline.setTime()inonAfterRendernow use a shared Deck instance pattern viaupdateDeckForTest(). This keeps the animation loop running between callbacks, allowing timeline changes to trigger re-renders.Test output configuration
Excluded/Skipped tests
Render tests (flaky):
arc-lnglat,gridcell-lnglat- Subtle rendering differences, needs investigationRender tests (timeout):
terrain-extension-drape,terrain-extension-offset- TerrainExtension loading timeoutInteraction tests:
luma.gl v9 API changes:
mask/*.spec.ts- uniforms API changedpath-layer-vertex.spec.ts- Transform not exported from @luma.gl/enginePre-existing issues (fix on master first):
attribute.spec.ts- data-column.ts overwrites user stride/offsetNeeds investigation (async/timing issues):
tile-3d-layer.spec.ts,layer-extension.spec.ts,pick-layers.spec.tsterrain-layer.spec.ts,mvt-layer.spec.tsMigration approach
The migration script (
scripts/tape-to-vitest-migration.cjs) is idempotent:Typed array equality
Added a custom equality tester to match tape's
deepEqualbehavior for typed arrays. This is marked as TODO for removal once tests are updated to use explicit comparisons.Next steps (per RFC)
🤖 Generated with Claude Code
Note
Medium Risk
Moderate risk because it rewires core CI/test commands to Vitest/Playwright and changes
@deck.gl/test-utilsexports/peer deps, which can break contributor workflows and downstream test consumers if assumptions differ.Overview
Migrates the repo’s test workflow from
ocular-test/tape to Vitest projects (node/headless/browser/render) and updates CI to runyarn test-ci, upload render diff artifacts on failure, and keep atape-compatsmoke test for backwards compatibility.Updates
@deck.gl/test-utilsto support both runners by introducing@deck.gl/test-utils/vitest, making spy creation/reset injectable, and adding async cleanup to avoid luma.gl shader-error race unhandled rejections; also adds a new export map entry and optionalvitestpeer dependency.Adds/updates migration tracking docs (new
docs/TEST-STATUS.md, expanded RFC notes, CONTRIBUTING test commands), adjusts lint/ignore lists and gitignore for new configs/screenshots, and removes the oldindex.htmlbrowser test entry.Written by Cursor Bugbot for commit 79bc238. This will update automatically on new commits. Configure here.