@deck.gl/test-utils 9.0.0-beta.2 → 9.0.0-beta.4
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/generate-layer-tests.d.ts +20 -0
- package/dist/generate-layer-tests.d.ts.map +1 -0
- package/dist/generate-layer-tests.js +209 -0
- package/dist/index.cjs +645 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/interaction-test-runner.d.ts +29 -0
- package/dist/interaction-test-runner.d.ts.map +1 -0
- package/dist/interaction-test-runner.js +57 -0
- package/dist/lifecycle-test.d.ts +119 -0
- package/dist/lifecycle-test.d.ts.map +1 -0
- package/dist/lifecycle-test.js +232 -0
- package/dist/snapshot-test-runner.d.ts +46 -0
- package/dist/snapshot-test-runner.d.ts.map +1 -0
- package/dist/snapshot-test-runner.js +101 -0
- package/dist/test-runner.d.ts +56 -0
- package/dist/test-runner.d.ts.map +1 -0
- package/dist/test-runner.js +143 -0
- package/dist/utils/dom.d.ts +7 -0
- package/dist/utils/dom.d.ts.map +1 -0
- package/dist/utils/dom.js +11 -0
- package/dist/utils/precision.d.ts +4 -0
- package/dist/utils/precision.d.ts.map +1 -0
- package/dist/utils/precision.js +19 -0
- package/dist/utils/setup-gl.d.ts +5 -0
- package/dist/utils/setup-gl.d.ts.map +1 -0
- package/dist/utils/setup-gl.js +15 -0
- package/package.json +15 -6
- package/src/generate-layer-tests.ts +54 -15
- package/src/index.ts +6 -3
- package/src/interaction-test-runner.ts +29 -13
- package/src/lifecycle-test.ts +214 -27
- package/src/snapshot-test-runner.ts +79 -47
- package/src/test-runner.ts +76 -58
- package/src/utils/dom.ts +6 -1
- package/src/utils/precision.ts +13 -6
- package/dist/es5/generate-layer-tests.js +0 -243
- package/dist/es5/generate-layer-tests.js.map +0 -1
- package/dist/es5/index.js +0 -88
- package/dist/es5/index.js.map +0 -1
- package/dist/es5/interaction-test-runner.js +0 -119
- package/dist/es5/interaction-test-runner.js.map +0 -1
- package/dist/es5/lifecycle-test.js +0 -456
- package/dist/es5/lifecycle-test.js.map +0 -1
- package/dist/es5/snapshot-test-runner.js +0 -145
- package/dist/es5/snapshot-test-runner.js.map +0 -1
- package/dist/es5/test-runner.js +0 -198
- package/dist/es5/test-runner.js.map +0 -1
- package/dist/es5/utils/dom.js +0 -17
- package/dist/es5/utils/dom.js.map +0 -1
- package/dist/es5/utils/precision.js +0 -33
- package/dist/es5/utils/precision.js.map +0 -1
- package/dist/es5/utils/setup-gl.js +0 -19
- package/dist/es5/utils/setup-gl.js.map +0 -1
- package/dist/esm/generate-layer-tests.js +0 -216
- package/dist/esm/generate-layer-tests.js.map +0 -1
- package/dist/esm/index.js +0 -8
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/interaction-test-runner.js +0 -52
- package/dist/esm/interaction-test-runner.js.map +0 -1
- package/dist/esm/lifecycle-test.js +0 -282
- package/dist/esm/lifecycle-test.js.map +0 -1
- package/dist/esm/snapshot-test-runner.js +0 -94
- package/dist/esm/snapshot-test-runner.js.map +0 -1
- package/dist/esm/test-runner.js +0 -134
- package/dist/esm/test-runner.js.map +0 -1
- package/dist/esm/utils/dom.js +0 -10
- package/dist/esm/utils/dom.js.map +0 -1
- package/dist/esm/utils/precision.js +0 -18
- package/dist/esm/utils/precision.js.map +0 -1
- package/dist/esm/utils/setup-gl.js +0 -9
- package/dist/esm/utils/setup-gl.js.map +0 -1
|
@@ -19,48 +19,64 @@
|
|
|
19
19
|
// THE SOFTWARE.
|
|
20
20
|
|
|
21
21
|
/* global window */
|
|
22
|
-
import TestRunner from './test-runner';
|
|
22
|
+
import {TestRunner} from './test-runner';
|
|
23
|
+
import type {Deck, Layer} from '@deck.gl/core';
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
type InteractionEvent =
|
|
26
|
+
| {
|
|
27
|
+
type: string;
|
|
28
|
+
[key: string]: any;
|
|
29
|
+
}
|
|
30
|
+
| {
|
|
31
|
+
wait: number;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type InteractionTestCase = {
|
|
35
|
+
name: string;
|
|
36
|
+
events: InteractionEvent[];
|
|
37
|
+
timeout?: number;
|
|
38
|
+
context?: any;
|
|
39
|
+
onBeforeEvents: (params: {deck: Deck}) => any;
|
|
40
|
+
onAfterEvents: (params: {deck: Deck; layers: Layer[]; context: any}) => void;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const DEFAULT_TEST_CASE: InteractionTestCase = {
|
|
25
44
|
name: 'Unnamed interaction test',
|
|
26
45
|
events: [],
|
|
27
46
|
onBeforeEvents: ({deck}) => {},
|
|
28
47
|
onAfterEvents: ({deck, layers, context}) => {}
|
|
29
48
|
};
|
|
30
49
|
|
|
31
|
-
function sleep(timeout) {
|
|
50
|
+
function sleep(timeout: number): Promise<void> {
|
|
32
51
|
return new Promise(resolve => window.setTimeout(resolve, timeout));
|
|
33
52
|
}
|
|
34
53
|
|
|
35
|
-
export
|
|
54
|
+
export class InteractionTestRunner extends TestRunner<InteractionTestCase, {}> {
|
|
36
55
|
get defaultTestCase() {
|
|
37
56
|
return DEFAULT_TEST_CASE;
|
|
38
57
|
}
|
|
39
58
|
|
|
40
59
|
// chain events
|
|
41
|
-
|
|
42
|
-
runTestCase(testCase, onDone) {
|
|
60
|
+
async runTestCase(testCase: InteractionTestCase) {
|
|
43
61
|
testCase.context = testCase.onBeforeEvents({
|
|
44
|
-
deck: this.deck
|
|
62
|
+
deck: this.deck!
|
|
45
63
|
});
|
|
46
64
|
|
|
47
|
-
let promise = Promise.resolve();
|
|
48
65
|
for (const event of testCase.events) {
|
|
49
66
|
if (event.wait) {
|
|
50
|
-
|
|
67
|
+
await sleep(event.wait);
|
|
51
68
|
} else {
|
|
52
|
-
|
|
69
|
+
await window.browserTestDriver_emulateInput(event);
|
|
53
70
|
}
|
|
54
71
|
}
|
|
55
|
-
return promise.then(onDone);
|
|
56
72
|
}
|
|
57
73
|
|
|
58
|
-
assert(testCase) {
|
|
74
|
+
async assert(testCase) {
|
|
59
75
|
testCase.onAfterEvents({
|
|
60
76
|
deck: this.deck,
|
|
77
|
+
// @ts-expect-error Accessing protected layerManager
|
|
61
78
|
layers: this.deck.layerManager.getLayers(),
|
|
62
79
|
context: testCase.context
|
|
63
80
|
});
|
|
64
|
-
this._next();
|
|
65
81
|
}
|
|
66
82
|
}
|
package/src/lifecycle-test.ts
CHANGED
|
@@ -23,19 +23,38 @@ import {LayerManager, MapView, DeckRenderer} from '@deck.gl/core';
|
|
|
23
23
|
import {makeSpy} from '@probe.gl/test-utils';
|
|
24
24
|
import {device} from './utils/setup-gl';
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
import type {Layer, CompositeLayer, Viewport} from '@deck.gl/core';
|
|
27
|
+
import type {Timeline} from '@luma.gl/engine';
|
|
28
|
+
import type {StatsManager} from '@luma.gl/core';
|
|
29
|
+
|
|
30
|
+
const testViewport = new MapView({}).makeViewport({
|
|
27
31
|
width: 100,
|
|
28
32
|
height: 100,
|
|
29
33
|
viewState: {longitude: 0, latitude: 0, zoom: 1}
|
|
30
|
-
});
|
|
34
|
+
}) as Viewport;
|
|
31
35
|
|
|
32
|
-
function defaultOnError(error, title) {
|
|
36
|
+
function defaultOnError(error: unknown, title: string): void {
|
|
33
37
|
if (error) {
|
|
34
38
|
throw error;
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
41
|
|
|
38
|
-
|
|
42
|
+
type InitializeLayerTestOptions = {
|
|
43
|
+
/** The layer instance to test */
|
|
44
|
+
layer: Layer;
|
|
45
|
+
/** The initial viewport
|
|
46
|
+
* @default WebMercatorViewport
|
|
47
|
+
*/
|
|
48
|
+
viewport?: Viewport;
|
|
49
|
+
/** Callback if any error is thrown */
|
|
50
|
+
onError?: (error: unknown, title: string) => void;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
function initializeLayerManager({
|
|
54
|
+
layer,
|
|
55
|
+
viewport = testViewport,
|
|
56
|
+
onError = defaultOnError
|
|
57
|
+
}: InitializeLayerTestOptions): LayerManager {
|
|
39
58
|
const layerManager = new LayerManager(device, {viewport});
|
|
40
59
|
layerManager.setProps({
|
|
41
60
|
onError: error => onError(error, `initializing ${layer.id}`)
|
|
@@ -45,7 +64,34 @@ function initializeLayerManager({layer, viewport = testViewport, onError = defau
|
|
|
45
64
|
return layerManager;
|
|
46
65
|
}
|
|
47
66
|
|
|
48
|
-
|
|
67
|
+
/** Test that initializing a layer does not throw.
|
|
68
|
+
* Use `testInitializeLayerAsync` if the layer's initialization flow contains async operations.
|
|
69
|
+
*/
|
|
70
|
+
export function testInitializeLayer(
|
|
71
|
+
opts: InitializeLayerTestOptions & {
|
|
72
|
+
/** Automatically finalize the layer and release all resources after the test */
|
|
73
|
+
finalize?: true;
|
|
74
|
+
}
|
|
75
|
+
): null;
|
|
76
|
+
export function testInitializeLayer(
|
|
77
|
+
opts: InitializeLayerTestOptions & {
|
|
78
|
+
/** Automatically finalize the layer and release all resources after the test */
|
|
79
|
+
finalize: false;
|
|
80
|
+
}
|
|
81
|
+
): {
|
|
82
|
+
/** Finalize the layer and release all resources */
|
|
83
|
+
finalize: () => void;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export function testInitializeLayer(
|
|
87
|
+
opts: InitializeLayerTestOptions & {
|
|
88
|
+
/** Automatically finalize the layer and release all resources after the test */
|
|
89
|
+
finalize?: boolean;
|
|
90
|
+
}
|
|
91
|
+
): {
|
|
92
|
+
/** Finalize the layer and release all resources */
|
|
93
|
+
finalize: () => void;
|
|
94
|
+
} | null {
|
|
49
95
|
const layerManager = initializeLayerManager(opts);
|
|
50
96
|
if (opts.finalize === false) {
|
|
51
97
|
return {
|
|
@@ -56,11 +102,38 @@ export function testInitializeLayer(opts) {
|
|
|
56
102
|
return null;
|
|
57
103
|
}
|
|
58
104
|
|
|
59
|
-
|
|
105
|
+
/** Test that initializing a layer does not throw.
|
|
106
|
+
* Resolves when the layer's isLoaded flag becomes true.
|
|
107
|
+
*/
|
|
108
|
+
export function testInitializeLayerAsync(
|
|
109
|
+
opts: InitializeLayerTestOptions & {
|
|
110
|
+
/** Automatically finalize the layer and release all resources after the test */
|
|
111
|
+
finalize?: true;
|
|
112
|
+
}
|
|
113
|
+
): Promise<null>;
|
|
114
|
+
export function testInitializeLayerAsync(
|
|
115
|
+
opts: InitializeLayerTestOptions & {
|
|
116
|
+
/** Automatically finalize the layer and release all resources after the test */
|
|
117
|
+
finalize: false;
|
|
118
|
+
}
|
|
119
|
+
): Promise<{
|
|
120
|
+
/** Finalize the layer and release all resources */
|
|
121
|
+
finalize: () => void;
|
|
122
|
+
}>;
|
|
123
|
+
|
|
124
|
+
export async function testInitializeLayerAsync(
|
|
125
|
+
opts: InitializeLayerTestOptions & {
|
|
126
|
+
/** Automatically finalize the layer and release all resources after the test */
|
|
127
|
+
finalize?: boolean;
|
|
128
|
+
}
|
|
129
|
+
): Promise<{
|
|
130
|
+
/** Finalize the layer and release all resources */
|
|
131
|
+
finalize: () => void;
|
|
132
|
+
} | null> {
|
|
60
133
|
const layerManager = initializeLayerManager(opts);
|
|
61
134
|
const deckRenderer = new DeckRenderer(device);
|
|
62
135
|
while (!opts.layer.isLoaded) {
|
|
63
|
-
await update({layerManager, deckRenderer});
|
|
136
|
+
await update({layerManager, deckRenderer, oldResourceCounts: {}});
|
|
64
137
|
}
|
|
65
138
|
if (opts.finalize === false) {
|
|
66
139
|
return {
|
|
@@ -71,7 +144,68 @@ export async function testInitializeLayerAsync(opts) {
|
|
|
71
144
|
return null;
|
|
72
145
|
}
|
|
73
146
|
|
|
74
|
-
export
|
|
147
|
+
// TODO - export from probe.gl
|
|
148
|
+
type Spy = ReturnType<typeof makeSpy>;
|
|
149
|
+
|
|
150
|
+
export type LayerClass<LayerT extends Layer> = {
|
|
151
|
+
new (...args): LayerT;
|
|
152
|
+
layerName: string;
|
|
153
|
+
defaultProps: Partial<LayerT['props']>;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export type LayerTestCase<LayerT extends Layer> = {
|
|
157
|
+
title: string;
|
|
158
|
+
viewport?: Viewport;
|
|
159
|
+
/** Reset the props of the test layer instance */
|
|
160
|
+
props?: Partial<LayerT['props']>;
|
|
161
|
+
/** Update the given props of the test layer instance */
|
|
162
|
+
updateProps?: Partial<LayerT['props']>;
|
|
163
|
+
/** List of layer method names to watch */
|
|
164
|
+
spies?: string[];
|
|
165
|
+
|
|
166
|
+
/** Called before layer updates */
|
|
167
|
+
onBeforeUpdate?: (params: {layer: Layer; testCase: LayerTestCase<LayerT>}) => void;
|
|
168
|
+
|
|
169
|
+
/** Called after layer is updated */
|
|
170
|
+
onAfterUpdate?: (params: {
|
|
171
|
+
testCase: LayerTestCase<LayerT>;
|
|
172
|
+
layer: LayerT;
|
|
173
|
+
oldState: any;
|
|
174
|
+
subLayers: Layer[];
|
|
175
|
+
subLayer: Layer | null;
|
|
176
|
+
spies: Record<string, Spy>;
|
|
177
|
+
}) => void;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
type TestResources = {
|
|
181
|
+
layerManager: LayerManager;
|
|
182
|
+
deckRenderer: DeckRenderer;
|
|
183
|
+
oldResourceCounts: Record<string, number>;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Initialize and updates a layer over a sequence of scenarios (test cases).
|
|
188
|
+
* Use `testLayerAsync` if the layer's update flow contains async operations.
|
|
189
|
+
*/
|
|
190
|
+
export function testLayer<LayerT extends Layer>(opts: {
|
|
191
|
+
/** The layer class to test against */
|
|
192
|
+
Layer: LayerClass<LayerT>;
|
|
193
|
+
/** The initial viewport
|
|
194
|
+
* @default WebMercatorViewport
|
|
195
|
+
*/
|
|
196
|
+
viewport?: Viewport;
|
|
197
|
+
/**
|
|
198
|
+
* If provided, used to controls time progression. Useful for testing transitions and animations.
|
|
199
|
+
*/
|
|
200
|
+
timeline?: Timeline;
|
|
201
|
+
testCases?: LayerTestCase<LayerT>[];
|
|
202
|
+
/**
|
|
203
|
+
* List of layer method names to watch
|
|
204
|
+
*/
|
|
205
|
+
spies?: string[];
|
|
206
|
+
/** Callback if any error is thrown */
|
|
207
|
+
onError?: (error: Error, title: string) => void;
|
|
208
|
+
}): void {
|
|
75
209
|
const {Layer, testCases = [], spies = [], onError = defaultOnError} = opts;
|
|
76
210
|
|
|
77
211
|
const resources = setupLayerTests(`testing ${Layer.layerName}`, opts);
|
|
@@ -97,7 +231,29 @@ export function testLayer(opts) {
|
|
|
97
231
|
}
|
|
98
232
|
}
|
|
99
233
|
|
|
100
|
-
|
|
234
|
+
/**
|
|
235
|
+
* Initialize and updates a layer over a sequence of scenarios (test cases).
|
|
236
|
+
* Each test case is awaited until the layer's isLoaded flag is true.
|
|
237
|
+
*/
|
|
238
|
+
export async function testLayerAsync<LayerT extends Layer>(opts: {
|
|
239
|
+
/** The layer class to test against */
|
|
240
|
+
Layer: LayerClass<LayerT>;
|
|
241
|
+
/** The initial viewport
|
|
242
|
+
* @default WebMercatorViewport
|
|
243
|
+
*/
|
|
244
|
+
viewport?: Viewport;
|
|
245
|
+
/**
|
|
246
|
+
* If provided, used to controls time progression. Useful for testing transitions and animations.
|
|
247
|
+
*/
|
|
248
|
+
timeline?: Timeline;
|
|
249
|
+
testCases?: LayerTestCase<LayerT>[];
|
|
250
|
+
/**
|
|
251
|
+
* List of layer method names to watch
|
|
252
|
+
*/
|
|
253
|
+
spies?: string[];
|
|
254
|
+
/** Callback if any error is thrown */
|
|
255
|
+
onError?: (error: Error, title: string) => void;
|
|
256
|
+
}): Promise<void> {
|
|
101
257
|
const {Layer, testCases = [], spies = [], onError = defaultOnError} = opts;
|
|
102
258
|
|
|
103
259
|
const resources = setupLayerTests(`testing ${Layer.layerName}`, opts);
|
|
@@ -129,19 +285,25 @@ export async function testLayerAsync(opts) {
|
|
|
129
285
|
}
|
|
130
286
|
|
|
131
287
|
function setupLayerTests(
|
|
132
|
-
testTitle,
|
|
133
|
-
{
|
|
134
|
-
|
|
288
|
+
testTitle: string,
|
|
289
|
+
{
|
|
290
|
+
viewport = testViewport,
|
|
291
|
+
timeline,
|
|
292
|
+
onError = defaultOnError
|
|
293
|
+
}: {
|
|
294
|
+
viewport?: Viewport;
|
|
295
|
+
timeline?: Timeline;
|
|
296
|
+
onError?: (error: Error, title: string) => void;
|
|
297
|
+
}
|
|
298
|
+
): TestResources {
|
|
135
299
|
const oldResourceCounts = getResourceCounts();
|
|
136
300
|
|
|
137
301
|
const layerManager = new LayerManager(device, {viewport, timeline});
|
|
138
302
|
const deckRenderer = new DeckRenderer(device);
|
|
139
303
|
|
|
140
|
-
layerManager.context.animationProps = {
|
|
141
|
-
time: 0
|
|
142
|
-
};
|
|
143
|
-
|
|
144
304
|
const props = {
|
|
305
|
+
layerFilter: null,
|
|
306
|
+
drawPickingColors: false,
|
|
145
307
|
onError: error => onError(error, testTitle)
|
|
146
308
|
};
|
|
147
309
|
layerManager.setProps(props);
|
|
@@ -150,7 +312,11 @@ function setupLayerTests(
|
|
|
150
312
|
return {layerManager, deckRenderer, oldResourceCounts};
|
|
151
313
|
}
|
|
152
314
|
|
|
153
|
-
function cleanupAfterLayerTests({
|
|
315
|
+
function cleanupAfterLayerTests({
|
|
316
|
+
layerManager,
|
|
317
|
+
deckRenderer,
|
|
318
|
+
oldResourceCounts
|
|
319
|
+
}: TestResources): Error | null {
|
|
154
320
|
layerManager.setLayers([]);
|
|
155
321
|
layerManager.finalize();
|
|
156
322
|
deckRenderer.finalize();
|
|
@@ -167,17 +333,17 @@ function cleanupAfterLayerTests({layerManager, deckRenderer, oldResourceCounts})
|
|
|
167
333
|
return null;
|
|
168
334
|
}
|
|
169
335
|
|
|
170
|
-
function getResourceCounts() {
|
|
336
|
+
function getResourceCounts(): Record<string, number> {
|
|
171
337
|
/* global luma */
|
|
172
|
-
const resourceStats = luma.stats.get('Resource Counts');
|
|
338
|
+
const resourceStats = (luma.stats as StatsManager).get('Resource Counts');
|
|
173
339
|
return {
|
|
174
340
|
Texture2D: resourceStats.get('Texture2Ds Active').count,
|
|
175
341
|
Buffer: resourceStats.get('Buffers Active').count
|
|
176
342
|
};
|
|
177
343
|
}
|
|
178
344
|
|
|
179
|
-
function injectSpies(layer, spies) {
|
|
180
|
-
const spyMap = {};
|
|
345
|
+
function injectSpies(layer: Layer, spies: string[]): Record<string, Spy> {
|
|
346
|
+
const spyMap: Record<string, Spy> = {};
|
|
181
347
|
if (spies) {
|
|
182
348
|
for (const functionName of spies) {
|
|
183
349
|
spyMap[functionName] = makeSpy(Object.getPrototypeOf(layer), functionName);
|
|
@@ -186,13 +352,20 @@ function injectSpies(layer, spies) {
|
|
|
186
352
|
return spyMap;
|
|
187
353
|
}
|
|
188
354
|
|
|
189
|
-
function runLayerTestPostUpdateCheck
|
|
355
|
+
function runLayerTestPostUpdateCheck<LayerT extends Layer>(
|
|
356
|
+
testCase: LayerTestCase<LayerT>,
|
|
357
|
+
newLayer: LayerT,
|
|
358
|
+
oldState: any,
|
|
359
|
+
spyMap: Record<string, Spy>
|
|
360
|
+
) {
|
|
190
361
|
// assert on updated layer
|
|
191
362
|
if (testCase.onAfterUpdate) {
|
|
192
363
|
// layer manager should handle match subLayer and tranfer state and props
|
|
193
364
|
// here we assume subLayer matches copy over the new props from a new subLayer
|
|
194
|
-
const subLayers = newLayer.isComposite
|
|
195
|
-
|
|
365
|
+
const subLayers = newLayer.isComposite
|
|
366
|
+
? (newLayer as Layer as CompositeLayer).getSubLayers()
|
|
367
|
+
: [];
|
|
368
|
+
const subLayer = subLayers.length ? subLayers[0] : null;
|
|
196
369
|
|
|
197
370
|
testCase.onAfterUpdate({
|
|
198
371
|
testCase,
|
|
@@ -205,7 +378,15 @@ function runLayerTestPostUpdateCheck(testCase, newLayer, oldState, spyMap) {
|
|
|
205
378
|
}
|
|
206
379
|
}
|
|
207
380
|
|
|
208
|
-
function runLayerTestUpdate
|
|
381
|
+
function runLayerTestUpdate<LayerT extends Layer>(
|
|
382
|
+
testCase: LayerTestCase<LayerT>,
|
|
383
|
+
{layerManager, deckRenderer}: TestResources,
|
|
384
|
+
layer: LayerT,
|
|
385
|
+
spies: string[]
|
|
386
|
+
): {
|
|
387
|
+
layer: LayerT;
|
|
388
|
+
spyMap: Record<string, Spy>;
|
|
389
|
+
} {
|
|
209
390
|
const {props, updateProps, onBeforeUpdate, viewport = layerManager.context.viewport} = testCase;
|
|
210
391
|
|
|
211
392
|
if (onBeforeUpdate) {
|
|
@@ -214,7 +395,7 @@ function runLayerTestUpdate(testCase, {layerManager, deckRenderer}, layer, spies
|
|
|
214
395
|
|
|
215
396
|
if (props) {
|
|
216
397
|
// Test case can reset the props on every iteration
|
|
217
|
-
layer = new layer.constructor(props);
|
|
398
|
+
layer = new (layer.constructor as LayerClass<LayerT>)(props);
|
|
218
399
|
} else if (updateProps) {
|
|
219
400
|
// Test case can override with new props on every iteration
|
|
220
401
|
layer = layer.clone(updateProps);
|
|
@@ -225,6 +406,9 @@ function runLayerTestUpdate(testCase, {layerManager, deckRenderer}, layer, spies
|
|
|
225
406
|
const spyMap = injectSpies(layer, spies);
|
|
226
407
|
const drawLayers = () => {
|
|
227
408
|
deckRenderer.renderLayers({
|
|
409
|
+
pass: 'test',
|
|
410
|
+
views: {},
|
|
411
|
+
effects: [],
|
|
228
412
|
viewports: [viewport],
|
|
229
413
|
layers: layerManager.getLayers(),
|
|
230
414
|
onViewportActive: layerManager.activateViewport
|
|
@@ -244,13 +428,16 @@ function runLayerTestUpdate(testCase, {layerManager, deckRenderer}, layer, spies
|
|
|
244
428
|
}
|
|
245
429
|
|
|
246
430
|
/* global setTimeout */
|
|
247
|
-
function update({layerManager, deckRenderer}) {
|
|
431
|
+
function update({layerManager, deckRenderer}: TestResources): Promise<void> {
|
|
248
432
|
return new Promise(resolve => {
|
|
249
433
|
const onAnimationFrame = () => {
|
|
250
434
|
if (layerManager.needsUpdate()) {
|
|
251
435
|
layerManager.updateLayers();
|
|
252
436
|
|
|
253
437
|
deckRenderer.renderLayers({
|
|
438
|
+
pass: 'test',
|
|
439
|
+
views: {},
|
|
440
|
+
effects: [],
|
|
254
441
|
viewports: [layerManager.context.viewport],
|
|
255
442
|
layers: layerManager.getLayers(),
|
|
256
443
|
onViewportActive: layerManager.activateViewport
|
|
@@ -19,14 +19,45 @@
|
|
|
19
19
|
// THE SOFTWARE.
|
|
20
20
|
|
|
21
21
|
/* global window */
|
|
22
|
-
import TestRunner from './test-runner';
|
|
22
|
+
import {TestRunner} from './test-runner';
|
|
23
23
|
import {getBoundingBoxInPage} from './utils/dom';
|
|
24
24
|
|
|
25
|
+
import type {DeckProps, Deck, Layer} from '@deck.gl/core';
|
|
26
|
+
|
|
27
|
+
// TODO - export from probe.gl
|
|
28
|
+
type ImageDiffOptions = {
|
|
29
|
+
saveOnFail?: boolean;
|
|
30
|
+
saveAs?: string;
|
|
31
|
+
threshold?: number; // 0.99,
|
|
32
|
+
createDiffImage?: boolean; // false,
|
|
33
|
+
tolerance?: number; // 0.1,
|
|
34
|
+
includeAA?: boolean; // false,
|
|
35
|
+
includeEmpty?: boolean; // true
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
type DiffImageResult = {
|
|
39
|
+
headless: boolean;
|
|
40
|
+
match: string | number;
|
|
41
|
+
matchPercentage: string;
|
|
42
|
+
success: boolean;
|
|
43
|
+
error: Error | string | null;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type SnapshotTestCase = {
|
|
47
|
+
name: string;
|
|
48
|
+
props: DeckProps;
|
|
49
|
+
goldenImage: string;
|
|
50
|
+
onBeforeRender?: (params: {deck: Deck; layers: Layer[]}) => void;
|
|
51
|
+
onAfterRender?: (params: {deck: Deck; layers: Layer[]; done: () => void}) => void;
|
|
52
|
+
timeout?: number;
|
|
53
|
+
imageDiffOptions?: ImageDiffOptions;
|
|
54
|
+
};
|
|
55
|
+
|
|
25
56
|
const DEFAULT_TEST_OPTIONS = {
|
|
26
57
|
imageDiffOptions: {}
|
|
27
58
|
};
|
|
28
59
|
|
|
29
|
-
const DEFAULT_TEST_CASE = {
|
|
60
|
+
const DEFAULT_TEST_CASE: SnapshotTestCase = {
|
|
30
61
|
name: 'Unnamed snapshot test',
|
|
31
62
|
props: {},
|
|
32
63
|
onBeforeRender: ({deck, layers}) => {
|
|
@@ -40,77 +71,78 @@ const DEFAULT_TEST_CASE = {
|
|
|
40
71
|
goldenImage: ''
|
|
41
72
|
};
|
|
42
73
|
|
|
43
|
-
export
|
|
44
|
-
|
|
45
|
-
|
|
74
|
+
export class SnapshotTestRunner extends TestRunner<
|
|
75
|
+
SnapshotTestCase,
|
|
76
|
+
DiffImageResult,
|
|
77
|
+
{imageDiffOptions: ImageDiffOptions}
|
|
78
|
+
> {
|
|
79
|
+
private _isDiffing: boolean = false;
|
|
46
80
|
|
|
47
|
-
|
|
81
|
+
constructor(props) {
|
|
82
|
+
super(props, DEFAULT_TEST_OPTIONS);
|
|
48
83
|
|
|
49
|
-
|
|
84
|
+
this._isDiffing = false;
|
|
50
85
|
}
|
|
51
86
|
|
|
52
87
|
get defaultTestCase() {
|
|
53
88
|
return DEFAULT_TEST_CASE;
|
|
54
89
|
}
|
|
55
90
|
|
|
56
|
-
initTestCase(testCase) {
|
|
91
|
+
initTestCase(testCase: SnapshotTestCase) {
|
|
57
92
|
super.initTestCase(testCase);
|
|
58
93
|
if (!testCase.goldenImage) {
|
|
59
94
|
throw new Error(`Test case ${testCase.name} does not have golden image`);
|
|
60
95
|
}
|
|
61
96
|
}
|
|
62
97
|
|
|
63
|
-
runTestCase(testCase
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
deck.setProps({
|
|
67
|
-
...this.props,
|
|
68
|
-
...testCase,
|
|
69
|
-
onBeforeRender: () => {
|
|
70
|
-
testCase.onBeforeRender({
|
|
71
|
-
deck,
|
|
72
|
-
layers: deck.props.layers
|
|
73
|
-
});
|
|
74
|
-
},
|
|
75
|
-
onAfterRender: () => {
|
|
76
|
-
testCase.onAfterRender({
|
|
77
|
-
deck,
|
|
78
|
-
layers: deck.props.layers,
|
|
79
|
-
done: onDone
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
}
|
|
98
|
+
runTestCase(testCase: SnapshotTestCase) {
|
|
99
|
+
const deck = this.deck!;
|
|
84
100
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
101
|
+
return new Promise<void>(resolve => {
|
|
102
|
+
deck.setProps({
|
|
103
|
+
...this.props,
|
|
104
|
+
...testCase,
|
|
105
|
+
onBeforeRender: () => {
|
|
106
|
+
testCase.onBeforeRender!({
|
|
107
|
+
deck,
|
|
108
|
+
// @ts-expect-error Accessing protected layerManager
|
|
109
|
+
layers: this.deck.layerManager.getLayers()
|
|
110
|
+
});
|
|
111
|
+
},
|
|
112
|
+
onAfterRender: () => {
|
|
113
|
+
testCase.onAfterRender!({
|
|
114
|
+
deck,
|
|
115
|
+
// @ts-expect-error Accessing protected layerManager
|
|
116
|
+
layers: this.deck.layerManager.getLayers(),
|
|
117
|
+
done: resolve
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
});
|
|
88
122
|
}
|
|
89
123
|
|
|
90
|
-
assert(testCase) {
|
|
91
|
-
if (this.
|
|
124
|
+
async assert(testCase: SnapshotTestCase) {
|
|
125
|
+
if (this._isDiffing) {
|
|
92
126
|
// already performing diffing
|
|
93
127
|
return;
|
|
94
128
|
}
|
|
95
|
-
this.
|
|
129
|
+
this._isDiffing = true;
|
|
96
130
|
|
|
97
131
|
const diffOptions = {
|
|
98
132
|
...this.testOptions.imageDiffOptions,
|
|
99
133
|
...testCase.imageDiffOptions,
|
|
100
134
|
goldenImage: testCase.goldenImage,
|
|
101
|
-
region: getBoundingBoxInPage(this.deck
|
|
135
|
+
region: getBoundingBoxInPage(this.deck!.getCanvas()!)
|
|
102
136
|
};
|
|
103
137
|
// Take screenshot and compare
|
|
104
|
-
window.browserTestDriver_captureAndDiffScreen(diffOptions)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
this._next();
|
|
114
|
-
});
|
|
138
|
+
const result = await window.browserTestDriver_captureAndDiffScreen(diffOptions);
|
|
139
|
+
// invoke user callback
|
|
140
|
+
if (result.success) {
|
|
141
|
+
this.pass(result);
|
|
142
|
+
} else {
|
|
143
|
+
this.fail(result);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
this._isDiffing = false;
|
|
115
147
|
}
|
|
116
148
|
}
|