@deck.gl/test-utils 9.0.0-beta.2 → 9.0.0-beta.3

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.
Files changed (74) hide show
  1. package/dist/generate-layer-tests.d.ts +20 -0
  2. package/dist/generate-layer-tests.d.ts.map +1 -0
  3. package/dist/generate-layer-tests.js +209 -0
  4. package/dist/index.cjs +645 -0
  5. package/dist/index.cjs.map +7 -0
  6. package/dist/index.d.ts +10 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +11 -0
  9. package/dist/interaction-test-runner.d.ts +29 -0
  10. package/dist/interaction-test-runner.d.ts.map +1 -0
  11. package/dist/interaction-test-runner.js +57 -0
  12. package/dist/lifecycle-test.d.ts +119 -0
  13. package/dist/lifecycle-test.d.ts.map +1 -0
  14. package/dist/lifecycle-test.js +232 -0
  15. package/dist/snapshot-test-runner.d.ts +46 -0
  16. package/dist/snapshot-test-runner.d.ts.map +1 -0
  17. package/dist/snapshot-test-runner.js +101 -0
  18. package/dist/test-runner.d.ts +56 -0
  19. package/dist/test-runner.d.ts.map +1 -0
  20. package/dist/test-runner.js +143 -0
  21. package/dist/utils/dom.d.ts +7 -0
  22. package/dist/utils/dom.d.ts.map +1 -0
  23. package/dist/utils/dom.js +11 -0
  24. package/dist/utils/precision.d.ts +4 -0
  25. package/dist/utils/precision.d.ts.map +1 -0
  26. package/dist/utils/precision.js +19 -0
  27. package/dist/utils/setup-gl.d.ts +5 -0
  28. package/dist/utils/setup-gl.d.ts.map +1 -0
  29. package/dist/utils/setup-gl.js +15 -0
  30. package/package.json +15 -6
  31. package/src/generate-layer-tests.ts +54 -15
  32. package/src/index.ts +6 -3
  33. package/src/interaction-test-runner.ts +29 -13
  34. package/src/lifecycle-test.ts +214 -27
  35. package/src/snapshot-test-runner.ts +79 -47
  36. package/src/test-runner.ts +76 -58
  37. package/src/utils/dom.ts +6 -1
  38. package/src/utils/precision.ts +13 -6
  39. package/dist/es5/generate-layer-tests.js +0 -243
  40. package/dist/es5/generate-layer-tests.js.map +0 -1
  41. package/dist/es5/index.js +0 -88
  42. package/dist/es5/index.js.map +0 -1
  43. package/dist/es5/interaction-test-runner.js +0 -119
  44. package/dist/es5/interaction-test-runner.js.map +0 -1
  45. package/dist/es5/lifecycle-test.js +0 -456
  46. package/dist/es5/lifecycle-test.js.map +0 -1
  47. package/dist/es5/snapshot-test-runner.js +0 -145
  48. package/dist/es5/snapshot-test-runner.js.map +0 -1
  49. package/dist/es5/test-runner.js +0 -198
  50. package/dist/es5/test-runner.js.map +0 -1
  51. package/dist/es5/utils/dom.js +0 -17
  52. package/dist/es5/utils/dom.js.map +0 -1
  53. package/dist/es5/utils/precision.js +0 -33
  54. package/dist/es5/utils/precision.js.map +0 -1
  55. package/dist/es5/utils/setup-gl.js +0 -19
  56. package/dist/es5/utils/setup-gl.js.map +0 -1
  57. package/dist/esm/generate-layer-tests.js +0 -216
  58. package/dist/esm/generate-layer-tests.js.map +0 -1
  59. package/dist/esm/index.js +0 -8
  60. package/dist/esm/index.js.map +0 -1
  61. package/dist/esm/interaction-test-runner.js +0 -52
  62. package/dist/esm/interaction-test-runner.js.map +0 -1
  63. package/dist/esm/lifecycle-test.js +0 -282
  64. package/dist/esm/lifecycle-test.js.map +0 -1
  65. package/dist/esm/snapshot-test-runner.js +0 -94
  66. package/dist/esm/snapshot-test-runner.js.map +0 -1
  67. package/dist/esm/test-runner.js +0 -134
  68. package/dist/esm/test-runner.js.map +0 -1
  69. package/dist/esm/utils/dom.js +0 -10
  70. package/dist/esm/utils/dom.js.map +0 -1
  71. package/dist/esm/utils/precision.js +0 -18
  72. package/dist/esm/utils/precision.js.map +0 -1
  73. package/dist/esm/utils/setup-gl.js +0 -9
  74. 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
- const DEFAULT_TEST_CASE = {
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 default class InteractionTestRunner extends TestRunner {
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
- // TODO - switch to async/await
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
- promise = promise.then(() => sleep(event.wait));
67
+ await sleep(event.wait);
51
68
  } else {
52
- promise = promise.then(() => window.browserTestDriver_emulateInput(event));
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
  }
@@ -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
- const testViewport = new MapView().makeViewport({
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
- function initializeLayerManager({layer, viewport = testViewport, onError = defaultOnError}) {
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
- export function testInitializeLayer(opts) {
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
- export async function testInitializeLayerAsync(opts) {
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 function testLayer(opts) {
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
- export async function testLayerAsync(opts) {
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
- {viewport = testViewport, timeline = null, onError = defaultOnError}
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({layerManager, deckRenderer, oldResourceCounts}) {
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(testCase, newLayer, oldState, spyMap) {
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 ? newLayer.getSubLayers() : [];
195
- const subLayer = subLayers.length && subLayers[0];
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(testCase, {layerManager, deckRenderer}, layer, spies) {
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 default class SnapshotTestRunner extends TestRunner {
44
- constructor(props) {
45
- super(props);
74
+ export class SnapshotTestRunner extends TestRunner<
75
+ SnapshotTestCase,
76
+ DiffImageResult,
77
+ {imageDiffOptions: ImageDiffOptions}
78
+ > {
79
+ private _isDiffing: boolean = false;
46
80
 
47
- this.isDiffing = false;
81
+ constructor(props) {
82
+ super(props, DEFAULT_TEST_OPTIONS);
48
83
 
49
- Object.assign(this.testOptions, DEFAULT_TEST_OPTIONS);
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, onDone) {
64
- const {deck} = this;
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
- shouldRender() {
86
- // wait for the current diffing to finish
87
- return !this.isDiffing;
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.isDiffing) {
124
+ async assert(testCase: SnapshotTestCase) {
125
+ if (this._isDiffing) {
92
126
  // already performing diffing
93
127
  return;
94
128
  }
95
- this.isDiffing = true;
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.canvas)
135
+ region: getBoundingBoxInPage(this.deck!.getCanvas()!)
102
136
  };
103
137
  // Take screenshot and compare
104
- window.browserTestDriver_captureAndDiffScreen(diffOptions).then(result => {
105
- // invoke user callback
106
- if (result.success) {
107
- this._pass(result);
108
- } else {
109
- this._fail(result);
110
- }
111
-
112
- this.isDiffing = false;
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
  }