Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Jest] Migrate geojson_worker_source.test.js #731

Merged
merged 4 commits into from
Dec 28, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
import '../../stub_loader';
import {test} from '../../util/test';
import GeoJSONWorkerSource from '../../../rollup/build/tsc/src/source/geojson_worker_source';
import StyleLayerIndex from '../../../rollup/build/tsc/src/style/style_layer_index';
import {OverscaledTileID} from '../../../rollup/build/tsc/src/source/tile_id';
import perf from '../../../rollup/build/tsc/src/util/performance';

const actor = {send: () => {}};
import GeoJSONWorkerSource, {LoadGeoJSONParameters} from './geojson_worker_source';
import StyleLayerIndex from '../style/style_layer_index';
import {OverscaledTileID} from './tile_id';
import perf from '../util/performance';
import {LayerSpecification} from '../style-spec/types';
import Actor from '../util/actor';
import {WorkerTileParameters} from './worker_source';
import {setPerformance} from '../util/test/util';

const actor = {send: () => {}} as any as Actor;

beforeEach(() => {
setPerformance();
});

test('reloadTile', (t) => {
t.test('does not rebuild vector data unless data has changed', (t) => {
describe('reloadTile', () => {
test('does not rebuild vector data unless data has changed', done => {
const layers = [
{
id: 'mylayer',
source: 'sourceId',
type: 'symbol',
}
];
] as LayerSpecification[];
const layerIndex = new StyleLayerIndex(layers);
const source = new GeoJSONWorkerSource(actor, layerIndex, []);
const originalLoadVectorData = source.loadVectorData;
Expand All @@ -25,10 +31,10 @@ test('reloadTile', (t) => {
return originalLoadVectorData.call(this, params, callback);
};
const geoJson = {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [0, 0]
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [0, 0]
}
};
const tileParams = {
Expand All @@ -39,16 +45,16 @@ test('reloadTile', (t) => {
};

function addData(callback) {
source.loadData({source: 'sourceId', data: JSON.stringify(geoJson)}, (err) => {
source.coalesce({source: 'sourceId'});
t.equal(err, null);
source.loadData({source: 'sourceId', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters, (err) => {
source.coalesce();
expect(err).toBeNull();
callback();
});
}

function reloadTile(callback) {
source.reloadTile(tileParams, (err, data) => {
t.equal(err, null);
source.reloadTile(tileParams as any as WorkerTileParameters, (err, data) => {
expect(err).toBeNull();
return callback(data);
});
}
Expand All @@ -59,52 +65,51 @@ test('reloadTile', (t) => {
reloadTile(data => {
firstData = data;
});
t.equal(loadVectorCallCount, 1);
expect(loadVectorCallCount).toBe(1);

// second call won't give us new rawTileData
reloadTile(data => {
t.notOk('rawTileData' in data);
expect('rawTileData' in data).toBeFalsy();
data.rawTileData = firstData.rawTileData;
t.deepEqual(data, firstData);
expect(data).toEqual(firstData);
});

// also shouldn't call loadVectorData again
t.equal(loadVectorCallCount, 1);
expect(loadVectorCallCount).toBe(1);

// replace geojson data
addData(() => {
// should call loadVectorData again after changing geojson data
reloadTile(data => {
t.ok('rawTileData' in data);
t.deepEqual(data, firstData);
expect('rawTileData' in data).toBeTruthy();
expect(data).toEqual(firstData);
});
t.equal(loadVectorCallCount, 2);
t.end();
expect(loadVectorCallCount).toBe(2);
done();
});
});
});

t.end();
});

test('resourceTiming', (t) => {
describe('resourceTiming', () => {

const layers = [
{
id: 'mylayer',
source: 'sourceId',
type: 'symbol',
}
];
] as LayerSpecification[];
const geoJson = {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [0, 0]
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [0, 0]
}
};
} as GeoJSON.GeoJSON;

t.test('loadData - url', (t) => {
test('loadData - url', done => {
const exampleResourceTiming = {
connectEnd: 473,
connectStart: 473,
Expand All @@ -113,41 +118,41 @@ test('resourceTiming', (t) => {
domainLookupStart: 473,
duration: 341,
encodedBodySize: 52528,
entryType: "resource",
entryType: 'resource',
fetchStart: 473.5,
initiatorType: "xmlhttprequest",
name: "http://localhost:2900/fake.geojson",
nextHopProtocol: "http/1.1",
initiatorType: 'xmlhttprequest',
name: 'http://localhost:2900/fake.geojson',
nextHopProtocol: 'http/1.1',
redirectEnd: 0,
redirectStart: 0,
requestStart: 477,
responseEnd: 815,
responseStart: 672,
secureConnectionStart: 0
};
} as any as PerformanceEntry;

t.stub(perf, 'getEntriesByName').callsFake(() => { return [ exampleResourceTiming ]; });
window.performance.getEntriesByName = jest.fn().mockReturnValue([ exampleResourceTiming ]);

const layerIndex = new StyleLayerIndex(layers);
const source = new GeoJSONWorkerSource(actor, layerIndex, [], (params, callback) => { return callback(null, geoJson); });

source.loadData({source: 'testSource', request: {url: 'http://localhost/nonexistent', collectResourceTiming: true}}, (err, result) => {
t.equal(err, null);
t.deepEquals(result.resourceTiming.testSource, [ exampleResourceTiming ], 'got expected resource timing');
t.end();
source.loadData({source: 'testSource', request: {url: 'http://localhost/nonexistent', collectResourceTiming: true}} as LoadGeoJSONParameters, (err, result) => {
expect(err).toBeNull();
expect(result.resourceTiming.testSource).toEqual([ exampleResourceTiming ]);
done();
});
});

t.test('loadData - url (resourceTiming fallback method)', (t) => {
test('loadData - url (resourceTiming fallback method)', done => {
const sampleMarks = [100, 350];
const marks = {};
const measures = {};
t.stub(perf, 'getEntriesByName').callsFake((name) => { return measures[name] || []; });
t.stub(perf, 'mark').callsFake((name) => {
window.performance.getEntriesByName = jest.fn().mockImplementation((name) => { return measures[name] || []; });
jest.spyOn(perf, 'mark').mockImplementation((name) => {
marks[name] = sampleMarks.shift();
return null;
});
t.stub(perf, 'measure').callsFake((name, start, end) => {
window.performance.measure = jest.fn().mockImplementation((name, start, end) => {
measures[name] = measures[name] || [];
measures[name].push({
duration: marks[end] - marks[start],
Expand All @@ -157,34 +162,35 @@ test('resourceTiming', (t) => {
});
return null;
});
t.stub(perf, 'clearMarks').callsFake(() => { return null; });
t.stub(perf, 'clearMeasures').callsFake(() => { return null; });
jest.spyOn(perf, 'clearMarks').mockImplementation(() => { return null; });
jest.spyOn(perf, 'clearMeasures').mockImplementation(() => { return null; });

const layerIndex = new StyleLayerIndex(layers);
const source = new GeoJSONWorkerSource(actor, layerIndex, [], (params, callback) => { return callback(null, geoJson); });

source.loadData({source: 'testSource', request: {url: 'http://localhost/nonexistent', collectResourceTiming: true}}, (err, result) => {
t.equal(err, null);
t.deepEquals(result.resourceTiming.testSource, [{"duration": 250, "entryType": "measure", "name": "http://localhost/nonexistent", "startTime": 100}], 'got expected resource timing');
t.end();
source.loadData({source: 'testSource', request: {url: 'http://localhost/nonexistent', collectResourceTiming: true}} as LoadGeoJSONParameters, (err, result) => {
expect(err).toBeNull();
expect(result.resourceTiming.testSource).toEqual(
[{'duration': 250, 'entryType': 'measure', 'name': 'http://localhost/nonexistent', 'startTime': 100}]
);
done();
});
});

t.test('loadData - data', (t) => {
test('loadData - data', done => {
const layerIndex = new StyleLayerIndex(layers);
const source = new GeoJSONWorkerSource(actor, layerIndex, []);

source.loadData({source: 'testSource', data: JSON.stringify(geoJson)}, (err, result) => {
t.equal(err, null);
t.equal(result.resourceTiming, undefined, 'no resourceTiming property when loadData is not sent a URL');
t.end();
source.loadData({source: 'testSource', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters, (err, result) => {
expect(err).toBeNull();
expect(result.resourceTiming).toBeUndefined();
done();
});
});

t.end();
});

test('loadData', (t) => {
describe('loadData', () => {
const layers = [
{
id: 'layer1',
Expand All @@ -196,15 +202,15 @@ test('loadData', (t) => {
source: 'source2',
type: 'symbol',
}
];
] as LayerSpecification[];

const geoJson = {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [0, 0]
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [0, 0]
}
};
} as GeoJSON.GeoJSON;

const layerIndex = new StyleLayerIndex(layers);
function createWorker() {
Expand All @@ -222,51 +228,50 @@ test('loadData', (t) => {
return worker;
}

t.test('abandons coalesced callbacks', (t) => {
test('abandons coalesced callbacks', done => {
// Expect first call to run, second to be abandoned,
// and third to run in response to coalesce
const worker = createWorker();
worker.loadData({source: 'source1', data: JSON.stringify(geoJson)}, (err, result) => {
t.equal(err, null);
t.notOk(result && result.abandoned);
worker.coalesce({source: 'source1'});
worker.loadData({source: 'source1', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters, (err, result) => {
expect(err).toBeNull();
expect(result && result.abandoned).toBeFalsy();
worker.coalesce();
});

worker.loadData({source: 'source1', data: JSON.stringify(geoJson)}, (err, result) => {
t.equal(err, null);
t.ok(result && result.abandoned);
worker.loadData({source: 'source1', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters, (err, result) => {
expect(err).toBeNull();
expect(result && result.abandoned).toBeTruthy();
});

worker.loadData({source: 'source1', data: JSON.stringify(geoJson)}, (err, result) => {
t.equal(err, null);
t.notOk(result && result.abandoned);
t.end();
worker.loadData({source: 'source1', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters, (err, result) => {
expect(err).toBeNull();
expect(result && result.abandoned).toBeFalsy();
done();
});
});

t.test('removeSource aborts callbacks', (t) => {
test('removeSource aborts callbacks', done => {
// Expect:
// First loadData starts running before removeSource arrives
// Second loadData is pending when removeSource arrives, gets cancelled
// removeSource is executed immediately
// First loadData finishes running, sends results back to foreground
const worker = createWorker();
worker.loadData({source: 'source1', data: JSON.stringify(geoJson)}, (err, result) => {
t.equal(err, null);
t.notOk(result && result.abandoned);
t.end();
worker.loadData({source: 'source1', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters, (err, result) => {
expect(err).toBeNull();
expect(result && result.abandoned).toBeFalsy();
done();
});

worker.loadData({source: 'source1', data: JSON.stringify(geoJson)}, (err, result) => {
t.equal(err, null);
t.ok(result && result.abandoned);
worker.loadData({source: 'source1', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters, (err, result) => {
expect(err).toBeNull();
expect(result && result.abandoned).toBeTruthy();
});

worker.removeSource({source: 'source1'}, (err) => {
t.notOk(err);
expect(err).toBeFalsy();
});

});

t.end();
});