UNPKG

maplibre-gl

Version:

BSD licensed community fork of mapbox-gl, a WebGL interactive maps library

307 lines (258 loc) 10.8 kB
import fs from 'fs'; import path from 'path'; import vt from '@mapbox/vector-tile'; import Protobuf from 'pbf'; import VectorTileWorkerSource from '../source/vector_tile_worker_source'; import StyleLayerIndex from '../style/style_layer_index'; import {fakeServer, FakeServer} from 'nise'; import Actor from '../util/actor'; import {TileParameters, WorkerTileParameters} from './worker_source'; import WorkerTile from './worker_tile'; import {setPerformance} from '../util/test/util'; describe('vector tile worker source', () => { const actor = {send: () => {}} as any as Actor; let server: FakeServer; let originalGetEntriesByName; let originalMeasure; let originalMark; beforeEach(() => { global.fetch = null; server = fakeServer.create(); setPerformance(); originalGetEntriesByName = window.performance.getEntriesByName; originalMeasure = window.performance.measure; originalMark = window.performance.mark; }); afterEach(() => { server.restore(); jest.clearAllMocks(); window.performance.getEntriesByName = originalGetEntriesByName; window.performance.measure = originalMeasure; window.performance.mark = originalMark; }); test('VectorTileWorkerSource#abortTile aborts pending request', () => { const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []); source.loadTile({ source: 'source', uid: 0, tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}}, request: {url: 'http://localhost:2900/abort'} } as any as WorkerTileParameters, (err, res) => { expect(err).toBeFalsy(); expect(res).toBeFalsy(); }); source.abortTile({ source: 'source', uid: 0 } as any as TileParameters, (err, res) => { expect(err).toBeFalsy(); expect(res).toBeFalsy(); }); expect(source.loading).toEqual({}); }); test('VectorTileWorkerSource#removeTile removes loaded tile', () => { const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []); source.loaded = { '0': {} as WorkerTile }; source.removeTile({ source: 'source', uid: 0 } as any as TileParameters, (err, res) => { expect(err).toBeFalsy(); expect(res).toBeFalsy(); }); expect(source.loaded).toEqual({}); }); test('VectorTileWorkerSource#reloadTile reloads a previously-loaded tile', () => { const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []); const parse = jest.fn(); source.loaded = { '0': { status: 'done', vectorTile: {}, parse } as any as WorkerTile }; const callback = jest.fn(); source.reloadTile({uid: 0} as any as WorkerTileParameters, callback); expect(parse).toHaveBeenCalledTimes(1); parse.mock.calls[0][4](); expect(callback).toHaveBeenCalledTimes(1); }); test('VectorTileWorkerSource#reloadTile queues a reload when parsing is in progress', () => { const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []); const parse = jest.fn(); source.loaded = { '0': { status: 'done', vectorTile: {}, parse } as any as WorkerTile }; const callback1 = jest.fn(); const callback2 = jest.fn(); source.reloadTile({uid: 0} as any as WorkerTileParameters, callback1); expect(parse).toHaveBeenCalledTimes(1); source.loaded[0].status = 'parsing'; source.reloadTile({uid: 0} as any as WorkerTileParameters, callback2); expect(parse).toHaveBeenCalledTimes(1); parse.mock.calls[0][4](); expect(parse).toHaveBeenCalledTimes(2); expect(callback1).toHaveBeenCalledTimes(1); expect(callback2).toHaveBeenCalledTimes(0); parse.mock.calls[1][4](); expect(callback1).toHaveBeenCalledTimes(1); expect(callback2).toHaveBeenCalledTimes(1); }); test('VectorTileWorkerSource#reloadTile handles multiple pending reloads', () => { // https://github.com/mapbox/mapbox-gl-js/issues/6308 const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []); const parse = jest.fn(); source.loaded = { '0': { status: 'done', vectorTile: {}, parse } as any as WorkerTile }; const callback1 = jest.fn(); const callback2 = jest.fn(); const callback3 = jest.fn(); source.reloadTile({uid: 0} as any as WorkerTileParameters, callback1); expect(parse).toHaveBeenCalledTimes(1); source.loaded[0].status = 'parsing'; source.reloadTile({uid: 0} as any as WorkerTileParameters, callback2); expect(parse).toHaveBeenCalledTimes(1); parse.mock.calls[0][4](); expect(parse).toHaveBeenCalledTimes(2); expect(callback1).toHaveBeenCalledTimes(1); expect(callback2).toHaveBeenCalledTimes(0); expect(callback3).toHaveBeenCalledTimes(0); source.reloadTile({uid: 0} as any as WorkerTileParameters, callback3); expect(parse).toHaveBeenCalledTimes(2); expect(callback1).toHaveBeenCalledTimes(1); expect(callback2).toHaveBeenCalledTimes(0); expect(callback3).toHaveBeenCalledTimes(0); parse.mock.calls[1][4](); expect(parse).toHaveBeenCalledTimes(3); expect(callback1).toHaveBeenCalledTimes(1); expect(callback2).toHaveBeenCalledTimes(1); expect(callback3).toHaveBeenCalledTimes(0); parse.mock.calls[2][4](); expect(callback1).toHaveBeenCalledTimes(1); expect(callback2).toHaveBeenCalledTimes(1); expect(callback3).toHaveBeenCalledTimes(1); }); test('VectorTileWorkerSource#reloadTile does not reparse tiles with no vectorTile data but does call callback', () => { const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []); const parse = jest.fn(); source.loaded = { '0': { status: 'done', parse } as any as WorkerTile }; const callback = jest.fn(); source.reloadTile({uid: 0} as any as WorkerTileParameters, callback); expect(parse).not.toHaveBeenCalled(); expect(callback).toHaveBeenCalledTimes(1); }); test('VectorTileWorkerSource provides resource timing information', done => { const rawTileData = fs.readFileSync(path.join(__dirname, '/../../test/unit/assets/mbsv5-6-18-23.vector.pbf')); function loadVectorData(params, callback) { return callback(null, { vectorTile: new vt.VectorTile(new Protobuf(rawTileData)), rawData: rawTileData, cacheControl: null, expires: null }); } const exampleResourceTiming = { connectEnd: 473, connectStart: 473, decodedBodySize: 86494, domainLookupEnd: 473, domainLookupStart: 473, duration: 341, encodedBodySize: 52528, entryType: 'resource', fetchStart: 473.5, initiatorType: 'xmlhttprequest', name: 'http://localhost:2900/faketile.pbf', nextHopProtocol: 'http/1.1', redirectEnd: 0, redirectStart: 0, requestStart: 477, responseEnd: 815, responseStart: 672, secureConnectionStart: 0 }; const layerIndex = new StyleLayerIndex([{ id: 'test', source: 'source', 'source-layer': 'test', type: 'fill' }]); const source = new VectorTileWorkerSource(actor, layerIndex, [], loadVectorData); window.performance.getEntriesByName = jest.fn().mockReturnValue([exampleResourceTiming]); source.loadTile({ source: 'source', uid: 0, tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}}, request: {url: 'http://localhost:2900/faketile.pbf', collectResourceTiming: true} } as any as WorkerTileParameters, (err, res) => { expect(err).toBeFalsy(); expect(res.resourceTiming[0]).toEqual(exampleResourceTiming); done(); }); }); test('VectorTileWorkerSource provides resource timing information (fallback method)', done => { const rawTileData = fs.readFileSync(path.join(__dirname, '/../../test/unit/assets/mbsv5-6-18-23.vector.pbf')); function loadVectorData(params, callback) { return callback(null, { vectorTile: new vt.VectorTile(new Protobuf(rawTileData)), rawData: rawTileData, cacheControl: null, expires: null }); } const layerIndex = new StyleLayerIndex([{ id: 'test', source: 'source', 'source-layer': 'test', type: 'fill' }]); const source = new VectorTileWorkerSource(actor, layerIndex, [], loadVectorData); const sampleMarks = [100, 350]; const marks = {}; const measures = {}; window.performance.getEntriesByName = jest.fn().mockImplementation(name => (measures[name] || [])); window.performance.mark = jest.fn().mockImplementation(name => { marks[name] = sampleMarks.shift(); return null; }); window.performance.measure = jest.fn().mockImplementation((name, start, end) => { measures[name] = measures[name] || []; measures[name].push({ duration: marks[end] - marks[start], entryType: 'measure', name, startTime: marks[start] }); return null; }); source.loadTile({ source: 'source', uid: 0, tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}}, request: {url: 'http://localhost:2900/faketile.pbf', collectResourceTiming: true} } as any as WorkerTileParameters, (err, res) => { expect(err).toBeFalsy(); expect(res.resourceTiming[0]).toEqual( {'duration': 250, 'entryType': 'measure', 'name': 'http://localhost:2900/faketile.pbf', 'startTime': 100} ); done(); }); }); });