From bb84962e5d1a7ab9e680dbb491ea3aef6590e2a9 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 16 Aug 2021 13:23:38 -0400 Subject: [PATCH 01/10] Only insert sources into the fileMap if not already there This allows us to setup the fileMap correctly for testing so that it never tries to fetch assets from the CDN. --- modules/core/localizer.js | 27 ++++++++++++--------------- modules/services/nsi.js | 2 +- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/modules/core/localizer.js b/modules/core/localizer.js index 12e5df0ed..ebb3ecb22 100644 --- a/modules/core/localizer.js +++ b/modules/core/localizer.js @@ -78,14 +78,11 @@ export function coreLocalizer() { var _loadPromise; localizer.ensureLoaded = () => { - if (_loadPromise) return _loadPromise; let filesToFetch = [ - // load the list of languages - 'languages', - // load the list of supported locales - 'locales' + 'languages', // load the list of languages + 'locales' // load the list of supported locales ]; const localeDirs = { @@ -95,8 +92,10 @@ export function coreLocalizer() { let fileMap = fileFetcher.fileMap(); for (let scopeId in localeDirs) { - let key = `locales_index_${scopeId}`; - fileMap[key] = localeDirs[scopeId] + '/index.min.json'; + const key = `locales_index_${scopeId}`; + if (!fileMap[key]) { + fileMap[key] = localeDirs[scopeId] + '/index.min.json'; + } filesToFetch.push(key); } @@ -106,16 +105,12 @@ export function coreLocalizer() { _dataLocales = results[1]; let indexes = results.slice(2); - let requestedLocales = (_preferredLocaleCodes || []) - // List of locales preferred by the browser in priority order. - .concat(utilDetect().browserLocales) - // fallback to English since it's the only guaranteed complete language - .concat(['en']); + .concat(utilDetect().browserLocales) // List of locales preferred by the browser in priority order. + .concat(['en']); // fallback to English since it's the only guaranteed complete language _localeCodes = localesToUseFrom(requestedLocales); - // Run iD in the highest-priority locale; the rest are fallbacks - _localeCode = _localeCodes[0]; + _localeCode = _localeCodes[0]; // Run iD in the highest-priority locale; the rest are fallbacks let loadStringsPromises = []; @@ -198,7 +193,9 @@ export function coreLocalizer() { let fileMap = fileFetcher.fileMap(); const key = `locale_${scopeId}_${locale}`; - fileMap[key] = `${directory}/${locale}.min.json`; + if (!fileMap[key]) { + fileMap[key] = `${directory}/${locale}.min.json`; + } return fileFetcher.get(key) .then(d => { diff --git a/modules/services/nsi.js b/modules/services/nsi.js index d3094ef29..06cc94f92 100644 --- a/modules/services/nsi.js +++ b/modules/services/nsi.js @@ -59,7 +59,7 @@ function setNsiSources() { let fileMap = fileFetcher.fileMap(); for (const k in sources) { - fileMap[k] = sources[k]; + if (!fileMap[k]) fileMap[k] = sources[k]; } } From 5aee120a86494e7fb877252d47cc3514970ddd51 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 16 Aug 2021 14:02:25 -0400 Subject: [PATCH 02/10] Prefill the locale_tagging_en with fake string data This avoids the numerous "missing translation" errors filling up the console --- test/spec/spec_helpers.js | 90 ++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 15 deletions(-) diff --git a/test/spec/spec_helpers.js b/test/spec/spec_helpers.js index 97f08cec6..137ca83b4 100644 --- a/test/spec/spec_helpers.js +++ b/test/spec/spec_helpers.js @@ -6,30 +6,90 @@ iD.debug = true; for (var k in iD.services) { delete iD.services[k]; } // Run without data for speed (tests which need data can set it up themselves) - iD.fileFetcher.assetPath('../dist/'); +var cached = iD.fileFetcher.cache(); // Initializing `coreContext` will try loading the locale data and English locale strings: -iD.fileFetcher.cache().locales = { en: { rtl: false, pct: 1}}; -iD.fileFetcher.cache().locales_index_tagging = { en: { rtl: false, pct: 1 } }; -iD.fileFetcher.cache().locale_tagging_en = { en: {} }; -iD.fileFetcher.cache().locales_index_general = { en: { rtl: false, pct: 1 } }; -// load the actual data for `iD.fileFetcher.cache().locale_general_en` +cached.locales = { en: { rtl: false, pct: 1 } }; +cached.locales_index_general = { en: { rtl: false, pct: 1 } }; +cached.locales_index_tagging = { en: { rtl: false, pct: 1 } }; + +// Use fake data for the 'tagging' scope +cached.locale_tagging_en = { + en: { + presets: { + fields: { + restrictions: { + label: 'Turn Restrictions' + }, + access: { + label: 'Allowed Access', + placeholder: 'Not Specified', + types: { + access: 'All', + foot: 'Foot', + motor_vehicle: 'Motor Vehicles', + bicycle: 'Bicycles', + horse: 'Horses' + }, + options: { + yes: { + title: 'Allowed', + description: 'Access allowed by law; a right of way' + }, + no: { + title: 'Prohibited', + description: 'Access not allowed to the general public' + }, + permissive: { + title: 'Permissive', + description: 'Access allowed until such time as the owner revokes the permission' + }, + private: { + title: 'Private', + description: 'Access allowed only with permission of the owner on an individual basis' + }, + designated: { + title: 'Designated', + description: 'Access allowed according to signs or specific local laws' + }, + destination: { + title: 'Destination', + description: 'Access allowed only to reach a destination' + }, + dismount: { + title: 'Dismount', + description: 'Access allowed but rider must dismount' + }, + permit: { + title: 'Permit', + description: 'Access allowed only with a valid permit or license' + } + } + } + } + } + } +}; + +// Load the actual data from `dist/locales/` for the 'general' scope iD.localizer.loadLocale('en', 'general', 'locales'); +// Load the fake data seeded above for the 'tagging' scope +iD.localizer.loadLocale('en', 'tagging'); + // Initializing `coreContext` initializes `_background`, which tries loading: -iD.fileFetcher.cache().imagery = []; +cached.imagery = []; // Initializing `coreContext` initializes `_presets`, which tries loading: -iD.fileFetcher.cache().preset_categories = {}; -iD.fileFetcher.cache().preset_defaults = {}; -iD.fileFetcher.cache().preset_fields = {}; -iD.fileFetcher.cache().preset_presets = {}; - +cached.preset_categories = {}; +cached.preset_defaults = {}; +cached.preset_fields = {}; +cached.preset_presets = {}; // Initializing `coreContext` initializes `_validator`, which tries loading: -iD.fileFetcher.cache().deprecated = []; - +cached.deprecated = []; // Initializing `coreContext` initializes `_uploader`, which tries loading: -iD.fileFetcher.cache().discarded = {}; +cached.discarded = {}; + mocha.setup({ timeout: 5000, // 5 sec From 746417e1f4f59e3ba0dd9cb3d7cac8bda1e0ee88 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 16 Aug 2021 14:11:36 -0400 Subject: [PATCH 03/10] Fix coreLocations tests access of locationSetID property --- test/spec/core/locations.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/spec/core/locations.js b/test/spec/core/locations.js index cf1706060..230e2de2e 100644 --- a/test/spec/core/locations.js +++ b/test/spec/core/locations.js @@ -62,8 +62,8 @@ describe('iD.coreLocations', function() { prom .then(function(data) { expect(data).to.be.a('array'); - expect(data[0]).locationSetID.to.eql('+[Q2]'); - expect(data[1]).locationSetID.to.eql('+[Q30]'); + expect(data[0].locationSetID).to.eql('+[Q2]'); + expect(data[1].locationSetID).to.eql('+[Q30]'); }) .finally(done); @@ -79,8 +79,8 @@ describe('iD.coreLocations', function() { prom .then(function(data) { expect(data).to.be.a('array'); - expect(data[0]).locationSetID.to.eql('+[Q2]'); - expect(data[1]).locationSetID.to.eql('+[Q2]'); + expect(data[0].locationSetID).to.eql('+[Q2]'); + expect(data[1].locationSetID).to.eql('+[Q2]'); }) .finally(done); From 1282d3b0599ce2b63ef4a1ac3e34d432bf16c156 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 16 Aug 2021 14:23:24 -0400 Subject: [PATCH 04/10] Don't use a util function for a thing that exists 1x in the code --- modules/core/file_fetcher.js | 11 +++++++++-- modules/util/index.js | 1 - modules/util/util.js | 11 ----------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/modules/core/file_fetcher.js b/modules/core/file_fetcher.js index 5ba723b81..a8196f14e 100644 --- a/modules/core/file_fetcher.js +++ b/modules/core/file_fetcher.js @@ -1,4 +1,3 @@ -import { utilFetchJson } from '../util/util'; import parseVersion from 'vparse'; // Double check this resolves to iD's `package.json` import packageJSON from '../../package.json'; @@ -60,7 +59,15 @@ export function coreFileFetcher() { let prom = _inflight[url]; if (!prom) { - _inflight[url] = prom = utilFetchJson(url) + _inflight[url] = prom = fetch(url) + .then(response => { + // fetch in PhantomJS tests may return ok=false and status=0 even if it's okay + if ((!response.ok && response.status !== 0) || !response.json) { + throw new Error(response.status + ' ' + response.statusText); + } + if (response.status === 204 || response.status === 205) return; // No Content, Reset Content + return response.json(); + }) .then(result => { delete _inflight[url]; if (!result) { diff --git a/modules/util/index.js b/modules/util/index.js index 3c0836aed..45e1266ef 100644 --- a/modules/util/index.js +++ b/modules/util/index.js @@ -27,7 +27,6 @@ export { utilEntityOrMemberSelector } from './util'; export { utilEntityOrDeepMemberSelector } from './util'; export { utilEntitySelector } from './util'; export { utilFastMouse } from './util'; -export { utilFetchJson } from './util'; export { utilFunctor } from './util'; export { utilGetAllNodes } from './util'; export { utilGetSetValue } from './get_set_value'; diff --git a/modules/util/util.js b/modules/util/util.js index 53c8c0d24..388ba7261 100644 --- a/modules/util/util.js +++ b/modules/util/util.js @@ -580,14 +580,3 @@ export function utilUnicodeCharsCount(str) { export function utilUnicodeCharsTruncated(str, limit) { return Array.from(str).slice(0, limit).join(''); } - -// Variation of d3.json (https://github.com/d3/d3-fetch/blob/master/src/json.js) -export function utilFetchJson(resourse, init) { - return fetch(resourse, init) - .then((response) => { - // fetch in PhantomJS tests may return ok=false and status=0 even if it's okay - if ((!response.ok && response.status !== 0) || !response.json) throw new Error(response.status + ' ' + response.statusText); - if (response.status === 204 || response.status === 205) return; - return response.json(); - }); -} From e7ad3845f94069cff7bb6804afe3595b11ed85cb Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 16 Aug 2021 15:23:31 -0400 Subject: [PATCH 05/10] Fix file fetcher tests that touch the intro_graph - Before it wasn't actually loading the intro graph because assetPath not set - The test for Three Rivers City Hall was using the wrong nodeid - All these test errors were being ignored because of the use of .finally(done) - To actually make an error happen, we can call `done(err)` with the Error --- test/spec/core/file_fetcher.js | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/test/spec/core/file_fetcher.js b/test/spec/core/file_fetcher.js index 47aec5888..5f82f2053 100644 --- a/test/spec/core/file_fetcher.js +++ b/test/spec/core/file_fetcher.js @@ -1,14 +1,5 @@ describe('iD.coreFileFetcher', function() { - before(function() { - iD.fileFetcher.cache().test = { hello: 'world' }; - }); - - after(function() { - delete iD.fileFetcher.cache().test; - }); - - describe('#fileMap', function() { it('gets the fileMap', function() { var data = iD.coreFileFetcher(); @@ -24,44 +15,52 @@ describe('iD.coreFileFetcher', function() { describe('#get', function() { it('returns a promise resolved if we already have the data', function(done) { var data = iD.coreFileFetcher(); + data.cache().test = { hello: 'world' }; + var prom = data.get('test'); // expect(prom).to.be.a('promise'); // these are polyfilled in phantomjs prom .then(function(data) { expect(data).to.be.a('object'); expect(data.hello).to.eql('world'); + done(); }) - .finally(done); + .catch(function(err) { + done(err); + }); window.setTimeout(function() {}, 20); // async - to let the promise settle in phantomjs }); it('returns a promise rejected if we can not get the data', function(done) { - var data = iD.coreFileFetcher(); + var data = iD.coreFileFetcher().assetPath('../dist/'); var prom = data.get('wat'); prom .then(function(data) { - throw new Error('We were not supposed to get data but did: ' + 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; - }) - .finally(done); + done(); + }); window.setTimeout(function() {}, 20); // async - to let the promise settle in phantomjs }); it('returns a promise to fetch data if we do not already have the data', function(done) { var files = { 'intro_graph': 'data/intro_graph.min.json' }; - var data = iD.coreFileFetcher().fileMap(files); + var data = iD.coreFileFetcher().assetPath('../dist/').fileMap(files); var prom = data.get('intro_graph'); // expect(prom).to.be.a('promise'); // these are polyfilled in phantomjs prom .then(function(data) { expect(data).to.be.a('object'); - expect(data.n1.tags.name).to.eql('Three Rivers City Hall'); + expect(data.n2061.tags.name).to.eql('Three Rivers City Hall'); + done(); }) - .finally(done); + .catch(function(err) { + done(err); + }); window.setTimeout(function() {}, 20); // async - to let the promise settle in phantomjs }); From 4f1d5f08516771dc4a4083ffcc1adf8173684546 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 16 Aug 2021 15:34:26 -0400 Subject: [PATCH 06/10] Similar to e7ad3845f, avoid using finally(done) as it swallows errors --- test/spec/core/locations.js | 21 +++++++++++++++------ test/spec/core/validator.js | 6 ++++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/test/spec/core/locations.js b/test/spec/core/locations.js index 230e2de2e..6fa094319 100644 --- a/test/spec/core/locations.js +++ b/test/spec/core/locations.js @@ -43,12 +43,12 @@ describe('iD.coreLocations', function() { var prom = locationManager.mergeLocationSets({}); prom .then(function() { - throw new Error('This was supposed to fail, but somehow succeeded.'); + done(new Error('This was supposed to fail, but somehow succeeded.')); }) .catch(function(err) { expect(/^nothing to do/.test(err)).to.be.true; - }) - .finally(done); + done(); + }); window.setTimeout(function() {}, 20); // async - to let the promise settle in phantomjs }); @@ -64,8 +64,11 @@ describe('iD.coreLocations', function() { expect(data).to.be.a('array'); expect(data[0].locationSetID).to.eql('+[Q2]'); expect(data[1].locationSetID).to.eql('+[Q30]'); + done(); }) - .finally(done); + .catch(function(err) { + done(err); + }); window.setTimeout(function() {}, 20); // async - to let the promise settle in phantomjs }); @@ -81,8 +84,11 @@ describe('iD.coreLocations', function() { expect(data).to.be.a('array'); expect(data[0].locationSetID).to.eql('+[Q2]'); expect(data[1].locationSetID).to.eql('+[Q2]'); + done(); }) - .finally(done); + .catch(function(err) { + done(err); + }); window.setTimeout(function() {}, 20); // async - to let the promise settle in phantomjs }); @@ -139,8 +145,11 @@ describe('iD.coreLocations', function() { expect(result2).to.be.an('object').that.has.all.keys('+[Q2]', '+[Q30]'); var result3 = locationManager.locationsAt([13.575, 41.207,]); // Gaeta expect(result3).to.be.an('object').that.has.all.keys('+[Q2]'); + done(); }) - .finally(done); + .catch(function(err) { + done(err); + }); window.setTimeout(function() {}, 20); // async - to let the promise settle in phantomjs }); diff --git a/test/spec/core/validator.js b/test/spec/core/validator.js index 8f8fc0cbb..525da71e6 100644 --- a/test/spec/core/validator.js +++ b/test/spec/core/validator.js @@ -40,9 +40,11 @@ describe('iD.coreValidator', function () { expect(issue.type).to.eql('missing_tag'); expect(issue.entityIds).to.have.lengthOf(1); expect(issue.entityIds[0]).to.eql('w-1'); - + done(); }) - .finally(done); + .catch(function(err) { + done(err); + }); window.setTimeout(function() {}, 20); // async - to let the promise settle in phantomjs }); From 33fab5580ba33410bb99f8f5f0862ba658869cc7 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 16 Aug 2021 22:06:42 -0400 Subject: [PATCH 07/10] Before calling init() make sure the assetPath is set init kicks off building the ui, which can fetch spritesheets for the The assetPath needs to be set otherwise these files will not be found --- test/spec/behavior/hash.js | 2 +- test/spec/behavior/lasso.js | 2 +- test/spec/behavior/select.js | 2 +- test/spec/core/context.js | 10 +++++----- test/spec/core/history.js | 2 +- test/spec/core/validator.js | 2 +- test/spec/modes/add_note.js | 4 +--- test/spec/modes/add_point.js | 6 +----- test/spec/renderer/features.js | 2 +- test/spec/renderer/map.js | 2 +- test/spec/renderer/tile_layer.js | 2 +- test/spec/services/osm.js | 2 +- test/spec/svg/areas.js | 2 +- test/spec/svg/data.js | 2 +- test/spec/svg/layers.js | 4 ++-- test/spec/svg/lines.js | 2 +- test/spec/svg/midpoints.js | 2 +- test/spec/svg/points.js | 2 +- test/spec/svg/vertices.js | 2 +- test/spec/ui/combobox.js | 2 +- test/spec/ui/fields/access.js | 2 +- test/spec/ui/fields/localized.js | 2 +- test/spec/ui/fields/wikipedia.js | 2 +- test/spec/ui/flash.js | 2 +- test/spec/ui/sections/raw_tag_editor.js | 2 +- test/spec/validations/almost_junction.js | 2 +- test/spec/validations/crossing_ways.js | 2 +- test/spec/validations/disconnected_way.js | 2 +- test/spec/validations/incompatible_source.js | 2 +- test/spec/validations/missing_role.js | 2 +- test/spec/validations/missing_tag.js | 2 +- test/spec/validations/private_data.js | 2 +- test/spec/validations/suspicious_name.js | 2 +- 33 files changed, 38 insertions(+), 44 deletions(-) diff --git a/test/spec/behavior/hash.js b/test/spec/behavior/hash.js index 767d149f0..c1af7adbe 100644 --- a/test/spec/behavior/hash.js +++ b/test/spec/behavior/hash.js @@ -5,7 +5,7 @@ describe('iD.behaviorHash', function () { beforeEach(function () { var container = d3.select(document.createElement('div')); - context = iD.coreContext().init().container(container); + context = iD.coreContext().assetPath('../dist/').init().container(container); container.call(context.map()); hash = iD.behaviorHash(context); }); diff --git a/test/spec/behavior/lasso.js b/test/spec/behavior/lasso.js index f342cec3c..b86add2e0 100644 --- a/test/spec/behavior/lasso.js +++ b/test/spec/behavior/lasso.js @@ -2,7 +2,7 @@ describe('iD.behaviorLasso', function () { var context, lasso; beforeEach(function () { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); d3.select(document.createElement('div')) .attr('class', 'main-map') .call(context.map()); diff --git a/test/spec/behavior/select.js b/test/spec/behavior/select.js index df7dfc9c8..3af70a808 100644 --- a/test/spec/behavior/select.js +++ b/test/spec/behavior/select.js @@ -3,7 +3,7 @@ describe('iD.behaviorSelect', function() { beforeEach(function() { container = d3.select('body').append('div'); - context = iD.coreContext().init().container(container); + context = iD.coreContext().assetPath('../dist/').init().container(container); a = iD.osmNode({loc: [0, 0]}); b = iD.osmNode({loc: [0, 0]}); diff --git a/test/spec/core/context.js b/test/spec/core/context.js index 6b603aafd..0e55ad0be 100644 --- a/test/spec/core/context.js +++ b/test/spec/core/context.js @@ -5,7 +5,7 @@ describe('iD.coreContext', function() { describe('#assetPath', function() { it('sets and gets assetPath', function() { - var context = iD.coreContext().init(); + var context = iD.coreContext(); expect(context.assetPath()).to.eql(''); context.assetPath('iD/'); @@ -15,7 +15,7 @@ describe('iD.coreContext', function() { describe('#assetMap', function() { it('sets and gets assetMap', function() { - var context = iD.coreContext().init(); + var context = iD.coreContext(); expect(context.assetMap()).to.eql({}); context.assetMap(assets); @@ -26,7 +26,7 @@ describe('iD.coreContext', function() { describe('#asset', function() { var context; beforeEach(function() { - context = iD.coreContext().assetPath('iD/').assetMap(assets).init(); + context = iD.coreContext().assetPath('iD/').assetMap(assets); }); it('ignores absolute urls', function() { @@ -44,7 +44,7 @@ describe('iD.coreContext', function() { describe('#imagePath', function() { var context; beforeEach(function() { - context = iD.coreContext().assetPath('iD/').assetMap(assets).init(); + context = iD.coreContext().assetPath('iD/').assetMap(assets); }); it('looks first in assetMap', function() { @@ -57,7 +57,7 @@ describe('iD.coreContext', function() { describe('#debug', function() { it('sets and gets debug flags', function() { - var context = iD.coreContext().init(); + var context = iD.coreContext(); var flags = { tile: false, collision: false, diff --git a/test/spec/core/history.js b/test/spec/core/history.js index 1bffa491a..d9313a454 100644 --- a/test/spec/core/history.js +++ b/test/spec/core/history.js @@ -8,7 +8,7 @@ describe('iD.coreHistory', function () { }; beforeEach(function () { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); history = context.history(); spy = sinon.spy(); // clear lock diff --git a/test/spec/core/validator.js b/test/spec/core/validator.js index 525da71e6..5e1f5ed37 100644 --- a/test/spec/core/validator.js +++ b/test/spec/core/validator.js @@ -2,7 +2,7 @@ describe('iD.coreValidator', function () { var context; beforeEach(function() { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); }); function createInvalidWay() { diff --git a/test/spec/modes/add_note.js b/test/spec/modes/add_note.js index 9c22c2d36..6650e8576 100644 --- a/test/spec/modes/add_note.js +++ b/test/spec/modes/add_note.js @@ -11,9 +11,7 @@ describe('iD.modeAddNote', function() { beforeEach(function() { var container = d3.select(document.createElement('div')); - context = iD.coreContext() - .container(container) - .init(); + context = iD.coreContext().assetPath('../dist/').container(container).init(); context.loadTiles = function () {}; diff --git a/test/spec/modes/add_point.js b/test/spec/modes/add_point.js index cb00a7fa4..cbf8720f1 100644 --- a/test/spec/modes/add_point.js +++ b/test/spec/modes/add_point.js @@ -3,11 +3,7 @@ describe.skip('iD.modeAddPoint', function() { beforeEach(function() { var container = d3.select(document.createElement('div')); - - context = iD.coreContext() - .container(container) - .init(); - + context = iD.coreContext().assetPath('../dist/').container(container).init(); context.loadTiles = function () {}; container.call(context.map()) diff --git a/test/spec/renderer/features.js b/test/spec/renderer/features.js index 1a8e174a5..76752ea28 100644 --- a/test/spec/renderer/features.js +++ b/test/spec/renderer/features.js @@ -3,7 +3,7 @@ describe('iD.rendererFeatures', function() { var context, features; beforeEach(function() { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); d3.select(document.createElement('div')) .attr('class', 'main-map') .call(context.map()); diff --git a/test/spec/renderer/map.js b/test/spec/renderer/map.js index e71ce50de..38f270f5b 100644 --- a/test/spec/renderer/map.js +++ b/test/spec/renderer/map.js @@ -3,7 +3,7 @@ describe('iD.Map', function() { beforeEach(function() { content = d3.select('body').append('div'); - context = iD.coreContext().init().container(content); + context = iD.coreContext().assetPath('../dist/').init().container(content); map = context.map(); content.call(map); }); diff --git a/test/spec/renderer/tile_layer.js b/test/spec/renderer/tile_layer.js index 4dcbadb9c..9587e95e9 100644 --- a/test/spec/renderer/tile_layer.js +++ b/test/spec/renderer/tile_layer.js @@ -2,7 +2,7 @@ describe('iD.rendererTileLayer', function() { var context, d, c; beforeEach(function() { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); d = d3.select(document.createElement('div')); c = iD.rendererTileLayer(context).projection(d3.geoMercator()); }); diff --git a/test/spec/services/osm.js b/test/spec/services/osm.js index 3619e3270..bc5542ef6 100644 --- a/test/spec/services/osm.js +++ b/test/spec/services/osm.js @@ -27,7 +27,7 @@ describe('iD.serviceOsm', function () { beforeEach(function () { serverFetch = window.fakeFetch().create(); // unauthenticated calls use d3-fetch serverXHR = sinon.fakeServer.create(); // authenticated calls use XHR via osm-auth - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); connection = context.connection(); connection.switch({ urlroot: 'http://www.openstreetmap.org' }); connection.reset(); diff --git a/test/spec/svg/areas.js b/test/spec/svg/areas.js index f4652ac62..571698787 100644 --- a/test/spec/svg/areas.js +++ b/test/spec/svg/areas.js @@ -10,7 +10,7 @@ describe('iD.svgAreas', function () { beforeEach(function () { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); d3.select(document.createElement('div')) .attr('class', 'main-map') .call(context.map().centerZoom([0, 0], 17)); diff --git a/test/spec/svg/data.js b/test/spec/svg/data.js index 6e1b2d759..d064e1a77 100644 --- a/test/spec/svg/data.js +++ b/test/spec/svg/data.js @@ -81,7 +81,7 @@ describe('iD.svgData', function () { } beforeEach(function () { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); d3.select(document.createElement('div')) .attr('class', 'main-map') .call(context.map().centerZoom([-74.389286, 40.1502754], 17)); diff --git a/test/spec/svg/layers.js b/test/spec/svg/layers.js index 512d62f90..70d4b7f49 100644 --- a/test/spec/svg/layers.js +++ b/test/spec/svg/layers.js @@ -6,7 +6,7 @@ describe('iD.svgLayers', function () { .clipExtent([[0, 0], [Infinity, Infinity]]); beforeEach(function () { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); container = d3.select(document.createElement('div')); }); @@ -44,4 +44,4 @@ describe('iD.svgLayers', function () { expect(d3.select(nodes[14]).classed('touch')).to.be.true; }); -}); \ No newline at end of file +}); diff --git a/test/spec/svg/lines.js b/test/spec/svg/lines.js index 7ee42c6c6..e4f6c60b8 100644 --- a/test/spec/svg/lines.js +++ b/test/spec/svg/lines.js @@ -9,7 +9,7 @@ describe('iD.svgLines', function () { beforeEach(function () { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); d3.select(document.createElement('div')) .attr('class', 'main-map') .call(context.map().centerZoom([0, 0], 17)); diff --git a/test/spec/svg/midpoints.js b/test/spec/svg/midpoints.js index 723771a26..d3cd11919 100644 --- a/test/spec/svg/midpoints.js +++ b/test/spec/svg/midpoints.js @@ -9,7 +9,7 @@ describe('iD.svgMidpoints', function () { beforeEach(function () { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); context.enter({ id: 'select', enter: function() { }, diff --git a/test/spec/svg/points.js b/test/spec/svg/points.js index a41e4cb1d..51472e48f 100644 --- a/test/spec/svg/points.js +++ b/test/spec/svg/points.js @@ -6,7 +6,7 @@ describe('iD.svgPoints', function () { .clipExtent([[0, 0], [Infinity, Infinity]]); beforeEach(function () { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); d3.select(document.createElement('div')) .attr('class', 'main-map') .call(context.map().centerZoom([0, 0], 17)); diff --git a/test/spec/svg/vertices.js b/test/spec/svg/vertices.js index 2e1846332..cb79f1e66 100644 --- a/test/spec/svg/vertices.js +++ b/test/spec/svg/vertices.js @@ -8,7 +8,7 @@ describe('iD.svgVertices', function () { beforeEach(function () { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); d3.select(document.createElement('div')) .attr('class', 'main-map') .call(context.map().centerZoom([0, 0], 17)); diff --git a/test/spec/ui/combobox.js b/test/spec/ui/combobox.js index 6362018e8..1ea23de51 100644 --- a/test/spec/ui/combobox.js +++ b/test/spec/ui/combobox.js @@ -63,7 +63,7 @@ describe('uiCombobox', function() { beforeEach(function() { body = d3.select('body'); container = body.append('div').attr('class', 'ideditor'); - context = iD.coreContext().init().container(container); + context = iD.coreContext().assetPath('../dist/').init().container(container); content = container.append('div'); input = content.append('input'); combobox = iD.uiCombobox(context); diff --git a/test/spec/ui/fields/access.js b/test/spec/ui/fields/access.js index f629d4482..cab0f527d 100644 --- a/test/spec/ui/fields/access.js +++ b/test/spec/ui/fields/access.js @@ -2,7 +2,7 @@ describe('iD.uiFieldAccess', function() { var context, selection, field; beforeEach(function() { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); selection = d3.select(document.createElement('div')); field = iD.presetField('access', { keys: ['access', 'foot', 'motor_vehicle', 'bicycle', 'horse'], diff --git a/test/spec/ui/fields/localized.js b/test/spec/ui/fields/localized.js index b2ac474c0..56dc7ad7a 100644 --- a/test/spec/ui/fields/localized.js +++ b/test/spec/ui/fields/localized.js @@ -15,7 +15,7 @@ describe('iD.uiFieldLocalized', function() { }); beforeEach(function() { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); selection = d3.select(document.createElement('div')); field = iD.presetField('name', { key: 'name', type: 'localized' }); field.locked = function() { return false; }; diff --git a/test/spec/ui/fields/wikipedia.js b/test/spec/ui/fields/wikipedia.js index e45e4fe41..24583535c 100644 --- a/test/spec/ui/fields/wikipedia.js +++ b/test/spec/ui/fields/wikipedia.js @@ -18,7 +18,7 @@ describe('iD.uiFieldWikipedia', function() { beforeEach(function() { entity = iD.osmNode({id: 'n12345'}); - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); context.history().merge([entity]); selection = d3.select(document.createElement('div')); field = iD.presetField('wikipedia', { diff --git a/test/spec/ui/flash.js b/test/spec/ui/flash.js index ec2919f48..3a929f834 100644 --- a/test/spec/ui/flash.js +++ b/test/spec/ui/flash.js @@ -3,7 +3,7 @@ describe('iD.uiFlash', function () { beforeEach(function() { var container = d3.select('body'); - context = iD.coreContext().init().container(container); + context = iD.coreContext().assetPath('../dist/').init().container(container); container .append('div') .attr('class', 'flash-wrap') diff --git a/test/spec/ui/sections/raw_tag_editor.js b/test/spec/ui/sections/raw_tag_editor.js index 739d72849..5a9c9466e 100644 --- a/test/spec/ui/sections/raw_tag_editor.js +++ b/test/spec/ui/sections/raw_tag_editor.js @@ -16,7 +16,7 @@ describe('iD.uiSectionRawTagEditor', function() { beforeEach(function () { entity = iD.osmNode({id: 'n12345'}); - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); context.history().merge([entity]); render({highway: 'residential'}); }); diff --git a/test/spec/validations/almost_junction.js b/test/spec/validations/almost_junction.js index e9a6a2fc4..a08bfa4e0 100644 --- a/test/spec/validations/almost_junction.js +++ b/test/spec/validations/almost_junction.js @@ -2,7 +2,7 @@ describe('iD.validations.almost_junction', function () { var context; beforeEach(function() { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); }); function horizontalVertialCloserThanThd() { diff --git a/test/spec/validations/crossing_ways.js b/test/spec/validations/crossing_ways.js index a511b40a0..ae46b98f7 100644 --- a/test/spec/validations/crossing_ways.js +++ b/test/spec/validations/crossing_ways.js @@ -2,7 +2,7 @@ describe('iD.validations.crossing_ways', function () { var context; beforeEach(function() { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); }); function createWaysWithOneCrossingPoint(tags1, tags2) { diff --git a/test/spec/validations/disconnected_way.js b/test/spec/validations/disconnected_way.js index e10eab331..859b822c8 100644 --- a/test/spec/validations/disconnected_way.js +++ b/test/spec/validations/disconnected_way.js @@ -2,7 +2,7 @@ describe('iD.validations.disconnected_way', function () { var context; beforeEach(function() { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); }); function createWay(tags) { diff --git a/test/spec/validations/incompatible_source.js b/test/spec/validations/incompatible_source.js index 1801ac263..bb7c72952 100644 --- a/test/spec/validations/incompatible_source.js +++ b/test/spec/validations/incompatible_source.js @@ -2,7 +2,7 @@ describe('iD.validations.incompatible_source', function () { var context; beforeEach(function() { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); }); function createWay(tags) { diff --git a/test/spec/validations/missing_role.js b/test/spec/validations/missing_role.js index de63a4ecd..6401a8765 100644 --- a/test/spec/validations/missing_role.js +++ b/test/spec/validations/missing_role.js @@ -2,7 +2,7 @@ describe('iD.validations.missing_role', function () { var context; beforeEach(function() { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); }); function createWay(tags) { diff --git a/test/spec/validations/missing_tag.js b/test/spec/validations/missing_tag.js index 94aa7fe76..345faeb0a 100644 --- a/test/spec/validations/missing_tag.js +++ b/test/spec/validations/missing_tag.js @@ -2,7 +2,7 @@ describe('iD.validations.missing_tag', function () { var context; beforeEach(function() { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); }); function createWay(tags) { diff --git a/test/spec/validations/private_data.js b/test/spec/validations/private_data.js index bafbe0300..031e92ecf 100644 --- a/test/spec/validations/private_data.js +++ b/test/spec/validations/private_data.js @@ -2,7 +2,7 @@ describe('iD.validations.private_data', function () { var context; beforeEach(function() { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); }); function createWay(tags) { diff --git a/test/spec/validations/suspicious_name.js b/test/spec/validations/suspicious_name.js index 66b6446ee..bdd6d9cfd 100644 --- a/test/spec/validations/suspicious_name.js +++ b/test/spec/validations/suspicious_name.js @@ -38,7 +38,7 @@ describe('iD.validations.suspicious_name', function () { }); beforeEach(function() { - context = iD.coreContext().init(); + context = iD.coreContext().assetPath('../dist/').init(); }); function createWay(tags) { From 003628d6b089587070e31333ca9da977f4322cb1 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 16 Aug 2021 22:51:39 -0400 Subject: [PATCH 08/10] Try not to load imagery when running tests By default, the `rendererBackground` code will choose an initial imagery based on what sources are available at the given map location. It looks like this code will fallback to "custom" _before_ "none", and I noticed that in some cases it was trying to fetch whatever source happened to be stored in the "custom" template in localStorage. This commit adds an explicit window.location.hash in a few places to encourage the background layer to be "none". Some tests do change the hash, so this isn't perfect. --- test/spec/modes/add_note.js | 1 + test/spec/spec_helpers.js | 3 +++ 2 files changed, 4 insertions(+) diff --git a/test/spec/modes/add_note.js b/test/spec/modes/add_note.js index 6650e8576..def8159ae 100644 --- a/test/spec/modes/add_note.js +++ b/test/spec/modes/add_note.js @@ -2,6 +2,7 @@ describe('iD.modeAddNote', function() { var context; before(function() { + window.location.hash = '#background=none'; // Try not to load imagery iD.services.osm = iD.serviceOsm; }); diff --git a/test/spec/spec_helpers.js b/test/spec/spec_helpers.js index 137ca83b4..5fb66a4b7 100644 --- a/test/spec/spec_helpers.js +++ b/test/spec/spec_helpers.js @@ -5,6 +5,9 @@ iD.debug = true; // Disable things that use the network for (var k in iD.services) { delete iD.services[k]; } +// Try not to load imagery +window.location.hash = '#background=none'; + // Run without data for speed (tests which need data can set it up themselves) iD.fileFetcher.assetPath('../dist/'); var cached = iD.fileFetcher.cache(); From b2d18d1ebef342ea3448cedc0182d9804f125f18 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Wed, 18 Aug 2021 12:40:51 -0400 Subject: [PATCH 09/10] Fix hash tests in Chrome, avoid loading imagery tiles --- test/spec/behavior/hash.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/test/spec/behavior/hash.js b/test/spec/behavior/hash.js index c1af7adbe..f6d52b896 100644 --- a/test/spec/behavior/hash.js +++ b/test/spec/behavior/hash.js @@ -4,6 +4,7 @@ describe('iD.behaviorHash', function () { var hash, context; beforeEach(function () { + window.location.hash = '#background=none'; // Try not to load imagery var container = d3.select(document.createElement('div')); context = iD.coreContext().assetPath('../dist/').init().container(container); container.call(context.map()); @@ -12,17 +13,18 @@ describe('iD.behaviorHash', function () { afterEach(function () { hash.off(); - location.hash = ''; + window.location.hash = '#background=none'; // Try not to load imagery }); - it('sets hadHash if location.hash is present', function () { - location.hash = 'map=20.00/38.87952/-77.02405'; + + it('sets hadHash if window.location.hash is present', function () { + window.location.hash = '#background=none&map=20.00/38.87952/-77.02405'; hash(); expect(hash.hadHash).to.be.true; }); it('centerZooms map to requested level', function () { - location.hash = 'map=20.00/38.87952/-77.02405'; + window.location.hash = '#background=none&map=20.00/38.87952/-77.02405'; hash(); expect(context.map().center()[0]).to.be.closeTo(-77.02405, 0.1); expect(context.map().center()[1]).to.be.closeTo(38.87952, 0.1); @@ -38,16 +40,15 @@ describe('iD.behaviorHash', function () { d3.select(window).on('hashchange', null); done(); }); - location.hash = 'map=20.00/38.87952/-77.02405'; + window.location.hash = '#background=none&map=20.00/38.87952/-77.02405'; }); - it('stores the current zoom and coordinates in location.hash on map move events', function (done) { - location.hash = ''; + it('stores the current zoom and coordinates in window.location.hash on map move events', function (done) { hash(); context.map().center([-77.0, 38.9]); context.map().zoom(2.0); window.setTimeout(function() { - expect(location.hash).to.equal('#map=2.00/38.9/-77.0'); + expect(window.location.hash).to.equal('#background=none&map=2.00/38.9/-77.0'); done(); }, 300); }); From 08c765236fbf697a969923ca964c09cdfef2af10 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Wed, 18 Aug 2021 18:55:28 -0400 Subject: [PATCH 10/10] Force tests to use mouse events instead of pointer events The pointer events use a different mechanism for counting clicks that doesn't work when the tests are run in a real browser like Chrome. This change forces iD to always use mouse events during testing, even in a real browser. --- test/spec/behavior/select.js | 43 +++++++++++++++++++----------------- test/spec/spec_helpers.js | 1 + 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/test/spec/behavior/select.js b/test/spec/behavior/select.js index 3af70a808..606d25229 100644 --- a/test/spec/behavior/select.js +++ b/test/spec/behavior/select.js @@ -1,6 +1,15 @@ describe('iD.behaviorSelect', function() { var a, b, context, behavior, container; + function simulateClick(el, o) { + // clicks need to appear wherever the map is + var mapNode = context.container().select('.main-map').node(); + var rect = mapNode.getBoundingClientRect(); + var click = { clientX: rect.left, clientY: rect.top }; + happen.mousedown(el, Object.assign({}, click, o)); + happen.mouseup(el, Object.assign({}, click, o)); + } + beforeEach(function() { container = d3.select('body').append('div'); context = iD.coreContext().assetPath('../dist/').init().container(container); @@ -34,77 +43,71 @@ describe('iD.behaviorSelect', function() { container.remove(); }); - specify('refuse to enter select mode with no ids', function() { + it('refuses to enter select mode with no ids', function() { context.enter(iD.modeSelect(context, [])); expect(context.mode().id, 'empty array').to.eql('browse'); context.enter(iD.modeSelect(context, undefined)); expect(context.mode().id, 'undefined').to.eql('browse'); }); - specify('refuse to enter select mode with nonexistent ids', function() { + it('refuses to enter select mode with nonexistent ids', function() { context.enter(iD.modeSelect(context, ['w-1'])); expect(context.mode().id).to.eql('browse'); }); - specify('click on entity selects the entity', function(done) { + it('click on entity selects the entity', function(done) { var el = context.surface().selectAll('.' + a.id).node(); - happen.mousedown(el, { clientX: 100, clientY: 100 }); - happen.mouseup(el, { clientX: 100, clientY: 100 }); + simulateClick(el, {}); window.setTimeout(function() { expect(context.selectedIDs()).to.eql([a.id]); done(); }, 50); }); - specify('click on empty space clears the selection', function(done) { + it('click on empty space clears the selection', function(done) { context.enter(iD.modeSelect(context, [a.id])); var el = context.surface().node(); - happen.mousedown(el, { clientX: 100, clientY: 100 }); - happen.mouseup(el, { clientX: 100, clientY: 100 }); + simulateClick(el, {}); window.setTimeout(function() { expect(context.mode().id).to.eql('browse'); done(); }, 50); }); - specify('shift-click on unselected entity adds it to the selection', function(done) { + it('shift-click on unselected entity adds it to the selection', function(done) { context.enter(iD.modeSelect(context, [a.id])); var el = context.surface().selectAll('.' + b.id).node(); - happen.mousedown(el, { clientX: 100, clientY: 100, shiftKey: true }); - happen.mouseup(el, { clientX: 100, clientY: 100, shiftKey: true }); + simulateClick(el, { shiftKey: true }); window.setTimeout(function() { expect(context.selectedIDs()).to.eql([a.id, b.id]); done(); }, 50); }); - specify('shift-click on selected entity removes it from the selection', function(done) { + it('shift-click on selected entity removes it from the selection', function(done) { context.enter(iD.modeSelect(context, [a.id, b.id])); var el = context.surface().selectAll('.' + b.id).node(); - happen.mousedown(el, { clientX: 100, clientY: 100, shiftKey: true }); - happen.mouseup(el, { clientX: 100, clientY: 100, shiftKey: true }); + simulateClick(el, { shiftKey: true }); window.setTimeout(function() { expect(context.selectedIDs()).to.eql([a.id]); done(); }, 50); }); - specify('shift-click on last selected entity clears the selection', function(done) { + it('shift-click on last selected entity clears the selection', function(done) { context.enter(iD.modeSelect(context, [a.id])); var el = context.surface().selectAll('.' + a.id).node(); - happen.mousedown(el, { clientX: 100, clientY: 100, shiftKey: true }); - happen.mouseup(el, { clientX: 100, clientY: 100, shiftKey: true }); + simulateClick(el, { shiftKey: true }); window.setTimeout(function() { expect(context.mode().id).to.eql('browse'); done(); }, 50); }); - specify('shift-click on empty space leaves the selection unchanged', function(done) { + it('shift-click on empty space leaves the selection unchanged', function(done) { context.enter(iD.modeSelect(context, [a.id])); var el = context.surface().node(); - happen.mousedown(el, { clientX: 100, clientY: 100, shiftKey: true }); - happen.mouseup(el, { clientX: 100, clientY: 100, shiftKey: true }); + simulateClick(el, { shiftKey: true }); window.setTimeout(function() { expect(context.selectedIDs()).to.eql([a.id]); done(); diff --git a/test/spec/spec_helpers.js b/test/spec/spec_helpers.js index 5fb66a4b7..5258ab753 100644 --- a/test/spec/spec_helpers.js +++ b/test/spec/spec_helpers.js @@ -110,6 +110,7 @@ mocha.setup({ expect = chai.expect; window.d3 = iD.d3; // Remove this if we can avoid exporting all of d3.js +delete window.PointerEvent; // force the brower to use mouse events // Workaround for `Array.from` polyfill in PhantomJS // https://github.com/openstreetmap/iD/issues/6087#issuecomment-476219308