diff --git a/package.json b/package.json index 19c2db35c5..2ee4725af0 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "pretest": "eslint tasks test test_rendering src examples", "lint-package": "eslint --fix build/package", "test": "node tasks/test.js", - "debug-server": "node tasks/serve-lib.js" + "debug-server": "node tasks/serve-lib.js", + "karma": "node tasks/test-all.js start test/karma.config.js" }, "main": "dist/ol.js", "repository": { @@ -61,6 +62,10 @@ "istanbul": "0.4.5", "jquery": "3.2.1", "jscodeshift": "^0.3.30", + "karma": "^1.7.0", + "karma-chrome-launcher": "^2.1.1", + "karma-mocha": "^1.3.0", + "karma-sauce-launcher": "^1.1.0", "marked": "0.3.6", "metalsmith": "2.3.0", "metalsmith-layouts": "1.8.1", diff --git a/tasks/test-all.js b/tasks/test-all.js new file mode 100644 index 0000000000..27afe7b81b --- /dev/null +++ b/tasks/test-all.js @@ -0,0 +1,71 @@ +const Server = require('karma').Server; +const closure = require('closure-util'); +const path = require('path'); +const processCliArgs = require('karma/lib/cli').process; + +/** + * Start Karma. This prepends the Karma `files` config with all library files + * sorted in dependency order. + * @param {Object} config Karma options. + * @param {Manager} manager The dependency file manager. + * @param {function(Error)} callback Called with any error. + */ +function serve(config, manager, callback) { + function exit(code) { + let error = null; + if (code) { + error = new Error(`Karma exited with ${code}`); + error.code = code; + } + callback(error); + } + const server = new Server(config, exit); + + const files = server.get('config.files'); + const dependencies = manager.getDependencies().map(script => script.path); + dependencies.reverse().forEach(filePath => { + files.unshift({ + pattern: filePath, + included: true, + served: true, + watched: true + }); + }); + + // stop goog base.js from trying to load deps.js + files.unshift({ + pattern: path.resolve(__dirname, '../test/no-deps.js'), + included: true, + served: true, + watched: false + }); + + server.start(); +} + +function main(config, callback) { + const manager = new closure.Manager({ + lib: [ + 'src/**/*.js', + 'build/ol.ext/*.js' + ] + }); + + manager.on('error', callback); + + manager.on('ready', () => { + serve(config, manager, callback); + }); +} + +if (require.main === module) { + const config = processCliArgs(); + main(config, (err, manager) => { + if (err) { + process.stderr.write(err.message, () => process.exit(1)); + return; + } else { + process.exit(0); + } + }); +} diff --git a/test/karma.config.js b/test/karma.config.js new file mode 100644 index 0000000000..dbd1943ccc --- /dev/null +++ b/test/karma.config.js @@ -0,0 +1,99 @@ +var pkg = require('../package.json'); +var path = require('path'); + +/** + * The config below is not enough to run Karma. In addition, we need to add + * all library files in dependency order. This could be done with a plugin if + * Karma supported async plugins (there may other alternatives as well). But + * for now we start Karma with the `tasks/test-all.js` script. This script + * sorts dependencies and add files to the Karma config below. + */ + +module.exports = function(karma) { + karma.set({ + frameworks: ['mocha'], + files: [ + { + pattern: path.resolve(__dirname, require.resolve('jquery/dist/jquery.js')), + watched: false + }, { + pattern: path.resolve(__dirname, require.resolve('expect.js/index.js')), + watched: false + }, { + pattern: path.resolve(__dirname, require.resolve('sinon/pkg/sinon.js')), + watched: false + }, { + pattern: path.resolve(__dirname, require.resolve('proj4/dist/proj4.js')), + watched: false + }, { + pattern: path.resolve(__dirname, './test-extensions.js') + }, { + pattern: '**/*.test.js' + }, { + pattern: '**/*', + included: false, + watched: false + } + ], + proxies: { + '/spec/': '/base/spec/' + } + }); + + if (process.env.TRAVIS) { + if (!process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY) { + process.stderr.write('SAUCE_USERNAME or SAUCE_ACCESS_KEY not set\n'); + process.exit(1); + } + + // see https://wiki.saucelabs.com/display/DOCS/Platform+Configurator + // for platform and browserName options (Selenium API, node.js code) + var customLaunchers = { + SL_Chrome: { + base: 'SauceLabs', + browserName: 'chrome' + }, + SL_Firefox: { + base: 'SauceLabs', + browserName: 'firefox' + }, + SL_IE: { + base: 'SauceLabs', + platform: 'Windows 10', + browserName: 'internet explorer' + }, + SL_Edge: { + base: 'SauceLabs', + platform: 'Windows 10', + browserName: 'MicrosoftEdge' + }, + SL_Safari: { + base: 'SauceLabs', + platform: 'macos 10.12', + browserName: 'safari' + } + }; + karma.set({ + sauceLabs: { + testName: pkg.name + ' ' + pkg.version, + recordScreenshots: false, + connectOptions: { + port: 5757 + }, + startConnect: false, + tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER, + username: process.env.SAUCE_USERNAME, + accessKey: process.env.SAUCE_ACCESS_KEY + }, + reporters: ['dots', 'saucelabs'], + captureTimeout: 240000, + browserNoActivityTimeout: 240000, + customLaunchers: customLaunchers, + browsers: Object.keys(customLaunchers) + }); + } else { + karma.set({ + browsers: ['Chrome'] + }); + } +}; diff --git a/test/no-deps.js b/test/no-deps.js new file mode 100644 index 0000000000..f870b409a7 --- /dev/null +++ b/test/no-deps.js @@ -0,0 +1,2 @@ +// TODO: get rid of this when we get rid of goog base.js +var CLOSURE_NO_DEPS = true; // eslint-disable-line diff --git a/test/spec/ol/format/kml.test.js b/test/spec/ol/format/kml.test.js index 85cf8124cf..48ac137bd9 100644 --- a/test/spec/ol/format/kml.test.js +++ b/test/spec/ol/format/kml.test.js @@ -3334,7 +3334,7 @@ describe('ol.format.KML', function() { var nl = format.readNetworkLinks(text); expect(nl).to.have.length(2); expect(nl[0].name).to.be('bar'); - expect(nl[0].href.replace(window.location.href, '')).to.be('bar/bar.kml'); + expect(nl[0].href.replace(window.location.origin, '')).to.be('/bar/bar.kml'); expect(nl[1].href).to.be('http://foo.com/foo.kml'); }); diff --git a/test/zoomify-url/TileGroup0/0-0-0.jpg b/test/spec/ol/source/images/zoomify/TileGroup0/0-0-0.jpg similarity index 100% rename from test/zoomify-url/TileGroup0/0-0-0.jpg rename to test/spec/ol/source/images/zoomify/TileGroup0/0-0-0.jpg diff --git a/test/spec/ol/source/zoomify.test.js b/test/spec/ol/source/zoomify.test.js index ea5e513e8e..aee503e965 100644 --- a/test/spec/ol/source/zoomify.test.js +++ b/test/spec/ol/source/zoomify.test.js @@ -11,7 +11,7 @@ describe('ol.source.Zoomify', function() { var w = 1024; var h = 512; var size = [w, h]; - var url = 'zoomify-url/{TileGroup}/{z}-{x}-{y}.jpg'; + var url = 'spec/ol/source/images/zoomify/{TileGroup}/{z}-{x}-{y}.jpg'; var proj = new ol.proj.Projection({ code: 'ZOOMIFY', units: 'pixels', @@ -171,27 +171,27 @@ describe('ol.source.Zoomify', function() { var source = getZoomifySource(); var tileUrlFunction = source.getTileUrlFunction(); // zoomlevel 0 - expect(tileUrlFunction([0, 0, -1])).to.eql('zoomify-url/TileGroup0/0-0-0.jpg'); + expect(tileUrlFunction([0, 0, -1])).to.eql('spec/ol/source/images/zoomify/TileGroup0/0-0-0.jpg'); // zoomlevel 1 - expect(tileUrlFunction([1, 0, -1])).to.eql('zoomify-url/TileGroup0/1-0-0.jpg'); - expect(tileUrlFunction([1, 1, -1])).to.eql('zoomify-url/TileGroup0/1-1-0.jpg'); - expect(tileUrlFunction([1, 0, -2])).to.eql('zoomify-url/TileGroup0/1-0-1.jpg'); - expect(tileUrlFunction([1, 1, -2])).to.eql('zoomify-url/TileGroup0/1-1-1.jpg'); + expect(tileUrlFunction([1, 0, -1])).to.eql('spec/ol/source/images/zoomify/TileGroup0/1-0-0.jpg'); + expect(tileUrlFunction([1, 1, -1])).to.eql('spec/ol/source/images/zoomify/TileGroup0/1-1-0.jpg'); + expect(tileUrlFunction([1, 0, -2])).to.eql('spec/ol/source/images/zoomify/TileGroup0/1-0-1.jpg'); + expect(tileUrlFunction([1, 1, -2])).to.eql('spec/ol/source/images/zoomify/TileGroup0/1-1-1.jpg'); }); it('creates an expected tileUrlFunction without template', function() { var source = new ol.source.Zoomify({ - url: 'zoomify-url/', + url: 'spec/ol/source/images/zoomify/', size: size }); var tileUrlFunction = source.getTileUrlFunction(); // zoomlevel 0 - expect(tileUrlFunction([0, 0, -1])).to.eql('zoomify-url/TileGroup0/0-0-0.jpg'); + expect(tileUrlFunction([0, 0, -1])).to.eql('spec/ol/source/images/zoomify/TileGroup0/0-0-0.jpg'); // zoomlevel 1 - expect(tileUrlFunction([1, 0, -1])).to.eql('zoomify-url/TileGroup0/1-0-0.jpg'); - expect(tileUrlFunction([1, 1, -1])).to.eql('zoomify-url/TileGroup0/1-1-0.jpg'); - expect(tileUrlFunction([1, 0, -2])).to.eql('zoomify-url/TileGroup0/1-0-1.jpg'); - expect(tileUrlFunction([1, 1, -2])).to.eql('zoomify-url/TileGroup0/1-1-1.jpg'); + expect(tileUrlFunction([1, 0, -1])).to.eql('spec/ol/source/images/zoomify/TileGroup0/1-0-0.jpg'); + expect(tileUrlFunction([1, 1, -1])).to.eql('spec/ol/source/images/zoomify/TileGroup0/1-1-0.jpg'); + expect(tileUrlFunction([1, 0, -2])).to.eql('spec/ol/source/images/zoomify/TileGroup0/1-0-1.jpg'); + expect(tileUrlFunction([1, 1, -2])).to.eql('spec/ol/source/images/zoomify/TileGroup0/1-1-1.jpg'); }); it('returns undefined if no tileCoord passed', function() { var source = getZoomifySource();