mass-replace done() function with async/await (#10781)

This commit is contained in:
Kyℓe Hensel
2025-02-17 23:10:04 +11:00
committed by GitHub
parent 2f4c05c90e
commit 6f16060a78
29 changed files with 984 additions and 1294 deletions
+16
View File
@@ -51,6 +51,7 @@
"@types/d3": "^7.4.3",
"@types/happen": "^0.3.0",
"@types/lodash-es": "^4.17.12",
"@types/node": "^22.13.4",
"@types/sinon": "^17.0.3",
"@types/sinon-chai": "^4.0.0",
"autoprefixer": "^10.4.20",
@@ -1958,6 +1959,15 @@
"@types/lodash": "*"
}
},
"node_modules/@types/node": {
"version": "22.13.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz",
"integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==",
"devOptional": true,
"dependencies": {
"undici-types": "~6.20.0"
}
},
"node_modules/@types/pako": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.7.tgz",
@@ -23639,6 +23649,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/undici-types": {
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"devOptional": true
},
"node_modules/update-browserslist-db": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz",
+1
View File
@@ -86,6 +86,7 @@
"@types/d3": "^7.4.3",
"@types/happen": "^0.3.0",
"@types/lodash-es": "^4.17.12",
"@types/node": "^22.13.4",
"@types/sinon": "^17.0.3",
"@types/sinon-chai": "^4.0.0",
"autoprefixer": "^10.4.20",
+13 -15
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.behaviorHash', function () {
var hash, context;
@@ -30,16 +32,14 @@ describe('iD.behaviorHash', function () {
expect(context.map().zoom()).to.equal(20.0);
});
it('centerZooms map at requested coordinates on hash change', function (done) {
it('centerZooms map at requested coordinates on hash change', async () => {
hash();
d3.select(window).on('hashchange', function () {
expect(context.map().center()[0]).to.be.closeTo(-77.02405, 0.1);
expect(context.map().center()[1]).to.be.closeTo(38.87952, 0.1);
expect(context.map().zoom()).to.equal(20.0);
d3.select(window).on('hashchange', null);
done();
});
window.location.hash = '#background=none&map=20.00/38.87952/-77.02405';
await new Promise(cb => { d3.select(window).on('hashchange', cb); });
expect(context.map().center()[0]).to.be.closeTo(-77.02405, 0.1);
expect(context.map().center()[1]).to.be.closeTo(38.87952, 0.1);
expect(context.map().zoom()).to.equal(20.0);
d3.select(window).on('hashchange', null);
});
it('sets hadLocation if map-location is in local storage', function () {
@@ -68,16 +68,14 @@ describe('iD.behaviorHash', function () {
iD.prefs('map-location', null);
});
it('stores the current zoom and coordinates in window.location.hash on map move events', function (done) {
it('stores the current zoom and coordinates in window.location.hash on map move events', async () => {
hash();
context.map().center([-77.0, 38.9]);
context.map().zoom(2.0);
window.setTimeout(function() {
// the hash might contain other things like `disable_features`
expect(window.location.hash).to.include('background=none');
expect(window.location.hash).to.include('map=2.00/38.9/-77.0');
done();
}, 600);
await setTimeout(600);
// the hash might contain other things like `disable_features`
expect(window.location.hash).to.include('background=none');
expect(window.location.hash).to.include('map=2.00/38.9/-77.0');
});
it('accepts default changeset comment as hash parameter', function () {
+20 -30
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.behaviorSelect', function() {
var a, b, context, behavior, container;
@@ -55,62 +57,50 @@ describe('iD.behaviorSelect', function() {
expect(context.mode().id).to.eql('browse');
});
it('click on entity selects the entity', function(done) {
it('click on entity selects the entity', async () => {
var el = context.surface().selectAll('.' + a.id).node();
simulateClick(el, {});
window.setTimeout(function() {
expect(context.selectedIDs()).to.eql([a.id]);
done();
}, 50);
await setTimeout(50);
expect(context.selectedIDs()).to.eql([a.id]);
});
it('click on empty space clears the selection', function(done) {
it('click on empty space clears the selection', async () => {
context.enter(iD.modeSelect(context, [a.id]));
var el = context.surface().node();
simulateClick(el, {});
window.setTimeout(function() {
expect(context.mode().id).to.eql('browse');
done();
}, 50);
await setTimeout(50);
expect(context.mode().id).to.eql('browse');
});
it('shift-click on unselected entity adds it to the selection', function(done) {
it('shift-click on unselected entity adds it to the selection', async () => {
context.enter(iD.modeSelect(context, [a.id]));
var el = context.surface().selectAll('.' + b.id).node();
simulateClick(el, { shiftKey: true });
window.setTimeout(function() {
expect(context.selectedIDs()).to.eql([a.id, b.id]);
done();
}, 50);
await setTimeout(50);
expect(context.selectedIDs()).to.eql([a.id, b.id]);
});
it('shift-click on selected entity removes it from the selection', function(done) {
it('shift-click on selected entity removes it from the selection', async () => {
context.enter(iD.modeSelect(context, [a.id, b.id]));
var el = context.surface().selectAll('.' + b.id).node();
simulateClick(el, { shiftKey: true });
window.setTimeout(function() {
expect(context.selectedIDs()).to.eql([a.id]);
done();
}, 50);
await setTimeout(50);
expect(context.selectedIDs()).to.eql([a.id]);
});
it('shift-click on last selected entity clears the selection', function(done) {
it('shift-click on last selected entity clears the selection', async () => {
context.enter(iD.modeSelect(context, [a.id]));
var el = context.surface().selectAll('.' + a.id).node();
simulateClick(el, { shiftKey: true });
window.setTimeout(function() {
expect(context.mode().id).to.eql('browse');
done();
}, 50);
await setTimeout(50);
expect(context.mode().id).to.eql('browse');
});
it('shift-click on empty space leaves the selection unchanged', function(done) {
it('shift-click on empty space leaves the selection unchanged', async () => {
context.enter(iD.modeSelect(context, [a.id]));
var el = context.surface().node();
simulateClick(el, { shiftKey: true });
window.setTimeout(function() {
expect(context.selectedIDs()).to.eql([a.id]);
done();
}, 50);
await setTimeout(50);
expect(context.selectedIDs()).to.eql([a.id]);
});
});
+21 -48
View File
@@ -38,56 +38,35 @@ describe('LocationManager', () => {
describe('#mergeLocationSets', () => {
it('returns a promise rejected if not passed an array', done => {
it('returns a promise rejected if not passed an array', async () => {
const prom = locationManager.mergeLocationSets({});
prom
.then(() => {
done(new Error('This was supposed to fail, but somehow succeeded.'));
})
.catch(err => {
expect(/^nothing to do/.test(err)).to.be.true;
done();
});
window.setTimeout(() => {}, 20); // async - to let the promise settle in phantomjs
await expect(prom).rejects.toThrow(/^nothing to do/);
});
it('resolves locationSets, assigning locationSetID', done => {
it('resolves locationSets, assigning locationSetID', async () => {
const data = [
{ id: 'world', locationSet: { include: ['001'] } },
{ id: 'usa', locationSet: { include: ['usa'] } }
];
const prom = locationManager.mergeLocationSets(data);
prom
.then(data => {
expect(data).to.be.a('array');
expect(data[0].locationSetID).to.eql('+[Q2]');
expect(data[1].locationSetID).to.eql('+[Q30]');
done();
})
.catch(err => done(err));
window.setTimeout(() => {}, 20); // async - to let the promise settle in phantomjs
await prom;
expect(data).to.be.a('array');
expect(data[0].locationSetID).to.eql('+[Q2]');
expect(data[1].locationSetID).to.eql('+[Q30]');
});
it('resolves locationSets, falls back to world locationSetID on errror', done => {
it('resolves locationSets, falls back to world locationSetID on errror', async () => {
const data = [
{ id: 'bogus1', locationSet: { foo: 'bar' } },
{ id: 'bogus2', locationSet: { include: ['fake.geojson'] } }
];
const prom = locationManager.mergeLocationSets(data);
prom
.then(data => {
expect(data).to.be.a('array');
expect(data[0].locationSetID).to.eql('+[Q2]');
expect(data[1].locationSetID).to.eql('+[Q2]');
done();
})
.catch(err => done(err));
window.setTimeout(() => {}, 20); // async - to let the promise settle in phantomjs
await prom;
expect(data).to.be.a('array');
expect(data[0].locationSetID).to.eql('+[Q2]');
expect(data[1].locationSetID).to.eql('+[Q2]');
});
});
@@ -127,26 +106,20 @@ describe('LocationManager', () => {
expect(result3).to.be.an('object').that.has.all.keys('+[Q2]');
});
it('returns valid locationSets at a given lon,lat', done => {
it('returns valid locationSets at a given lon,lat', async () => {
// setup, load colorado.geojson and resolve some locationSets
locationManager.mergeCustomGeoJSON(fc);
locationManager.mergeLocationSets([
await locationManager.mergeLocationSets([
{ id: 'OSM-World', locationSet: { include: ['001'] } },
{ id: 'OSM-USA', locationSet: { include: ['us'] } },
{ id: 'OSM-Colorado', locationSet: { include: ['colorado.geojson'] } }
])
.then(() => {
const result1 = locationManager.locationSetsAt([-108.557, 39.065]); // Grand Junction
expect(result1).to.be.an('object').that.has.all.keys('+[Q2]', '+[Q30]', '+[colorado.geojson]');
const result2 = locationManager.locationSetsAt([-74.481, 40.797]); // Morristown
expect(result2).to.be.an('object').that.has.all.keys('+[Q2]', '+[Q30]');
const result3 = locationManager.locationSetsAt([13.575, 41.207,]); // Gaeta
expect(result3).to.be.an('object').that.has.all.keys('+[Q2]');
done();
})
.catch(err => done(err));
window.setTimeout(() => {}, 20); // async - to let the promise settle in phantomjs
]);
const result1 = locationManager.locationSetsAt([-108.557, 39.065]); // Grand Junction
expect(result1).to.be.an('object').that.has.all.keys('+[Q2]', '+[Q30]', '+[colorado.geojson]');
const result2 = locationManager.locationSetsAt([-74.481, 40.797]); // Morristown
expect(result2).to.be.an('object').that.has.all.keys('+[Q2]', '+[Q30]');
const result3 = locationManager.locationSetsAt([13.575, 41.207,]); // Gaeta
expect(result3).to.be.an('object').that.has.all.keys('+[Q2]');
});
});
+10 -29
View File
@@ -13,50 +13,31 @@ describe('iD.coreFileFetcher', function() {
});
describe('#get', function() {
it('returns a promise resolved if we already have the data', function(done) {
it('returns a promise resolved if we already have the data', async () => {
var data = iD.coreFileFetcher();
data.cache().test = { hello: 'world' };
var prom = data.get('test');
expect(prom).to.be.a('promise');
prom
.then(function(data) {
expect(data).to.be.a('object');
expect(data.hello).to.eql('world');
done();
})
.catch(function(err) {
done(err);
});
data = await prom;
expect(data).to.be.a('object');
expect(data.hello).to.eql('world');
});
it('returns a promise rejected if we can not get the data', function(done) {
it('returns a promise rejected if we can not get the data', async () => {
var data = iD.coreFileFetcher().assetPath('../dist/');
var prom = data.get('wat');
prom
.then(function(data) {
done(new Error('We were not supposed to get data but did: ' + data));
})
.catch(function(err) {
expect(/^Unknown data file/.test(err)).to.be.true;
done();
});
await expect(prom).rejects.toThrow(/^Unknown data file/);
});
it('returns a promise to fetch data if we do not already have the data', function(done) {
it('returns a promise to fetch data if we do not already have the data', async () => {
var files = { 'intro_graph': 'data/intro_graph.min.json' };
var data = iD.coreFileFetcher().assetPath('../dist/').fileMap(files);
var prom = data.get('intro_graph');
expect(prom).to.be.a('promise');
prom
.then(function(data) {
expect(data).to.be.a('object');
expect(data.n2061.tags.name).to.eql('Three Rivers City Hall');
done();
})
.catch(function(err) {
done(err);
});
data = await prom;
expect(data).to.be.a('object');
expect(data.n2061.tags.name).to.eql('Three Rivers City Hall');
});
});
+5 -5
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.coreHistory', function () {
var context, history, spy;
var actionNoop = function(g) { return g; };
@@ -68,15 +70,13 @@ describe('iD.coreHistory', function () {
expect(history.undoAnnotation()).to.equal('annotation');
});
it('performs transitionable actions in a transition', function (done) {
it('performs transitionable actions in a transition', async () => {
var action1 = function() { return iD.coreGraph(); };
action1.transitionable = true;
history.on('change', spy);
history.perform(action1);
window.setTimeout(function() {
expect(spy.callCount).to.be.above(2);
done();
}, 300);
await setTimeout(300);
expect(spy.callCount).to.be.above(2);
});
});
+37 -58
View File
@@ -24,7 +24,7 @@ describe('iD.coreValidator', function() {
expect(issues).to.have.lengthOf(0);
});
it('validate returns a promise, fulfilled when the validation has completed', function(done) {
it('validate returns a promise, fulfilled when the validation has completed', async () => {
createInvalidWay();
var validator = new iD.coreValidator(context);
validator.init();
@@ -32,22 +32,16 @@ describe('iD.coreValidator', function() {
expect(issues).to.have.lengthOf(0);
var prom = validator.validate();
prom
.then(function() {
issues = validator.getIssues();
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('missing_tag');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('w-1');
done();
})
.catch(function(err) {
done(err);
});
await prom;
issues = validator.getIssues();
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('missing_tag');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('w-1');
});
it('removes validation issue when highway is no longer disconnected', function(done) {
it('removes validation issue when highway is no longer disconnected', async () => {
// Add a way which is disconnected from the rest of the map
var n1 = iD.osmNode({ id: 'n-1', loc: [4, 4] });
var n2 = iD.osmNode({ id: 'n-2', loc: [4, 5] });
@@ -59,32 +53,25 @@ describe('iD.coreValidator', function() {
);
var validator = new iD.coreValidator(context);
validator.init();
validator.validate().then(function() {
// Should produce disconnected way error
let issues = validator.getIssues();
expect(issues).to.have.lengthOf(1);
await validator.validate();
// Should produce disconnected way error
let issues = validator.getIssues();
expect(issues).to.have.lengthOf(1);
// Add new node with entrance node to simulate connection with rest of map
var n3 = iD.osmNode({ id: 'n-3', loc: [4, 6], tags: { 'entrance': 'yes' } });
var w2 = iD.osmWay({ id: 'w-2', nodes: ['n-2', 'n-3'], tags: { 'highway': 'unclassified' } });
context.perform(
iD.actionAddEntity(n3),
iD.actionAddEntity(w2)
);
validator.validate().then(function() {
// Should be no errors
issues = validator.getIssues();
expect(issues).to.have.lengthOf(0);
done();
}).catch(function(err) {
done(err);
});
}).catch(function(err) {
done(err);
});
// Add new node with entrance node to simulate connection with rest of map
var n3 = iD.osmNode({ id: 'n-3', loc: [4, 6], tags: { 'entrance': 'yes' } });
var w2 = iD.osmWay({ id: 'w-2', nodes: ['n-2', 'n-3'], tags: { 'highway': 'unclassified' } });
context.perform(
iD.actionAddEntity(n3),
iD.actionAddEntity(w2)
);
await validator.validate();
// Should be no errors
issues = validator.getIssues();
expect(issues).to.have.lengthOf(0);
});
it('add validation issue when highway becomes disconnected', function(done) {
it('add validation issue when highway becomes disconnected', async () => {
// Add a way which is connected to another way with an entrance node to simulate connection with rest of map
var n1 = iD.osmNode({ id: 'n-1', loc: [4, 4] });
var n2 = iD.osmNode({ id: 'n-2', loc: [4, 5] });
@@ -100,27 +87,19 @@ describe('iD.coreValidator', function() {
);
var validator = new iD.coreValidator(context);
validator.init();
validator.validate().then(function() {
// Should be no errors
let issues = validator.getIssues();
expect(issues).to.have.lengthOf(0);
await validator.validate();
// Should be no errors
let issues = validator.getIssues();
expect(issues).to.have.lengthOf(0);
// delete second way -> first way becomes disconnected form the rest of the network
context.perform(
iD.actionDeleteWay(w2.id)
);
// delete second way -> first way becomes disconnected form the rest of the network
context.perform(
iD.actionDeleteWay(w2.id)
);
validator.validate().then(function() {
// Should produce disconnected way error
issues = validator.getIssues();
expect(issues).to.have.lengthOf(1);
done();
}).catch(function(err) {
done(err);
});
}).catch(function(err) {
done(err);
});
await validator.validate();
// Should produce disconnected way error
issues = validator.getIssues();
expect(issues).to.have.lengthOf(1);
});
});
+102 -140
View File
@@ -48,55 +48,47 @@ describe('iD.presetIndex', function () {
park: { tags: { leisure: 'park' }, geometry: ['point', 'area'] }
};
it('returns a collection containing presets matching a geometry and tags', function (done) {
it('returns a collection containing presets matching a geometry and tags', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
presets.ensureLoaded().then(function() {
var way = iD.osmWay({ tags: { highway: 'residential' } });
var graph = iD.coreGraph([way]);
expect(presets.match(way, graph).id).to.eql('residential');
done();
});
await presets.ensureLoaded();
var way = iD.osmWay({ tags: { highway: 'residential' } });
var graph = iD.coreGraph([way]);
expect(presets.match(way, graph).id).to.eql('residential');
});
it('returns the appropriate fallback preset when no tags match', function (done) {
it('returns the appropriate fallback preset when no tags match', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
var point = iD.osmNode();
var line = iD.osmWay({ tags: { foo: 'bar' } });
var graph = iD.coreGraph([point, line]);
presets.ensureLoaded().then(function() {
expect(presets.match(point, graph).id).to.eql('point');
expect(presets.match(line, graph).id).to.eql('line');
done();
});
await presets.ensureLoaded();
expect(presets.match(point, graph).id).to.eql('point');
expect(presets.match(line, graph).id).to.eql('line');
});
it('matches vertices on a line as points', function (done) {
it('matches vertices on a line as points', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
var point = iD.osmNode({ tags: { leisure: 'park' } });
var line = iD.osmWay({ nodes: [point.id], tags: { 'highway': 'residential' } });
var graph = iD.coreGraph([point, line]);
presets.ensureLoaded().then(function() {
expect(presets.match(point, graph).id).to.eql('point');
done();
});
await presets.ensureLoaded();
expect(presets.match(point, graph).id).to.eql('point');
});
it('matches vertices on an addr:interpolation line as points', function (done) {
it('matches vertices on an addr:interpolation line as points', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
var point = iD.osmNode({ tags: { leisure: 'park' } });
var line = iD.osmWay({ nodes: [point.id], tags: { 'addr:interpolation': 'even' } });
var graph = iD.coreGraph([point, line]);
presets.ensureLoaded().then(function() {
expect(presets.match(point, graph).id).to.eql('park');
done();
});
await presets.ensureLoaded();
expect(presets.match(point, graph).id).to.eql('park');
});
});
@@ -112,68 +104,55 @@ describe('iD.presetIndex', function () {
'natural/wood': { tags: { 'natural': 'wood' }, geometry: ['point', 'area'] }
};
it('includes keys for presets with area geometry', function (done) {
it('includes keys for presets with area geometry', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
presets.ensureLoaded().then(function() {
expect(presets.areaKeys()).to.include.keys('natural');
done();
});
await presets.ensureLoaded();
expect(presets.areaKeys()).to.include.keys('natural');
});
it('discards key-values for presets with a line geometry', function (done) {
it('discards key-values for presets with a line geometry', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
presets.ensureLoaded().then(function() {
expect(presets.areaKeys().natural).to.include.keys('tree_row');
expect(presets.areaKeys().natural.tree_row).to.be.true;
done();
});
await presets.ensureLoaded();
expect(presets.areaKeys().natural).to.include.keys('tree_row');
expect(presets.areaKeys().natural.tree_row).to.be.true;
});
it('discards key-values for presets with both area and line geometry', function (done) {
it('discards key-values for presets with both area and line geometry', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
presets.ensureLoaded().then(function() {
expect(presets.areaKeys().leisure).to.include.keys('track');
done();
});
await presets.ensureLoaded();
expect(presets.areaKeys().leisure).to.include.keys('track');
});
it('does not discard key-values for presets with neither area nor line geometry', function (done) {
it('does not discard key-values for presets with neither area nor line geometry', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
presets.ensureLoaded().then(function() {
expect(presets.areaKeys().natural).not.to.include.keys('peak');
done();
});
await presets.ensureLoaded();
expect(presets.areaKeys().natural).not.to.include.keys('peak');
});
it('does not discard generic \'*\' key-values', function (done) {
it('does not discard generic \'*\' key-values', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
presets.ensureLoaded().then(function() {
expect(presets.areaKeys().natural).not.to.include.keys('natural');
done();
});
await presets.ensureLoaded();
expect(presets.areaKeys().natural).not.to.include.keys('natural');
});
it('ignores keys like \'highway\' that are assumed to be lines', function (done) {
it('ignores keys like \'highway\' that are assumed to be lines', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
presets.ensureLoaded().then(function() {
expect(presets.areaKeys()).not.to.include.keys('highway');
done();
});
await presets.ensureLoaded();
expect(presets.areaKeys()).not.to.include.keys('highway');
});
it('ignores suggestion presets', function (done) {
it('ignores suggestion presets', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
presets.ensureLoaded().then(function() {
expect(presets.areaKeys()).not.to.include.keys('amenity');
done();
});
await presets.ensureLoaded();
expect(presets.areaKeys()).not.to.include.keys('amenity');
});
});
@@ -185,94 +164,83 @@ describe('iD.presetIndex', function () {
bench: { tags: { amenity: 'bench' }, geometry: ['point', 'line'] }
};
it('addablePresetIDs is initially null', function (done) {
it('addablePresetIDs is initially null', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
presets.ensureLoaded().then(function() {
expect(presets.addablePresetIDs()).to.be.null;
done();
});
await presets.ensureLoaded();
expect(presets.addablePresetIDs()).to.be.null;
});
it('can set and get addablePresetIDs', function (done) {
it('can set and get addablePresetIDs', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
presets.ensureLoaded().then(function() {
await presets.ensureLoaded();
expect(presets.item('residential').addable()).to.be.true;
expect(presets.item('park').addable()).to.be.true;
expect(presets.item('residential').addable()).to.be.true;
expect(presets.item('park').addable()).to.be.true;
var ids = new Set(['residential']); // can only add preset with this ID
presets.addablePresetIDs(ids);
var ids = new Set(['residential']); // can only add preset with this ID
presets.addablePresetIDs(ids);
expect(presets.item('residential').addable()).to.be.true;
expect(presets.item('park').addable()).to.be.false;
expect(presets.addablePresetIDs()).to.eql(ids);
expect(presets.item('residential').addable()).to.be.true;
expect(presets.item('park').addable()).to.be.false;
expect(presets.addablePresetIDs()).to.eql(ids);
presets.addablePresetIDs(null);
expect(presets.item('residential').addable()).to.be.true;
expect(presets.item('park').addable()).to.be.true;
done();
});
presets.addablePresetIDs(null);
expect(presets.item('residential').addable()).to.be.true;
expect(presets.item('park').addable()).to.be.true;
});
it('ignores invalid IDs in addablePresetIDs', function (done) {
it('ignores invalid IDs in addablePresetIDs', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
presets.ensureLoaded().then(function() {
await presets.ensureLoaded();
expect(presets.item(null)).to.eql(undefined);
expect(presets.item(undefined)).to.eql(undefined);
expect(presets.item('')).to.eql(undefined);
expect(presets.item('garbage')).to.eql(undefined);
expect(presets.item('residential').addable()).to.be.true;
expect(presets.item('park').addable()).to.be.true;
expect(presets.item(null)).to.eql(undefined);
expect(presets.item(undefined)).to.eql(undefined);
expect(presets.item('')).to.eql(undefined);
expect(presets.item('garbage')).to.eql(undefined);
expect(presets.item('residential').addable()).to.be.true;
expect(presets.item('park').addable()).to.be.true;
var ids = new Set([null, undefined, '', 'garbage', 'residential']); // can only add preset with these IDs
presets.addablePresetIDs(ids);
var ids = new Set([null, undefined, '', 'garbage', 'residential']); // can only add preset with these IDs
presets.addablePresetIDs(ids);
expect(presets.item(null)).to.eql(undefined);
expect(presets.item(undefined)).to.eql(undefined);
expect(presets.item('')).to.eql(undefined);
expect(presets.item('garbage')).to.eql(undefined);
expect(presets.item('residential').addable()).to.be.true;
expect(presets.item('park').addable()).to.be.false;
expect(presets.addablePresetIDs()).to.eql(ids);
expect(presets.item(null)).to.eql(undefined);
expect(presets.item(undefined)).to.eql(undefined);
expect(presets.item('')).to.eql(undefined);
expect(presets.item('garbage')).to.eql(undefined);
expect(presets.item('residential').addable()).to.be.true;
expect(presets.item('park').addable()).to.be.false;
expect(presets.addablePresetIDs()).to.eql(ids);
presets.addablePresetIDs(null);
expect(presets.item(null)).to.eql(undefined);
expect(presets.item(undefined)).to.eql(undefined);
expect(presets.item('')).to.eql(undefined);
expect(presets.item('garbage')).to.eql(undefined);
expect(presets.item('residential').addable()).to.be.true;
expect(presets.item('park').addable()).to.be.true;
done();
});
presets.addablePresetIDs(null);
expect(presets.item(null)).to.eql(undefined);
expect(presets.item(undefined)).to.eql(undefined);
expect(presets.item('')).to.eql(undefined);
expect(presets.item('garbage')).to.eql(undefined);
expect(presets.item('residential').addable()).to.be.true;
expect(presets.item('park').addable()).to.be.true;
});
it('addablePresetIDs are default presets', function (done) {
it('addablePresetIDs are default presets', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
presets.ensureLoaded().then(function() {
var ids = new Set(['bench', 'residential']); // can only add presets with these IDs
presets.addablePresetIDs(ids);
await presets.ensureLoaded();
var ids = new Set(['bench', 'residential']); // can only add presets with these IDs
presets.addablePresetIDs(ids);
var areaDefaults = presets.defaults('area', 10).collection;
expect(areaDefaults.length).to.eql(0);
var areaDefaults = presets.defaults('area', 10).collection;
expect(areaDefaults.length).to.eql(0);
var pointDefaults = presets.defaults('point', 10).collection;
expect(pointDefaults.length).to.eql(1);
expect(pointDefaults[0].id).to.eql('bench');
var pointDefaults = presets.defaults('point', 10).collection;
expect(pointDefaults.length).to.eql(1);
expect(pointDefaults[0].id).to.eql('bench');
var lineDefaults = presets.defaults('line', 10).collection;
expect(lineDefaults.length).to.eql(2);
expect(lineDefaults[0].id).to.eql('bench');
expect(lineDefaults[1].id).to.eql('residential');
done();
});
var lineDefaults = presets.defaults('line', 10).collection;
expect(lineDefaults.length).to.eql(2);
expect(lineDefaults[0].id).to.eql('bench');
expect(lineDefaults[1].id).to.eql('residential');
});
});
@@ -347,40 +315,34 @@ describe('iD.presetIndex', function () {
}
};
it('prefers building to multipolygon', function (done) {
it('prefers building to multipolygon', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
var relation = iD.osmRelation({ tags: { type: 'multipolygon', building: 'yes' } });
var graph = iD.coreGraph([relation]);
presets.ensureLoaded().then(function() {
var match = presets.match(relation, graph);
expect(match.id).to.eql('building');
done();
});
await presets.ensureLoaded();
var match = presets.match(relation, graph);
expect(match.id).to.eql('building');
});
it('prefers building to address', function (done) {
it('prefers building to address', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
var way = iD.osmWay({ tags: { area: 'yes', building: 'yes', 'addr:housenumber': '1234' } });
var graph = iD.coreGraph([way]);
presets.ensureLoaded().then(function() {
var match = presets.match(way, graph);
expect(match.id).to.eql('building');
done();
});
await presets.ensureLoaded();
var match = presets.match(way, graph);
expect(match.id).to.eql('building');
});
it('prefers pedestrian to area', function (done) {
it('prefers pedestrian to area', async () => {
iD.fileFetcher.cache().preset_presets = testPresets;
var presets = iD.presetIndex();
var way = iD.osmWay({ tags: { area: 'yes', highway: 'pedestrian' } });
var graph = iD.coreGraph([way]);
presets.ensureLoaded().then(function() {
var match = presets.match(way, graph);
expect(match.id).to.eql('highway/pedestrian_area');
done();
});
await presets.ensureLoaded();
var match = presets.match(way, graph);
expect(match.id).to.eql('highway/pedestrian_area');
});
});
+14 -19
View File
@@ -1,3 +1,4 @@
import { setTimeout } from 'node:timers/promises';
import css from '../../../css/55_cursors.css?raw';
describe('iD.Map', function() {
@@ -45,26 +46,22 @@ describe('iD.Map', function() {
});
describe('#zoomIn', function() {
it('increments zoom', function(done) {
it('increments zoom', async () => {
expect(map.zoom(4)).to.equal(map);
map.zoomIn();
window.setTimeout(function() {
d3.timerFlush();
expect(map.zoom()).to.be.closeTo(5, 1e-6);
done();
}, 275);
await setTimeout(275);
d3.timerFlush();
expect(map.zoom()).to.be.closeTo(5, 1e-6);
});
});
describe('#zoomOut', function() {
it('decrements zoom', function(done) {
it('decrements zoom', async () => {
expect(map.zoom(4)).to.equal(map);
map.zoomOut();
window.setTimeout(function() {
d3.timerFlush();
expect(map.zoom()).to.be.closeTo(3, 1e-6);
done();
}, 275);
await setTimeout(275);
d3.timerFlush();
expect(map.zoom()).to.be.closeTo(3, 1e-6);
});
});
@@ -102,15 +99,13 @@ describe('iD.Map', function() {
});
describe('#centerEase', function() {
it('sets center', function(done) {
it('sets center', async () => {
expect(map.center([10, 10])).to.equal(map);
expect(map.centerEase([20, 20], 250)).to.equal(map);
window.setTimeout(function() {
d3.timerFlush();
expect(map.center()[0]).to.be.closeTo(20, 1e-6);
expect(map.center()[1]).to.be.closeTo(20, 1e-6);
done();
}, 275);
await setTimeout(275);
d3.timerFlush();
expect(map.center()[0]).to.be.closeTo(20, 1e-6);
expect(map.center()[1]).to.be.closeTo(20, 1e-6);
});
});
+14 -18
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.serviceKartaview', function() {
var dimensions = [64, 64];
var context, kartaview;
@@ -52,7 +54,7 @@ describe('iD.serviceKartaview', function() {
});
describe('#loadImages', function() {
it('fires loadedImages when images are loaded', function(done) {
it('fires loadedImages when images are loaded', async () => {
var data = {
status: { apiCode: '600', httpCode: 200, httpMessage: 'Success' },
currentPageItems:[{
@@ -101,15 +103,13 @@ describe('iD.serviceKartaview', function() {
headers: { 'Content-Type': 'application/json' }
});
kartaview.on('loadedImages', function() {
expect(fetchMock.calls().length).to.eql(1); // 1 nearby-photos
done();
});
kartaview.loadImages(context.projection);
await new Promise(cb => { kartaview.on('loadedImages', cb); });
expect(fetchMock.calls().length).to.eql(1); // 1 nearby-photos
});
it('does not load images around null island', function (done) {
it('does not load images around null island', async () => {
var data = {
status: { apiCode: '600', httpCode: 200, httpMessage: 'Success' },
currentPageItems:[{
@@ -164,14 +164,12 @@ describe('iD.serviceKartaview', function() {
kartaview.on('loadedImages', spy);
kartaview.loadImages(context.projection);
window.setTimeout(function() {
expect(spy).to.have.been.not.called;
expect(fetchMock.calls().length).to.eql(0); // no tile requests of any kind
done();
}, 200);
await setTimeout(200);
expect(spy).to.have.been.not.called;
expect(fetchMock.calls().length).to.eql(0); // no tile requests of any kind
});
it('loads multiple pages of image results', function(done) {
it('loads multiple pages of image results', async () => {
var features = [];
for (var i = 0; i < 1000; i++) {
var key = String(i);
@@ -202,12 +200,10 @@ describe('iD.serviceKartaview', function() {
headers: { 'Content-Type': 'application/json' }
});
kartaview.on('loadedImages', function() {
expect(fetchMock.calls().length).to.eql(2); // 2 nearby-photos
done();
});
kartaview.loadImages(context.projection);
await new Promise(cb => { kartaview.on('loadedImages', cb); });
expect(fetchMock.calls().length).to.eql(2); // 2 nearby-photos
});
});
+58 -68
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.serviceNominatim', function() {
var nominatim;
@@ -25,7 +27,7 @@ describe('iD.serviceNominatim', function() {
}
describe('#countryCode', function() {
it('calls the given callback with the results of the country code query', function(done) {
it('calls the given callback with the results of the country code query', async () => {
var callback = sinon.spy();
fetchMock.mock(new RegExp('https://nominatim.openstreetmap.org/reverse'), {
body: '{"address":{"country_code":"at"}}',
@@ -35,18 +37,16 @@ describe('iD.serviceNominatim', function() {
nominatim.countryCode([16, 48], callback);
window.setTimeout(function() {
expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
{zoom: '13', format: 'json', addressdetails: '1', lat: '48', lon: '16'}
);
expect(callback).to.have.been.calledWithExactly(null, 'at');
done();
}, 50);
await setTimeout(50);
expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
{zoom: '13', format: 'json', addressdetails: '1', lat: '48', lon: '16'}
);
expect(callback).to.have.been.calledWithExactly(null, 'at');
});
});
describe('#reverse', function() {
it('should not cache distant result', function(done) {
it('should not cache distant result', async () => {
var callback = sinon.spy();
fetchMock.mock(new RegExp('https://nominatim.openstreetmap.org/reverse'), {
body: '{"address":{"country_code":"at"}}',
@@ -56,36 +56,33 @@ describe('iD.serviceNominatim', function() {
nominatim.reverse([16, 48], callback);
window.setTimeout(function() {
expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
{zoom: '13', format: 'json', addressdetails: '1', lat: '48', lon: '16'}
);
expect(callback).to.have.been.calledWithExactly(null, {address: {country_code:'at'}});
await setTimeout(50);
expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
{zoom: '13', format: 'json', addressdetails: '1', lat: '48', lon: '16'}
);
expect(callback).to.have.been.calledWithExactly(null, {address: {country_code:'at'}});
fetchMock.reset();
fetchMock.mock(new RegExp('https://nominatim.openstreetmap.org/reverse'), {
body: '{"address":{"country_code":"cz"}}',
status: 200,
headers: { 'Content-Type': 'application/json' }
});
fetchMock.reset();
fetchMock.mock(new RegExp('https://nominatim.openstreetmap.org/reverse'), {
body: '{"address":{"country_code":"cz"}}',
status: 200,
headers: { 'Content-Type': 'application/json' }
});
callback = sinon.spy();
nominatim.reverse([17, 49], callback);
callback = sinon.spy();
nominatim.reverse([17, 49], callback);
window.setTimeout(function() {
expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
{zoom: '13', format: 'json', addressdetails: '1', lat: '49', lon: '17'}
);
expect(fetchMock.calls()[0][1].headers).to.eql({
'Accept-Language': 'en'
});
expect(callback).to.have.been.calledWithExactly(null, {address: {country_code:'cz'}});
done();
}, 50);
}, 50);
await setTimeout(50);
expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
{zoom: '13', format: 'json', addressdetails: '1', lat: '49', lon: '17'}
);
expect(fetchMock.calls()[0][1].headers).to.eql({
'Accept-Language': 'en'
});
expect(callback).to.have.been.calledWithExactly(null, {address: {country_code:'cz'}});
});
it('should cache nearby result', function(done) {
it('should cache nearby result', async () => {
var callback = sinon.spy();
fetchMock.mock(new RegExp('https://nominatim.openstreetmap.org/reverse'), {
body: '{"address":{"country_code":"at"}}',
@@ -95,25 +92,22 @@ describe('iD.serviceNominatim', function() {
nominatim.reverse([16, 48], callback);
window.setTimeout(function() {
expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
{zoom: '13', format: 'json', addressdetails: '1', lat: '48', lon: '16'}
);
expect(callback).to.have.been.calledWithExactly(null, {address: {country_code:'at'}});
await setTimeout(50);
expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
{zoom: '13', format: 'json', addressdetails: '1', lat: '48', lon: '16'}
);
expect(callback).to.have.been.calledWithExactly(null, {address: {country_code:'at'}});
fetchMock.resetHistory();
fetchMock.resetHistory();
callback = sinon.spy();
nominatim.reverse([16.000001, 48.000001], callback);
callback = sinon.spy();
nominatim.reverse([16.000001, 48.000001], callback);
window.setTimeout(function() {
expect(callback).to.have.been.calledWithExactly(null, {address: {country_code:'at'}});
done();
}, 50);
}, 50);
await setTimeout(50);
expect(callback).to.have.been.calledWithExactly(null, {address: {country_code:'at'}});
});
it('calls the given callback with an error', function(done) {
it('calls the given callback with an error', async () => {
var callback = sinon.spy();
fetchMock.mock(new RegExp('https://nominatim.openstreetmap.org/reverse'), {
body: '{"error":"Unable to geocode"}',
@@ -124,19 +118,17 @@ describe('iD.serviceNominatim', function() {
nominatim.reverse([1000, 1000], callback);
window.setTimeout(function() {
expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
{zoom: '13', format: 'json', addressdetails: '1', lat: '1000', lon: '1000'}
);
expect(callback).to.have.been.calledWithExactly('Unable to geocode');
done();
}, 50);
await setTimeout(50);
expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
{zoom: '13', format: 'json', addressdetails: '1', lat: '1000', lon: '1000'}
);
expect(callback).to.have.been.calledWithExactly('Unable to geocode');
});
});
describe('#search', function() {
it('calls the given callback with the results of the search query', function(done) {
it('calls the given callback with the results of the search query', async () => {
var callback = sinon.spy();
fetchMock.mock(new RegExp('https://nominatim.openstreetmap.org/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}]',
@@ -146,18 +138,16 @@ describe('iD.serviceNominatim', function() {
nominatim.search('philadelphia', callback);
window.setTimeout(function() {
expect(parseQueryString(fetchMock.calls()[0][0])).to.eql({
q: 'philadelphia',
format: 'json',
limit: '10'
});
expect(fetchMock.calls()[0][1].headers).to.eql({
'Accept-Language': 'en'
});
expect(callback).to.have.been.calledOnce;
done();
}, 50);
await setTimeout(50);
expect(parseQueryString(fetchMock.calls()[0][0])).to.eql({
q: 'philadelphia',
format: 'json',
limit: '10'
});
expect(fetchMock.calls()[0][1].headers).to.eql({
'Accept-Language': 'en'
});
expect(callback).to.have.been.calledOnce;
});
});
+126 -158
View File
@@ -1,3 +1,6 @@
import { setTimeout } from 'node:timers/promises';
import { promisify } from 'node:util';
describe('iD.serviceOsm', function () {
var context, connection, spy;
var serverXHR;
@@ -149,21 +152,18 @@ describe('iD.serviceOsm', function () {
' ]' +
'}';
it('returns an object', function(done) {
it('returns an object', async () => {
fetchMock.mock('https://www.openstreetmap.org' + path, {
body: response,
status: 200,
headers: { 'Content-Type': 'application/json' }
});
connection.loadFromAPI(path, function (err, payload) {
expect(err).to.not.be.ok;
expect(typeof payload).to.eql('object');
done();
});
const payload = await promisify(connection.loadFromAPI).call(connection, path);
expect(typeof payload).to.eql('object');
});
it('retries an authenticated call unauthenticated if 401 Unauthorized', function (done) {
it('retries an authenticated call unauthenticated if 401 Unauthorized', async () => {
fetchMock.mock('https://www.openstreetmap.org' + path, {
body: response,
status: 200,
@@ -174,19 +174,15 @@ describe('iD.serviceOsm', function () {
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();
});
const xml = promisify(connection.loadFromAPI).call(connection, path);
serverXHR.respond();
expect(typeof await xml).to.eql('object');
expect(connection.authenticated()).to.be.not.ok;
expect(fetchMock.called()).to.be.true;
});
it('retries an authenticated call unauthenticated if 401 Unauthorized', function (done) {
it('retries an authenticated call unauthenticated if 401 Unauthorized', async () => {
fetchMock.mock('https://www.openstreetmap.org' + path, {
body: response,
status: 200,
@@ -196,19 +192,16 @@ describe('iD.serviceOsm', function () {
[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();
});
const xml = promisify(connection.loadFromAPI).call(connection, path);
serverXHR.respond();
expect(typeof await xml).to.eql('object');
expect(connection.authenticated()).to.be.not.ok;
expect(fetchMock.called()).to.be.true;
});
it('retries an authenticated call unauthenticated if 403 Forbidden', function (done) {
it('retries an authenticated call unauthenticated if 403 Forbidden', async () => {
fetchMock.mock('https://www.openstreetmap.org' + path, {
body: response,
status: 200,
@@ -218,20 +211,16 @@ describe('iD.serviceOsm', function () {
[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();
});
const xml = promisify(connection.loadFromAPI).call(connection, path);
serverXHR.respond();
expect(typeof await xml).to.eql('object');
expect(connection.authenticated()).to.be.not.ok;
expect(fetchMock.called()).to.be.true;
});
it('dispatches change event if 509 Bandwidth Limit Exceeded', function (done) {
it('dispatches change event if 509 Bandwidth Limit Exceeded', async () => {
fetchMock.mock('https://www.openstreetmap.org' + path, {
body: 'Bandwidth Limit Exceeded',
status: 509,
@@ -240,14 +229,14 @@ describe('iD.serviceOsm', function () {
logout();
connection.on('change', spy);
connection.loadFromAPI(path, function (err) {
expect(err).to.have.property('status', 509);
expect(spy).to.have.been.calledOnce;
done();
});
const promise = promisify(connection.loadFromAPI).call(connection, path);
await expect(promise).rejects.toThrow(expect.objectContaining({ status: 509 }));
expect(spy).to.have.been.calledOnce;
});
it('dispatches change event if 429 Too Many Requests', function (done) {
it('dispatches change event if 429 Too Many Requests', async () => {
fetchMock.mock('https://www.openstreetmap.org' + path, {
body: '429 Too Many Requests',
status: 429,
@@ -256,14 +245,13 @@ describe('iD.serviceOsm', function () {
logout();
connection.on('change', spy);
connection.loadFromAPI(path, function (err) {
expect(err).to.have.property('status', 429);
expect(spy).to.have.been.calledOnce;
done();
});
const promise = promisify(connection.loadFromAPI).call(connection, path);
await expect(promise).rejects.toThrow(expect.objectContaining({ status: 429 }));
expect(spy).to.have.been.calledOnce;
});
it('uses apiUrl', function(done) {
it('uses apiUrl', async () => {
fetchMock.mock('https://api.openstreetmap.org' + path, {
body: response,
status: 200,
@@ -275,12 +263,10 @@ describe('iD.serviceOsm', function () {
apiUrl: 'https://api.openstreetmap.org'
});
connection.loadFromAPI(path, function (err) {
expect(err).to.not.be.ok;
expect(fetchMock.calls().length).to.eql(1);
expect(fetchMock.calls()[0][0]).to.eql('https://api.openstreetmap.org' + path);
done();
});
await promisify(connection.loadFromAPI).call(connection, path);
expect(fetchMock.calls().length).to.eql(1);
expect(fetchMock.calls()[0][0]).to.eql('https://api.openstreetmap.org' + path);
});
});
@@ -303,7 +289,7 @@ describe('iD.serviceOsm', function () {
.clipExtent([[0,0], dimensions]);
});
it('calls callback when data tiles are loaded', function(done) {
it('calls callback when data tiles are loaded', async () => {
fetchMock.mock(/map.json\?bbox/, {
body: tileResponse,
status: 200,
@@ -313,13 +299,11 @@ describe('iD.serviceOsm', function () {
var spy = sinon.spy();
connection.loadTiles(context.projection, spy);
window.setTimeout(function() {
expect(spy).to.have.been.calledOnce;
done();
}, 500);
await setTimeout(500);
expect(spy).to.have.been.calledOnce;
});
it('#isDataLoaded', function(done) {
it('#isDataLoaded', async () => {
fetchMock.mock(/map.json\?bbox/, {
body: tileResponse,
status: 200,
@@ -338,11 +322,9 @@ describe('iD.serviceOsm', function () {
connection.loadTiles(context.projection);
window.setTimeout(function() {
expect(fetchMock.called()).to.be.true;
expect(connection.isDataLoaded([-74.0444216, 40.6694299])).to.be.true;
done();
}, 500);
await setTimeout(500);
expect(fetchMock.called()).to.be.true;
expect(connection.isDataLoaded([-74.0444216, 40.6694299])).to.be.true;
});
});
@@ -364,7 +346,7 @@ describe('iD.serviceOsm', function () {
' ]' +
'}';
it('loads a node', function(done) {
it('loads a node', async () => {
fetchMock.mock('https://www.openstreetmap.org/api/0.6/node/1.json', {
body: nodeResponse,
status: 200,
@@ -372,14 +354,13 @@ describe('iD.serviceOsm', function () {
});
var id = 'n1';
connection.loadEntity(id, function(err, result) {
var entity = result.data.find(function(e) { return e.id === id; });
expect(entity).to.be.an.instanceOf(iD.osmNode);
done();
});
const result = await promisify(connection.loadEntity).call(connection, id);
var entity = result.data.find(function(e) { return e.id === id; });
expect(entity).to.be.an.instanceOf(iD.osmNode);
});
it('loads a way', function(done) {
it('loads a way', async () => {
fetchMock.mock('https://www.openstreetmap.org/api/0.6/way/1/full.json', {
body: wayResponse,
status: 200,
@@ -387,14 +368,13 @@ describe('iD.serviceOsm', function () {
});
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();
});
const result = await promisify(connection.loadEntity).call(connection, id);
var entity = result.data.find(function(e) { return e.id === id; });
expect(entity).to.be.an.instanceOf(iD.osmWay);
});
it('does not ignore repeat requests', function(done) {
it('does not ignore repeat requests', async () => {
fetchMock.mock('https://www.openstreetmap.org/api/0.6/node/1.json', {
body: wayResponse,
status: 200,
@@ -402,16 +382,13 @@ describe('iD.serviceOsm', function () {
});
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);
const result1 = await promisify(connection.loadEntity).call(connection, id);
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();
});
});
const result2 = await promisify(connection.loadEntity).call(connection, id);
var entity2 = result2.data.find(function(e2) { return e2.id === id; });
expect(entity2).to.be.an.instanceOf(iD.osmNode);
});
});
@@ -433,7 +410,7 @@ describe('iD.serviceOsm', function () {
' ]' +
'}';
it('loads a node', function(done) {
it('loads a node', async () => {
fetchMock.mock('https://www.openstreetmap.org/api/0.6/node/1/1.json', {
body: nodeResponse,
status: 200,
@@ -441,14 +418,13 @@ describe('iD.serviceOsm', function () {
});
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();
});
const result = await promisify(connection.loadEntityVersion).call(connection, id, 1);
var entity = result.data.find(function(e) { return e.id === id; });
expect(entity).to.be.an.instanceOf(iD.osmNode);
});
it('loads a way', function(done) {
it('loads a way', async () => {
fetchMock.mock('https://www.openstreetmap.org/api/0.6/way/1/1.json', {
body: wayResponse,
status: 200,
@@ -456,14 +432,13 @@ describe('iD.serviceOsm', function () {
});
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();
});
const result = await promisify(connection.loadEntityVersion).call(connection, id, 1);
var entity = result.data.find(function(e) { return e.id === id; });
expect(entity).to.be.an.instanceOf(iD.osmWay);
});
it('does not ignore repeat requests', function(done) {
it('does not ignore repeat requests', async () => {
fetchMock.mock('https://www.openstreetmap.org/api/0.6/node/1/1.json', {
body: nodeResponse,
status: 200,
@@ -471,16 +446,15 @@ describe('iD.serviceOsm', function () {
});
var id = 'n1';
connection.loadEntityVersion(id, 1, function(err1, result1) {
var entity1 = result1.data.find(function(e1) { return e1.id === id; });
expect(entity1).to.be.an.instanceOf(iD.osmNode);
const result1 = await promisify(connection.loadEntityVersion).call(connection, id, 1);
connection.loadEntityVersion(id, 1, function(err2, result2) {
var entity2 = result2.data.find(function(e2) { return e2.id === id; });
expect(entity2).to.be.an.instanceOf(iD.osmNode);
done();
});
});
var entity1 = result1.data.find(function(e1) { return e1.id === id; });
expect(entity1).to.be.an.instanceOf(iD.osmNode);
const result2 = await promisify(connection.loadEntityVersion).call(connection, id, 1);
var entity2 = result2.data.find(function(e2) { return e2.id === id; });
expect(entity2).to.be.an.instanceOf(iD.osmNode);
});
});
@@ -507,7 +481,7 @@ describe('iD.serviceOsm', function () {
});
it('loads user changesets', function(done) {
it('loads user changesets', async () => {
var changesetsXML = '<?xml version="1.0" encoding="UTF-8"?>' +
'<osm>' +
'<changeset id="36777543" user="Steve" uid="1" created_at="2016-01-24T15:02:06Z" closed_at="2016-01-24T15:02:07Z" open="false" min_lat="39.3823819" min_lon="-104.8639728" max_lat="39.3834184" max_lon="-104.8618622" comments_count="0">' +
@@ -517,23 +491,23 @@ describe('iD.serviceOsm', function () {
'</osm>';
login();
connection.userChangesets(function(err, changesets) {
expect(changesets).to.deep.equal([{
tags: {
comment: 'Caprice Court has been extended',
created_by: 'iD 2.0.0'
}
}]);
connection.logout();
done();
});
serverXHR.respondWith('GET', 'https://www.openstreetmap.org/api/0.6/changesets\\?user=1',
[200, { 'Content-Type': 'text/xml' }, changesetsXML]);
serverXHR.respond();
const changesets = await promisify(connection.userChangesets).call(connection);
expect(changesets).to.deep.equal([{
tags: {
comment: 'Caprice Court has been extended',
created_by: 'iD 2.0.0'
}
}]);
connection.logout();
});
it('excludes changesets without comment tag', function(done) {
it('excludes changesets without comment tag', async () => {
var changesetsXML = '<?xml version="1.0" encoding="UTF-8"?>' +
'<osm>' +
'<changeset id="36777543" user="Steve" uid="1" created_at="2016-01-24T15:02:06Z" closed_at="2016-01-24T15:02:07Z" open="false" min_lat="39.3823819" min_lon="-104.8639728" max_lat="39.3834184" max_lon="-104.8618622" comments_count="0">' +
@@ -546,23 +520,23 @@ describe('iD.serviceOsm', function () {
'</osm>';
login();
connection.userChangesets(function(err, changesets) {
expect(changesets).to.deep.equal([{
tags: {
comment: 'Caprice Court has been extended',
created_by: 'iD 2.0.0'
}
}]);
connection.logout();
done();
});
serverXHR.respondWith('GET', 'https://www.openstreetmap.org/api/0.6/changesets\\?user=1',
[200, { 'Content-Type': 'text/xml' }, changesetsXML]);
serverXHR.respond();
const changesets = await promisify(connection.userChangesets).call(connection);
expect(changesets).to.deep.equal([{
tags: {
comment: 'Caprice Court has been extended',
created_by: 'iD 2.0.0'
}
}]);
connection.logout();
});
it('excludes changesets with empty comment', function(done) {
it('excludes changesets with empty comment', async () => {
var changesetsXML = '<?xml version="1.0" encoding="UTF-8"?>' +
'<osm>' +
'<changeset id="36777543" user="Steve" uid="1" created_at="2016-01-24T15:02:06Z" closed_at="2016-01-24T15:02:07Z" open="false" min_lat="39.3823819" min_lon="-104.8639728" max_lat="39.3834184" max_lon="-104.8618622" comments_count="0">' +
@@ -576,20 +550,20 @@ describe('iD.serviceOsm', function () {
'</osm>';
login();
connection.userChangesets(function(err, changesets) {
expect(changesets).to.deep.equal([{
tags: {
comment: 'Caprice Court has been extended',
created_by: 'iD 2.0.0'
}
}]);
connection.logout();
done();
});
serverXHR.respondWith('GET', 'https://www.openstreetmap.org/api/0.6/changesets\\?user=1',
[200, { 'Content-Type': 'text/xml' }, changesetsXML]);
serverXHR.respond();
const changesets = await promisify(connection.userChangesets)();
expect(changesets).to.deep.equal([{
tags: {
comment: 'Caprice Court has been extended',
created_by: 'iD 2.0.0'
}
}]);
connection.logout();
});
});
@@ -668,7 +642,7 @@ describe('iD.serviceOsm', function () {
.clipExtent([[0,0], dimensions]);
});
it('fires loadedNotes when notes are loaded', function(done) {
it('fires loadedNotes when notes are loaded', async () => {
fetchMock.mock(/notes\?/, {
body: notesXML,
status: 200,
@@ -678,10 +652,8 @@ describe('iD.serviceOsm', function () {
connection.on('loadedNotes', spy);
connection.loadNotes(context.projection, {});
window.setTimeout(function() {
expect(spy).to.have.been.calledOnce;
done();
}, 500);
await setTimeout(500);
expect(spy).to.have.been.calledOnce;
});
});
@@ -785,7 +757,7 @@ describe('iD.serviceOsm', function () {
</osm>`;
describe('#status', function() {
it('gets API status', function(done) {
it('gets API status', async () => {
fetchMock.mock('https://www.openstreetmap.org/api/capabilities', {
body: capabilitiesXML,
status: 200,
@@ -794,15 +766,13 @@ describe('iD.serviceOsm', function () {
overwriteRoutes: true
});
connection.status(function (err, val) {
expect(val).to.eql('online');
done();
});
const val = await promisify(connection.status).call(connection);
expect(val).to.eql('online');
});
});
describe('#imageryBlocklists', function() {
it('updates imagery blocklists', function(done) {
it('updates imagery blocklists', async () => {
fetchMock.mock('https://www.openstreetmap.org/api/capabilities', {
body: capabilitiesXML,
status: 200,
@@ -811,11 +781,9 @@ describe('iD.serviceOsm', function () {
overwriteRoutes: true
});
connection.status(function() {
var blocklists = connection.imageryBlocklists();
expect(blocklists).to.deep.equal([new RegExp('\.foo\.com'), new RegExp('\.bar\.org')]);
done();
});
await promisify(connection.status).call(connection);
var blocklists = connection.imageryBlocklists();
expect(blocklists).to.deep.equal([new RegExp('\.foo\.com'), new RegExp('\.bar\.org')]);
});
});
+19 -19
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.serviceOsmWikibase', function () {
var wikibase;
@@ -262,7 +264,7 @@ describe('iD.serviceOsmWikibase', function () {
};
describe('#getEntity', function () {
it('calls the given callback with the results of the getEntity data item query', function (done) {
it('calls the given callback with the results of the getEntity data item query', async () => {
var callback = sinon.spy();
fetchMock.mock(/action=wbgetentities/, {
body: JSON.stringify({
@@ -279,24 +281,22 @@ describe('iD.serviceOsmWikibase', function () {
wikibase.getEntity({ key: 'amenity', value: 'parking', langCodes: ['fr'] }, callback);
window.setTimeout(function () {
expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
{
action: 'wbgetentities',
sites: 'wiki',
titles: 'Locale:fr|Key:amenity|Tag:amenity=parking',
languages: 'fr',
languagefallback: '1',
origin: '*',
format: 'json',
}
);
expect(callback).to.have.been.calledWith(null, {
key: keyData(),
tag: tagData()
});
done();
}, 50);
await setTimeout(50);
expect(parseQueryString(fetchMock.calls()[0][0])).to.eql(
{
action: 'wbgetentities',
sites: 'wiki',
titles: 'Locale:fr|Key:amenity|Tag:amenity=parking',
languages: 'fr',
languagefallback: '1',
origin: '*',
format: 'json',
}
);
expect(callback).to.have.been.calledWith(null, {
key: keyData(),
tag: tagData()
});
});
});
+8 -10
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.serviceStreetside', function() {
var dimensions = [64, 64];
var context, streetside;
@@ -47,7 +49,7 @@ describe('iD.serviceStreetside', function() {
});
describe('#loadBubbles', function() {
it('fires loadedImages when bubbles are loaded', function(done) {
it('fires loadedImages when bubbles are loaded', async () => {
// adjust projection so that only one tile is fetched
// (JSONP hack will return the same data for every fetch)
context.projection
@@ -71,13 +73,11 @@ describe('iD.serviceStreetside', function() {
streetside.loadBubbles(context.projection, 0); // 0 = don't fetch margin tiles
window.setTimeout(function() {
expect(spy).to.have.been.calledOnce;
done();
}, 200);
await setTimeout(200);
expect(spy).to.have.been.calledOnce;
});
it('does not load bubbles around null island', function(done) {
it('does not load bubbles around null island', async () => {
context.projection
.scale(iD.geoZoomToScale(18))
.translate([0, 0])
@@ -99,10 +99,8 @@ describe('iD.serviceStreetside', function() {
streetside.loadBubbles(context.projection, 0); // 0 = don't fetch margin tiles
window.setTimeout(function() {
expect(spy).to.have.been.not.called;
done();
}, 200);
await setTimeout(200);
expect(spy).to.have.been.not.called;
});
});
+116 -152
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.serviceTaginfo', function() {
var taginfo;
@@ -33,7 +35,7 @@ describe('iD.serviceTaginfo', function() {
}
describe('#keys', function() {
it('calls the given callback with the results of the keys query', function(done) {
it('calls the given callback with the results of the keys query', async () => {
fetchMock.mock(/\/keys\/all/, {
body: '{"data":[{"count_all":5190337,"key":"amenity","count_all_fraction":1.0}]}',
status: 200,
@@ -43,18 +45,16 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.keys({ query: 'amen' }, callback);
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'}]
);
done();
}, 50);
await setTimeout(50);
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'}]
);
});
it('includes popular keys', function(done) {
it('includes popular keys', async () => {
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}]}',
@@ -65,15 +65,13 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.keys({ query: 'amen' }, callback);
window.setTimeout(function() {
expect(callback).to.have.been.calledWith(
null, [{'title':'amenity', 'value':'amenity'}]
);
done();
}, 50);
await setTimeout(50);
expect(callback).to.have.been.calledWith(
null, [{'title':'amenity', 'value':'amenity'}]
);
});
it('includes popular keys with an entity type filter', function(done) {
it('includes popular keys with an entity type filter', async () => {
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}]}',
@@ -84,15 +82,13 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.keys({ query: 'amen', filter: 'nodes' }, callback);
window.setTimeout(function() {
expect(callback).to.have.been.calledWith(
null, [{'title':'amenity', 'value':'amenity'}]
);
done();
}, 50);
await setTimeout(50);
expect(callback).to.have.been.calledWith(
null, [{'title':'amenity', 'value':'amenity'}]
);
});
it('includes unpopular keys with a wiki page', function(done) {
it('includes unpopular keys with a wiki page', async () => {
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}]}',
@@ -103,16 +99,14 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.keys({ query: 'amen' }, callback);
window.setTimeout(function() {
expect(callback).to.have.been.calledWith(null, [
{'title':'amenity', 'value':'amenity'},
{'title':'amenityother', 'value':'amenityother'}
]);
done();
}, 50);
await setTimeout(50);
expect(callback).to.have.been.calledWith(null, [
{'title':'amenity', 'value':'amenity'},
{'title':'amenityother', 'value':'amenityother'}
]);
});
it('sorts keys with \':\' below keys without \':\'', function(done) {
it('sorts keys with \':\' below keys without \':\'', async () => {
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}]}',
@@ -123,17 +117,15 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.keys({ query: 'ref' }, callback);
window.setTimeout(function() {
expect(callback).to.have.been.calledWith(
null, [{'title':'ref', 'value':'ref'},{'title':'ref:bag', 'value':'ref:bag'}]
);
done();
}, 50);
await setTimeout(50);
expect(callback).to.have.been.calledWith(
null, [{'title':'ref', 'value':'ref'},{'title':'ref:bag', 'value':'ref:bag'}]
);
});
});
describe('#multikeys', function() {
it('calls the given callback with the results of the multikeys query', function(done) {
it('calls the given callback with the results of the multikeys query', async () => {
fetchMock.mock(/\/keys\/all/, {
body: '{"data":[{"count_all":69593,"key":"recycling:glass","count_all_fraction":0.0}]}',
status: 200,
@@ -143,18 +135,16 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.multikeys({ query: 'recycling:' }, callback);
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'}]
);
done();
}, 50);
await setTimeout(50);
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'}]
);
});
it('excludes multikeys with extra colons', function(done) {
it('excludes multikeys with extra colons', async () => {
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}]}',
@@ -165,15 +155,13 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.multikeys({ query: 'service:bicycle:' }, callback);
window.setTimeout(function() {
expect(callback).to.have.been.calledWith(
null, [{'title':'service:bicycle:retail', 'value':'service:bicycle:retail'}]
);
done();
}, 50);
await setTimeout(50);
expect(callback).to.have.been.calledWith(
null, [{'title':'service:bicycle:retail', 'value':'service:bicycle:retail'}]
);
});
it('excludes multikeys with wrong prefix', function(done) {
it('excludes multikeys with wrong prefix', async () => {
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}]}',
@@ -184,17 +172,15 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.multikeys({ query: 'service:bicycle:' }, callback);
window.setTimeout(function() {
expect(callback).to.have.been.calledWith(
null, [{'title':'service:bicycle:retail', 'value':'service:bicycle:retail'}]
);
done();
}, 50);
await setTimeout(50);
expect(callback).to.have.been.calledWith(
null, [{'title':'service:bicycle:retail', 'value':'service:bicycle:retail'}]
);
});
});
describe('#values', function() {
it('calls the given callback with the results of the values query', function(done) {
it('calls the given callback with the results of the values query', async () => {
fetchMock.mock(/\/key\/values/, {
body: '{"data":[{"value":"parking","description":"A place for parking cars", "count":1000}]}',
status: 200,
@@ -204,18 +190,16 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.values({ key: 'amenity', query: 'par' }, callback);
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'}]
);
done();
}, 50);
await setTimeout(50);
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'}]
);
});
it('includes popular values', function(done) {
it('includes popular values', async () => {
fetchMock.mock(/\/key\/values/, {
body: '{"data":[{"value":"parking","description":"A place for parking cars", "count":1000},' +
'{"value":"party","description":"A place for partying", "count":1}]}',
@@ -226,15 +210,13 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.values({ key: 'amenity', query: 'par' }, callback);
window.setTimeout(function() {
expect(callback).to.have.been.calledWith(
null, [{'value':'parking','title':'A place for parking cars'}]
);
done();
}, 50);
await setTimeout(50);
expect(callback).to.have.been.calledWith(
null, [{'value':'parking','title':'A place for parking cars'}]
);
});
it('does not get values for extremely unpopular keys', function(done) {
it('does not get values for extremely unpopular keys', async () => {
fetchMock.mock(/\/key\/values/, {
body: '{"data":[{"value":"Rue Pasteur","description":"", "count":3},' +
'{"value":"Via Trieste","description":"", "count":1}]}',
@@ -245,13 +227,11 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.values({ key: 'name', query: 'ste' }, callback);
window.setTimeout(function() {
expect(callback).to.have.been.calledWith(null, []);
done();
}, 50);
await setTimeout(50);
expect(callback).to.have.been.calledWith(null, []);
});
it('includes unpopular values with a wiki page', function(done) {
it('includes unpopular values with a wiki page', async () => {
fetchMock.mock(/\/key\/values/, {
body: '{"data":[{"value":"party","description":"A place for partying", "count":1, "in_wiki": true}]}',
status: 200,
@@ -261,15 +241,13 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.values({ key: 'amenity', query: 'par' }, callback);
window.setTimeout(function() {
expect(callback).to.have.been.calledWith(
null, [{'value':'party','title':'A place for partying'}]
);
done();
}, 50);
await setTimeout(50);
expect(callback).to.have.been.calledWith(
null, [{'value':'party','title':'A place for partying'}]
);
});
it('excludes values with capital letters and some punctuation', function(done) {
it('excludes values with capital letters and some punctuation', async () => {
fetchMock.mock(/\/key\/values/, {
body: '{"data":[{"value":"parking","description":"A place for parking cars", "count":2000},'
+ '{"value":"PArking","description":"A common misspelling", "count":200},'
@@ -283,15 +261,13 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.values({ key: 'amenity', query: 'par' }, callback);
window.setTimeout(function() {
expect(callback).to.have.been.calledWith(
null, [{'value':'parking','title':'A place for parking cars'}]
);
done();
}, 50);
await setTimeout(50);
expect(callback).to.have.been.calledWith(
null, [{'value':'parking','title':'A place for parking cars'}]
);
});
it('includes network values with capital letters and some punctuation', function(done) {
it('includes network values with capital letters and some punctuation', async () => {
fetchMock.mock(/\/key\/values/, {
body: '{"data":[{"value":"US:TX:FM","description":"Farm to Market Roads in the U.S. state of Texas.", "count":34000},'
+ '{"value":"US:KY","description":"Primary and secondary state highways in the U.S. state of Kentucky.", "count":31000},'
@@ -305,19 +281,17 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.values({ key: 'network', query: 'us' }, callback);
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.'}
]);
done();
}, 50);
await setTimeout(50);
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.'}
]);
});
it('includes biological genus values with capital letters', function(done) {
it('includes biological genus values with capital letters', async () => {
fetchMock.mock(/\/key\/values/, {
body: '{"data":[{"value":"Quercus","description":"Oak", "count": 1000}]}',
status: 200,
@@ -327,15 +301,13 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.values({ key: 'genus', query: 'qu' }, callback);
window.setTimeout(function() {
expect(callback).to.have.been.calledWith(
null, [{'value':'Quercus','title':'Oak'}]
);
done();
}, 50);
await setTimeout(50);
expect(callback).to.have.been.calledWith(
null, [{'value':'Quercus','title':'Oak'}]
);
});
it('includes biological taxon values with capital letters', function(done) {
it('includes biological taxon values with capital letters', async () => {
fetchMock.mock(/\/key\/values/, {
body: '{"data":[{"value":"Quercus robur","description":"Oak", "count": 1000}]}',
status: 200,
@@ -345,15 +317,13 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.values({ key: 'taxon', query: 'qu' }, callback);
window.setTimeout(function() {
expect(callback).to.have.been.calledWith(
null, [{'value':'Quercus robur','title':'Oak'}]
);
done();
}, 50);
await setTimeout(50);
expect(callback).to.have.been.calledWith(
null, [{'value':'Quercus robur','title':'Oak'}]
);
});
it('includes biological species values with capital letters', function(done) {
it('includes biological species values with capital letters', async () => {
fetchMock.mock(/\/key\/values/, {
body: '{"data":[{"value":"Quercus robur","description":"Oak", "count": 1000}]}',
status: 200,
@@ -363,17 +333,15 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.values({ key: 'species', query: 'qu' }, callback);
window.setTimeout(function() {
expect(callback).to.have.been.calledWith(
null, [{'value':'Quercus robur','title':'Oak'}]
);
done();
}, 50);
await setTimeout(50);
expect(callback).to.have.been.calledWith(
null, [{'value':'Quercus robur','title':'Oak'}]
);
});
});
describe('#roles', function() {
it('calls the given callback with the results of the roles query', function(done) {
it('calls the given callback with the results of the roles query', async () => {
fetchMock.mock(/\/relation\/roles/, {
body: '{"data":[{"role":"stop","count_relation_members_fraction":0.1757},' +
'{"role":"south","count_relation_members_fraction":0.0035}]}',
@@ -384,21 +352,19 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.roles({ rtype: 'route', query: 's', geometry: 'relation' }, callback);
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'}
]);
done();
}, 50);
await setTimeout(50);
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'}
]);
});
});
describe('#docs', function() {
it('calls the given callback with the results of the docs query', function(done) {
it('calls the given callback with the results of the docs query', async () => {
fetchMock.mock(/\/tag\/wiki_page/, {
body: '{"data":[{"on_way":false,"lang":"en","on_area":true,"image":"File:Car park2.jpg"}]}',
status: 200,
@@ -408,15 +374,13 @@ describe('iD.serviceTaginfo', function() {
var callback = sinon.spy();
taginfo.docs({ key: 'amenity', value: 'parking' }, callback);
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'}]
);
done();
}, 50);
await setTimeout(50);
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'}]
);
});
});
+3 -1
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.serviceVegbilder', function() {
const dimensions = [64, 64];
const testImages = [{
@@ -248,7 +250,7 @@ describe('iD.serviceVegbilder', function() {
vegbilder.on('loadedImages', spy);
vegbilder.loadImages(context, 0);
await new Promise((resolve) => { window.setTimeout(resolve, 200); });
await setTimeout(200);
expect(spy).to.have.been.not.called;
expect(fetchMock.calls().length).to.eql(0);
+40 -44
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.svgData', function () {
var context;
var surface;
@@ -114,72 +116,66 @@ describe('iD.svgData', function () {
});
describe('#fileList', function() {
it('handles gpx files', function (done) {
it('handles gpx files', async () => {
var files = [ makeFile(gpx, 'test.gpx', 'application/gpx+xml') ];
var render = iD.svgData(projection, context, dispatch);
var spy = sinon.spy();
dispatch.on('change', spy);
render.fileList(files);
window.setTimeout(function() {
expect(spy).to.have.been.calledOnce;
surface.call(render);
var path;
path = surface.selectAll('path.shadow');
expect(path.nodes().length).to.eql(1);
expect(path.attr('d')).to.match(/^M.*z$/);
path = surface.selectAll('path.stroke');
expect(path.nodes().length).to.eql(1);
expect(path.attr('d')).to.match(/^M.*z$/);
done();
}, 200);
await setTimeout(200);
expect(spy).to.have.been.calledOnce;
surface.call(render);
var path;
path = surface.selectAll('path.shadow');
expect(path.nodes().length).to.eql(1);
expect(path.attr('d')).to.match(/^M.*z$/);
path = surface.selectAll('path.stroke');
expect(path.nodes().length).to.eql(1);
expect(path.attr('d')).to.match(/^M.*z$/);
});
it('handles kml files', function (done) {
it('handles kml files', async () => {
var files = [ makeFile(kml, 'test.kml', 'application/vnd.google-earth.kml+xml') ];
var render = iD.svgData(projection, context, dispatch);
var spy = sinon.spy();
dispatch.on('change', spy);
render.fileList(files);
window.setTimeout(function() {
expect(spy).to.have.been.calledOnce;
surface.call(render);
var path;
path = surface.selectAll('path.shadow');
expect(path.nodes().length).to.eql(1);
expect(path.attr('d')).to.match(/^M.*z$/);
path = surface.selectAll('path.stroke');
expect(path.nodes().length).to.eql(1);
expect(path.attr('d')).to.match(/^M.*z$/);
done();
}, 200);
await setTimeout(200);
expect(spy).to.have.been.calledOnce;
surface.call(render);
var path;
path = surface.selectAll('path.shadow');
expect(path.nodes().length).to.eql(1);
expect(path.attr('d')).to.match(/^M.*z$/);
path = surface.selectAll('path.stroke');
expect(path.nodes().length).to.eql(1);
expect(path.attr('d')).to.match(/^M.*z$/);
});
it('handles geojson files', function (done) {
it('handles geojson files', async () => {
var files = [ makeFile(geojson, 'test.geojson', 'application/vnd.geo+json') ];
var render = iD.svgData(projection, context, dispatch);
var spy = sinon.spy();
dispatch.on('change', spy);
render.fileList(files);
window.setTimeout(function() {
expect(spy).to.have.been.calledOnce;
surface.call(render);
var path;
path = surface.selectAll('path.shadow');
expect(path.nodes().length).to.eql(1);
expect(path.attr('d')).to.match(/^M.*z$/);
path = surface.selectAll('path.stroke');
expect(path.nodes().length).to.eql(1);
expect(path.attr('d')).to.match(/^M.*z$/);
expect(render.geojson().features[0].properties.osm_id).to.be.a('string');
expect(render.geojson().features[0].properties.flag).to.be.a('string');
expect(render.geojson().features[0].properties.list).to.be.a('string');
expect(render.geojson().features[0].properties.null).to.be.a('string');
expect(render.geojson().features[0].properties.object).to.be.a('string');
done();
}, 200);
await setTimeout(200);
expect(spy).to.have.been.calledOnce;
surface.call(render);
var path;
path = surface.selectAll('path.shadow');
expect(path.nodes().length).to.eql(1);
expect(path.attr('d')).to.match(/^M.*z$/);
path = surface.selectAll('path.stroke');
expect(path.nodes().length).to.eql(1);
expect(path.attr('d')).to.match(/^M.*z$/);
expect(render.geojson().features[0].properties.osm_id).to.be.a('string');
expect(render.geojson().features[0].properties.flag).to.be.a('string');
expect(render.geojson().features[0].properties.list).to.be.a('string');
expect(render.geojson().features[0].properties.null).to.be.a('string');
expect(render.geojson().features[0].properties.object).to.be.a('string');
});
});
+8 -12
View File
@@ -231,28 +231,24 @@ describe('uiCombobox', function() {
expect(input.property('value')).to.equal('foobar');
});
it('emits accepted event with selected datum on ⇥', function(done) {
combobox.on('accept', function(d) {
expect(d).to.eql({title: 'bar', value: 'bar'});
combobox.on('accept', null);
done();
});
it('emits accepted event with selected datum on ⇥', async () => {
const d = new Promise(cb => { combobox.on('accept', cb); });
input.call(combobox.data(data));
focusTypeahead(input);
simulateKeypress('b');
simulateKeypress('⇥');
expect(await d).to.eql({title: 'bar', value: 'bar'});
combobox.on('accept', null);
});
it('emits accepted event with selected datum on ↩', function(done) {
combobox.on('accept', function(d) {
expect(d).to.eql({title: 'bar', value: 'bar'});
combobox.on('accept', null);
done();
});
it('emits accepted event with selected datum on ↩', async () => {
const d = new Promise(cb => { combobox.on('accept', cb); });
input.call(combobox.data(data));
focusTypeahead(input);
simulateKeypress('b');
simulateKeypress('↩');
expect(await d).to.eql({title: 'bar', value: 'bar'});
combobox.on('accept', null);
});
it('emits cancel event on ⎋', function() {
+22 -30
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.uiConfirm', function () {
var elem;
@@ -37,55 +39,45 @@ describe('iD.uiConfirm', function () {
expect(selection.selectAll('div.content div.buttons button.action').size()).to.equal(1);
});
it('can be dismissed by calling close function', function (done) {
it('can be dismissed by calling close function', async () => {
var selection = iD.uiConfirm(elem);
selection.close();
window.setTimeout(function() {
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
done();
}, 275);
await setTimeout(275);
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
});
it('can be dismissed by clicking the close button', function (done) {
it('can be dismissed by clicking the close button', async () => {
var selection = iD.uiConfirm(elem);
happen.click(selection.select('button.close').node());
window.setTimeout(function() {
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
done();
}, 275);
await setTimeout(275);
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
});
it('can be dismissed by pressing escape', function (done) {
it('can be dismissed by pressing escape', async () => {
var selection = iD.uiConfirm(elem);
happen.keydown(document, {keyCode: 27});
happen.keyup(document, {keyCode: 27});
window.setTimeout(function() {
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
done();
}, 275);
await setTimeout(275);
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
});
it('can be dismissed by pressing backspace', function (done) {
it('can be dismissed by pressing backspace', async () => {
var selection = iD.uiConfirm(elem);
happen.keydown(document, {keyCode: 8});
happen.keyup(document, {keyCode: 8});
window.setTimeout(function() {
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
done();
}, 275);
await setTimeout(275);
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
});
it('can be dismissed by clicking the ok button', function (done) {
it('can be dismissed by clicking the ok button', async () => {
var selection = iD.uiConfirm(elem).okButton();
happen.click(selection.select('div.content div.buttons button.action').node());
window.setTimeout(function() {
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
done();
}, 275);
await setTimeout(275);
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
});
});
+89 -107
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.uiFieldLocalized', function() {
var context, selection, field;
@@ -22,158 +24,138 @@ describe('iD.uiFieldLocalized', function() {
});
it('adds a blank set of fields when the + button is clicked', function(done) {
it('adds a blank set of fields when the + button is clicked', async () => {
var localized = iD.uiFieldLocalized(field, context);
window.setTimeout(function() { // async, so data will be available
selection.call(localized);
happen.click(selection.selectAll('.localized-add').node());
expect(selection.selectAll('.localized-lang').nodes().length).to.equal(1);
expect(selection.selectAll('.localized-value').nodes().length).to.equal(1);
done();
}, 20);
await setTimeout(20);
selection.call(localized);
happen.click(selection.selectAll('.localized-add').node());
expect(selection.selectAll('.localized-lang').nodes().length).to.equal(1);
expect(selection.selectAll('.localized-value').nodes().length).to.equal(1);
});
it('doesn\'t create a tag when the value is empty', function(done) {
it('doesn\'t create a tag when the value is empty', async () => {
var localized = iD.uiFieldLocalized(field, context);
window.setTimeout(function() { // async, so data will be available
selection.call(localized);
happen.click(selection.selectAll('.localized-add').node());
await setTimeout(20);
selection.call(localized);
happen.click(selection.selectAll('.localized-add').node());
localized.on('change', function(tags) {
expect(tags).to.eql({});
});
localized.on('change', function(tags) {
expect(tags).to.eql({});
});
iD.utilGetSetValue(selection.selectAll('.localized-lang'), 'Deutsch');
happen.once(selection.selectAll('.localized-lang').node(), {type: 'change'});
happen.once(selection.selectAll('.localized-lang').node(), {type: 'blur'});
done();
}, 20);
iD.utilGetSetValue(selection.selectAll('.localized-lang'), 'Deutsch');
happen.once(selection.selectAll('.localized-lang').node(), {type: 'change'});
happen.once(selection.selectAll('.localized-lang').node(), {type: 'blur'});
});
it('doesn\'t create a tag when the name is empty', function(done) {
it('doesn\'t create a tag when the name is empty', async () => {
var localized = iD.uiFieldLocalized(field, context);
window.setTimeout(function() { // async, so data will be available
selection.call(localized);
happen.click(selection.selectAll('.localized-add').node());
await setTimeout(20);
selection.call(localized);
happen.click(selection.selectAll('.localized-add').node());
localized.on('change', function(tags) {
expect(tags).to.eql({});
});
localized.on('change', function(tags) {
expect(tags).to.eql({});
});
iD.utilGetSetValue(selection.selectAll('.localized-value'), 'Value');
happen.once(selection.selectAll('.localized-value').node(), {type: 'change'});
happen.once(selection.selectAll('.localized-value').node(), {type: 'blur'});
done();
}, 20);
iD.utilGetSetValue(selection.selectAll('.localized-value'), 'Value');
happen.once(selection.selectAll('.localized-value').node(), {type: 'change'});
happen.once(selection.selectAll('.localized-value').node(), {type: 'blur'});
});
it('creates a tag after setting language then value', function(done) {
it('creates a tag after setting language then value', async () => {
var localized = iD.uiFieldLocalized(field, context);
window.setTimeout(function() { // async, so data will be available
selection.call(localized);
happen.click(selection.selectAll('.localized-add').node());
await setTimeout(20);
selection.call(localized);
happen.click(selection.selectAll('.localized-add').node());
iD.utilGetSetValue(selection.selectAll('.localized-lang'), 'Deutsch');
happen.once(selection.selectAll('.localized-lang').node(), {type: 'change'});
iD.utilGetSetValue(selection.selectAll('.localized-lang'), 'Deutsch');
happen.once(selection.selectAll('.localized-lang').node(), {type: 'change'});
localized.on('change', function(tags) {
expect(tags).to.eql({'name:de': 'Value'});
});
localized.on('change', function(tags) {
expect(tags).to.eql({'name:de': 'Value'});
});
iD.utilGetSetValue(selection.selectAll('.localized-value'), 'Value');
happen.once(selection.selectAll('.localized-value').node(), {type: 'change'});
done();
}, 20);
iD.utilGetSetValue(selection.selectAll('.localized-value'), 'Value');
happen.once(selection.selectAll('.localized-value').node(), {type: 'change'});
});
it('creates a tag after setting value then language', function(done) {
it('creates a tag after setting value then language', async () => {
var localized = iD.uiFieldLocalized(field, context);
window.setTimeout(function() { // async, so data will be available
selection.call(localized);
happen.click(selection.selectAll('.localized-add').node());
await setTimeout(20);
selection.call(localized);
happen.click(selection.selectAll('.localized-add').node());
iD.utilGetSetValue(selection.selectAll('.localized-value'), 'Value');
happen.once(selection.selectAll('.localized-value').node(), {type: 'change'});
iD.utilGetSetValue(selection.selectAll('.localized-value'), 'Value');
happen.once(selection.selectAll('.localized-value').node(), {type: 'change'});
localized.on('change', function(tags) {
expect(tags).to.eql({'name:de': 'Value'});
});
localized.on('change', function(tags) {
expect(tags).to.eql({'name:de': 'Value'});
});
iD.utilGetSetValue(selection.selectAll('.localized-lang'), 'Deutsch');
happen.once(selection.selectAll('.localized-lang').node(), {type: 'change'});
done();
}, 20);
iD.utilGetSetValue(selection.selectAll('.localized-lang'), 'Deutsch');
happen.once(selection.selectAll('.localized-lang').node(), {type: 'change'});
});
it('changes an existing language', function(done) {
it('changes an existing language', async () => {
var localized = iD.uiFieldLocalized(field, context);
window.setTimeout(function() { // async, so data will be available
selection.call(localized);
localized.tags({'name:de': 'Value'});
await setTimeout(20);
selection.call(localized);
localized.tags({'name:de': 'Value'});
localized.on('change', function(tags) {
expect(tags).to.eql({
'name:de': undefined,
'name:en': 'Value'});
});
localized.on('change', function(tags) {
expect(tags).to.eql({
'name:de': undefined,
'name:en': 'Value'});
});
iD.utilGetSetValue(selection.selectAll('.localized-lang'), 'English');
happen.once(selection.selectAll('.localized-lang').node(), {type: 'change'});
done();
}, 20);
iD.utilGetSetValue(selection.selectAll('.localized-lang'), 'English');
happen.once(selection.selectAll('.localized-lang').node(), {type: 'change'});
});
it('ignores similar keys like `old_name`', function(done) {
it('ignores similar keys like `old_name`', async () => {
var localized = iD.uiFieldLocalized(field, context);
window.setTimeout(function() { // async, so data will be available
selection.call(localized);
localized.tags({'old_name:de': 'Value'});
await setTimeout(20);
selection.call(localized);
localized.tags({'old_name:de': 'Value'});
expect(selection.selectAll('.localized-lang').empty()).to.be.ok;
expect(selection.selectAll('.localized-value').empty()).to.be.ok;
done();
}, 20);
expect(selection.selectAll('.localized-lang').empty()).to.be.ok;
expect(selection.selectAll('.localized-value').empty()).to.be.ok;
});
it('removes the tag when the language is emptied', function(done) {
it('removes the tag when the language is emptied', async () => {
var localized = iD.uiFieldLocalized(field, context);
window.setTimeout(function() { // async, so data will be available
selection.call(localized);
localized.tags({'name:de': 'Value'});
await setTimeout(20);
selection.call(localized);
localized.tags({'name:de': 'Value'});
localized.on('change', function(tags) {
expect(tags).to.eql({'name:de': undefined});
});
localized.on('change', function(tags) {
expect(tags).to.eql({'name:de': undefined});
});
iD.utilGetSetValue(selection.selectAll('.localized-lang'), '');
happen.once(selection.selectAll('.localized-lang').node(), {type: 'change'});
done();
}, 20);
iD.utilGetSetValue(selection.selectAll('.localized-lang'), '');
happen.once(selection.selectAll('.localized-lang').node(), {type: 'change'});
});
it('removes the tag when the value is emptied', function(done) {
it('removes the tag when the value is emptied', async () => {
var localized = iD.uiFieldLocalized(field, context);
window.setTimeout(function() { // async, so data will be available
selection.call(localized);
localized.tags({'name:de': 'Value'});
await setTimeout(20);
selection.call(localized);
localized.tags({'name:de': 'Value'});
localized.on('change', function(tags) {
expect(tags).to.eql({'name:de': undefined});
});
localized.on('change', function(tags) {
expect(tags).to.eql({'name:de': undefined});
});
iD.utilGetSetValue(selection.selectAll('.localized-value'), '');
happen.once(selection.selectAll('.localized-value').node(), {type: 'change'});
done();
}, 20);
iD.utilGetSetValue(selection.selectAll('.localized-value'), '');
happen.once(selection.selectAll('.localized-value').node(), {type: 'change'});
});
it('has a lang attribute on an existing multilingual name field', function(done) {
var localized = iD.uiFieldLocalized(field, context);
localized.tags({'name:de': 'Value'});
window.setTimeout(function() {
it('has a lang attribute on an existing multilingual name field', async () => {
var localized = iD.uiFieldLocalized(field, context);
localized.tags({'name:de': 'Value'});
await setTimeout(20);
selection.call(localized);
expect(selection.selectAll('.localized-value').attr('lang')).to.eql('de');
done();
}, 20);
});
});
+56 -72
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.uiFieldWikipedia', function() {
var entity, context, selection, field;
@@ -60,119 +62,104 @@ describe('iD.uiFieldWikipedia', function() {
}
}
it('recognizes lang:title format', function(done) {
it('recognizes lang:title format', async () => {
var wikipedia = iD.uiFieldWikipedia(field, context);
window.setTimeout(function() { // async, so data will be available
selection.call(wikipedia);
wikipedia.tags({wikipedia: 'en:Title'});
await setTimeout(20);
selection.call(wikipedia);
wikipedia.tags({wikipedia: 'en:Title'});
expect(iD.utilGetSetValue(selection.selectAll('.wiki-lang'))).to.equal('English');
expect(iD.utilGetSetValue(selection.selectAll('.wiki-title'))).to.equal('Title');
done();
}, 20);
expect(iD.utilGetSetValue(selection.selectAll('.wiki-lang'))).to.equal('English');
expect(iD.utilGetSetValue(selection.selectAll('.wiki-title'))).to.equal('Title');
});
it('sets language, value', function(done) {
it('sets language, value', async () => {
var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]);
window.setTimeout(function() { // async, so data will be available
wikipedia.on('change', changeTags);
selection.call(wikipedia);
await setTimeout(20);
wikipedia.on('change', changeTags);
selection.call(wikipedia);
var spy = sinon.spy();
wikipedia.on('change.spy', spy);
var spy = sinon.spy();
wikipedia.on('change.spy', spy);
iD.utilGetSetValue(selection.selectAll('.wiki-lang'), 'Deutsch');
happen.once(selection.selectAll('.wiki-lang').node(), { type: 'change' });
happen.once(selection.selectAll('.wiki-lang').node(), { type: 'blur' });
iD.utilGetSetValue(selection.selectAll('.wiki-lang'), 'Deutsch');
happen.once(selection.selectAll('.wiki-lang').node(), { type: 'change' });
happen.once(selection.selectAll('.wiki-lang').node(), { type: 'blur' });
iD.utilGetSetValue(selection.selectAll('.wiki-title'), 'Title');
happen.once(selection.selectAll('.wiki-title').node(), { type: 'change' });
happen.once(selection.selectAll('.wiki-title').node(), { type: 'blur' });
iD.utilGetSetValue(selection.selectAll('.wiki-title'), 'Title');
happen.once(selection.selectAll('.wiki-title').node(), { type: 'change' });
happen.once(selection.selectAll('.wiki-title').node(), { type: 'blur' });
expect(spy.callCount).to.equal(4);
expect(spy.getCall(0)).to.have.been.calledWith({ wikipedia: undefined}); // lang on change
expect(spy.getCall(1)).to.have.been.calledWith({ wikipedia: undefined}); // lang on blur
expect(spy.getCall(2)).to.have.been.calledWith({ wikipedia: 'de:Title' }); // title on change
expect(spy.getCall(3)).to.have.been.calledWith({ wikipedia: 'de:Title' }); // title on blur
done();
}, 20);
expect(spy.callCount).to.equal(4);
expect(spy.getCall(0)).to.have.been.calledWith({ wikipedia: undefined}); // lang on change
expect(spy.getCall(1)).to.have.been.calledWith({ wikipedia: undefined}); // lang on blur
expect(spy.getCall(2)).to.have.been.calledWith({ wikipedia: 'de:Title' }); // title on change
expect(spy.getCall(3)).to.have.been.calledWith({ wikipedia: 'de:Title' }); // title on blur
});
it('recognizes pasted URLs', function(done) {
it('recognizes pasted URLs', async () => {
var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]);
window.setTimeout(function() { // async, so data will be available
wikipedia.on('change', changeTags);
selection.call(wikipedia);
await setTimeout(20);
wikipedia.on('change', changeTags);
selection.call(wikipedia);
iD.utilGetSetValue(selection.selectAll('.wiki-title'), 'http://de.wikipedia.org/wiki/Title');
happen.once(selection.selectAll('.wiki-title').node(), { type: 'change' });
iD.utilGetSetValue(selection.selectAll('.wiki-title'), 'http://de.wikipedia.org/wiki/Title');
happen.once(selection.selectAll('.wiki-title').node(), { type: 'change' });
expect(iD.utilGetSetValue(selection.selectAll('.wiki-lang'))).to.equal('Deutsch');
expect(iD.utilGetSetValue(selection.selectAll('.wiki-title'))).to.equal('Title');
done();
}, 20);
expect(iD.utilGetSetValue(selection.selectAll('.wiki-lang'))).to.equal('Deutsch');
expect(iD.utilGetSetValue(selection.selectAll('.wiki-title'))).to.equal('Title');
});
describe('encodePath', function() {
it('returns an encoded URI component that contains the title with spaces replaced by underscores', function(done) {
it('returns an encoded URI component that contains the title with spaces replaced by underscores', () => {
var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]);
expect(wikipedia.encodePath('? (film)', undefined)).to.equal('%3F_(film)');
done();
});
it('returns an encoded URI component that includes an anchor fragment', function(done) {
it('returns an encoded URI component that includes an anchor fragment', () => {
var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]);
// this can be tested manually by entering '? (film)#Themes and style in the search box before focusing out'
expect(wikipedia.encodePath('? (film)', 'Themes and style')).to.equal('%3F_(film)#Themes_and_style');
done();
});
});
describe('encodeURIAnchorFragment', function() {
it('returns an encoded URI anchor fragment', function(done) {
it('returns an encoded URI anchor fragment', () => {
var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]);
// this can be similarly tested by entering 'Section#Arts, entertainment and media' in the search box before focusing out'
expect(wikipedia.encodeURIAnchorFragment('Theme?')).to.equal('#Theme%3F');
done();
});
it('replaces all whitespace characters with underscore', function(done) {
it('replaces all whitespace characters with underscore', () => {
var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]);
expect(wikipedia.encodeURIAnchorFragment('Themes And Styles')).to.equal('#Themes_And_Styles');
done();
});
it('encodes % characters, does not replace them with a dot', function(done) {
it('encodes % characters, does not replace them with a dot', () => {
var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]);
expect(wikipedia.encodeURIAnchorFragment('Is%this_100% correct')).to.equal('#Is%25this_100%25_correct');
done();
});
it('encodes characters that are URI encoded characters', function (done) {
it('encodes characters that are URI encoded characters', () => {
var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]);
expect(wikipedia.encodeURIAnchorFragment('Section %20%25')).to.equal('#Section_%2520%2525');
done();
});
});
// note - currently skipping the tests that use `options` to delay responses
it('preserves existing language', function(done) {
it('preserves existing language', async () => {
var wikipedia1 = iD.uiFieldWikipedia(field, context);
window.setTimeout(function() { // async, so data will be available
selection.call(wikipedia1);
iD.utilGetSetValue(selection.selectAll('.wiki-lang'), 'Deutsch');
await setTimeout(20);
selection.call(wikipedia1);
iD.utilGetSetValue(selection.selectAll('.wiki-lang'), 'Deutsch');
var wikipedia2 = iD.uiFieldWikipedia(field, context);
window.setTimeout(function() { // async, so data will be available
selection.call(wikipedia2);
wikipedia2.tags({});
expect(iD.utilGetSetValue(selection.selectAll('.wiki-lang'))).to.equal('Deutsch');
done();
}, 20);
}, 20);
var wikipedia2 = iD.uiFieldWikipedia(field, context);
await setTimeout(20);
selection.call(wikipedia2);
wikipedia2.tags({});
expect(iD.utilGetSetValue(selection.selectAll('.wiki-lang'))).to.equal('Deutsch');
});
it.skip('does not set delayed wikidata tag if graph has changed', function(done) {
it.skip('does not set delayed wikidata tag if graph has changed', async () => {
var wikipedia = iD.uiFieldWikipedia(field, context).entityIDs([entity.id]);
wikipedia.on('change', changeTags);
selection.call(wikipedia);
@@ -227,16 +214,13 @@ describe('iD.uiFieldWikipedia', function() {
// t90: at t30 + 60ms (delay), wikidata SHOULD be set because graph is unchanged.
// t100: check that wikidata has changed
window.setTimeout(function() {
expect(context.entity(entity.id).tags.wikidata).to.equal('Q216353');
expect(spy.callCount).to.equal(4);
expect(spy.getCall(0)).to.have.been.calledWith({ wikipedia: 'de:Skip' }); // 'Skip' on change
expect(spy.getCall(1)).to.have.been.calledWith({ wikipedia: 'de:Skip' }); // 'Skip' on blur
expect(spy.getCall(2)).to.have.been.calledWith({ wikipedia: 'de:Title' }); // 'Title' on change +10ms
expect(spy.getCall(3)).to.have.been.calledWith({ wikipedia: 'de:Title' }); // 'Title' on blur +10ms
done();
}, 100);
await setTimeout(100);
expect(context.entity(entity.id).tags.wikidata).to.equal('Q216353');
expect(spy.callCount).to.equal(4);
expect(spy.getCall(0)).to.have.been.calledWith({ wikipedia: 'de:Skip' }); // 'Skip' on change
expect(spy.getCall(1)).to.have.been.calledWith({ wikipedia: 'de:Skip' }); // 'Skip' on blur
expect(spy.getCall(2)).to.have.been.calledWith({ wikipedia: 'de:Title' }); // 'Title' on change +10ms
expect(spy.getCall(3)).to.have.been.calledWith({ wikipedia: 'de:Title' }); // 'Title' on blur +10ms
});
});
+9 -9
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.uiFlash', function () {
var context;
@@ -24,16 +26,14 @@ describe('iD.uiFlash', function () {
expect(footerWrap.classed('footer-hide')).to.be.ok;
});
it('flash goes away', function(done) {
it('flash goes away', async () => {
iD.uiFlash(context).duration(200)();
window.setTimeout(function() {
d3.timerFlush();
var flashWrap = d3.selectAll('.flash-wrap');
var footerWrap = d3.selectAll('.main-footer-wrap');
expect(flashWrap.classed('footer-hide')).to.be.ok;
expect(footerWrap.classed('footer-show')).to.be.ok;
done();
}, 225);
await setTimeout(225);
d3.timerFlush();
var flashWrap = d3.selectAll('.flash-wrap');
var footerWrap = d3.selectAll('.main-footer-wrap');
expect(flashWrap.classed('footer-hide')).to.be.ok;
expect(footerWrap.classed('footer-show')).to.be.ok;
});
});
+18 -24
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.uiModal', function () {
var elem;
@@ -22,46 +24,38 @@ describe('iD.uiModal', function () {
expect(selection.selectAll('div.content').size()).to.equal(1);
});
it('can be dismissed by calling close function', function (done) {
it('can be dismissed by calling close function', async () => {
var selection = iD.uiModal(elem);
selection.close();
window.setTimeout(function() {
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
done();
}, 275);
await setTimeout(275);
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
});
it('can be dismissed by clicking the close button', function (done) {
it('can be dismissed by clicking the close button', async () => {
var selection = iD.uiModal(elem);
happen.click(selection.select('button.close').node());
window.setTimeout(function() {
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
done();
}, 275);
await setTimeout(275);
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
});
it('can be dismissed by pressing escape', function (done) {
it('can be dismissed by pressing escape', async () => {
var selection = iD.uiModal(elem);
happen.keydown(document, {keyCode: 27});
happen.keyup(document, {keyCode: 27});
window.setTimeout(function() {
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
done();
}, 275);
await setTimeout(275);
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
});
it('can be dismissed by pressing backspace', function (done) {
it('can be dismissed by pressing backspace', async () => {
var selection = iD.uiModal(elem);
happen.keydown(document, {keyCode: 8});
happen.keyup(document, {keyCode: 8});
window.setTimeout(function() {
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
done();
}, 275);
await setTimeout(275);
d3.timerFlush();
expect(selection.node().parentNode).to.be.null;
});
});
+19 -23
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.uiSectionRawTagEditor', function() {
var taglist, element, entity, context;
@@ -39,42 +41,36 @@ describe('iD.uiSectionRawTagEditor', function() {
expect(element.select('.tag-list').selectAll('input.key').property('value')).to.be.empty;
});
it('adds tags when clicking the add button', function (done) {
it('adds tags when clicking the add button', async () => {
happen.click(element.selectAll('button.add-tag').node());
setTimeout(function() {
expect(element.select('.tag-list').selectAll('input').nodes()[2].value).to.be.empty;
expect(element.select('.tag-list').selectAll('input').nodes()[3].value).to.be.empty;
done();
}, 20);
await setTimeout(20);
expect(element.select('.tag-list').selectAll('input').nodes()[2].value).to.be.empty;
expect(element.select('.tag-list').selectAll('input').nodes()[3].value).to.be.empty;
});
it('removes tags when clicking the remove button', function (done) {
taglist.on('change', function(entityIDs, tags) {
expect(tags).to.eql({highway: undefined});
done();
});
it('removes tags when clicking the remove button', async () => {
iD.utilTriggerEvent(element.selectAll('button.remove'), 'mousedown', { button: 0 });
const tags = await new Promise(cb => {
taglist.on('change', (_, tags) => cb(tags));
});
expect(tags).to.eql({highway: undefined});
});
it('adds tags when pressing the TAB key on last input.value', function (done) {
it('adds tags when pressing the TAB key on last input.value', async () => {
expect(element.selectAll('.tag-list li').nodes().length).to.eql(1);
var input = d3.select('.tag-list li:last-child input.value').nodes()[0];
happen.keydown(d3.select(input).node(), {keyCode: 9});
setTimeout(function() {
expect(element.selectAll('.tag-list li').nodes().length).to.eql(2);
expect(element.select('.tag-list').selectAll('input').nodes()[2].value).to.be.empty;
expect(element.select('.tag-list').selectAll('input').nodes()[3].value).to.be.empty;
done();
}, 20);
await setTimeout(20);
expect(element.selectAll('.tag-list li').nodes().length).to.eql(2);
expect(element.select('.tag-list').selectAll('input').nodes()[2].value).to.be.empty;
expect(element.select('.tag-list').selectAll('input').nodes()[3].value).to.be.empty;
});
it('does not add a tag when pressing TAB while shift is pressed', function (done) {
it('does not add a tag when pressing TAB while shift is pressed', async () => {
expect(element.selectAll('.tag-list li').nodes().length).to.eql(1);
var input = d3.select('.tag-list li:last-child input.value').nodes()[0];
happen.keydown(d3.select(input).node(), {keyCode: 9, shiftKey: true});
setTimeout(function() {
expect(element.selectAll('.tag-list li').nodes().length).to.eql(1);
done();
}, 20);
await setTimeout(20);
expect(element.selectAll('.tag-list li').nodes().length).to.eql(1);
});
});
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.validations.mutually_exclusive_tags', function () {
var context;
@@ -22,71 +24,61 @@ describe('iD.validations.mutually_exclusive_tags', function () {
}
it('has no errors on init', function(done) {
it('has no errors on init', async () => {
var validator = iD.validationMutuallyExclusiveTags(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
});
it('has no errors on good tags', function(done) {
it('has no errors on good tags', async () => {
createNode({'name': 'Trader Joe', 'not:name': 'Trader Jane'});
var validator = iD.validationMutuallyExclusiveTags(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
});
it('flags mutually exclusive tags', function(done) {
it('flags mutually exclusive tags', async () => {
createNode({'name': 'Trader Joe', 'noname': 'yes'});
var validator = iD.validationMutuallyExclusiveTags(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('mutually_exclusive_tags');
expect(issue.subtype).to.eql('default');
expect(issue.severity).to.eql('warning');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('n-1');
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('mutually_exclusive_tags');
expect(issue.subtype).to.eql('default');
expect(issue.severity).to.eql('warning');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('n-1');
});
it('flags feature with a mutually exclusive `not:name` value', function(done) {
it('flags feature with a mutually exclusive `not:name` value', async () => {
createNode({ shop: 'supermarket', name: 'Lous', 'not:name': 'Lous' });
var validator = iD.validationMutuallyExclusiveTags(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('mutually_exclusive_tags');
expect(issue.subtype).to.eql('same_value');
expect(issue.severity).to.eql('warning');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('n-1');
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('mutually_exclusive_tags');
expect(issue.subtype).to.eql('same_value');
expect(issue.severity).to.eql('warning');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('n-1');
});
it('flags feature with a mutually exclusive semicolon-separated `not:name` value', function(done) {
it('flags feature with a mutually exclusive semicolon-separated `not:name` value', async () => {
createNode({ shop: 'supermarket', name: 'Lous', 'not:name': 'Louis\';Lous;Louis\'s' });
var validator = iD.validationMutuallyExclusiveTags(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('mutually_exclusive_tags');
expect(issue.subtype).to.eql('same_value');
expect(issue.severity).to.eql('warning');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('n-1');
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('mutually_exclusive_tags');
expect(issue.subtype).to.eql('same_value');
expect(issue.severity).to.eql('warning');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('n-1');
});
});
+38 -48
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.validations.outdated_tags', function () {
var context;
@@ -55,74 +57,62 @@ describe('iD.validations.outdated_tags', function () {
return issues;
}
it('has no errors on init', function(done) {
it('has no errors on init', async () => {
var validator = iD.validationOutdatedTags(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
});
it('has no errors on good tags', function(done) {
it('has no errors on good tags', async () => {
createWay({'highway': 'unclassified'});
var validator = iD.validationOutdatedTags(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
});
it('flags deprecated tag with replacement', function(done) {
it('flags deprecated tag with replacement', async () => {
createWay({'highway': 'ford'});
var validator = iD.validationOutdatedTags(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('outdated_tags');
expect(issue.subtype).to.eql('deprecated_tags');
expect(issue.severity).to.eql('warning');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('w-1');
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('outdated_tags');
expect(issue.subtype).to.eql('deprecated_tags');
expect(issue.severity).to.eql('warning');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('w-1');
});
it('flags deprecated tag with no replacement', function(done) {
it('flags deprecated tag with no replacement', async () => {
createWay({'highway': 'no'});
var validator = iD.validationOutdatedTags(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('outdated_tags');
expect(issue.subtype).to.eql('deprecated_tags');
expect(issue.severity).to.eql('warning');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('w-1');
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('outdated_tags');
expect(issue.subtype).to.eql('deprecated_tags');
expect(issue.severity).to.eql('warning');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('w-1');
});
it('ignores way with no relations', function(done) {
it('ignores way with no relations', async () => {
createWay({});
var validator = iD.validationOutdatedTags(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
});
it('ignores multipolygon tagged on the relation', function(done) {
it('ignores multipolygon tagged on the relation', async () => {
createRelation({}, { type: 'multipolygon', building: 'yes' });
var validator = iD.validationOutdatedTags(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
});
});
+62 -80
View File
@@ -1,3 +1,5 @@
import { setTimeout } from 'node:timers/promises';
describe('iD.validations.suspicious_name', function () {
var context;
@@ -69,123 +71,103 @@ describe('iD.validations.suspicious_name', function () {
return issues;
}
it('has no errors on init', function(done) {
it('has no errors on init', async () => {
var validator = iD.validationSuspiciousName(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
});
it('ignores way with no tags', function(done) {
it('ignores way with no tags', async () => {
createWay({});
var validator = iD.validationSuspiciousName(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
});
it('ignores feature with no name', function(done) {
it('ignores feature with no name', async () => {
createWay({ shop: 'supermarket' });
var validator = iD.validationSuspiciousName(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
});
it('ignores feature with a specific name', function(done) {
it('ignores feature with a specific name', async () => {
createWay({ shop: 'supermarket', name: 'Lou\'s' });
var validator = iD.validationSuspiciousName(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
});
it('ignores feature with a specific name that includes a generic name', function(done) {
it('ignores feature with a specific name that includes a generic name', async () => {
createWay({ shop: 'supermarket', name: 'Lou\'s Store' });
var validator = iD.validationSuspiciousName(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
});
it('ignores feature matching excludeNamed pattern in name-suggestion-index', function(done) {
it('ignores feature matching excludeNamed pattern in name-suggestion-index', async () => {
createWay({ shop: 'supermarket', name: 'famiglia cooperativa' });
var validator = iD.validationSuspiciousName(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(0);
});
it('flags feature matching a excludeGeneric pattern in name-suggestion-index', function(done) {
it('flags feature matching a excludeGeneric pattern in name-suggestion-index', async () => {
createWay({ shop: 'supermarket', name: 'super mercado' });
var validator = iD.validationSuspiciousName(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('suspicious_name');
expect(issue.subtype).to.eql('generic_name');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('w-1');
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('suspicious_name');
expect(issue.subtype).to.eql('generic_name');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('w-1');
});
it('flags feature matching a global exclude pattern in name-suggestion-index', function(done) {
it('flags feature matching a global exclude pattern in name-suggestion-index', async () => {
createWay({ shop: 'supermarket', name: 'store' });
var validator = iD.validationSuspiciousName(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('suspicious_name');
expect(issue.subtype).to.eql('generic_name');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('w-1');
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('suspicious_name');
expect(issue.subtype).to.eql('generic_name');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('w-1');
});
it('flags feature with a name that is just a defining tag key', function(done) {
it('flags feature with a name that is just a defining tag key', async () => {
createWay({ amenity: 'drinking_water', name: 'Amenity' });
var validator = iD.validationSuspiciousName(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('suspicious_name');
expect(issue.subtype).to.eql('generic_name');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('w-1');
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('suspicious_name');
expect(issue.subtype).to.eql('generic_name');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('w-1');
});
it('flags feature with a name that is just a defining tag value', function(done) {
it('flags feature with a name that is just a defining tag value', async () => {
createWay({ shop: 'red_bicycle_emporium', name: 'Red Bicycle Emporium' });
var validator = iD.validationSuspiciousName(context);
window.setTimeout(function() { // async, so data will be available
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('suspicious_name');
expect(issue.subtype).to.eql('generic_name');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('w-1');
done();
}, 20);
await setTimeout(20);
var issues = validate(validator);
expect(issues).to.have.lengthOf(1);
var issue = issues[0];
expect(issue.type).to.eql('suspicious_name');
expect(issue.subtype).to.eql('generic_name');
expect(issue.entityIds).to.have.lengthOf(1);
expect(issue.entityIds[0]).to.eql('w-1');
});
it('flags feature with a name that matches the preset name', async () => {
-27
View File
@@ -34,33 +34,6 @@ UIEvent.prototype.initUIEvent = function (...args) {
return initUIEvent.apply(this, args);
};
// vitest has deprecated the done() callback, so we overwrite the `it` function
const _it = it;
Reflect.set(
global,
'it',
Object.assign(
(msg: string, fn: (done?: (err?: any) => void) => void | Promise<void>) => {
_it(msg, () => {
if (fn.length) {
// there is a done callback -> return a promise instead
return new Promise<void>((resolve, reject) => fn(err => {
if (err) {
reject(err);
} else {
resolve();
}
}));
} else {
// no done callback -> normal behaviour
return fn();
}
});
},
{ todo: _it.todo, skip: _it.skip, only: _it.only, each: _it.each },
),
);
// must be imported after global envs are defined
await import('../modules/id.js');
const iD = global.iD;