@deck.gl/test-utils 9.3.0-alpha.2 → 9.3.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +64 -24
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/lifecycle-test.d.ts +31 -27
- package/dist/lifecycle-test.d.ts.map +1 -1
- package/dist/lifecycle-test.js +40 -21
- package/dist/lifecycle-test.js.map +1 -1
- package/dist/tape.d.ts +22 -0
- package/dist/tape.d.ts.map +1 -0
- package/dist/tape.js +50 -0
- package/dist/tape.js.map +1 -0
- package/dist/test-runner.js +3 -3
- package/dist/test-runner.js.map +1 -1
- package/dist/utils/setup-gl.d.ts +1 -2
- package/dist/utils/setup-gl.d.ts.map +1 -1
- package/dist/utils/setup-gl.js +1 -0
- package/dist/utils/setup-gl.js.map +1 -1
- package/dist/vitest.cjs +465 -0
- package/dist/vitest.cjs.map +7 -0
- package/dist/vitest.d.ts +17 -0
- package/dist/vitest.d.ts.map +1 -0
- package/dist/vitest.js +28 -0
- package/dist/vitest.js.map +1 -0
- package/package.json +19 -8
- package/src/globals.d.ts +42 -0
- package/src/index.ts +3 -7
- package/src/lifecycle-test.ts +98 -50
- package/src/tape.ts +85 -0
- package/src/test-runner.ts +3 -3
- package/src/utils/setup-gl.ts +1 -2
- package/src/vitest.ts +49 -0
package/src/globals.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// deck.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
// Type declarations for browser test driver functions injected by @probe.gl/test-utils
|
|
6
|
+
|
|
7
|
+
interface BrowserTestDriverDiffOptions {
|
|
8
|
+
goldenImage: string;
|
|
9
|
+
region?: {x: number; y: number; width: number; height: number};
|
|
10
|
+
saveOnFail?: boolean;
|
|
11
|
+
saveAs?: string;
|
|
12
|
+
threshold?: number;
|
|
13
|
+
createDiffImage?: boolean;
|
|
14
|
+
tolerance?: number;
|
|
15
|
+
includeAA?: boolean;
|
|
16
|
+
includeEmpty?: boolean;
|
|
17
|
+
platform?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface BrowserTestDriverDiffResult {
|
|
21
|
+
headless: boolean;
|
|
22
|
+
match: string | number;
|
|
23
|
+
matchPercentage: string;
|
|
24
|
+
success: boolean;
|
|
25
|
+
error: Error | string | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface BrowserTestDriverInputEvent {
|
|
29
|
+
type: string;
|
|
30
|
+
[key: string]: any;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
declare global {
|
|
34
|
+
interface Window {
|
|
35
|
+
browserTestDriver_emulateInput(event: BrowserTestDriverInputEvent): Promise<void>;
|
|
36
|
+
browserTestDriver_captureAndDiffScreen(
|
|
37
|
+
options: BrowserTestDriverDiffOptions
|
|
38
|
+
): Promise<BrowserTestDriverDiffResult>;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export {};
|
package/src/index.ts
CHANGED
|
@@ -7,12 +7,8 @@ export {toLowPrecision} from './utils/precision';
|
|
|
7
7
|
export {gl, device} from './utils/setup-gl';
|
|
8
8
|
|
|
9
9
|
// Utilities for update tests (lifecycle tests)
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
testLayerAsync,
|
|
13
|
-
testInitializeLayer,
|
|
14
|
-
testInitializeLayerAsync
|
|
15
|
-
} from './lifecycle-test';
|
|
10
|
+
// Re-export from tape.ts which provides default spy factory for backward compat
|
|
11
|
+
export {testLayer, testLayerAsync, testInitializeLayer, testInitializeLayerAsync} from './tape';
|
|
16
12
|
export {generateLayerTests} from './generate-layer-tests';
|
|
17
13
|
|
|
18
14
|
// Basic utility for rendering multiple scenes (could go into "deck.gl/core")
|
|
@@ -23,6 +19,6 @@ export {SnapshotTestRunner} from './snapshot-test-runner';
|
|
|
23
19
|
// A utility that emulates input events
|
|
24
20
|
export {InteractionTestRunner} from './interaction-test-runner';
|
|
25
21
|
|
|
26
|
-
export type {LayerTestCase} from './
|
|
22
|
+
export type {LayerTestCase, ResetSpy, SpyFactory} from './tape';
|
|
27
23
|
export type {SnapshotTestCase} from './snapshot-test-runner';
|
|
28
24
|
export type {InteractionTestCase} from './interaction-test-runner';
|
package/src/lifecycle-test.ts
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import {LayerManager, MapView, DeckRenderer} from '@deck.gl/core';
|
|
6
6
|
|
|
7
|
-
import {makeSpy} from '@probe.gl/test-utils';
|
|
8
7
|
import {device} from './utils/setup-gl';
|
|
9
8
|
|
|
10
9
|
import type {Layer, CompositeLayer, Viewport} from '@deck.gl/core';
|
|
@@ -128,8 +127,25 @@ export async function testInitializeLayerAsync(
|
|
|
128
127
|
return null;
|
|
129
128
|
}
|
|
130
129
|
|
|
131
|
-
|
|
132
|
-
type Spy =
|
|
130
|
+
/** Spy object compatible with both vitest and probe.gl */
|
|
131
|
+
export type Spy = {
|
|
132
|
+
/** Restore the original method (vitest) */
|
|
133
|
+
mockRestore?: () => void;
|
|
134
|
+
/** Restore the original method (probe.gl) */
|
|
135
|
+
restore?: () => void;
|
|
136
|
+
/** Call history (vitest) */
|
|
137
|
+
mock?: {calls: unknown[][]};
|
|
138
|
+
/** Call history (probe.gl) */
|
|
139
|
+
calls?: unknown[][];
|
|
140
|
+
/** Whether the spy was called (probe.gl) */
|
|
141
|
+
called?: boolean;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/** Factory function to create a spy on an object method */
|
|
145
|
+
export type SpyFactory = (obj: object, method: string) => Spy;
|
|
146
|
+
|
|
147
|
+
/** Function to reset/cleanup a spy after each test case */
|
|
148
|
+
export type ResetSpy = (spy: Spy) => void;
|
|
133
149
|
|
|
134
150
|
export type LayerClass<LayerT extends Layer> = {
|
|
135
151
|
new (...args): LayerT;
|
|
@@ -167,11 +183,7 @@ type TestResources = {
|
|
|
167
183
|
oldResourceCounts: Record<string, number>;
|
|
168
184
|
};
|
|
169
185
|
|
|
170
|
-
|
|
171
|
-
* Initialize and updates a layer over a sequence of scenarios (test cases).
|
|
172
|
-
* Use `testLayerAsync` if the layer's update flow contains async operations.
|
|
173
|
-
*/
|
|
174
|
-
export function testLayer<LayerT extends Layer>(opts: {
|
|
186
|
+
export type TestLayerOptions<LayerT extends Layer> = {
|
|
175
187
|
/** The layer class to test against */
|
|
176
188
|
Layer: LayerClass<LayerT>;
|
|
177
189
|
/** The initial viewport
|
|
@@ -189,8 +201,18 @@ export function testLayer<LayerT extends Layer>(opts: {
|
|
|
189
201
|
spies?: string[];
|
|
190
202
|
/** Callback if any error is thrown */
|
|
191
203
|
onError?: (error: Error, title: string) => void;
|
|
192
|
-
|
|
193
|
-
|
|
204
|
+
/** Factory function to create spies */
|
|
205
|
+
createSpy: SpyFactory;
|
|
206
|
+
/** Function to reset/cleanup a spy after each test case */
|
|
207
|
+
resetSpy: ResetSpy;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Initialize and updates a layer over a sequence of scenarios (test cases).
|
|
212
|
+
* Use `testLayerAsync` if the layer's update flow contains async operations.
|
|
213
|
+
*/
|
|
214
|
+
export function testLayer<LayerT extends Layer>(opts: TestLayerOptions<LayerT>): void {
|
|
215
|
+
const {Layer, testCases = [], spies = [], onError = defaultOnError, createSpy, resetSpy} = opts;
|
|
194
216
|
|
|
195
217
|
const resources = setupLayerTests(`testing ${Layer.layerName}`, opts);
|
|
196
218
|
|
|
@@ -200,12 +222,18 @@ export function testLayer<LayerT extends Layer>(opts: {
|
|
|
200
222
|
// Save old state before update
|
|
201
223
|
const oldState = {...layer.state};
|
|
202
224
|
|
|
203
|
-
const {layer: newLayer, spyMap} = runLayerTestUpdate(
|
|
225
|
+
const {layer: newLayer, spyMap} = runLayerTestUpdate(
|
|
226
|
+
testCase,
|
|
227
|
+
resources,
|
|
228
|
+
layer,
|
|
229
|
+
spies,
|
|
230
|
+
createSpy
|
|
231
|
+
);
|
|
204
232
|
|
|
205
233
|
runLayerTestPostUpdateCheck(testCase, newLayer, oldState, spyMap);
|
|
206
234
|
|
|
207
|
-
//
|
|
208
|
-
Object.keys(spyMap).forEach(k => spyMap[k]
|
|
235
|
+
// Reset spies between test cases
|
|
236
|
+
Object.keys(spyMap).forEach(k => resetSpy(spyMap[k]));
|
|
209
237
|
layer = newLayer;
|
|
210
238
|
}
|
|
211
239
|
|
|
@@ -219,26 +247,10 @@ export function testLayer<LayerT extends Layer>(opts: {
|
|
|
219
247
|
* Initialize and updates a layer over a sequence of scenarios (test cases).
|
|
220
248
|
* Each test case is awaited until the layer's isLoaded flag is true.
|
|
221
249
|
*/
|
|
222
|
-
export async function testLayerAsync<LayerT extends Layer>(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
* @default WebMercatorViewport
|
|
227
|
-
*/
|
|
228
|
-
viewport?: Viewport;
|
|
229
|
-
/**
|
|
230
|
-
* If provided, used to controls time progression. Useful for testing transitions and animations.
|
|
231
|
-
*/
|
|
232
|
-
timeline?: Timeline;
|
|
233
|
-
testCases?: LayerTestCase<LayerT>[];
|
|
234
|
-
/**
|
|
235
|
-
* List of layer method names to watch
|
|
236
|
-
*/
|
|
237
|
-
spies?: string[];
|
|
238
|
-
/** Callback if any error is thrown */
|
|
239
|
-
onError?: (error: Error, title: string) => void;
|
|
240
|
-
}): Promise<void> {
|
|
241
|
-
const {Layer, testCases = [], spies = [], onError = defaultOnError} = opts;
|
|
250
|
+
export async function testLayerAsync<LayerT extends Layer>(
|
|
251
|
+
opts: TestLayerOptions<LayerT>
|
|
252
|
+
): Promise<void> {
|
|
253
|
+
const {Layer, testCases = [], spies = [], onError = defaultOnError, createSpy, resetSpy} = opts;
|
|
242
254
|
|
|
243
255
|
const resources = setupLayerTests(`testing ${Layer.layerName}`, opts);
|
|
244
256
|
|
|
@@ -248,7 +260,13 @@ export async function testLayerAsync<LayerT extends Layer>(opts: {
|
|
|
248
260
|
// Save old state before update
|
|
249
261
|
const oldState = {...layer.state};
|
|
250
262
|
|
|
251
|
-
const {layer: newLayer, spyMap} = runLayerTestUpdate(
|
|
263
|
+
const {layer: newLayer, spyMap} = runLayerTestUpdate(
|
|
264
|
+
testCase,
|
|
265
|
+
resources,
|
|
266
|
+
layer,
|
|
267
|
+
spies,
|
|
268
|
+
createSpy
|
|
269
|
+
);
|
|
252
270
|
|
|
253
271
|
runLayerTestPostUpdateCheck(testCase, newLayer, oldState, spyMap);
|
|
254
272
|
|
|
@@ -257,12 +275,13 @@ export async function testLayerAsync<LayerT extends Layer>(opts: {
|
|
|
257
275
|
runLayerTestPostUpdateCheck(testCase, newLayer, oldState, spyMap);
|
|
258
276
|
}
|
|
259
277
|
|
|
260
|
-
//
|
|
261
|
-
Object.keys(spyMap).forEach(k => spyMap[k]
|
|
278
|
+
// Reset spies between test cases
|
|
279
|
+
Object.keys(spyMap).forEach(k => resetSpy(spyMap[k]));
|
|
262
280
|
layer = newLayer;
|
|
263
281
|
}
|
|
264
282
|
|
|
265
|
-
|
|
283
|
+
// Use async cleanup to allow pending luma.gl async operations to complete
|
|
284
|
+
const error = await cleanupAfterLayerTestsAsync(resources);
|
|
266
285
|
if (error) {
|
|
267
286
|
onError(error, `${Layer.layerName} should delete all resources`);
|
|
268
287
|
}
|
|
@@ -305,16 +324,31 @@ function cleanupAfterLayerTests({
|
|
|
305
324
|
layerManager.finalize();
|
|
306
325
|
deckRenderer.finalize();
|
|
307
326
|
|
|
308
|
-
|
|
327
|
+
return getResourceCountDelta(oldResourceCounts);
|
|
328
|
+
}
|
|
309
329
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
330
|
+
/**
|
|
331
|
+
* Async cleanup that waits for pending async operations before finalizing resources.
|
|
332
|
+
* This prevents unhandled rejections from luma.gl's async shader error reporting
|
|
333
|
+
* which may try to access destroyed WebGL resources if cleanup happens too early.
|
|
334
|
+
*/
|
|
335
|
+
async function cleanupAfterLayerTestsAsync({
|
|
336
|
+
layerManager,
|
|
337
|
+
deckRenderer,
|
|
338
|
+
oldResourceCounts
|
|
339
|
+
}: TestResources): Promise<Error | null> {
|
|
340
|
+
layerManager.setLayers([]);
|
|
341
|
+
|
|
342
|
+
// Wait for any pending async operations (e.g., luma.gl's deferred shader compilation
|
|
343
|
+
// error handling) to complete before destroying resources. This prevents
|
|
344
|
+
// "getProgramInfoLog" errors when async error reporting tries to access
|
|
345
|
+
// already-destroyed WebGL programs.
|
|
346
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
347
|
+
|
|
348
|
+
layerManager.finalize();
|
|
349
|
+
deckRenderer.finalize();
|
|
350
|
+
|
|
351
|
+
return getResourceCountDelta(oldResourceCounts);
|
|
318
352
|
}
|
|
319
353
|
|
|
320
354
|
function getResourceCounts(): Record<string, number> {
|
|
@@ -326,11 +360,24 @@ function getResourceCounts(): Record<string, number> {
|
|
|
326
360
|
};
|
|
327
361
|
}
|
|
328
362
|
|
|
329
|
-
function
|
|
363
|
+
function getResourceCountDelta(oldResourceCounts: Record<string, number>): Error | null {
|
|
364
|
+
const resourceCounts = getResourceCounts();
|
|
365
|
+
|
|
366
|
+
for (const resourceName in resourceCounts) {
|
|
367
|
+
if (resourceCounts[resourceName] !== oldResourceCounts[resourceName]) {
|
|
368
|
+
return new Error(
|
|
369
|
+
`${resourceCounts[resourceName] - oldResourceCounts[resourceName]} ${resourceName}s`
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function injectSpies(layer: Layer, spies: string[], spyFactory: SpyFactory): Record<string, Spy> {
|
|
330
377
|
const spyMap: Record<string, Spy> = {};
|
|
331
378
|
if (spies) {
|
|
332
379
|
for (const functionName of spies) {
|
|
333
|
-
spyMap[functionName] =
|
|
380
|
+
spyMap[functionName] = spyFactory(Object.getPrototypeOf(layer), functionName);
|
|
334
381
|
}
|
|
335
382
|
}
|
|
336
383
|
return spyMap;
|
|
@@ -366,7 +413,8 @@ function runLayerTestUpdate<LayerT extends Layer>(
|
|
|
366
413
|
testCase: LayerTestCase<LayerT>,
|
|
367
414
|
{layerManager, deckRenderer}: TestResources,
|
|
368
415
|
layer: LayerT,
|
|
369
|
-
spies: string[]
|
|
416
|
+
spies: string[],
|
|
417
|
+
spyFactory: SpyFactory
|
|
370
418
|
): {
|
|
371
419
|
layer: LayerT;
|
|
372
420
|
spyMap: Record<string, Spy>;
|
|
@@ -387,7 +435,7 @@ function runLayerTestUpdate<LayerT extends Layer>(
|
|
|
387
435
|
|
|
388
436
|
// Create a map of spies that the test case can inspect
|
|
389
437
|
spies = testCase.spies || spies;
|
|
390
|
-
const spyMap = injectSpies(layer, spies);
|
|
438
|
+
const spyMap = injectSpies(layer, spies, spyFactory);
|
|
391
439
|
const drawLayers = () => {
|
|
392
440
|
deckRenderer.renderLayers({
|
|
393
441
|
pass: 'test',
|
package/src/tape.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// deck.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
// Tape entry point - wraps lifecycle-test and adds @probe.gl/test-utils as the default spy factory
|
|
6
|
+
// For vitest users, use @deck.gl/test-utils/vitest which doesn't import probe.gl
|
|
7
|
+
|
|
8
|
+
import {makeSpy} from '@probe.gl/test-utils';
|
|
9
|
+
import {
|
|
10
|
+
testLayer as testLayerCore,
|
|
11
|
+
testLayerAsync as testLayerAsyncCore,
|
|
12
|
+
testInitializeLayer,
|
|
13
|
+
testInitializeLayerAsync
|
|
14
|
+
} from './lifecycle-test';
|
|
15
|
+
import type {Layer} from '@deck.gl/core';
|
|
16
|
+
import type {
|
|
17
|
+
LayerClass,
|
|
18
|
+
LayerTestCase,
|
|
19
|
+
ResetSpy,
|
|
20
|
+
SpyFactory,
|
|
21
|
+
TestLayerOptions
|
|
22
|
+
} from './lifecycle-test';
|
|
23
|
+
|
|
24
|
+
export {testInitializeLayer, testInitializeLayerAsync};
|
|
25
|
+
export type {LayerClass, LayerTestCase, ResetSpy, SpyFactory};
|
|
26
|
+
|
|
27
|
+
let _hasWarnedCreateSpy = false;
|
|
28
|
+
let _hasWarnedResetSpy = false;
|
|
29
|
+
|
|
30
|
+
function getDefaultSpyFactory(): SpyFactory {
|
|
31
|
+
if (!_hasWarnedCreateSpy) {
|
|
32
|
+
_hasWarnedCreateSpy = true;
|
|
33
|
+
// eslint-disable-next-line no-console
|
|
34
|
+
console.warn(
|
|
35
|
+
'[@deck.gl/test-utils] Implicit @probe.gl/test-utils usage is deprecated. ' +
|
|
36
|
+
'Pass createSpy option: createSpy: (obj, method) => vi.spyOn(obj, method) for vitest, ' +
|
|
37
|
+
'or createSpy: makeSpy for probe.gl.'
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
return makeSpy;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Default reset for probe.gl spies - clears call tracking but keeps spy active */
|
|
44
|
+
function getDefaultResetSpy(): ResetSpy {
|
|
45
|
+
if (!_hasWarnedResetSpy) {
|
|
46
|
+
_hasWarnedResetSpy = true;
|
|
47
|
+
// eslint-disable-next-line no-console
|
|
48
|
+
console.warn(
|
|
49
|
+
'[@deck.gl/test-utils] Implicit spy reset is deprecated. ' +
|
|
50
|
+
'Pass resetSpy option: resetSpy: (spy) => spy.mockRestore() for vitest, ' +
|
|
51
|
+
'or resetSpy: (spy) => spy.reset() for probe.gl.'
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
return spy => (spy as ReturnType<typeof makeSpy>).reset();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Initialize and updates a layer over a sequence of scenarios (test cases).
|
|
59
|
+
* Use `testLayerAsync` if the layer's update flow contains async operations.
|
|
60
|
+
*/
|
|
61
|
+
export function testLayer<LayerT extends Layer>(
|
|
62
|
+
opts: Omit<TestLayerOptions<LayerT>, 'createSpy' | 'resetSpy'> & {
|
|
63
|
+
createSpy?: SpyFactory;
|
|
64
|
+
resetSpy?: ResetSpy;
|
|
65
|
+
}
|
|
66
|
+
): void {
|
|
67
|
+
const createSpy = opts.createSpy || getDefaultSpyFactory();
|
|
68
|
+
const resetSpy = opts.resetSpy || getDefaultResetSpy();
|
|
69
|
+
testLayerCore({...opts, createSpy, resetSpy});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Initialize and updates a layer over a sequence of scenarios (test cases).
|
|
74
|
+
* Each test case is awaited until the layer's isLoaded flag is true.
|
|
75
|
+
*/
|
|
76
|
+
export async function testLayerAsync<LayerT extends Layer>(
|
|
77
|
+
opts: Omit<TestLayerOptions<LayerT>, 'createSpy' | 'resetSpy'> & {
|
|
78
|
+
createSpy?: SpyFactory;
|
|
79
|
+
resetSpy?: ResetSpy;
|
|
80
|
+
}
|
|
81
|
+
): Promise<void> {
|
|
82
|
+
const createSpy = opts.createSpy || getDefaultSpyFactory();
|
|
83
|
+
const resetSpy = opts.resetSpy || getDefaultResetSpy();
|
|
84
|
+
await testLayerAsyncCore({...opts, createSpy, resetSpy});
|
|
85
|
+
}
|
package/src/test-runner.ts
CHANGED
|
@@ -163,7 +163,7 @@ export abstract class TestRunner<TestCaseT extends TestCase, ResultT, ExtraOptio
|
|
|
163
163
|
const task = this.runTestCase(testCase);
|
|
164
164
|
const timeoutTask = new Promise((_, reject) => {
|
|
165
165
|
setTimeout(() => {
|
|
166
|
-
reject(
|
|
166
|
+
reject(`Timeout after ${timeout}ms`);
|
|
167
167
|
}, timeout);
|
|
168
168
|
});
|
|
169
169
|
|
|
@@ -171,8 +171,8 @@ export abstract class TestRunner<TestCaseT extends TestCase, ResultT, ExtraOptio
|
|
|
171
171
|
await Promise.race([task, timeoutTask]);
|
|
172
172
|
await this.assert(testCase);
|
|
173
173
|
} catch (err: unknown) {
|
|
174
|
-
if (err === 'Timeout') {
|
|
175
|
-
this.fail({error:
|
|
174
|
+
if (typeof err === 'string' && err.startsWith('Timeout')) {
|
|
175
|
+
this.fail({error: err});
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
}
|
package/src/utils/setup-gl.ts
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import {CanvasContextProps} from '@luma.gl/core';
|
|
6
|
-
import {WebGLDevice} from '@luma.gl/webgl';
|
|
7
5
|
import {webglDevice, NullDevice} from '@luma.gl/test-utils';
|
|
8
6
|
|
|
7
|
+
// Use pre-created device from @luma.gl/test-utils, fall back to NullDevice in Node
|
|
9
8
|
export const device = webglDevice || new NullDevice({});
|
|
10
9
|
export const gl = webglDevice?.gl || 1;
|
|
11
10
|
|
package/src/vitest.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// deck.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
// Vitest-specific entry point with vi.spyOn default
|
|
6
|
+
// Use: import { testLayer } from '@deck.gl/test-utils/vitest'
|
|
7
|
+
|
|
8
|
+
import {vi} from 'vitest';
|
|
9
|
+
import {testLayer as testLayerCore, testLayerAsync as testLayerAsyncCore} from './lifecycle-test';
|
|
10
|
+
import type {Layer} from '@deck.gl/core';
|
|
11
|
+
import type {ResetSpy, SpyFactory, TestLayerOptions} from './lifecycle-test';
|
|
12
|
+
|
|
13
|
+
/** Default spy factory using vi.spyOn */
|
|
14
|
+
const defaultSpyFactory: SpyFactory = (obj, method) => vi.spyOn(obj, method as never);
|
|
15
|
+
|
|
16
|
+
/** Default reset for vitest spies - restores original implementation */
|
|
17
|
+
const defaultResetSpy: ResetSpy = spy => spy.mockRestore?.();
|
|
18
|
+
|
|
19
|
+
export function testLayer<LayerT extends Layer>(
|
|
20
|
+
opts: Omit<TestLayerOptions<LayerT>, 'createSpy' | 'resetSpy'> & {
|
|
21
|
+
createSpy?: SpyFactory;
|
|
22
|
+
resetSpy?: ResetSpy;
|
|
23
|
+
}
|
|
24
|
+
) {
|
|
25
|
+
const createSpy = opts.createSpy || defaultSpyFactory;
|
|
26
|
+
const resetSpy = opts.resetSpy || defaultResetSpy;
|
|
27
|
+
return testLayerCore({...opts, createSpy, resetSpy});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function testLayerAsync<LayerT extends Layer>(
|
|
31
|
+
opts: Omit<TestLayerOptions<LayerT>, 'createSpy' | 'resetSpy'> & {
|
|
32
|
+
createSpy?: SpyFactory;
|
|
33
|
+
resetSpy?: ResetSpy;
|
|
34
|
+
}
|
|
35
|
+
) {
|
|
36
|
+
const createSpy = opts.createSpy || defaultSpyFactory;
|
|
37
|
+
const resetSpy = opts.resetSpy || defaultResetSpy;
|
|
38
|
+
return testLayerAsyncCore({...opts, createSpy, resetSpy});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Re-export non-spy utilities
|
|
42
|
+
export {testInitializeLayer, testInitializeLayerAsync} from './lifecycle-test';
|
|
43
|
+
export {getLayerUniforms} from './utils/layer';
|
|
44
|
+
export {toLowPrecision} from './utils/precision';
|
|
45
|
+
export {gl, device} from './utils/setup-gl';
|
|
46
|
+
export {generateLayerTests} from './generate-layer-tests';
|
|
47
|
+
|
|
48
|
+
// Types
|
|
49
|
+
export type {LayerTestCase, ResetSpy, SpyFactory, TestLayerOptions} from './lifecycle-test';
|