diff --git a/karma.conf.cjs b/karma.conf.cjs
index f6becc4c8..f8c5cbc8c 100644
--- a/karma.conf.cjs
+++ b/karma.conf.cjs
@@ -19,7 +19,6 @@ module.exports = function (config) {
files: [
'node_modules/sinon/pkg/sinon.js',
'node_modules/happen/happen.js',
- 'node_modules/fetch-mock/es5/client-bundle.js',
{ pattern: 'dist/rapid.js', included: true },
{ pattern: 'dist/rapid.css', included: true },
{ pattern: 'dist/**/*', included: false },
diff --git a/modules/main_dev.js b/modules/main_dev.js
index 698b5b7e6..cd88498a7 100644
--- a/modules/main_dev.js
+++ b/modules/main_dev.js
@@ -22,6 +22,8 @@ window.Rapid.isDebug = true;
// For dev build, we'll bundle additional things
// that are useful for testing or debugging.
+import fetchMock from 'fetch-mock';
+window.fetchMock = fetchMock;
// Include rapid-sdk as a single `sdk` namespace.
// (This works because we know there are no name conflicts)
diff --git a/package-lock.json b/package-lock.json
index bbe7a3e38..c4ddd2fd5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -71,7 +71,7 @@
"esbuild": "^0.24.0",
"esbuild-visualizer": "^0.6.0",
"eslint": "^9.17.0",
- "fetch-mock": "^9.11.0",
+ "fetch-mock": "^12.2.0",
"gaze": "^1.1.3",
"glob": "^10.4.5",
"globals": "^15.13.0",
@@ -342,17 +342,6 @@
"node": ">=6.0.0"
}
},
- "node_modules/@babel/runtime": {
- "version": "7.25.6",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "regenerator-runtime": "^0.14.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
"node_modules/@babel/template": {
"version": "7.25.0",
"dev": true,
@@ -1269,6 +1258,13 @@
"version": "7946.0.14",
"license": "MIT"
},
+ "node_modules/@types/glob-to-regexp": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/@types/glob-to-regexp/-/glob-to-regexp-0.4.4.tgz",
+ "integrity": "sha512-nDKoaKJYbnn1MZxUY0cA1bPmmgZbg0cTq7Rh13d0KWYNOiKbqoR+2d89SnRPszGh7ROzSwZ/GOjZ4jPbmmZ6Eg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/gradient-parser": {
"version": "0.1.5",
"license": "MIT"
@@ -2924,6 +2920,16 @@
"node": ">= 0.8"
}
},
+ "node_modules/dequal": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/destroy": {
"version": "1.2.0",
"dev": true,
@@ -3742,35 +3748,20 @@
"license": "MIT"
},
"node_modules/fetch-mock": {
- "version": "9.11.0",
+ "version": "12.2.0",
+ "resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-12.2.0.tgz",
+ "integrity": "sha512-XjgxM582kB0SzPOqH2UdGTwSqga8A8aBPjxcYr0wTeOlCWpZoK6zBrPzltECUTu6Zt3VTWafmKF599LN9BRN5Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/core": "^7.0.0",
- "@babel/runtime": "^7.0.0",
- "core-js": "^3.0.0",
- "debug": "^4.1.1",
- "glob-to-regexp": "^0.4.0",
- "is-subset": "^0.1.1",
- "lodash.isequal": "^4.5.0",
- "path-to-regexp": "^2.2.1",
- "querystring": "^0.2.0",
- "whatwg-url": "^6.5.0"
+ "@types/glob-to-regexp": "^0.4.4",
+ "dequal": "^2.0.3",
+ "glob-to-regexp": "^0.4.1",
+ "is-subset-of": "^3.1.10",
+ "regexparam": "^3.0.0"
},
"engines": {
- "node": ">=4.0.0"
- },
- "funding": {
- "type": "charity",
- "url": "https://www.justgiving.com/refugee-support-europe"
- },
- "peerDependencies": {
- "node-fetch": "*"
- },
- "peerDependenciesMeta": {
- "node-fetch": {
- "optional": true
- }
+ "node": ">=18.11.0"
}
},
"node_modules/fflate": {
@@ -5024,10 +5015,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-subset": {
- "version": "0.1.1",
+ "node_modules/is-subset-of": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/is-subset-of/-/is-subset-of-3.1.10.tgz",
+ "integrity": "sha512-avvaYgVmYWyaZ1NDFiv4y9JGkrE2je3op1Po4VYKKJKR8H2qVPsg1GZuuXl5elCTxTlwAIsrAjWAs4BVrISFRw==",
+ "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "dependencies": {
+ "typedescriptor": "3.0.2"
+ }
},
"node_modules/is-symbol": {
"version": "1.0.4",
@@ -5835,11 +5832,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/lodash.isequal": {
- "version": "4.5.0",
- "dev": true,
- "license": "MIT"
- },
"node_modules/lodash.keys": {
"version": "3.1.2",
"dev": true,
@@ -5860,11 +5852,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/lodash.sortby": {
- "version": "4.7.0",
- "dev": true,
- "license": "MIT"
- },
"node_modules/lodash.template": {
"version": "3.6.2",
"dev": true,
@@ -7135,11 +7122,6 @@
"dev": true,
"license": "ISC"
},
- "node_modules/path-to-regexp": {
- "version": "2.4.0",
- "dev": true,
- "license": "MIT"
- },
"node_modules/path-type": {
"version": "3.0.0",
"dev": true,
@@ -7559,14 +7541,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/querystring": {
- "version": "0.2.1",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.4.x"
- }
- },
"node_modules/quickselect": {
"version": "2.0.0",
"license": "ISC"
@@ -7800,11 +7774,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/regenerator-runtime": {
- "version": "0.14.1",
- "dev": true,
- "license": "MIT"
- },
"node_modules/regexp.prototype.flags": {
"version": "1.5.2",
"dev": true,
@@ -7822,6 +7791,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/regexparam": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-3.0.0.tgz",
+ "integrity": "sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/remap-istanbul": {
"version": "0.9.6",
"dev": true,
@@ -9068,22 +9047,6 @@
"node": ">=0.6"
}
},
- "node_modules/tr46": {
- "version": "1.0.1",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
- "node_modules/tr46/node_modules/punycode": {
- "version": "2.3.1",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/trim-newlines": {
"version": "1.0.0",
"dev": true,
@@ -9204,6 +9167,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/typedescriptor": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/typedescriptor/-/typedescriptor-3.0.2.tgz",
+ "integrity": "sha512-hyVbaCUd18UiXk656g/imaBLMogpdijIEpnhWYrSda9rhvO4gOU16n2nh7xG5lv/rjumnZzGOdz0CEGTmFe0fQ==",
+ "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/typewise": {
"version": "1.0.3",
"license": "MIT",
@@ -9458,25 +9429,10 @@
"pbf": "bin/pbf"
}
},
- "node_modules/webidl-conversions": {
- "version": "4.0.2",
- "dev": true,
- "license": "BSD-2-Clause"
- },
"node_modules/wgs84": {
"version": "0.0.0",
"license": "BSD-2-Clause"
},
- "node_modules/whatwg-url": {
- "version": "6.5.0",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "lodash.sortby": "^4.7.0",
- "tr46": "^1.0.1",
- "webidl-conversions": "^4.0.2"
- }
- },
"node_modules/which": {
"version": "4.0.0",
"dev": true,
diff --git a/package.json b/package.json
index 5b28feb6e..099bc2cd0 100644
--- a/package.json
+++ b/package.json
@@ -120,7 +120,7 @@
"esbuild": "^0.24.0",
"esbuild-visualizer": "^0.6.0",
"eslint": "^9.17.0",
- "fetch-mock": "^9.11.0",
+ "fetch-mock": "^12.2.0",
"gaze": "^1.1.3",
"glob": "^10.4.5",
"globals": "^15.13.0",
diff --git a/test/browser/core/AssetSystem.test.js b/test/browser/core/AssetSystem.test.js
index 40727b5b9..9c8325592 100644
--- a/test/browser/core/AssetSystem.test.js
+++ b/test/browser/core/AssetSystem.test.js
@@ -128,7 +128,7 @@ describe('AssetSystem', () => {
});
it('returns a promise to fetch data if we do not already have the data', () => {
- fetchMock.mock('/data/intro_graph.min.json', {
+ fetchMock.route(/\/data\/intro_graph\.min\.json/i, {
body: JSON.stringify({ value: 'success' }),
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -140,7 +140,7 @@ describe('AssetSystem', () => {
.then(data => {
expect(data).to.be.an('object');
expect(data.value).to.eql('success');
- fetchMock.resetHistory();
+ fetchMock.removeRoutes().clearHistory();
});
});
diff --git a/test/browser/services/KartaviewService.test.js b/test/browser/services/KartaviewService.test.js
index f4ab8779d..68c07f9d3 100644
--- a/test/browser/services/KartaviewService.test.js
+++ b/test/browser/services/KartaviewService.test.js
@@ -22,11 +22,15 @@ describe('KartaviewService', () => {
beforeEach(() => {
- fetchMock.reset();
+ fetchMock.removeRoutes().clearHistory();
_kartaview = new Rapid.KartaviewService(new MockContext());
return _kartaview.initAsync();
});
+ afterEach(() => {
+ fetchMock.removeRoutes().clearHistory();
+ });
+
describe('#initAsync', () => {
it('initializes cache', () => {
@@ -84,14 +88,14 @@ describe('KartaviewService', () => {
totalFilteredItems: ['3']
};
- fetchMock.mock(new RegExp('/nearby-photos/'), {
+ fetchMock.route(/nearby-photos/, {
body: JSON.stringify(nearbyResponse),
status: 200,
headers: { 'Content-Type': 'application/json' }
});
_kartaview.on('loadedData', () => {
- expect(fetchMock.calls().length).to.eql(1); // after /photo/?sequenceId=100
+ expect(fetchMock.callHistory.calls().length).to.eql(1); // after /photo/?sequenceId=100
done();
});
@@ -133,7 +137,7 @@ describe('KartaviewService', () => {
totalFilteredItems: ['3']
};
- fetchMock.mock(new RegExp('/nearby-photos/'), {
+ fetchMock.route(/nearby-photos/, {
body: JSON.stringify(nearbyResponse),
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -147,7 +151,7 @@ describe('KartaviewService', () => {
window.setTimeout(() => {
expect(spy.notCalled).to.be.ok;
- expect(fetchMock.calls().length).to.eql(0); // no tile requests of any kind
+ expect(fetchMock.callHistory.calls().length).to.eql(0); // no tile requests of any kind
done();
}, 20);
});
diff --git a/test/browser/services/MapillaryService.test.js b/test/browser/services/MapillaryService.test.js
index a6ecab0c3..a6797a377 100644
--- a/test/browser/services/MapillaryService.test.js
+++ b/test/browser/services/MapillaryService.test.js
@@ -21,7 +21,7 @@ describe('MapillaryService', () => {
beforeEach(() => {
- fetchMock.reset();
+ fetchMock.removeRoutes().clearHistory();
_mapillary = new Rapid.MapillaryService(new MockContext());
// Mock function for retieving tile data.. The original expects a protobuffer vector tile.
@@ -30,6 +30,10 @@ describe('MapillaryService', () => {
return _mapillary.initAsync();
});
+ afterEach(() => {
+ fetchMock.removeRoutes().clearHistory();
+ });
+
describe('#initAsync', () => {
it('initializes cache', () => {
@@ -171,14 +175,14 @@ describe('MapillaryService', () => {
describe('#loadTiles', () => {
it('fires loadedImages when image tiles are loaded', done => {
- fetchMock.mock(new RegExp('/mly1(_computed)?_public/'), {
+ fetchMock.route(/mly1(_computed)?_public/, {
body: '{"data":[]}',
status: 200,
headers: { 'Content-Type': 'application/json' }
});
_mapillary.on('loadedImages', () => {
- expect(fetchMock.calls().length).to.eql(1);
+ expect(fetchMock.callHistory.calls().length).to.eql(1);
done();
});
@@ -188,7 +192,7 @@ describe('MapillaryService', () => {
it('does not load tiles around Null Island', done => {
const spy = sinon.spy();
- fetchMock.mock(new RegExp('/mly1(_computed)?_public/'), {
+ fetchMock.route(/mly1(_computed)?_public/, {
body: '{"data":[]}',
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -200,7 +204,7 @@ describe('MapillaryService', () => {
window.setTimeout(() => {
expect(spy.notCalled).to.be.ok;
- expect(fetchMock.calls().length).to.eql(0); // no tile requests of any kind
+ expect(fetchMock.callHistory.calls().length).to.eql(0); // no tile requests of any kind
done();
}, 20);
});
diff --git a/test/browser/services/NominatimService.test.js b/test/browser/services/NominatimService.test.js
index a219e7a0c..dca5a8f6c 100644
--- a/test/browser/services/NominatimService.test.js
+++ b/test/browser/services/NominatimService.test.js
@@ -15,20 +15,20 @@ describe('NominatimService', () => {
}
beforeEach(() => {
- fetchMock.reset();
- fetchMock.mock(/reverse\?.*lat=48&lon=16/, {
+ fetchMock.removeRoutes().clearHistory();
+ fetchMock.route(/reverse\?.*lat=48&lon=16/, {
body: '{"address":{"country_code":"at"}}',
status: 200,
headers: { 'Content-Type': 'application/json' }
});
- fetchMock.mock(/reverse\?.*lat=49&lon=17/, {
+ fetchMock.route(/reverse\?.*lat=49&lon=17/, {
body: '{"address":{"country_code":"cz"}}',
status: 200,
headers: { 'Content-Type': 'application/json' }
});
- fetchMock.mock(/reverse\?.*lat=1000&lon=1000/, {
+ fetchMock.route(/reverse\?.*lat=1000&lon=1000/, {
body: '{"error":"Unable to geocode"}',
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -38,6 +38,10 @@ describe('NominatimService', () => {
return nominatim.initAsync();
});
+ afterEach(() => {
+ fetchMock.removeRoutes().clearHistory();
+ });
+
function parseQueryString(url) {
return Rapid.sdk.utilStringQs(url.substring(url.indexOf('?')));
@@ -50,7 +54,7 @@ describe('NominatimService', () => {
nominatim.countryCode([16, 48], callback);
window.setTimeout(() => {
- expect(parseQueryString(fetchMock.lastUrl())).to.eql(
+ expect(parseQueryString(fetchMock.callHistory.lastCall().url)).to.eql(
{ zoom: '13', format: 'json', addressdetails: '1', lat: '48', lon: '16' }
);
expect(callback.calledOnceWithExactly(null, 'at')).to.be.ok;
@@ -66,17 +70,17 @@ describe('NominatimService', () => {
nominatim.reverse([16, 48], callback);
window.setTimeout(() => {
- expect(parseQueryString(fetchMock.lastUrl())).to.eql(
+ expect(parseQueryString(fetchMock.callHistory.lastCall().url)).to.eql(
{ zoom: '13', format: 'json', addressdetails: '1', lat: '48', lon: '16' }
);
expect(callback.calledOnceWithExactly(null, { address: { country_code:'at' }})).to.be.ok;
- fetchMock.resetHistory();
+ fetchMock.clearHistory();
callback = sinon.spy();
nominatim.reverse([17, 49], callback);
window.setTimeout(() => {
- expect(parseQueryString(fetchMock.lastUrl())).to.eql(
+ expect(parseQueryString(fetchMock.callHistory.lastCall().url)).to.eql(
{ zoom: '13', format: 'json', addressdetails: '1', lat: '49', lon: '17' }
);
expect(callback.calledOnceWithExactly(null, { address: { country_code:'cz' }})).to.be.ok;
@@ -90,12 +94,12 @@ describe('NominatimService', () => {
nominatim.reverse([16, 48], callback);
window.setTimeout(() => {
- expect(parseQueryString(fetchMock.lastUrl())).to.eql(
+ expect(parseQueryString(fetchMock.callHistory.lastCall().url)).to.eql(
{ zoom: '13', format: 'json', addressdetails: '1', lat: '48', lon: '16' }
);
expect(callback.calledOnceWithExactly(null, { address: { country_code:'at' }})).to.be.ok;
- fetchMock.resetHistory();
+ fetchMock.clearHistory();
callback = sinon.spy();
nominatim.reverse([16.000001, 48.000001], callback);
@@ -113,7 +117,7 @@ describe('NominatimService', () => {
nominatim.reverse([1000, 1000], callback);
window.setTimeout(() => {
- expect(parseQueryString(fetchMock.lastUrl())).to.eql(
+ expect(parseQueryString(fetchMock.callHistory.lastCall().url)).to.eql(
{ zoom: '13', format: 'json', addressdetails: '1', lat: '1000', lon: '1000' }
);
expect(callback.calledOnceWithExactly('Unable to geocode')).to.be.ok;
@@ -126,7 +130,7 @@ describe('NominatimService', () => {
describe('#search', () => {
it('calls the given callback with the results of the search query', done => {
const callback = sinon.spy();
- fetchMock.mock(/search/, {
+ fetchMock.route(/search/, {
body: '[{"place_id":"158484588","osm_type":"relation","osm_id":"188022","boundingbox":["39.867005","40.1379593","-75.2802976","-74.9558313"],"lat":"39.9523993","lon":"-75.1635898","display_name":"Philadelphia, Philadelphia County, Pennsylvania, United States of America","class":"place","type":"city","importance":0.83238050437778}]',
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -135,7 +139,7 @@ describe('NominatimService', () => {
nominatim.search('philadelphia', callback);
window.setTimeout(() => {
- expect(parseQueryString(fetchMock.lastUrl())).to.eql({q: 'philadelphia', format: 'json', limit: '10' });
+ expect(parseQueryString(fetchMock.callHistory.lastCall().url)).to.eql({q: 'philadelphia', format: 'json', limit: '10' });
expect(callback.calledOnce).to.be.ok;
done();
}, 50);
diff --git a/test/browser/services/OsmService.test.js b/test/browser/services/OsmService.test.js
index 56af5011f..27a7afae2 100644
--- a/test/browser/services/OsmService.test.js
+++ b/test/browser/services/OsmService.test.js
@@ -22,7 +22,7 @@ describe('OsmService', () => {
beforeEach(() => {
spy = sinon.spy();
- fetchMock.reset();
+ fetchMock.removeRoutes().clearHistory();
const capabilitiesJSON =
`{
@@ -175,10 +175,10 @@ describe('OsmService', () => {
}`;
fetchMock
- .mock(/api\/capabilities\.json/, { status: 200, body: capabilitiesJSON, headers: { 'Content-Type': 'application/json' } })
- .mock(/api\/capabilities(?!\.json)/, { status: 200, body: capabilitiesXML, headers: { 'Content-Type': 'application/xml' } })
- .mock(/user\/details\.json/, { status: 200, body: userJSON, headers: { 'Content-Type': 'application/json' } })
- .mock(/changesets\.json/, { status: 200, body: changesetJSON, headers: { 'Content-Type': 'application/json' } });
+ .route(/api\/capabilities\.json/, { status: 200, body: capabilitiesJSON, headers: { 'Content-Type': 'application/json' } })
+ .route(/api\/capabilities(?!\.json)/, { status: 200, body: capabilitiesXML, headers: { 'Content-Type': 'application/xml' } })
+ .route(/user\/details\.json/, { status: 200, body: userJSON, headers: { 'Content-Type': 'application/json' } })
+ .route(/changesets\.json/, { status: 200, body: changesetJSON, headers: { 'Content-Type': 'application/json' } });
_osm = new Rapid.OsmService(new MockContext());
@@ -189,7 +189,7 @@ describe('OsmService', () => {
afterEach(() => {
_osm.throttledReloadApiStatus.cancel();
- fetchMock.reset();
+ fetchMock.removeRoutes().clearHistory();
});
@@ -322,7 +322,7 @@ describe('OsmService', () => {
const okResponse = { status: 200, body: body, headers: { 'Content-Type': 'application/json' } };
it('returns an object', done => {
- fetchMock.mock(/map\.json/, okResponse);
+ fetchMock.route(/map\.json/, okResponse);
_osm.loadFromAPI(path, (err, result) => {
expect(err).to.not.be.ok;
@@ -336,21 +336,21 @@ describe('OsmService', () => {
const badResponse = { status: 400, body: 'Bad Request', headers: { 'Content-Type': 'text/plain' } };
fetchMock
- .mock((url, { headers }) => /map\.json/.test(url) && !!headers?.Authorization, badResponse)
- .mock((url, { headers }) => /map\.json/.test(url) && !headers?.Authorization, okResponse);
+ .route(match => /map\.json/.test(match.url) && match.options.headers?.authorization, badResponse)
+ .route(match => /map\.json/.test(match.url) && !match.options.headers?.authorization, okResponse);
loginAsync()
.then(() => {
- fetchMock.resetHistory();
+ fetchMock.clearHistory();
_osm.loadFromAPI(path, (err, result) => {
expect(err).to.be.not.ok;
expect(typeof result).to.eql('object');
expect(_osm.authenticated()).to.be.not.ok;
- const calls = fetchMock.calls();
+ const calls = fetchMock.callHistory.calls();
expect(calls).to.have.lengthOf.at.least(2); // auth, unauth, capabilities
- expect(calls[0][1]).to.have.nested.property('headers.Authorization');
- expect(calls[1][1]).to.not.have.nested.property('headers.Authorization');
+ expect(calls[0].options.headers || {}).to.have.property('authorization');
+ expect(calls[1].options.headers || {}).to.not.have.property('authorization');
done();
});
});
@@ -361,21 +361,21 @@ describe('OsmService', () => {
const badResponse = { status: 401, body: 'Unauthorized', headers: { 'Content-Type': 'text/plain' } };
fetchMock
- .mock((url, { headers }) => /map\.json/.test(url) && !!headers?.Authorization, badResponse)
- .mock((url, { headers }) => /map\.json/.test(url) && !headers?.Authorization, okResponse);
+ .route(match => /map\.json/.test(match.url) && match.options.headers?.authorization, badResponse)
+ .route(match => /map\.json/.test(match.url) && !match.options.headers?.authorization, okResponse);
loginAsync()
.then(() => {
- fetchMock.resetHistory();
+ fetchMock.clearHistory();
_osm.loadFromAPI(path, (err, result) => {
expect(err).to.be.not.ok;
expect(typeof result).to.eql('object');
expect(_osm.authenticated()).to.be.not.ok;
- const calls = fetchMock.calls();
+ const calls = fetchMock.callHistory.calls();
expect(calls).to.have.lengthOf.at.least(2); // auth, unauth, capabilities
- expect(calls[0][1]).to.have.nested.property('headers.Authorization');
- expect(calls[1][1]).to.not.have.nested.property('headers.Authorization');
+ expect(calls[0].options.headers || {}).to.have.property('authorization');
+ expect(calls[1].options.headers || {}).to.not.have.property('authorization');
done();
});
});
@@ -384,22 +384,22 @@ describe('OsmService', () => {
it('retries an authenticated call unauthenticated if 403 Forbidden', done => {
const badResponse = { status: 403, body: 'Forbidden', headers: { 'Content-Type': 'text/plain' } };
- fetchMock
- .mock((url, { headers }) => /map\.json/.test(url) && !!headers?.Authorization, badResponse)
- .mock((url, { headers }) => /map\.json/.test(url) && !headers?.Authorization, okResponse);
+ fetchMock
+ .route(match => /map\.json/.test(match.url) && match.options.headers?.authorization, badResponse)
+ .route(match => /map\.json/.test(match.url) && !match.options.headers?.authorization, okResponse);
loginAsync()
.then(() => {
- fetchMock.resetHistory();
+ fetchMock.clearHistory();
_osm.loadFromAPI(path, (err, result) => {
expect(err).to.be.not.ok;
expect(typeof result).to.eql('object');
expect(_osm.authenticated()).to.be.not.ok;
- const calls = fetchMock.calls();
+ const calls = fetchMock.callHistory.calls();
expect(calls).to.have.lengthOf.at.least(2); // auth, unauth, capabilities
- expect(calls[0][1]).to.have.nested.property('headers.Authorization');
- expect(calls[1][1]).to.not.have.nested.property('headers.Authorization');
+ expect(calls[0].options.headers || {}).to.have.property('authorization');
+ expect(calls[1].options.headers || {}).to.not.have.property('authorization');
done();
});
});
@@ -423,7 +423,7 @@ describe('OsmService', () => {
const partialResponse = { status: 200, body: partialBody, headers: { 'Content-Type': 'application/json' } };
it('returns a partial JSON error', done => {
- fetchMock.mock(/map\.json/, partialResponse);
+ fetchMock.route(/map\.json/, partialResponse);
_osm.loadFromAPI(path, err => {
expect(err.message).to.eql('Partial JSON');
@@ -450,7 +450,7 @@ describe('OsmService', () => {
});
it('calls callback when data tiles are loaded', done => {
- fetchMock.mock(/map\.json/, {
+ fetchMock.route(/map\.json/, {
body: tileBody,
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -497,7 +497,7 @@ describe('OsmService', () => {
}`;
it('loads a node', done => {
- fetchMock.mock(/node\/1\.json/, {
+ fetchMock.route(/node\/1\.json/, {
body: nodeBody,
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -513,7 +513,7 @@ describe('OsmService', () => {
it('loads a way', done => {
- fetchMock.mock(/way\/1\/full\.json/, {
+ fetchMock.route(/way\/1\/full\.json/, {
body: wayBody,
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -529,7 +529,7 @@ describe('OsmService', () => {
it('does not ignore repeat requests', done => {
- fetchMock.mock(/node\/1\.json/, {
+ fetchMock.route(/node\/1\.json/, {
body: nodeBody,
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -568,7 +568,7 @@ describe('OsmService', () => {
}`;
it('loads a node', done => {
- fetchMock.mock(/node\/1\/1\.json/, {
+ fetchMock.route(/node\/1\/1\.json/, {
body: nodeBody,
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -584,7 +584,7 @@ describe('OsmService', () => {
it('loads a way', done => {
- fetchMock.mock(/way\/1\/1\.json/, {
+ fetchMock.route(/way\/1\/1\.json/, {
body: wayBody,
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -600,7 +600,7 @@ describe('OsmService', () => {
it('does not ignore repeat requests', done => {
- fetchMock.mock(/node\/1\/1\.json/, {
+ fetchMock.route(/node\/1\/1\.json/, {
body: nodeBody,
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -722,14 +722,14 @@ describe('OsmService', () => {
`;
it('fires loadedNotes when notes are loaded', done => {
- fetchMock.mock(/notes\?/, {
+ fetchMock.route(/notes\?/, {
body: notesBody,
status: 200,
headers: { 'Content-Type': 'text/xml' }
});
_osm.on('loadedNotes', () => {
- expect(fetchMock.calls()).to.have.lengthOf.at.least(1);
+ expect(fetchMock.callHistory.calls()).to.have.lengthOf.at.least(1);
done();
});
diff --git a/test/browser/services/OsmWikibaseService.test.js b/test/browser/services/OsmWikibaseService.test.js
index 1092731b7..ab55741a5 100644
--- a/test/browser/services/OsmWikibaseService.test.js
+++ b/test/browser/services/OsmWikibaseService.test.js
@@ -2,11 +2,15 @@ describe('OsmWikibaseService', () => {
let _wikibase;
beforeEach(() => {
- fetchMock.reset();
+ fetchMock.removeRoutes().clearHistory();
_wikibase = new Rapid.OsmWikibaseService();
return _wikibase.initAsync();
});
+ afterEach(() => {
+ fetchMock.removeRoutes().clearHistory();
+ });
+
function parseQueryString(url) {
return Rapid.sdk.utilStringQs(url.substring(url.indexOf('?')));
@@ -253,7 +257,7 @@ describe('OsmWikibaseService', () => {
describe('#getEntity', () => {
it('calls the given callback with the results of the getEntity data item query', done => {
const callback = sinon.spy();
- fetchMock.mock(/action=wbgetentities/, {
+ fetchMock.route(/action=wbgetentities/, {
body: JSON.stringify({
entities: {
Q42: keyData(),
@@ -269,7 +273,7 @@ describe('OsmWikibaseService', () => {
_wikibase.getEntity({ key: 'amenity', value: 'parking', langCodes: ['fr'] }, callback);
window.setTimeout(() => {
- expect(parseQueryString(fetchMock.lastUrl())).to.eql(
+ expect(parseQueryString(fetchMock.callHistory.lastCall().url)).to.eql(
{
action: 'wbgetentities',
sites: 'wiki',
diff --git a/test/browser/services/StreetsideService.test.js b/test/browser/services/StreetsideService.test.js
index cbf09e740..3a11abed0 100644
--- a/test/browser/services/StreetsideService.test.js
+++ b/test/browser/services/StreetsideService.test.js
@@ -21,11 +21,15 @@ describe('StreetsideService', () => {
beforeEach(() => {
- fetchMock.reset();
+ fetchMock.removeRoutes().clearHistory();
_streetside = new Rapid.StreetsideService(new MockContext());
return _streetside.initAsync();
});
+ afterEach(() => {
+ fetchMock.removeRoutes().clearHistory();
+ });
+
describe('#initAsync', () => {
it('initializes cache', () => {
@@ -70,7 +74,7 @@ describe('StreetsideService', () => {
}
];
- fetchMock.mock(/StreetSideBubbleMetaData/, {
+ fetchMock.route(/StreetSideBubbleMetaData/, {
body: JSON.stringify(data),
status: 200,
headers: { 'Content-Type': 'text/plain' }
@@ -109,7 +113,7 @@ describe('StreetsideService', () => {
}
];
- fetchMock.mock(/StreetSideBubbleMetaData/, {
+ fetchMock.route(/StreetSideBubbleMetaData/, {
body: JSON.stringify(data),
status: 200,
headers: { 'Content-Type': 'text/plain' }
@@ -119,7 +123,7 @@ describe('StreetsideService', () => {
window.setTimeout(() => {
expect(spy.notCalled).to.be.ok;
- expect(fetchMock.calls().length).to.eql(0); // no tile requests of any kind
+ expect(fetchMock.callHistory.calls().length).to.eql(0); // no tile requests of any kind
done();
}, 20);
});
diff --git a/test/browser/services/TaginfoService.test.js b/test/browser/services/TaginfoService.test.js
index da2607d12..d2decdbf8 100644
--- a/test/browser/services/TaginfoService.test.js
+++ b/test/browser/services/TaginfoService.test.js
@@ -16,18 +16,22 @@ describe('TaginfoService', () => {
beforeEach(() => {
-// fetchMock.reset();
-// fetchMock.mock(new RegExp('\/keys\/all.*sortname=values_all'), {
+ fetchMock.removeRoutes().clearHistory();
+// fetchMock.route(new RegExp('\/keys\/all.*sortname=values_all'), {
// body: '{"data":[{"count_all":56136034,"key":"name","count_all_fraction":0.0132}]}',
// status: 200,
// headers: { 'Content-Type': 'application/json' }
// });
// note - init() used to fetch these common values, this has been moved to startAsync().
- fetchMock.reset();
+
taginfo = new Rapid.TaginfoService(new MockContext());
return taginfo.initAsync();
});
+ afterEach(() => {
+ fetchMock.removeRoutes().clearHistory();
+ });
+
function parseQueryString(url) {
return Rapid.sdk.utilStringQs(url.substring(url.indexOf('?')));
@@ -36,7 +40,7 @@ describe('TaginfoService', () => {
describe('#keys', () => {
it('calls the given callback with the results of the keys query', done => {
- fetchMock.mock(/\/keys\/all/, {
+ fetchMock.route(/\/keys\/all/, {
body: '{"data":[{"count_all":5190337,"key":"amenity","count_all_fraction":1.0}]}',
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -46,7 +50,7 @@ describe('TaginfoService', () => {
taginfo.keys({ query: 'amen' }, callback);
window.setTimeout(() => {
- expect(parseQueryString(fetchMock.lastUrl())).to.eql(
+ expect(parseQueryString(fetchMock.callHistory.lastCall().url)).to.eql(
{ query: 'amen', page: '1', rp: '10', sortname: 'count_all', sortorder: 'desc', lang: 'en' }
);
expect(callback.calledOnceWithExactly(null, [{ title: 'amenity', value: 'amenity' }] )).to.be.ok;
@@ -55,7 +59,7 @@ describe('TaginfoService', () => {
});
it('includes popular keys', done => {
- fetchMock.mock(/\/keys\/all/, {
+ fetchMock.route(/\/keys\/all/, {
body: '{"data":[{"count_all":5190337,"count_nodes":500000,"key":"amenity","count_all_fraction":1.0, "count_nodes_fraction":1.0},'
+ '{"count_all":1,"key":"amenityother","count_all_fraction":0.0, "count_nodes":100}]}',
status: 200,
@@ -72,7 +76,7 @@ describe('TaginfoService', () => {
});
it('includes popular keys with an entity type filter', done => {
- fetchMock.mock(/\/keys\/all/, {
+ fetchMock.route(/\/keys\/all/, {
body: '{"data":[{"count_all":5190337,"count_nodes":500000,"key":"amenity","count_all_fraction":1.0, "count_nodes_fraction":1.0},'
+ '{"count_all":1,"key":"amenityother","count_all_fraction":0.0, "count_nodes":100}]}',
status: 200,
@@ -89,7 +93,7 @@ describe('TaginfoService', () => {
});
it('includes unpopular keys with a wiki page', done => {
- fetchMock.mock(/\/keys\/all/, {
+ fetchMock.route(/\/keys\/all/, {
body: '{"data":[{"count_all":5190337,"key":"amenity","count_all_fraction":1.0, "count_nodes_fraction":1.0},'
+ '{"count_all":1,"key":"amenityother","count_all_fraction":0.0, "count_nodes_fraction":0.0, "in_wiki": true}]}',
status: 200,
@@ -109,7 +113,7 @@ describe('TaginfoService', () => {
});
it('sorts keys with \':\' below keys without \':\'', done => {
- fetchMock.mock(/\/keys\/all/, {
+ fetchMock.route(/\/keys\/all/, {
body: '{"data":[{"key":"ref:bag","count_all":9790586,"count_all_fraction":0.0028},' +
'{"key":"ref","count_all":7933528,"count_all_fraction":0.0023}]}',
status: 200,
@@ -130,7 +134,7 @@ describe('TaginfoService', () => {
describe('#multikeys', () => {
it('calls the given callback with the results of the multikeys query', done => {
- fetchMock.mock(/\/keys\/all/, {
+ fetchMock.route(/\/keys\/all/, {
body: '{"data":[{"count_all":69593,"key":"recycling:glass","count_all_fraction":0.0}]}',
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -140,7 +144,7 @@ describe('TaginfoService', () => {
taginfo.multikeys({ query: 'recycling:' }, callback);
window.setTimeout(() => {
- expect(parseQueryString(fetchMock.lastUrl())).to.eql(
+ expect(parseQueryString(fetchMock.callHistory.lastCall().url)).to.eql(
{ query: 'recycling:', page: '1', rp: '25', sortname: 'count_all', sortorder: 'desc', lang: 'en' }
);
expect(callback.calledOnceWithExactly(
@@ -151,7 +155,7 @@ describe('TaginfoService', () => {
});
it('excludes multikeys with extra colons', done => {
- fetchMock.mock(/\/keys\/all/, {
+ fetchMock.route(/\/keys\/all/, {
body: '{"data":[{"count_all":4426,"key":"service:bicycle:retail","count_all_fraction":0.0},' +
'{"count_all":22,"key":"service:bicycle:retail:ebikes","count_all_fraction":0.0}]}',
status: 200,
@@ -170,7 +174,7 @@ describe('TaginfoService', () => {
});
it('excludes multikeys with wrong prefix', done => {
- fetchMock.mock(/\/keys\/all/, {
+ fetchMock.route(/\/keys\/all/, {
body: '{"data":[{"count_all":4426,"key":"service:bicycle:retail","count_all_fraction":0.0},' +
'{"count_all":22,"key":"disused:service:bicycle","count_all_fraction":0.0}]}',
status: 200,
@@ -191,7 +195,7 @@ describe('TaginfoService', () => {
describe('#values', () => {
it('calls the given callback with the results of the values query', done => {
- fetchMock.mock(/\/key\/values/, {
+ fetchMock.route(/\/key\/values/, {
body: '{"data":[{"value":"parking","description":"A place for parking cars", "fraction":0.1}]}',
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -201,7 +205,7 @@ describe('TaginfoService', () => {
taginfo.values({ key: 'amenity', query: 'par' }, callback);
window.setTimeout(() => {
- expect(parseQueryString(fetchMock.lastUrl())).to.eql(
+ expect(parseQueryString(fetchMock.callHistory.lastCall().url)).to.eql(
{key: 'amenity', query: 'par', page: '1', rp: '25', sortname: 'count_all', sortorder: 'desc', lang: 'en'}
);
expect(callback.calledOnceWithExactly(
@@ -212,7 +216,7 @@ describe('TaginfoService', () => {
});
it('includes popular values', done => {
- fetchMock.mock(/\/key\/values/, {
+ fetchMock.route(/\/key\/values/, {
body: '{"data":[{"value":"parking","description":"A place for parking cars", "fraction":1.0},' +
'{"value":"party","description":"A place for partying", "fraction":0.0}]}',
status: 200,
@@ -231,7 +235,7 @@ describe('TaginfoService', () => {
});
it('does not get values for extremely popular keys', done => {
- fetchMock.mock(/\/key\/values/, {
+ fetchMock.route(/\/key\/values/, {
body: '{"data":[{"value":"Rue Pasteur","description":"", "fraction":0.0001},' +
'{"value":"Via Trieste","description":"", "fraction":0.0001}]}',
status: 200,
@@ -248,7 +252,7 @@ describe('TaginfoService', () => {
});
it('excludes values with capital letters and some punctuation', done => {
- fetchMock.mock(/\/key\/values/, {
+ fetchMock.route(/\/key\/values/, {
body: '{"data":[{"value":"parking","description":"A place for parking cars", "fraction":0.2},'
+ '{"value":"PArking","description":"A common misspelling", "fraction":0.2},'
+ '{"value":"parking;partying","description":"A place for parking cars *and* partying", "fraction":0.2},'
@@ -270,7 +274,7 @@ describe('TaginfoService', () => {
});
it('includes network values with capital letters and some punctuation', done => {
- fetchMock.mock(/\/key\/values/, {
+ fetchMock.route(/\/key\/values/, {
body: '{"data":[{"value":"US:TX:FM","description":"Farm to Market Roads in the U.S. state of Texas.", "fraction":0.34},'
+ '{"value":"US:KY","description":"Primary and secondary state highways in the U.S. state of Kentucky.", "fraction":0.31},'
+ '{"value":"US:US","description":"U.S. routes in the United States.", "fraction":0.19},'
@@ -296,7 +300,7 @@ describe('TaginfoService', () => {
});
it('includes biological genus values with capital letters', done => {
- fetchMock.mock(/\/key\/values/, {
+ fetchMock.route(/\/key\/values/, {
body: '{"data":[{"value":"Quercus","description":"Oak", "fraction":0.5}]}',
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -312,7 +316,7 @@ describe('TaginfoService', () => {
});
it('includes biological taxon values with capital letters', done => {
- fetchMock.mock(/\/key\/values/, {
+ fetchMock.route(/\/key\/values/, {
body: '{"data":[{"value":"Quercus robur","description":"Oak", "fraction":0.5}]}',
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -328,7 +332,7 @@ describe('TaginfoService', () => {
});
it('includes biological species values with capital letters', done => {
- fetchMock.mock(/\/key\/values/, {
+ fetchMock.route(/\/key\/values/, {
body: '{"data":[{"value":"Quercus robur","description":"Oak", "fraction":0.5}]}',
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -346,7 +350,7 @@ describe('TaginfoService', () => {
describe('#roles', () => {
it('calls the given callback with the results of the roles query', done => {
- fetchMock.mock(/\/relation\/roles/, {
+ fetchMock.route(/\/relation\/roles/, {
body: '{"data":[{"role":"stop","count_relation_members_fraction":0.1757},' +
'{"role":"south","count_relation_members_fraction":0.0035}]}',
status: 200,
@@ -357,7 +361,7 @@ describe('TaginfoService', () => {
taginfo.roles({ rtype: 'route', query: 's', geometry: 'relation' }, callback);
window.setTimeout(() => {
- expect(parseQueryString(fetchMock.lastUrl())).to.eql(
+ expect(parseQueryString(fetchMock.callHistory.lastCall().url)).to.eql(
{ rtype: 'route', query: 's', page: '1', rp: '25', sortname: 'count_relation_members', sortorder: 'desc', lang: 'en' }
);
expect(callback.calledOnceWithExactly(null, [
@@ -371,7 +375,7 @@ describe('TaginfoService', () => {
describe('#docs', () => {
it('calls the given callback with the results of the docs query', done => {
- fetchMock.mock(/\/tag\/wiki_page/, {
+ fetchMock.route(/\/tag\/wiki_page/, {
body: '{"data":[{"on_way":false,"lang":"en","on_area":true,"image":"File:Car park2.jpg"}]}',
status: 200,
headers: { 'Content-Type': 'application/json' }
@@ -381,7 +385,7 @@ describe('TaginfoService', () => {
taginfo.docs({ key: 'amenity', value: 'parking' }, callback);
window.setTimeout(() => {
- expect(parseQueryString(fetchMock.lastUrl())).to.eql({ key: 'amenity', value: 'parking' });
+ expect(parseQueryString(fetchMock.callHistory.lastCall().url)).to.eql({ key: 'amenity', value: 'parking' });
expect(callback.calledOnceWithExactly(
null, [{ on_way: false, lang: 'en', on_area: true, image: 'File:Car park2.jpg' }]
)).to.be.ok;
diff --git a/test/index.html b/test/index.html
index 1085736a0..093ae0ce9 100644
--- a/test/index.html
+++ b/test/index.html
@@ -22,7 +22,6 @@
-
diff --git a/test/spec_helpers.js b/test/spec_helpers.js
index 840160cb9..78e094768 100644
--- a/test/spec_helpers.js
+++ b/test/spec_helpers.js
@@ -19,7 +19,6 @@ mocha.setup({
]
});
-delete window.PointerEvent; // force the brower to use mouse events
+delete window.PointerEvent; // force the browser to use mouse events
-fetchMock.config.fallbackToNetwork = false;
-fetchMock.config.overwriteRoutes = false;
+window.fetchMock.mockGlobal();