diff --git a/.travis.yml b/.travis.yml index 5235bf5..0e619df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,9 +26,9 @@ matrix: before_install: - npm config set spin false - - npm install -g bower phantomjs-prebuilt - - bower --version - - phantomjs --version + - "export DISPLAY=:99.0" + - "sh -e /etc/init.d/xvfb start" + - sleep 3 # give xvfb some time to start install: - npm install diff --git a/CHANGELOG.md b/CHANGELOG.md index a76c659..7d6bbcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased ### Changed -- added acceptance test +- added acceptance tests ## 0.1.2 diff --git a/addon/services/esri-loader.js b/addon/services/esri-loader.js index a56e707..ad39843 100644 --- a/addon/services/esri-loader.js +++ b/addon/services/esri-loader.js @@ -32,18 +32,56 @@ export default Ember.Service.extend({ // otherwise create a promise that will resolve when the JSAPI is loaded this._loadPromise = new Ember.RSVP.Promise((resolve, reject) => { esriLoader.bootstrap(err => { - Ember.run(() => { - if (err) { - reject(err); + if (err) { + const message = err.message || err; + // has esriLoader.bootstrap already been called? + if (message === 'The ArcGIS API for JavaScript is already loaded.') { + // this can happen when there is more than one instance of this service + // running on the page at a time, for example, in acceptance tests + + // TODO: this is _much_ better handled upstream + // so we want to get rid of all this once this issue is resolved: + // https://github.com/Esri/esri-loader/issues/28 + + // first check if it's the same script + // NOTE: will haev to update this every time it's updated here: + // https://github.com/Esri/esri-loader/blob/master/src/esri-loader.ts#L29 + const defaultUrl = 'https://js.arcgis.com/4.4/'; + const url = options.url || defaultUrl; + const script = document.querySelector('script[data-esri-loader]'); + if (script.src !== url) { + // user tried to load two different JSAPI scripts + reject(err); + } else { + // check if the script has loaded yet + if (script.dataset.esriLoader === 'loaded' || esriLoader.isLoaded()) { + resolve(); + } else { + // wait for the script to load and then resolve + script.addEventListener('load', () => { + // TODO: remove this event listener + resolve(); + }, false); + } + } } else { - // notify any watchers of isLoaded copmuted property - this.notifyPropertyChange('isLoaded'); - // let the caller know that the API has been successfully loaded - // TODO: would there be something more useful to return here? - resolve({ success: true }); + // not an error we can handle + reject(err); } - }); + } else { + // no err + resolve(); + } }, options); + }) + .then(() => { + // update the isLoaded computed property + this.notifyPropertyChange('isLoaded'); + // let the caller know that the API has been successfully loaded + // TODO: would there be something more useful to return here? + // bootstrap returns dojoRequire, + // but we want consumers to use loadModules instead + return { success: true }; }); return this._loadPromise; }, diff --git a/testem.js b/testem.js index 26044b2..d6e9831 100644 --- a/testem.js +++ b/testem.js @@ -4,10 +4,9 @@ module.exports = { "test_page": "tests/index.html?hidepassed", "disable_watching": true, "launch_in_ci": [ - "PhantomJS" + "FireFox" ], "launch_in_dev": [ - "PhantomJS", "Chrome" ] }; diff --git a/tests/.jshintrc b/tests/.jshintrc index d2bd113..cc5c777 100644 --- a/tests/.jshintrc +++ b/tests/.jshintrc @@ -21,7 +21,8 @@ "andThen", "currentURL", "currentPath", - "currentRouteName" + "currentRouteName", + "waitForElement" ], "node": false, "browser": false, diff --git a/tests/acceptance/map-test.js b/tests/acceptance/map-test.js new file mode 100644 index 0000000..8dc654f --- /dev/null +++ b/tests/acceptance/map-test.js @@ -0,0 +1,18 @@ +import { test } from 'qunit'; +import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; + +moduleForAcceptance('Acceptance | map'); + +test('visiting /map', function(assert) { + visit('/map'); + + andThen(function() { + assert.equal(currentURL(), '/map'); + // wait for the map to load + waitForElement('.esri-view-root'); + andThen(function() { + // validate the map DOM + assert.equal(find('.esri-view-root').css('height'), '400px'); + }); + }); +}); diff --git a/tests/dummy/app/components/scene-view.js b/tests/dummy/app/components/scene-view.js index a2bfe59..8691af4 100644 --- a/tests/dummy/app/components/scene-view.js +++ b/tests/dummy/app/components/scene-view.js @@ -13,6 +13,9 @@ export default Ember.Component.extend({ this._super(...arguments); // load the esri modules this.get('esriLoader').loadModules(['esri/views/SceneView', 'esri/Map']).then(modules => { + if (this.get('isDestroyed') || this.get('isDestroying')) { + return; + } const [SceneView, Map] = modules; // create a new scene view this._view = new SceneView({ diff --git a/tests/dummy/app/components/web-map.js b/tests/dummy/app/components/web-map.js index 810f1a0..bd639cf 100644 --- a/tests/dummy/app/components/web-map.js +++ b/tests/dummy/app/components/web-map.js @@ -9,6 +9,9 @@ export default Ember.Component.extend({ this._super(...arguments); // load the map modules this.get('esriLoader').loadModules(['esri/views/MapView', 'esri/WebMap']).then(modules => { + if (this.get('isDestroyed') || this.get('isDestroying')) { + return; + } const [MapView, WebMap] = modules; // load the webmap from a portal item const webmap = new WebMap({ diff --git a/tests/helpers/start-app.js b/tests/helpers/start-app.js index e098f1d..8f6b383 100644 --- a/tests/helpers/start-app.js +++ b/tests/helpers/start-app.js @@ -1,6 +1,7 @@ import Ember from 'ember'; import Application from '../../app'; import config from '../../config/environment'; +import './wait-for-element'; export default function startApp(attrs) { let application; diff --git a/tests/helpers/wait-for-element.js b/tests/helpers/wait-for-element.js new file mode 100644 index 0000000..6afd869 --- /dev/null +++ b/tests/helpers/wait-for-element.js @@ -0,0 +1,21 @@ +import Ember from 'ember'; + +export default Ember.Test.registerAsyncHelper('waitForElement', function(app, selector, context, interval=300) { + return new Ember.Test.promise(function (resolve) { + // inform the test framework that there is an async operation in progress, + // so it shouldn't consider the test complete + Ember.Test.adapter.asyncStart(); + let intervalId = window.setInterval(function () { + let $el = find(selector, context); + if ($el.length > 0) { + Ember.run (function () { + // stop this loop and resolve the promise + window.clearInterval(intervalId); + resolve(); + }); + // inform the test framework that this async operation is complete + Ember.Test.adapter.asyncEnd(); + } + }, interval); + }); +});