maplibre-gl 3.3.0 → 3.4.0

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 (50) hide show
  1. package/LICENSE.txt +1 -1
  2. package/README.md +3 -2
  3. package/build/generate-dist-package.js +7 -2
  4. package/build/generate-typings.ts +1 -1
  5. package/dist/LICENSE.txt +116 -0
  6. package/dist/maplibre-gl-csp-worker.js +1 -1
  7. package/dist/maplibre-gl-csp-worker.js.map +1 -1
  8. package/dist/maplibre-gl-csp.js +1 -1
  9. package/dist/maplibre-gl-csp.js.map +1 -1
  10. package/dist/maplibre-gl-dev.js +243 -100
  11. package/dist/maplibre-gl-dev.js.map +1 -1
  12. package/dist/maplibre-gl.d.ts +28 -15
  13. package/dist/maplibre-gl.js +4 -4
  14. package/dist/maplibre-gl.js.map +1 -1
  15. package/dist/package.json +1 -1
  16. package/package.json +48 -47
  17. package/src/data/dem_data.test.ts +120 -165
  18. package/src/data/dem_data.ts +38 -18
  19. package/src/render/program.ts +15 -0
  20. package/src/source/image_source.test.ts +17 -24
  21. package/src/source/raster_dem_tile_source.ts +15 -2
  22. package/src/source/raster_dem_tile_worker_source.ts +2 -2
  23. package/src/source/raster_tile_source.test.ts +1 -1
  24. package/src/source/raster_tile_source.ts +1 -1
  25. package/src/source/terrain_source_cache.test.ts +1 -1
  26. package/src/source/vector_tile_source.test.ts +1 -1
  27. package/src/source/vector_tile_source.ts +0 -1
  28. package/src/source/vector_tile_worker_source.test.ts +45 -1
  29. package/src/source/vector_tile_worker_source.ts +19 -6
  30. package/src/source/video_source.ts +4 -0
  31. package/src/source/worker_source.ts +6 -2
  32. package/src/style/load_glyph_range.test.ts +6 -8
  33. package/src/style/load_sprite.test.ts +48 -71
  34. package/src/style/style.test.ts +19 -49
  35. package/src/style/style.ts +14 -8
  36. package/src/style/style_layer/line_style_layer.test.ts +50 -0
  37. package/src/style/style_layer/line_style_layer.ts +8 -4
  38. package/src/style/style_layer/variable_text_anchor.ts +1 -1
  39. package/src/ui/control/navigation_control.ts +0 -1
  40. package/src/ui/handler/scroll_zoom.ts +6 -0
  41. package/src/ui/handler_manager.ts +2 -1
  42. package/src/ui/map.test.ts +37 -8
  43. package/src/ui/map.ts +15 -13
  44. package/src/ui/marker.test.ts +25 -0
  45. package/src/ui/marker.ts +9 -2
  46. package/src/ui/popup.ts +1 -1
  47. package/src/util/ajax.test.ts +1 -1
  48. package/src/util/image_request.test.ts +1 -1
  49. package/src/util/test/util.ts +12 -0
  50. package/src/util/throttle.ts +7 -3
@@ -2,7 +2,7 @@ import {ImageSource} from './image_source';
2
2
  import {Evented} from '../util/evented';
3
3
  import {Transform} from '../geo/transform';
4
4
  import {extend} from '../util/util';
5
- import {fakeXhr} from 'nise';
5
+ import {type FakeServer, fakeServer} from 'nise';
6
6
  import {RequestManager} from '../util/request_manager';
7
7
  import {Dispatcher} from '../util/dispatcher';
8
8
  import {stubAjaxGetImage} from '../util/test/util';
@@ -44,20 +44,15 @@ class StubMap extends Evented {
44
44
  }
45
45
 
46
46
  describe('ImageSource', () => {
47
- const requests = [];
48
- fakeXhr.useFakeXMLHttpRequest().onCreate = (req) => { requests.push(req); };
49
47
  stubAjaxGetImage(undefined);
48
+ let server: FakeServer;
49
+
50
50
  beforeEach(() => {
51
51
  global.fetch = null;
52
+ server = fakeServer.create();
53
+ server.respondWith(new ArrayBuffer(1));
52
54
  });
53
55
 
54
- const respond = () => {
55
- const req = requests.shift();
56
- req.setStatus(200);
57
- req.response = new ArrayBuffer(1);
58
- req.onload();
59
- };
60
-
61
56
  test('constructor', () => {
62
57
  const source = createSource({url: '/image.png'});
63
58
 
@@ -72,7 +67,7 @@ describe('ImageSource', () => {
72
67
  expect(e.dataType).toBe('source');
73
68
  });
74
69
  source.onAdd(new StubMap() as any);
75
- respond();
70
+ server.respond();
76
71
  expect(source.image).toBeTruthy();
77
72
  });
78
73
 
@@ -81,7 +76,7 @@ describe('ImageSource', () => {
81
76
  const map = new StubMap() as any;
82
77
  const spy = jest.spyOn(map._requestManager, 'transformRequest');
83
78
  source.onAdd(map);
84
- respond();
79
+ server.respond();
85
80
  expect(spy).toHaveBeenCalledTimes(1);
86
81
  expect(spy.mock.calls[0][0]).toBe('/image.png');
87
82
  expect(spy.mock.calls[0][1]).toBe('Image');
@@ -92,12 +87,12 @@ describe('ImageSource', () => {
92
87
  const map = new StubMap() as any;
93
88
  const spy = jest.spyOn(map._requestManager, 'transformRequest');
94
89
  source.onAdd(map);
95
- respond();
90
+ server.respond();
96
91
  expect(spy).toHaveBeenCalledTimes(1);
97
92
  expect(spy.mock.calls[0][0]).toBe('/image.png');
98
93
  expect(spy.mock.calls[0][1]).toBe('Image');
99
94
  source.updateImage({url: '/image2.png'});
100
- respond();
95
+ server.respond();
101
96
  expect(spy).toHaveBeenCalledTimes(2);
102
97
  expect(spy.mock.calls[1][0]).toBe('/image2.png');
103
98
  expect(spy.mock.calls[1][1]).toBe('Image');
@@ -107,7 +102,7 @@ describe('ImageSource', () => {
107
102
  const source = createSource({url: '/image.png'});
108
103
  const map = new StubMap() as any;
109
104
  source.onAdd(map);
110
- respond();
105
+ server.respond();
111
106
  const beforeSerialized = source.serialize();
112
107
  expect(beforeSerialized.coordinates).toEqual([[0, 0], [1, 0], [1, 1], [0, 1]]);
113
108
  source.setCoordinates([[0, 0], [-1, 0], [-1, -1], [0, -1]]);
@@ -119,14 +114,14 @@ describe('ImageSource', () => {
119
114
  const source = createSource({url: '/image.png'});
120
115
  const map = new StubMap() as any;
121
116
  source.onAdd(map);
122
- respond();
117
+ server.respond();
123
118
  const beforeSerialized = source.serialize();
124
119
  expect(beforeSerialized.coordinates).toEqual([[0, 0], [1, 0], [1, 1], [0, 1]]);
125
120
  source.updateImage({
126
121
  url: '/image2.png',
127
122
  coordinates: [[0, 0], [-1, 0], [-1, -1], [0, -1]]
128
123
  });
129
- respond();
124
+ server.respond();
130
125
  const afterSerialized = source.serialize();
131
126
  expect(afterSerialized.coordinates).toEqual([[0, 0], [-1, 0], [-1, -1], [0, -1]]);
132
127
  });
@@ -140,7 +135,7 @@ describe('ImageSource', () => {
140
135
  }
141
136
  });
142
137
  source.onAdd(new StubMap() as any);
143
- respond();
138
+ server.respond();
144
139
  });
145
140
 
146
141
  test('fires data event when metadata is loaded', done => {
@@ -151,7 +146,7 @@ describe('ImageSource', () => {
151
146
  }
152
147
  });
153
148
  source.onAdd(new StubMap() as any);
154
- respond();
149
+ server.respond();
155
150
  });
156
151
 
157
152
  test('fires idle event on prepare call when there is at least one not loaded tile', done => {
@@ -164,7 +159,7 @@ describe('ImageSource', () => {
164
159
  }
165
160
  });
166
161
  source.onAdd(new StubMap() as any);
167
- respond();
162
+ server.respond();
168
163
 
169
164
  source.tiles[String(tile.tileID.wrap)] = tile;
170
165
  source.image = new ImageBitmap();
@@ -190,10 +185,9 @@ describe('ImageSource', () => {
190
185
 
191
186
  source.onAdd(map);
192
187
 
193
- requests.shift();
194
188
  expect(source.image).toBeUndefined();
195
189
  source.updateImage({url: '/image2.png'});
196
- respond();
190
+ server.respond();
197
191
  expect(source.image).toBeTruthy();
198
192
  });
199
193
 
@@ -203,8 +197,7 @@ describe('ImageSource', () => {
203
197
 
204
198
  source.onAdd(map);
205
199
 
206
- const request = requests.shift() as any;
207
- const spy = jest.spyOn(request, 'abort');
200
+ const spy = jest.spyOn(server.requests[0] as any, 'abort');
208
201
 
209
202
  source.updateImage({url: '/image2.png'});
210
203
  expect(spy).toHaveBeenCalled();
@@ -8,6 +8,7 @@ import {OverscaledTileID} from './tile_id';
8
8
  import {RasterTileSource} from './raster_tile_source';
9
9
  // ensure DEMData is registered for worker transfer on main thread:
10
10
  import '../data/dem_data';
11
+ import type {DEMEncoding} from '../data/dem_data';
11
12
 
12
13
  import type {Source} from './source';
13
14
  import type {Dispatcher} from '../util/dispatcher';
@@ -33,7 +34,11 @@ import type {ExpiryData} from '../util/ajax';
33
34
  * @see [3D Terrain](https://maplibre.org/maplibre-gl-js/docs/examples/3d-terrain/)
34
35
  */
35
36
  export class RasterDEMTileSource extends RasterTileSource implements Source {
36
- encoding: 'mapbox' | 'terrarium';
37
+ encoding: DEMEncoding;
38
+ redFactor?: number;
39
+ greenFactor?: number;
40
+ blueFactor?: number;
41
+ baseShift?: number;
37
42
 
38
43
  constructor(id: string, options: RasterDEMSourceSpecification, dispatcher: Dispatcher, eventedParent: Evented) {
39
44
  super(id, options, dispatcher, eventedParent);
@@ -41,6 +46,10 @@ export class RasterDEMTileSource extends RasterTileSource implements Source {
41
46
  this.maxzoom = 22;
42
47
  this._options = extend({type: 'raster-dem'}, options);
43
48
  this.encoding = options.encoding || 'mapbox';
49
+ this.redFactor = options.redFactor;
50
+ this.greenFactor = options.greenFactor;
51
+ this.blueFactor = options.blueFactor;
52
+ this.baseShift = options.baseShift;
44
53
  }
45
54
 
46
55
  loadTile(tile: Tile, callback: Callback<void>) {
@@ -67,7 +76,11 @@ export class RasterDEMTileSource extends RasterTileSource implements Source {
67
76
  coord: tile.tileID,
68
77
  source: this.id,
69
78
  rawImageData,
70
- encoding: this.encoding
79
+ encoding: this.encoding,
80
+ redFactor: this.redFactor,
81
+ greenFactor: this.greenFactor,
82
+ blueFactor: this.blueFactor,
83
+ baseShift: this.baseShift
71
84
  };
72
85
 
73
86
  if (!tile.actor || tile.state === 'expired') {
@@ -19,10 +19,10 @@ export class RasterDEMTileWorkerSource {
19
19
  }
20
20
 
21
21
  loadTile(params: WorkerDEMTileParameters, callback: WorkerDEMTileCallback) {
22
- const {uid, encoding, rawImageData} = params;
22
+ const {uid, encoding, rawImageData, redFactor, greenFactor, blueFactor, baseShift} = params;
23
23
  // Main thread will transfer ImageBitmap if offscreen decode with OffscreenCanvas is supported, else it will transfer an already decoded image.
24
24
  const imagePixels = isImageBitmap(rawImageData) ? this.getImageData(rawImageData) : rawImageData as RGBAImage;
25
- const dem = new DEMData(uid, imagePixels, encoding);
25
+ const dem = new DEMData(uid, imagePixels, encoding, redFactor, greenFactor, blueFactor, baseShift);
26
26
  this.loaded = this.loaded || {};
27
27
  this.loaded[uid] = dem;
28
28
  callback(null, dem);
@@ -2,7 +2,7 @@ import {RasterTileSource} from './raster_tile_source';
2
2
  import {OverscaledTileID} from './tile_id';
3
3
  import {RequestManager} from '../util/request_manager';
4
4
  import {Dispatcher} from '../util/dispatcher';
5
- import {fakeServer, FakeServer} from 'nise';
5
+ import {fakeServer, type FakeServer} from 'nise';
6
6
  import {Tile} from './tile';
7
7
  import {stubAjaxGetImage} from '../util/test/util';
8
8
 
@@ -29,7 +29,7 @@ import type {
29
29
  * ```ts
30
30
  * map.addSource('raster-source', {
31
31
  * 'type': 'raster',
32
- * 'tiles': ['https://stamen-tiles.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.jpg'],
32
+ * 'tiles': ['https://tiles.stadiamaps.com/tiles/stamen_watercolor/{z}/{x}/{y}.jpg'],
33
33
  * 'tileSize': 256,
34
34
  * });
35
35
  * ```
@@ -2,7 +2,7 @@ import {TerrainSourceCache} from './terrain_source_cache';
2
2
  import {Style} from '../style/style';
3
3
  import {RequestManager} from '../util/request_manager';
4
4
  import {Dispatcher} from '../util/dispatcher';
5
- import {fakeServer, FakeServer} from 'nise';
5
+ import {fakeServer, type FakeServer} from 'nise';
6
6
  import {Transform} from '../geo/transform';
7
7
  import {Evented} from '../util/evented';
8
8
  import {Painter} from '../render/painter';
@@ -1,4 +1,4 @@
1
- import {fakeServer, FakeServer} from 'nise';
1
+ import {fakeServer, type FakeServer} from 'nise';
2
2
  import {Source} from './source';
3
3
  import {VectorTileSource} from './vector_tile_source';
4
4
  import {Tile} from './tile';
@@ -52,7 +52,6 @@ export type VectorTileSourceOptions = VectorSourceSpecification & {
52
52
  * map.getSource('some id').setTiles(['https://d25uarhxywzl1j.cloudfront.net/v0.1/{z}/{x}/{y}.mvt']);
53
53
  * ```
54
54
  * @see [Add a vector tile source](https://maplibre.org/maplibre-gl-js/docs/examples/vector-source/)
55
- * @see [Add a third party vector tile source](https://maplibre.org/maplibre-gl-js/docs/examples/third-party/)
56
55
  */
57
56
  export class VectorTileSource extends Evented implements Source {
58
57
  type: 'vector';
@@ -4,7 +4,7 @@ import vt from '@mapbox/vector-tile';
4
4
  import Protobuf from 'pbf';
5
5
  import {VectorTileWorkerSource} from '../source/vector_tile_worker_source';
6
6
  import {StyleLayerIndex} from '../style/style_layer_index';
7
- import {fakeServer, FakeServer} from 'nise';
7
+ import {fakeServer, type FakeServer} from 'nise';
8
8
  import {Actor} from '../util/actor';
9
9
  import {TileParameters, WorkerTileParameters, WorkerTileResult} from './worker_source';
10
10
  import {WorkerTile} from './worker_tile';
@@ -234,6 +234,50 @@ describe('vector tile worker source', () => {
234
234
 
235
235
  });
236
236
 
237
+ test('VectorTileWorkerSource#returns a good error message when failing to parse a tile', () => {
238
+ const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []);
239
+ const parse = jest.fn();
240
+ const callback = jest.fn();
241
+
242
+ server.respondWith(request => {
243
+ request.respond(200, {'Content-Type': 'application/pbf'}, 'something...');
244
+ });
245
+
246
+ source.loadTile({
247
+ source: 'source',
248
+ uid: 0,
249
+ tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}},
250
+ request: {url: 'http://localhost:2900/faketile.pbf'}
251
+ } as any as WorkerTileParameters, callback);
252
+
253
+ server.respond();
254
+
255
+ expect(parse).not.toHaveBeenCalled();
256
+ expect(callback).toHaveBeenCalledTimes(1);
257
+ expect(callback.mock.calls[0][0].message).toContain('Unable to parse the tile at');
258
+ });
259
+
260
+ test('VectorTileWorkerSource#returns a good error message when failing to parse a gzipped tile', () => {
261
+ const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []);
262
+ const parse = jest.fn();
263
+ const callback = jest.fn();
264
+
265
+ server.respondWith(new Uint8Array([0x1f, 0x8b]).buffer);
266
+
267
+ source.loadTile({
268
+ source: 'source',
269
+ uid: 0,
270
+ tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}},
271
+ request: {url: 'http://localhost:2900/faketile.pbf'}
272
+ } as any as WorkerTileParameters, callback);
273
+
274
+ server.respond();
275
+
276
+ expect(parse).not.toHaveBeenCalled();
277
+ expect(callback).toHaveBeenCalledTimes(1);
278
+ expect(callback.mock.calls[0][0].message).toContain('gzipped');
279
+ });
280
+
237
281
  test('VectorTileWorkerSource provides resource timing information', done => {
238
282
  const rawTileData = fs.readFileSync(path.join(__dirname, '/../../test/unit/assets/mbsv5-6-18-23.vector.pbf'));
239
283
 
@@ -46,12 +46,25 @@ function loadVectorTile(params: WorkerTileParameters, callback: LoadVectorDataCa
46
46
  if (err) {
47
47
  callback(err);
48
48
  } else if (data) {
49
- callback(null, {
50
- vectorTile: new vt.VectorTile(new Protobuf(data)),
51
- rawData: data,
52
- cacheControl,
53
- expires
54
- });
49
+ try {
50
+ const vectorTile = new vt.VectorTile(new Protobuf(data));
51
+ callback(null, {
52
+ vectorTile,
53
+ rawData: data,
54
+ cacheControl,
55
+ expires
56
+ });
57
+ } catch (ex) {
58
+ const bytes = new Uint8Array(data);
59
+ const isGzipped = bytes[0] === 0x1f && bytes[1] === 0x8b;
60
+ let errorMessage = `Unable to parse the tile at ${params.request.url}, `;
61
+ if (isGzipped) {
62
+ errorMessage += 'please make sure the data is not gzipped and that you have configured the relevant header in the server';
63
+ } else {
64
+ errorMessage += `got error: ${ex.messge}`;
65
+ }
66
+ callback(new Error(errorMessage));
67
+ }
55
68
  }
56
69
  });
57
70
  return () => {
@@ -48,6 +48,10 @@ import type {VideoSourceSpecification} from '@maplibre/maplibre-gl-style-spec';
48
48
  * map.removeSource('some id'); // remove
49
49
  * ```
50
50
  * @see [Add a video](https://maplibre.org/maplibre-gl-js/docs/examples/video-on-a-map/)
51
+ *
52
+ * Note that when rendered as a raster layer, the layer's `raster-fade-duration` property will cause the video to fade in.
53
+ * This happens when playback is started, paused and resumed, or when the video's coordinates are updated. To avoid this behavior,
54
+ * set the layer's `raster-fade-duration` property to `0`.
51
55
  */
52
56
  export class VideoSource extends ImageSource {
53
57
  options: VideoSourceSpecification;
@@ -6,7 +6,7 @@ import type {OverscaledTileID} from './tile_id';
6
6
  import type {Bucket} from '../data/bucket';
7
7
  import type {FeatureIndex} from '../data/feature_index';
8
8
  import type {CollisionBoxArray} from '../data/array_types.g';
9
- import type {DEMData} from '../data/dem_data';
9
+ import type {DEMData, DEMEncoding} from '../data/dem_data';
10
10
  import type {StyleGlyph} from '../style/style_glyph';
11
11
  import type {StyleImage} from '../style/style_image';
12
12
  import type {PromoteIdSpecification} from '@maplibre/maplibre-gl-style-spec';
@@ -37,7 +37,11 @@ export type WorkerDEMTileParameters = TileParameters & {
37
37
  w: number;
38
38
  };
39
39
  rawImageData: RGBAImage | ImageBitmap;
40
- encoding: 'mapbox' | 'terrarium';
40
+ encoding: DEMEncoding;
41
+ redFactor: number;
42
+ greenFactor: number;
43
+ blueFactor: number;
44
+ baseShift: number;
41
45
  };
42
46
 
43
47
  /**
@@ -2,7 +2,8 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import {RequestManager} from '../util/request_manager';
4
4
  import {loadGlyphRange} from './load_glyph_range';
5
- import {fakeXhr} from 'nise';
5
+ import {fakeServer} from 'nise';
6
+ import {bufferToArrayBuffer} from '../util/test/util';
6
7
 
7
8
  test('loadGlyphRange', done => {
8
9
  global.fetch = null;
@@ -13,8 +14,8 @@ test('loadGlyphRange', done => {
13
14
 
14
15
  const manager = new RequestManager(transform);
15
16
 
16
- let request;
17
- fakeXhr.useFakeXMLHttpRequest().onCreate = (req) => { request = req; };
17
+ const server = fakeServer.create();
18
+ server.respondWith(bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/0-255.pbf'))));
18
19
 
19
20
  loadGlyphRange('Arial Unicode MS', 0, 'https://localhost/fonts/v1/{fontstack}/{range}.pbf', manager, (err, result) => {
20
21
  expect(err).toBeFalsy();
@@ -35,9 +36,6 @@ test('loadGlyphRange', done => {
35
36
  }
36
37
  done();
37
38
  });
38
-
39
- expect(request.url).toBe('https://localhost/fonts/v1/Arial Unicode MS/0-255.pbf');
40
- request.setStatus(200);
41
- request.response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/0-255.pbf'));
42
- request.onload();
39
+ server.respond();
40
+ expect(server.requests[0].url).toBe('https://localhost/fonts/v1/Arial Unicode MS/0-255.pbf');
43
41
  });
@@ -2,18 +2,25 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import {RequestManager} from '../util/request_manager';
4
4
  import {loadSprite} from './load_sprite';
5
- import {fakeXhr} from 'nise';
5
+ import {type FakeServer, fakeServer} from 'nise';
6
6
  import * as util from '../util/util';
7
+ import {bufferToArrayBuffer} from '../util/test/util';
7
8
 
8
9
  describe('loadSprite', () => {
9
- jest.spyOn(util, 'arrayBufferToImageBitmap').mockImplementation((data: ArrayBuffer, callback: (err?: Error | null, image?: ImageBitmap | null) => void) => {
10
- createImageBitmap(new ImageData(1024, 824)).then((imgBitmap) => {
11
- callback(null, imgBitmap);
12
- }).catch((e) => {
13
- callback(new Error(`Could not load image because of ${e.message}. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.`));
10
+
11
+ let server: FakeServer;
12
+
13
+ beforeEach(() => {
14
+ jest.spyOn(util, 'arrayBufferToImageBitmap').mockImplementation((data: ArrayBuffer, callback: (err?: Error | null, image?: ImageBitmap | null) => void) => {
15
+ createImageBitmap(new ImageData(1024, 824)).then((imgBitmap) => {
16
+ callback(null, imgBitmap);
17
+ }).catch((e) => {
18
+ callback(new Error(`Could not load image because of ${e.message}. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.`));
19
+ });
14
20
  });
21
+ global.fetch = null;
22
+ server = fakeServer.create();
15
23
  });
16
- global.fetch = null;
17
24
 
18
25
  test('backwards compatibility: single string is treated as a URL for the default sprite', done => {
19
26
  const transform = jest.fn().mockImplementation((url, type) => {
@@ -22,8 +29,8 @@ describe('loadSprite', () => {
22
29
 
23
30
  const manager = new RequestManager(transform);
24
31
 
25
- const requests = [];
26
- fakeXhr.useFakeXMLHttpRequest().onCreate = (req) => { requests.push(req); };
32
+ server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString());
33
+ server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png'))));
27
34
 
28
35
  loadSprite('http://localhost:9966/test/unit/assets/sprite1', manager, 1, (err, result) => {
29
36
  expect(err).toBeFalsy();
@@ -43,15 +50,10 @@ describe('loadSprite', () => {
43
50
  done();
44
51
  });
45
52
 
46
- expect(requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json');
47
- requests[0].setStatus(200);
48
- requests[0].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json'));
49
- requests[0].onload();
53
+ server.respond();
50
54
 
51
- expect(requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png');
52
- requests[1].setStatus(200);
53
- requests[1].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')).buffer;
54
- requests[1].onload();
55
+ expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json');
56
+ expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png');
55
57
  });
56
58
 
57
59
  test('array of objects support', done => {
@@ -61,8 +63,10 @@ describe('loadSprite', () => {
61
63
 
62
64
  const manager = new RequestManager(transform);
63
65
 
64
- const requests = [];
65
- fakeXhr.useFakeXMLHttpRequest().onCreate = (req) => { requests.push(req); };
66
+ server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString());
67
+ server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png'))));
68
+ server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite2.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite2.json')).toString());
69
+ server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite2.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite2.png'))));
66
70
 
67
71
  loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}, {id: 'sprite2', url: 'http://localhost:9966/test/unit/assets/sprite2'}], manager, 1, (err, result) => {
68
72
  expect(err).toBeFalsy();
@@ -90,25 +94,11 @@ describe('loadSprite', () => {
90
94
  done();
91
95
  });
92
96
 
93
- expect(requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json');
94
- requests[0].setStatus(200);
95
- requests[0].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json'));
96
- requests[0].onload();
97
-
98
- expect(requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png');
99
- requests[1].setStatus(200);
100
- requests[1].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')).buffer;
101
- requests[1].onload();
102
-
103
- expect(requests[2].url).toBe('http://localhost:9966/test/unit/assets/sprite2.json');
104
- requests[2].setStatus(200);
105
- requests[2].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite2.json'));
106
- requests[2].onload();
107
-
108
- expect(requests[3].url).toBe('http://localhost:9966/test/unit/assets/sprite2.png');
109
- requests[3].setStatus(200);
110
- requests[3].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite2.png')).buffer;
111
- requests[3].onload();
97
+ server.respond();
98
+ expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json');
99
+ expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png');
100
+ expect(server.requests[2].url).toBe('http://localhost:9966/test/unit/assets/sprite2.json');
101
+ expect(server.requests[3].url).toBe('http://localhost:9966/test/unit/assets/sprite2.png');
112
102
  });
113
103
 
114
104
  test('error in callback', done => {
@@ -118,20 +108,19 @@ describe('loadSprite', () => {
118
108
 
119
109
  const manager = new RequestManager(transform);
120
110
 
121
- const requests = [];
122
- fakeXhr.useFakeXMLHttpRequest().onCreate = (req) => { requests.push(req); };
123
-
111
+ server.respondWith((xhr) => xhr.respond(500));
112
+ let last = false;
124
113
  loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}], manager, 1, (err, result) => {
125
114
  expect(err).toBeTruthy();
126
115
  expect(result).toBeUndefined();
127
-
128
- done();
116
+ if (!last) {
117
+ done();
118
+ last = true;
119
+ }
129
120
  });
130
121
 
131
- expect(requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json');
132
- requests[0].setStatus(500);
133
- requests[0].response = undefined;
134
- requests[0].onload();
122
+ server.respond();
123
+ expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json');
135
124
  });
136
125
 
137
126
  test('request canceling', done => {
@@ -141,30 +130,24 @@ describe('loadSprite', () => {
141
130
 
142
131
  const manager = new RequestManager(transform);
143
132
 
144
- const requests = [];
145
- fakeXhr.useFakeXMLHttpRequest().onCreate = (req) => { requests.push(req); };
133
+ server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString());
134
+ server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png'))));
146
135
 
147
136
  const cancelable = loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}], manager, 1, () => {});
148
137
 
149
138
  setTimeout(() => {
150
139
  cancelable.cancel();
151
140
 
152
- expect(requests[0].aborted).toBeTruthy();
153
- expect(requests[1].aborted).toBeTruthy();
141
+ expect((server.requests[0] as any).aborted).toBeTruthy();
142
+ expect((server.requests[1] as any).aborted).toBeTruthy();
154
143
 
155
144
  done();
156
145
  });
157
146
 
158
147
  setTimeout(() => {
159
- expect(requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json');
160
- requests[0].setStatus(200);
161
- requests[0].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json'));
162
- requests[0].onload();
163
-
164
- expect(requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png');
165
- requests[1].setStatus(200);
166
- requests[1].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')).buffer;
167
- requests[1].onload();
148
+ server.respond();
149
+ expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json');
150
+ expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png');
168
151
  }, 10);
169
152
  });
170
153
 
@@ -175,8 +158,8 @@ describe('loadSprite', () => {
175
158
 
176
159
  const manager = new RequestManager(transform);
177
160
 
178
- const requests = [];
179
- fakeXhr.useFakeXMLHttpRequest().onCreate = (req) => { requests.push(req); };
161
+ server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1@2x.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString());
162
+ server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1@2x.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png'))));
180
163
 
181
164
  loadSprite('http://localhost:9966/test/unit/assets/sprite1', manager, 2, (err, result) => {
182
165
  expect(err).toBeFalsy();
@@ -196,14 +179,8 @@ describe('loadSprite', () => {
196
179
  done();
197
180
  });
198
181
 
199
- expect(requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1@2x.json');
200
- requests[0].setStatus(200);
201
- requests[0].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json'));
202
- requests[0].onload();
203
-
204
- expect(requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1@2x.png');
205
- requests[1].setStatus(200);
206
- requests[1].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')).buffer;
207
- requests[1].onload();
182
+ server.respond();
183
+ expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1@2x.json');
184
+ expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1@2x.png');
208
185
  });
209
186
  });