From 0330cd17d26f51b4f3bd048a98c7935679440e7a Mon Sep 17 00:00:00 2001 From: Josh Date: Wed, 22 Nov 2017 05:46:28 +1300 Subject: [PATCH] feat(middleware): added manual file type option Adds a manual file type so that users can instruct Karma which method to use when loading a file without an extension (such as Google font files) or others like ES modules. Closes #2824 --- docs/config/02-files.md | 11 +++++++++ lib/config.js | 6 +++-- lib/file-list.js | 3 ++- lib/file.js | 4 +++- lib/middleware/karma.js | 25 ++++++++++++++++---- test/unit/middleware/karma.spec.js | 38 ++++++++++++++++++++++-------- 6 files changed, 68 insertions(+), 19 deletions(-) diff --git a/docs/config/02-files.md b/docs/config/02-files.md index d7d267484..141fe36df 100644 --- a/docs/config/02-files.md +++ b/docs/config/02-files.md @@ -24,6 +24,17 @@ Each pattern is either a simple string or an object with four properties: * **No Default.** * **Description.** The pattern to use for matching. This property is mandatory. +### `type` +* **Type.** String +* **Default.** Will attempt to determine type based on file extension. If that fails, defaults to `js`. +* **Description.** Choose the type to use when including a file. +* **Possible Values:** + * `css` + * `html` + * `js` + * `dart` + * `module` + ### `watched` * **Type.** Boolean * **Default.** `true` diff --git a/lib/config.js b/lib/config.js index 9d71045cc..f41860bb9 100644 --- a/lib/config.js +++ b/lib/config.js @@ -36,13 +36,14 @@ try { TYPE_SCRIPT_AVAILABLE = true } catch (e) {} -var Pattern = function (pattern, served, included, watched, nocache) { +var Pattern = function (pattern, served, included, watched, nocache, type) { this.pattern = pattern this.served = helper.isDefined(served) ? served : true this.included = helper.isDefined(included) ? included : true this.watched = helper.isDefined(watched) ? watched : true this.nocache = helper.isDefined(nocache) ? nocache : false this.weight = helper.mmPatternWeight(pattern) + this.type = type } Pattern.prototype.compare = function (other) { @@ -67,7 +68,8 @@ var createPatternObject = function (pattern) { pattern.served, pattern.included, pattern.watched, - pattern.nocache) + pattern.nocache, + pattern.type) } log.warn('Invalid pattern %s!\n\tObject is missing "pattern" property.', pattern) diff --git a/lib/file-list.js b/lib/file-list.js index 2351624e1..2645e855b 100644 --- a/lib/file-list.js +++ b/lib/file-list.js @@ -184,7 +184,8 @@ List.prototype._refresh = function () { var mtime = mg.statCache[path].mtime var doNotCache = patternObject.nocache - var file = new File(path, mtime, doNotCache) + var type = patternObject.type + var file = new File(path, mtime, doNotCache, type) if (file.doNotCache) { log.debug('Not preprocessing "%s" due to nocache') diff --git a/lib/file.js b/lib/file.js index 4eabe8e00..0dd0a4827 100644 --- a/lib/file.js +++ b/lib/file.js @@ -9,7 +9,7 @@ var _ = require('lodash') // Constructor -var File = function (path, mtime, doNotCache) { +var File = function (path, mtime, doNotCache, type) { // used for serving (processed path, eg some/file.coffee -> some/file.coffee.js) this.path = path @@ -23,6 +23,8 @@ var File = function (path, mtime, doNotCache) { this.isUrl = false this.doNotCache = _.isUndefined(doNotCache) ? false : doNotCache + + this.type = type } File.prototype.toString = function () { diff --git a/lib/middleware/karma.js b/lib/middleware/karma.js index 04dd47a3f..b0b926ed1 100644 --- a/lib/middleware/karma.js +++ b/lib/middleware/karma.js @@ -15,6 +15,7 @@ var path = require('path') var util = require('util') var url = require('url') var useragent = require('useragent') +var _ = require('lodash') var log = require('../logger').create('middleware:karma') @@ -32,9 +33,17 @@ var CROSSORIGIN_ATTRIBUTE = 'crossorigin="anonymous"' var LINK_TAG_CSS = '' var LINK_TAG_HTML = '' var SCRIPT_TYPE = { - '.js': 'text/javascript', - '.dart': 'application/dart' + 'js': 'text/javascript', + 'dart': 'application/dart', + 'module': 'module' } +var FILE_TYPES = [ + 'css', + 'html', + 'js', + 'dart', + 'module' +] var filePathToUrlPath = function (filePath, basePath, urlRoot, proxyPath) { if (filePath.indexOf(basePath) === 0) { @@ -178,11 +187,16 @@ var createKarmaMiddleware = function ( var file = files.included[i] var filePath = file.path var fileExt = path.extname(filePath) + var fileType = file.type if (!files.included.hasOwnProperty(i)) { continue } + if (!_.isUndefined(fileType) && FILE_TYPES.indexOf(fileType) === -1) { + log.warn('Invalid file type, defaulting to js.', fileType) + } + if (!file.isUrl) { filePath = filePathToUrlPath(filePath, basePath, urlRoot, proxyPath) @@ -193,18 +207,19 @@ var createKarmaMiddleware = function ( scriptUrls.push(filePath) - if (fileExt === '.css') { + if (fileType === 'css' || (!fileType && fileExt === '.css')) { scriptTags.push(util.format(LINK_TAG_CSS, filePath)) continue } - if (fileExt === '.html') { + if (fileType === 'html' || (!fileType && fileExt === '.html')) { scriptTags.push(util.format(LINK_TAG_HTML, filePath)) continue } // The script tag to be placed - var scriptType = (SCRIPT_TYPE[fileExt] || 'text/javascript') + var scriptFileType = (fileType || fileExt.substring(1)) + var scriptType = (SCRIPT_TYPE[scriptFileType] || 'text/javascript') // In case there is a JavaScript version specified and this is a Firefox browser if (jsVersion && jsVersion > 0 && isFirefox(request)) { diff --git a/test/unit/middleware/karma.spec.js b/test/unit/middleware/karma.spec.js index c400d769c..9804da6a0 100644 --- a/test/unit/middleware/karma.spec.js +++ b/test/unit/middleware/karma.spec.js @@ -13,8 +13,8 @@ describe('middleware.karma', () => { var nextSpy var response - var MockFile = function (path, sha) { - File.call(this, path) + var MockFile = function (path, sha, type) { + File.call(this, path, undefined, undefined, type) this.sha = sha || 'sha-default' } @@ -212,12 +212,14 @@ describe('middleware.karma', () => { it('should serve context.html with replaced link tags', (done) => { includedFiles([ new MockFile('/first.css', 'sha007'), - new MockFile('/second.html', 'sha678') + new MockFile('/second.html', 'sha678'), + new MockFile('/third', 'sha111', 'css'), + new MockFile('/fourth', 'sha222', 'html') ]) response.once('end', () => { expect(nextSpy).not.to.have.been.called - expect(response).to.beServedAs(200, 'CONTEXT\n\n') + expect(response).to.beServedAs(200, 'CONTEXT\n\n\n\n') done() }) @@ -244,12 +246,16 @@ describe('middleware.karma', () => { new MockFile('/some/abc/a.css', 'sha1'), new MockFile('/base/path/b.css', 'sha2'), new MockFile('/some/abc/c.html', 'sha3'), - new MockFile('/base/path/d.html', 'sha4') + new MockFile('/base/path/d.html', 'sha4'), + new MockFile('/some/abc/e', 'sha5', 'css'), + new MockFile('/base/path/f', 'sha6', 'css'), + new MockFile('/some/abc/g', 'sha7', 'html'), + new MockFile('/base/path/h', 'sha8', 'html') ]) response.once('end', () => { expect(nextSpy).not.to.have.been.called - expect(response).to.beServedAs(200, 'CONTEXT\n\n\n\n') + expect(response).to.beServedAs(200, 'CONTEXT\n\n\n\n\n\n\n\n') done() }) @@ -261,7 +267,11 @@ describe('middleware.karma', () => { new MockFile('/some/abc/a.css', 'sha1'), new MockFile('/base/path/b.css', 'sha2'), new MockFile('/some/abc/c.html', 'sha3'), - new MockFile('/base/path/d.html', 'sha4') + new MockFile('/base/path/d.html', 'sha4'), + new MockFile('/some/abc/e', 'sha5', 'css'), + new MockFile('/base/path/f', 'sha6', 'css'), + new MockFile('/some/abc/g', 'sha7', 'html'), + new MockFile('/base/path/h', 'sha8', 'html') ]) response.once('end', () => { @@ -271,7 +281,11 @@ describe('middleware.karma', () => { '/__proxy__/__karma__/absolute/some/abc/a.css?sha1', '/__proxy__/__karma__/base/b.css?sha2', '/__proxy__/__karma__/absolute/some/abc/c.html?sha3', - '/__proxy__/__karma__/base/d.html?sha4' + '/__proxy__/__karma__/base/d.html?sha4', + '/__proxy__/__karma__/absolute/some/abc/e?sha5', + '/__proxy__/__karma__/base/f?sha6', + '/__proxy__/__karma__/absolute/some/abc/g?sha7', + '/__proxy__/__karma__/base/h?sha8' ] })) done() @@ -361,12 +375,16 @@ describe('middleware.karma', () => { new MockFile('/first.css'), new MockFile('/base/path/b.css'), new MockFile('/second.html'), - new MockFile('/base/path/d.html') + new MockFile('/base/path/d.html'), + new MockFile('/third', null, 'css'), + new MockFile('/base/path/f', null, 'css'), + new MockFile('/fourth', null, 'html'), + new MockFile('/base/path/g', null, 'html') ]) response.once('end', () => { expect(nextSpy).not.to.have.been.called - expect(response).to.beServedAs(200, 'DEBUG\n\n\n\n') + expect(response).to.beServedAs(200, 'DEBUG\n\n\n\n\n\n\n\n') done() })