This commit is contained in:
Wouter van der Plas
2021-09-09 17:34:27 +02:00
parent 83ff3c4f5e
commit 4a8f423997
6 changed files with 381 additions and 334 deletions
-3
View File
@@ -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 },
+1 -1
View File
@@ -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": {
+141 -89
View File
@@ -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 = '<?xml version="1.0" encoding="UTF-8"?>' +
'<osm>' +
'<api>' +
'<version minimum="0.6" maximum="0.6"/>' +
'<area maximum="0.25"/>' +
'<tracepoints per_page="5000"/>' +
'<waynodes maximum="2000"/>' +
'<changesets maximum_elements="50000"/>' +
'<timeout seconds="300"/>' +
'<status database="online" api="online" gpx="online"/>' +
'</api>' +
'<policy><imagery>' +
'<blacklist regex="\.foo\.com"/>' +
'<blacklist regex="\.bar\.org"/>' +
'</imagery></policy>' +
'</osm>';
var capabilitiesXML = `<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="OpenStreetMap server" copyright="OpenStreetMap and contributors" attribution="http://www.openstreetmap.org/copyright" license="http://opendatacommons.org/licenses/odbl/1-0/">
<api>
<version minimum="0.6" maximum="0.6"/>
<area maximum="0.25"/>
<note_area maximum="25"/>
<tracepoints per_page="5000"/>
<waynodes maximum="2000"/>
<changesets maximum_elements="50000"/>
<timeout seconds="300"/>
<status database="online" api="online" gpx="online"/>
</api>
<policy>
<imagery>
<blacklist regex="\.foo\.com"/>
<blacklist regex="\.bar\.org"/>
</imagery>
</policy>
</osm>`;
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();
});
});
+231 -234
View File
@@ -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);
+7 -6
View File
@@ -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', `
<?xml version="1.0" encoding="UTF-8"?>
const capabilities = `<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="OpenStreetMap server" copyright="OpenStreetMap and contributors" attribution="http://www.openstreetmap.org/copyright" license="http://opendatacommons.org/licenses/odbl/1-0/">
<api>
<version minimum="0.6" maximum="0.6"/>
@@ -134,7 +132,10 @@ fetchMock.mock('https://www.openstreetmap.org/api/capabilities', `
<blacklist regex=".*\.here\.com[/:].*"/>
</imagery>
</policy>
</osm>
`, {sticky: true});
</osm>`;
fetchMock.config.fallbackToNetwork = true;
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;
+1 -1
View File
@@ -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' });