diff --git a/my.conf.js b/my.conf.js
index 390582538..243d1b2a4 100644
--- a/my.conf.js
+++ b/my.conf.js
@@ -17,14 +17,11 @@ module.exports = function (config) {
// list of files / patterns to load in the browser
files: [
- 'node_modules/mocha/mocha.css',
- 'node_modules/mocha/mocha.js',
'node_modules/chai/chai.js',
'node_modules/sinon/pkg/sinon.js',
'node_modules/sinon-chai/lib/sinon-chai.js',
'node_modules/happen/happen.js',
'node_modules/fetch-mock/es5/client-bundle.js',
- { pattern: 'dist/iD.js.map', included: false },
{ pattern: 'dist/iD.js', included: true },
{ pattern: 'dist/iD.css', included: true },
{ pattern: 'dist/**/*', included: false },
diff --git a/package.json b/package.json
index 7fcb7975f..595e7c265 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,7 @@
"quickstart": "npm-run-all -s build:dev start:server",
"start:server": "node scripts/server.js",
"test": "npm-run-all -s lint build:css build:data build:legacy test:spec",
- "test:spec": "phantomjs --web-security=no node_modules/mocha-phantomjs-core/mocha-phantomjs-core.js test/index.html spec",
+ "test:spec": "karma start my.conf.js",
"translations": "node scripts/update_locales.js"
},
"dependencies": {
diff --git a/test/spec/services/osm.js b/test/spec/services/osm.js
index 1e76aadbd..14a9d8966 100644
--- a/test/spec/services/osm.js
+++ b/test/spec/services/osm.js
@@ -34,7 +34,8 @@ describe('iD.serviceOsm', function () {
});
afterEach(function () {
- fetchMock.resetBehavior();
+ fetchMock.reset();
+ serverXHR.restore();
});
@@ -151,8 +152,8 @@ describe('iD.serviceOsm', function () {
'}';
it('returns an object', function (done) {
- fetchMock.mock('http://www.openstreetmap.org' + path, , {
- body: nodeResponse,
+ fetchMock.mock('http://www.openstreetmap.org' + path, {
+ body: response,
status: 200,
headers: { 'Content-Type': 'application/json' }
});
@@ -165,63 +166,80 @@ describe('iD.serviceOsm', function () {
});
it('retries an authenticated call unauthenticated if 400 Bad Request', function (done) {
- fetchMock.mock('http://www.openstreetmap.org' + path, )
+ fetchMock.mock('http://www.openstreetmap.org' + path, {
+ body: response,
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+ serverXHR.respondWith('GET', 'http://www.openstreetmap.org' + path,
+ [400, { 'Content-Type': 'text/plain' }, 'Bad Request']);
+
login();
connection.loadFromAPI(path, function (err, xml) {
expect(err).to.be.not.ok;
expect(typeof xml).to.eql('object');
expect(connection.authenticated()).to.be.not.ok;
+ expect(fetchMock.called()).to.be.true;
+
done();
});
- serverXHR.respondWith('GET', 'http://www.openstreetmap.org' + path,
- [400, { 'Content-Type': 'text/plain' }, 'Bad Request']);
- serverFetch.respondWith('GET', 'http://www.openstreetmap.org' + path,
- [200, { 'Content-Type': 'application/json' }, response]);
-
serverXHR.respond();
- serverFetch.respond();
});
it('retries an authenticated call unauthenticated if 401 Unauthorized', function (done) {
+ fetchMock.mock('http://www.openstreetmap.org' + path, {
+ body: response,
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+ serverXHR.respondWith('GET', 'http://www.openstreetmap.org' + path,
+ [401, { 'Content-Type': 'text/plain' }, 'Unauthorized']);
+
login();
connection.loadFromAPI(path, function (err, xml) {
expect(err).to.be.not.ok;
expect(typeof xml).to.eql('object');
expect(connection.authenticated()).to.be.not.ok;
+ expect(fetchMock.called()).to.be.true;
+
done();
});
- serverXHR.respondWith('GET', 'http://www.openstreetmap.org' + path,
- [401, { 'Content-Type': 'text/plain' }, 'Unauthorized']);
- serverFetch.respondWith('GET', 'http://www.openstreetmap.org' + path,
- [200, { 'Content-Type': 'application/json' }, response]);
-
serverXHR.respond();
- serverFetch.respond();
});
it('retries an authenticated call unauthenticated if 403 Forbidden', function (done) {
+ fetchMock.mock('http://www.openstreetmap.org' + path, {
+ body: response,
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+ serverXHR.respondWith('GET', 'http://www.openstreetmap.org' + path,
+ [403, { 'Content-Type': 'text/plain' }, 'Forbidden']);
+
login();
connection.loadFromAPI(path, function (err, xml) {
expect(err).to.be.not.ok;
expect(typeof xml).to.eql('object');
expect(connection.authenticated()).to.be.not.ok;
+ expect(fetchMock.called()).to.be.true;
+
done();
});
- serverXHR.respondWith('GET', 'http://www.openstreetmap.org' + path,
- [403, { 'Content-Type': 'text/plain' }, 'Forbidden']);
- serverFetch.respondWith('GET', 'http://www.openstreetmap.org' + path,
- [200, { 'Content-Type': 'application/json' }, response]);
-
serverXHR.respond();
- serverFetch.respond();
});
it('dispatches change event if 509 Bandwidth Limit Exceeded', function (done) {
+ fetchMock.mock('http://www.openstreetmap.org' + path, {
+ body: 'Bandwidth Limit Exceeded',
+ status: 509,
+ headers: { 'Content-Type': 'text/plain' }
+ });
+
logout();
connection.on('change', spy);
connection.loadFromAPI(path, function (err) {
@@ -229,13 +247,15 @@ describe('iD.serviceOsm', function () {
expect(spy).to.have.been.calledOnce;
done();
});
-
- serverFetch.respondWith('GET', 'http://www.openstreetmap.org' + path,
- [509, { 'Content-Type': 'text/plain' }, 'Bandwidth Limit Exceeded']);
- serverFetch.respond();
});
it('dispatches change event if 429 Too Many Requests', function (done) {
+ fetchMock.mock('http://www.openstreetmap.org' + path, {
+ body: '429 Too Many Requests',
+ status: 429,
+ headers: { 'Content-Type': 'text/plain' }
+ });
+
logout();
connection.on('change', spy);
connection.loadFromAPI(path, function (err) {
@@ -243,10 +263,6 @@ describe('iD.serviceOsm', function () {
expect(spy).to.have.been.calledOnce;
done();
});
-
- serverFetch.respondWith('GET', 'http://www.openstreetmap.org' + path,
- [429, { 'Content-Type': 'text/plain' }, '429 Too Many Requests']);
- serverFetch.respond();
});
});
@@ -270,13 +286,15 @@ describe('iD.serviceOsm', function () {
});
it('calls callback when data tiles are loaded', function (done) {
+ fetchMock.mock(/map.json\?bbox/, {
+ body: tileResponse,
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var spy = sinon.spy();
connection.loadTiles(context.projection, spy);
- serverFetch.respondWith('GET', /map.json\?bbox/,
- [200, { 'Content-Type': 'application/json' }, tileResponse]);
- serverFetch.respond();
-
window.setTimeout(function () {
expect(spy).to.have.been.calledOnce;
done();
@@ -284,15 +302,27 @@ describe('iD.serviceOsm', function () {
});
it('#isDataLoaded', function (done) {
- expect(connection.isDataLoaded([-74.0444216, 40.6694299])).to.be.not.ok;
+ fetchMock.mock(/map.json\?bbox/, {
+ body: tileResponse,
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
+ // resetting the cache
+ const caches = connection.caches('get');
+ caches.tile.toLoad = {};
+ caches.tile.loaded = {};
+ caches.tile.inflight = {};
+ caches.tile.seen = {};
+ caches.tile.rtree.clear();
+
+ expect(connection.isDataLoaded([-74.0444216, 40.6694299])).to.be.false;
connection.loadTiles(context.projection);
- serverFetch.respondWith('GET', /map.json\?bbox/,
- [200, { 'Content-Type': 'application/json' }, tileResponse]);
- serverFetch.respond();
window.setTimeout(function () {
- expect(connection.isDataLoaded([-74.0444216, 40.6694299])).to.be.ok;
+ expect(fetchMock.called()).to.be.true;
+ expect(connection.isDataLoaded([-74.0444216, 40.6694299])).to.be.true;
done();
}, 500);
});
@@ -332,34 +362,38 @@ describe('iD.serviceOsm', function () {
});
it('loads a way', function (done) {
+ fetchMock.mock('http://www.openstreetmap.org/api/0.6/way/1/full.json', {
+ body: wayResponse,
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var id = 'w1';
connection.loadEntity(id, function (err, result) {
var entity = result.data.find(function (e) { return e.id === id; });
expect(entity).to.be.an.instanceOf(iD.osmWay);
done();
});
-
- serverFetch.respondWith('GET', 'http://www.openstreetmap.org/api/0.6/way/1/full.json',
- [200, { 'Content-Type': 'application/json' }, wayResponse]);
- serverFetch.respond();
});
it('does not ignore repeat requests', function (done) {
+ fetchMock.mock('http://www.openstreetmap.org/api/0.6/node/1.json', {
+ body: wayResponse,
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var id = 'n1';
connection.loadEntity(id, function (err1, result1) {
var entity1 = result1.data.find(function (e1) { return e1.id === id; });
expect(entity1).to.be.an.instanceOf(iD.osmNode);
+
connection.loadEntity(id, function (err2, result2) {
var entity2 = result2.data.find(function (e2) { return e2.id === id; });
expect(entity2).to.be.an.instanceOf(iD.osmNode);
done();
});
- serverFetch.respond();
});
-
- serverFetch.respondWith('GET', 'http://www.openstreetmap.org/api/0.6/node/1.json',
- [200, { 'Content-Type': 'application/json' }, nodeResponse]);
- serverFetch.respond();
});
});
@@ -382,32 +416,42 @@ describe('iD.serviceOsm', function () {
'}';
it('loads a node', function (done) {
+ fetchMock.mock('http://www.openstreetmap.org/api/0.6/node/1/1.json', {
+ body: nodeResponse,
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var id = 'n1';
connection.loadEntityVersion(id, 1, function (err, result) {
var entity = result.data.find(function (e) { return e.id === id; });
expect(entity).to.be.an.instanceOf(iD.osmNode);
done();
});
-
- serverFetch.respondWith('GET', 'http://www.openstreetmap.org/api/0.6/node/1/1.json',
- [200, { 'Content-Type': 'application/json' }, nodeResponse]);
- serverFetch.respond();
});
it('loads a way', function (done) {
+ fetchMock.mock('http://www.openstreetmap.org/api/0.6/way/1/1.json', {
+ body: wayResponse,
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var id = 'w1';
connection.loadEntityVersion(id, 1, function (err, result) {
var entity = result.data.find(function (e) { return e.id === id; });
expect(entity).to.be.an.instanceOf(iD.osmWay);
done();
});
-
- serverFetch.respondWith('GET', 'http://www.openstreetmap.org/api/0.6/way/1/1.json',
- [200, { 'Content-Type': 'application/json' }, wayResponse]);
- serverFetch.respond();
});
it('does not ignore repeat requests', function (done) {
+ fetchMock.mock('http://www.openstreetmap.org/api/0.6/node/1/1.json', {
+ body: nodeResponse,
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var id = 'n1';
connection.loadEntityVersion(id, 1, function (err1, result1) {
var entity1 = result1.data.find(function (e1) { return e1.id === id; });
@@ -417,12 +461,7 @@ describe('iD.serviceOsm', function () {
expect(entity2).to.be.an.instanceOf(iD.osmNode);
done();
});
- serverFetch.respond();
});
-
- serverFetch.respondWith('GET', 'http://www.openstreetmap.org/api/0.6/node/1/1.json',
- [200, { 'Content-Type': 'application/json' }, nodeResponse]);
- serverFetch.respond();
});
});
@@ -611,13 +650,15 @@ describe('iD.serviceOsm', function () {
});
it('fires loadedNotes when notes are loaded', function (done) {
+ fetchMock.mock(/notes\?/, {
+ body: notesXML,
+ status: 200,
+ headers: { 'Content-Type': 'text/xml' }
+ });
+
connection.on('loadedNotes', spy);
connection.loadNotes(context.projection, {});
- serverFetch.respondWith('GET', /notes\?/,
- [200, { 'Content-Type': 'text/xml' }, notesXML]);
- serverFetch.respond();
-
window.setTimeout(function () {
expect(spy).to.have.been.calledOnce;
done();
@@ -704,47 +745,58 @@ describe('iD.serviceOsm', function () {
describe('API capabilities', function () {
- var capabilitiesXML = '' +
- '' +
- '' +
- '' +
- '' +
- '' +
- '' +
- '' +
- '' +
- '' +
- '' +
- '' +
- '' +
- '' +
- '' +
- '';
+ var capabilitiesXML = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
describe('#status', function () {
it('gets API status', function (done) {
+ fetchMock.mock('http://www.openstreetmap.org/api/capabilities', {
+ body: capabilitiesXML,
+ status: 200,
+ headers: { 'Content-Type': 'text/xml' }
+ }, {
+ overwriteRoutes: true
+ });
+
connection.status(function (err, val) {
expect(val).to.eql('online');
done();
});
-
- serverFetch.respondWith('GET', 'http://www.openstreetmap.org/api/capabilities',
- [200, { 'Content-Type': 'text/xml' }, capabilitiesXML]);
- serverFetch.respond();
});
});
describe('#imageryBlocklists', function () {
it('updates imagery blocklists', function (done) {
+ fetchMock.mock('http://www.openstreetmap.org/api/capabilities', {
+ body: capabilitiesXML,
+ status: 200,
+ headers: { 'Content-Type': 'text/xml' }
+ }, {
+ overwriteRoutes: true
+ });
+
connection.status(function () {
var blocklists = connection.imageryBlocklists();
expect(blocklists).to.deep.equal([new RegExp('\.foo\.com'), new RegExp('\.bar\.org')]);
done();
});
-
- serverFetch.respondWith('GET', 'http://www.openstreetmap.org/api/capabilities',
- [200, { 'Content-Type': 'text/xml' }, capabilitiesXML]);
- serverFetch.respond();
});
});
diff --git a/test/spec/services/taginfo.js b/test/spec/services/taginfo.js
index 0207fa0bd..3fe2e3094 100644
--- a/test/spec/services/taginfo.js
+++ b/test/spec/services/taginfo.js
@@ -1,404 +1,401 @@
-describe('iD.serviceTaginfo', function() {
- var server, taginfo;
+describe('iD.serviceTaginfo', function () {
+ var taginfo;
- before(function() {
+ before(function () {
iD.services.taginfo = iD.serviceTaginfo;
});
- after(function() {
+ after(function () {
delete iD.services.taginfo;
});
- beforeEach(function() {
- server = window.fakeFetch().create();
+ beforeEach(function () {
taginfo = iD.services.taginfo;
+ fetchMock.mock(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' }
+ });
+
// prepopulate popular keys list with "name"
taginfo.init();
- server.respondWith('GET',
- new RegExp('\/keys\/all.*sortname=values_all'),
- [200, { 'Content-Type': 'application/json' },
- '{"data":[{"count_all":56136034,"key":"name","count_all_fraction":0.0132}]}']
- );
- server.respond();
- server.restore();
- server = window.fakeFetch().create();
+ fetchMock.reset();
});
- afterEach(function() {
- server.restore();
+ afterEach(function () {
+ fetchMock.reset();
});
- function query(url) {
+ function parseQueryString(url) {
return iD.utilStringQs(url.substring(url.indexOf('?')));
}
+ describe('#keys', function () {
+ it('calls the given callback with the results of the keys query', function (done) {
+ fetchMock.mock(/\/keys\/all/, {
+ body: '{"data":[{"count_all":5190337,"key":"amenity","count_all_fraction":1.0}]}',
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
- describe('#keys', function() {
- it('calls the given callback with the results of the keys query', function(done) {
var callback = sinon.spy();
- taginfo.keys({query: 'amen'}, callback);
+ taginfo.keys({ query: 'amen' }, callback);
- server.respondWith('GET', /\/keys\/all/,
- [200, { 'Content-Type': 'application/json' },
- '{"data":[{"count_all":5190337,"key":"amenity","count_all_fraction":1.0}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
- expect(query(server.requests()[0].url)).to.eql(
- {query: 'amen', page: '1', rp: '10', sortname: 'count_all', sortorder: 'desc', lang: 'en'}
+ window.setTimeout(function () {
+ expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
+ { query: 'amen', page: '1', rp: '10', sortname: 'count_all', sortorder: 'desc', lang: 'en' }
);
expect(callback).to.have.been.calledWith(
- null, [{'title':'amenity', 'value':'amenity'}]
+ null, [{ 'title': 'amenity', 'value': 'amenity' }]
);
done();
}, 50);
});
- it('includes popular keys', function(done) {
+ it('includes popular keys', function (done) {
+ fetchMock.mock(/\/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,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.keys({query: 'amen'}, callback);
+ taginfo.keys({ query: 'amen' }, callback);
- server.respondWith('GET', /\/keys\/all/,
- [200, { 'Content-Type': 'application/json' },
- '{"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}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
+ window.setTimeout(function () {
expect(callback).to.have.been.calledWith(
- null, [{'title':'amenity', 'value':'amenity'}]
+ null, [{ 'title': 'amenity', 'value': 'amenity' }]
);
done();
}, 50);
});
- it('includes popular keys with an entity type filter', function(done) {
+ it('includes popular keys with an entity type filter', function (done) {
+ fetchMock.mock(/\/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,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.keys({query: 'amen', filter: 'nodes'}, callback);
+ taginfo.keys({ query: 'amen', filter: 'nodes' }, callback);
- server.respondWith('GET', /\/keys\/all/,
- [200, { 'Content-Type': 'application/json' },
- '{"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}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
+ window.setTimeout(function () {
expect(callback).to.have.been.calledWith(
- null, [{'title':'amenity', 'value':'amenity'}]
+ null, [{ 'title': 'amenity', 'value': 'amenity' }]
);
done();
}, 50);
});
- it('includes unpopular keys with a wiki page', function(done) {
+ it('includes unpopular keys with a wiki page', function (done) {
+ fetchMock.mock(/\/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,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.keys({query: 'amen'}, callback);
+ taginfo.keys({ query: 'amen' }, callback);
- server.respondWith('GET', /\/keys\/all/,
- [200, { 'Content-Type': 'application/json' },
- '{"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}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
+ window.setTimeout(function () {
expect(callback).to.have.been.calledWith(null, [
- {'title':'amenity', 'value':'amenity'},
- {'title':'amenityother', 'value':'amenityother'}
+ { 'title': 'amenity', 'value': 'amenity' },
+ { 'title': 'amenityother', 'value': 'amenityother' }
]);
done();
}, 50);
});
- it('sorts keys with \':\' below keys without \':\'', function(done) {
+ it('sorts keys with \':\' below keys without \':\'', function (done) {
+ fetchMock.mock(/\/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,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.keys({query: 'ref'}, callback);
+ taginfo.keys({ query: 'ref' }, callback);
- server.respondWith('GET', /\/keys\/all/,
- [200, { 'Content-Type': 'application/json' },
- '{"data":[{"key":"ref:bag","count_all":9790586,"count_all_fraction":0.0028},' +
- '{"key":"ref","count_all":7933528,"count_all_fraction":0.0023}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
+ window.setTimeout(function () {
expect(callback).to.have.been.calledWith(
- null, [{'title':'ref', 'value':'ref'},{'title':'ref:bag', 'value':'ref:bag'}]
+ null, [{ 'title': 'ref', 'value': 'ref' }, { 'title': 'ref:bag', 'value': 'ref:bag' }]
);
done();
}, 50);
});
});
- describe('#multikeys', function() {
- it('calls the given callback with the results of the multikeys query', function(done) {
+ describe('#multikeys', function () {
+ it('calls the given callback with the results of the multikeys query', function (done) {
+ fetchMock.mock(/\/keys\/all/, {
+ body: '{"data":[{"count_all":69593,"key":"recycling:glass","count_all_fraction":0.0}]}',
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.multikeys({query: 'recycling:'}, callback);
+ taginfo.multikeys({ query: 'recycling:' }, callback);
- server.respondWith('GET', /\/keys\/all/,
- [200, { 'Content-Type': 'application/json' },
- '{"data":[{"count_all":69593,"key":"recycling:glass","count_all_fraction":0.0}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
- expect(query(server.requests()[0].url)).to.eql(
- {query: 'recycling:', page: '1', rp: '25', sortname: 'count_all', sortorder: 'desc', lang: 'en'}
+ window.setTimeout(function () {
+ expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
+ { query: 'recycling:', page: '1', rp: '25', sortname: 'count_all', sortorder: 'desc', lang: 'en' }
);
expect(callback).to.have.been.calledWith(
- null, [{'title':'recycling:glass', 'value':'recycling:glass'}]
+ null, [{ 'title': 'recycling:glass', 'value': 'recycling:glass' }]
);
done();
}, 50);
});
- it('excludes multikeys with extra colons', function(done) {
+ it('excludes multikeys with extra colons', function (done) {
+ fetchMock.mock(/\/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,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.multikeys({query: 'service:bicycle:'}, callback);
+ taginfo.multikeys({ query: 'service:bicycle:' }, callback);
- server.respondWith('GET', /\/keys\/all/,
- [200, { 'Content-Type': 'application/json' },
- '{"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}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
+ window.setTimeout(function () {
expect(callback).to.have.been.calledWith(
- null, [{'title':'service:bicycle:retail', 'value':'service:bicycle:retail'}]
+ null, [{ 'title': 'service:bicycle:retail', 'value': 'service:bicycle:retail' }]
);
done();
}, 50);
});
- it('excludes multikeys with wrong prefix', function(done) {
+ it('excludes multikeys with wrong prefix', function (done) {
+ fetchMock.mock(/\/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,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.multikeys({query: 'service:bicycle:'}, callback);
+ taginfo.multikeys({ query: 'service:bicycle:' }, callback);
- server.respondWith('GET', /\/keys\/all/,
- [200, { 'Content-Type': 'application/json' },
- '{"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}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
+ window.setTimeout(function () {
expect(callback).to.have.been.calledWith(
- null, [{'title':'service:bicycle:retail', 'value':'service:bicycle:retail'}]
+ null, [{ 'title': 'service:bicycle:retail', 'value': 'service:bicycle:retail' }]
);
done();
}, 50);
});
});
- describe('#values', function() {
- it('calls the given callback with the results of the values query', function(done) {
+ describe('#values', function () {
+ it('calls the given callback with the results of the values query', function (done) {
+ fetchMock.mock(/\/key\/values/, {
+ body: '{"data":[{"value":"parking","description":"A place for parking cars", "fraction":0.1}]}',
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.values({key: 'amenity', query: 'par'}, callback);
+ taginfo.values({ key: 'amenity', query: 'par' }, callback);
- server.respondWith('GET', /\/key\/values/,
- [200, { 'Content-Type': 'application/json' },
- '{"data":[{"value":"parking","description":"A place for parking cars", "fraction":0.1}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
- expect(query(server.requests()[0].url)).to.eql(
- {key: 'amenity', query: 'par', page: '1', rp: '25', sortname: 'count_all', sortorder: 'desc', lang: 'en'}
+ window.setTimeout(function () {
+ expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
+ { key: 'amenity', query: 'par', page: '1', rp: '25', sortname: 'count_all', sortorder: 'desc', lang: 'en' }
);
expect(callback).to.have.been.calledWith(
- null, [{'value':'parking','title':'A place for parking cars'}]
+ null, [{ 'value': 'parking', 'title': 'A place for parking cars' }]
);
done();
}, 50);
});
- it('includes popular values', function(done) {
+ it('includes popular values', function (done) {
+ fetchMock.mock(/\/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,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.values({key: 'amenity', query: 'par'}, callback);
+ taginfo.values({ key: 'amenity', query: 'par' }, callback);
- server.respondWith('GET', /\/key\/values/,
- [200, { 'Content-Type': 'application/json' },
- '{"data":[{"value":"parking","description":"A place for parking cars", "fraction":1.0},' +
- '{"value":"party","description":"A place for partying", "fraction":0.0}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
+ window.setTimeout(function () {
expect(callback).to.have.been.calledWith(
- null, [{'value':'parking','title':'A place for parking cars'}]
+ null, [{ 'value': 'parking', 'title': 'A place for parking cars' }]
);
done();
}, 50);
});
- it('does not get values for extremely unpopular keys', function(done) {
+ it('does not get values for extremely unpopular keys', function (done) {
+ fetchMock.mock(/\/key\/values/, {
+ body: '{"data":[{"value":"Rue Pasteur","description":"", "fraction":0.0001},' +
+ '{"value":"Via Trieste","description":"", "fraction":0.0001}]}',
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.values({key: 'name', query: 'ste'}, callback);
+ taginfo.values({ key: 'name', query: 'ste' }, callback);
- server.respondWith('GET', /\/key\/values/,
- [200, { 'Content-Type': 'application/json' },
- '{"data":[{"value":"Rue Pasteur","description":"", "fraction":0.0001},' +
- '{"value":"Via Trieste","description":"", "fraction":0.0001}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
+ window.setTimeout(function () {
expect(callback).to.have.been.calledWith(null, []);
done();
}, 50);
});
- it('excludes values with capital letters and some punctuation', function(done) {
+ it('excludes values with capital letters and some punctuation', function (done) {
+ fetchMock.mock(/\/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},'
+ + '{"value":"parking, partying","description":"A place for parking cars *and* partying", "fraction":0.2},'
+ + '{"value":"*","description":"", "fraction":0.2}]}',
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.values({key: 'amenity', query: 'par'}, callback);
+ taginfo.values({ key: 'amenity', query: 'par' }, callback);
- server.respondWith('GET', /\/key\/values/,
- [200, { 'Content-Type': 'application/json' },
- '{"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},'
- + '{"value":"parking, partying","description":"A place for parking cars *and* partying", "fraction":0.2},'
- + '{"value":"*","description":"", "fraction":0.2}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
+ window.setTimeout(function () {
expect(callback).to.have.been.calledWith(
- null, [{'value':'parking','title':'A place for parking cars'}]
+ null, [{ 'value': 'parking', 'title': 'A place for parking cars' }]
);
done();
}, 50);
});
- it('includes network values with capital letters and some punctuation', function(done) {
+ it('includes network values with capital letters and some punctuation', function (done) {
+ fetchMock.mock(/\/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},'
+ + '{"value":"US:I","description":"Interstate highways in the United States.", "fraction":0.11},'
+ + '{"value":"US:MD","description":"State highways in the U.S. state of Maryland.", "fraction":0.06}]}',
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.values({key: 'network', query: 'us'}, callback);
+ taginfo.values({ key: 'network', query: 'us' }, callback);
- server.respondWith('GET', /\/key\/values/,
- [200, { 'Content-Type': 'application/json' },
- '{"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},'
- + '{"value":"US:I","description":"Interstate highways in the United States.", "fraction":0.11},'
- + '{"value":"US:MD","description":"State highways in the U.S. state of Maryland.", "fraction":0.06}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
+ window.setTimeout(function () {
expect(callback).to.have.been.calledWith(null, [
- {'value':'US:TX:FM','title':'Farm to Market Roads in the U.S. state of Texas.'},
- {'value':'US:KY','title':'Primary and secondary state highways in the U.S. state of Kentucky.'},
- {'value':'US:US','title':'U.S. routes in the United States.'},
- {'value':'US:I','title':'Interstate highways in the United States.'},
- {'value':'US:MD','title':'State highways in the U.S. state of Maryland.'}
+ { 'value': 'US:TX:FM', 'title': 'Farm to Market Roads in the U.S. state of Texas.' },
+ { 'value': 'US:KY', 'title': 'Primary and secondary state highways in the U.S. state of Kentucky.' },
+ { 'value': 'US:US', 'title': 'U.S. routes in the United States.' },
+ { 'value': 'US:I', 'title': 'Interstate highways in the United States.' },
+ { 'value': 'US:MD', 'title': 'State highways in the U.S. state of Maryland.' }
]);
done();
}, 50);
});
- it('includes biological genus values with capital letters', function(done) {
+ it('includes biological genus values with capital letters', function (done) {
+ fetchMock.mock(/\/key\/values/, {
+ body: '{"data":[{"value":"Quercus","description":"Oak", "fraction":0.5}]}',
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.values({key: 'genus', query: 'qu'}, callback);
+ taginfo.values({ key: 'genus', query: 'qu' }, callback);
- server.respondWith('GET', /\/key\/values/,
- [200, { 'Content-Type': 'application/json' },
- '{"data":[{"value":"Quercus","description":"Oak", "fraction":0.5}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
+ window.setTimeout(function () {
expect(callback).to.have.been.calledWith(
- null, [{'value':'Quercus','title':'Oak'}]
+ null, [{ 'value': 'Quercus', 'title': 'Oak' }]
);
done();
}, 50);
});
- it('includes biological taxon values with capital letters', function(done) {
+ it('includes biological taxon values with capital letters', function (done) {
+ fetchMock.mock(/\/key\/values/, {
+ body: '{"data":[{"value":"Quercus robur","description":"Oak", "fraction":0.5}]}',
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.values({key: 'taxon', query: 'qu'}, callback);
+ taginfo.values({ key: 'taxon', query: 'qu' }, callback);
- server.respondWith('GET', /\/key\/values/,
- [200, { 'Content-Type': 'application/json' },
- '{"data":[{"value":"Quercus robur","description":"Oak", "fraction":0.5}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
+ window.setTimeout(function () {
expect(callback).to.have.been.calledWith(
- null, [{'value':'Quercus robur','title':'Oak'}]
+ null, [{ 'value': 'Quercus robur', 'title': 'Oak' }]
);
done();
}, 50);
});
- it('includes biological species values with capital letters', function(done) {
+ it('includes biological species values with capital letters', function (done) {
+ fetchMock.mock(/\/key\/values/, {
+ body: '{"data":[{"value":"Quercus robur","description":"Oak", "fraction":0.5}]}',
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.values({key: 'species', query: 'qu'}, callback);
+ taginfo.values({ key: 'species', query: 'qu' }, callback);
- server.respondWith('GET', /\/key\/values/,
- [200, { 'Content-Type': 'application/json' },
- '{"data":[{"value":"Quercus robur","description":"Oak", "fraction":0.5}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
+ window.setTimeout(function () {
expect(callback).to.have.been.calledWith(
- null, [{'value':'Quercus robur','title':'Oak'}]
+ null, [{ 'value': 'Quercus robur', 'title': 'Oak' }]
);
done();
}, 50);
});
});
- describe('#roles', function() {
- it('calls the given callback with the results of the roles query', function(done) {
+ describe('#roles', function () {
+ it('calls the given callback with the results of the roles query', function (done) {
+ fetchMock.mock(/\/relation\/roles/, {
+ body: '{"data":[{"role":"stop","count_relation_members_fraction":0.1757},' +
+ '{"role":"south","count_relation_members_fraction":0.0035}]}',
+ status: 200,
+ headers: { 'Content-Type': 'application/json' }
+ });
+
var callback = sinon.spy();
- taginfo.roles({rtype: 'route', query: 's', geometry: 'relation'}, callback);
+ taginfo.roles({ rtype: 'route', query: 's', geometry: 'relation' }, callback);
- server.respondWith('GET', /\/relation\/roles/,
- [200, { 'Content-Type': 'application/json' },
- '{"data":[{"role":"stop","count_relation_members_fraction":0.1757},' +
- '{"role":"south","count_relation_members_fraction":0.0035}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
- expect(query(server.requests()[0].url)).to.eql(
- {rtype: 'route', query: 's', page: '1', rp: '25', sortname: 'count_relation_members', sortorder: 'desc', lang: 'en'}
+ window.setTimeout(function () {
+ expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
+ { rtype: 'route', query: 's', page: '1', rp: '25', sortname: 'count_relation_members', sortorder: 'desc', lang: 'en' }
);
expect(callback).to.have.been.calledWith(null, [
- {'value': 'stop', 'title': 'stop'},
- {'value': 'south', 'title': 'south'}
+ { 'value': 'stop', 'title': 'stop' },
+ { 'value': 'south', 'title': 'south' }
]);
done();
}, 50);
});
});
- describe('#docs', function() {
- it('calls the given callback with the results of the docs query', function(done) {
+ describe('#docs', function () {
+ it('calls the given callback with the results of the docs query', function (done) {
+ fetchMock.mock(/\/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' }
+ });
+
var callback = sinon.spy();
- taginfo.docs({key: 'amenity', value: 'parking'}, callback);
+ taginfo.docs({ key: 'amenity', value: 'parking' }, callback);
- server.respondWith('GET', /\/tag\/wiki_page/,
- [200, { 'Content-Type': 'application/json' },
- '{"data":[{"on_way":false,"lang":"en","on_area":true,"image":"File:Car park2.jpg"}]}']
- );
- server.respond();
-
- window.setTimeout(function() {
- expect(query(server.requests()[0].url)).to.eql(
- {key: 'amenity', value: 'parking'}
+ window.setTimeout(function () {
+ expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
+ { key: 'amenity', value: 'parking' }
);
expect(callback).to.have.been.calledWith(
- null, [{'on_way':false,'lang':'en','on_area':true,'image':'File:Car park2.jpg'}]
+ null, [{ 'on_way': false, 'lang': 'en', 'on_area': true, 'image': 'File:Car park2.jpg' }]
);
done();
}, 50);
diff --git a/test/spec/spec_helpers.js b/test/spec/spec_helpers.js
index 17fe57ccc..baccff507 100644
--- a/test/spec/spec_helpers.js
+++ b/test/spec/spec_helpers.js
@@ -113,9 +113,7 @@ window.d3 = iD.d3; // Remove this if we can avoid exporting all of d3.js
delete window.PointerEvent; // force the brower to use mouse events
// some sticky fallbacks
-
-fetchMock.mock('https://www.openstreetmap.org/api/capabilities', `
-
+const capabilities = `
@@ -134,7 +132,10 @@ fetchMock.mock('https://www.openstreetmap.org/api/capabilities', `
-
-`, {sticky: true});
+`;
-fetchMock.config.fallbackToNetwork = true;
\ No newline at end of file
+fetchMock.sticky('https://www.openstreetmap.org/api/capabilities', capabilities, {sticky: true});
+fetchMock.sticky('http://www.openstreetmap.org/api/capabilities', capabilities, {sticky: true});
+
+fetchMock.config.fallbackToNetwork = true;
+fetchMock.config.overwriteRoutes = false;
\ No newline at end of file
diff --git a/test/spec/util/util.js b/test/spec/util/util.js
index 95f8e1c18..3490e2ad0 100644
--- a/test/spec/util/util.js
+++ b/test/spec/util/util.js
@@ -78,7 +78,7 @@ describe('iD.util', function() {
expect(iD.utilTagText({tags:{foo:'bar',two:'three'}})).to.eql('foo=bar, two=three');
});
- it('utilStringQs', function() {
+ describe('utilStringQs', function() {
it('splits a parameter string into k=v pairs', function() {
expect(iD.utilStringQs('foo=bar')).to.eql({foo: 'bar'});
expect(iD.utilStringQs('foo=bar&one=2')).to.eql({foo: 'bar', one: '2' });