Skip to content

Commit

Permalink
feat(server): .dom files include HTML tags in page. (#3178)
Browse files Browse the repository at this point in the history
Add support for .dom extension files, insert the content of the file into the test HTML
document. This allows 'component' tests where JS interacts with HTML. Provides a simpler
alternative to solutions that use JS to embed HTML in JS then write it into the DOM.
Limited to cases where the DOM fragments from different tests do not interfere.
  • Loading branch information
johnjbarton committed Oct 12, 2018
1 parent 5cc4089 commit 4651524
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 12 deletions.
18 changes: 11 additions & 7 deletions docs/config/02-files.md
Expand Up @@ -34,6 +34,10 @@ Each pattern is either a simple string or an object with the following propertie
* `js`
* `dart`
* `module`
* `dom`
* **Description.** The type determines the mechanism for including the file. The `css` and `html` types
create `link` elements; the `js`, `dart`, and `module` elements create `script` elements. The `dom` type
includes the file content in the page, used, for example, to test components combinging HTML and JS.

### `watched`
* **Type.** Boolean
Expand All @@ -46,17 +50,17 @@ Each pattern is either a simple string or an object with the following propertie
* **Description.** Should the files be included in the browser using
`<script>` tag? Use `false` if you want to load them manually, eg.
using [Require.js](../plus/requirejs.html).

If a file is covered by multiple patterns with different `include` properties, the most specific pattern takes
precedence over the other.
The specificity of the pattern is defined as a six-tuple, where larger tuple implies lesser specificity:

The specificity of the pattern is defined as a six-tuple, where larger tuple implies lesser specificity:
*(n<sub>glob parts</sub>, n<sub>glob star</sub>, n<sub>star</sub>, n<sub>ext glob</sub>, n<sub>range</sub>, n<sub>optional</sub>)*.
Tuples are compared lexicographically.
The *n<sub>glob parts</sub>* is the number of patterns after the bracket sections are expanded. E.g. the
Tuples are compared lexicographically.

The *n<sub>glob parts</sub>* is the number of patterns after the bracket sections are expanded. E.g. the
the pattern *{0...9}* will yield *n<sub>glob parts</sub>=10*. The rest of the tuple is decided as the least
specific of each expanded pattern.
specific of each expanded pattern.

### `served`
* **Type.** Boolean
Expand Down
22 changes: 20 additions & 2 deletions lib/middleware/karma.js
Expand Up @@ -30,7 +30,8 @@ const FILE_TYPES = [
'html',
'js',
'dart',
'module'
'module',
'dom'
]

function filePathToUrlPath (filePath, basePath, urlRoot, proxyPath) {
Expand Down Expand Up @@ -64,6 +65,7 @@ function createKarmaMiddleware (
filesPromise,
serveStaticFile,
serveFile,
readFilePromise,
injector,
basePath,
urlRoot,
Expand Down Expand Up @@ -133,8 +135,21 @@ function createKarmaMiddleware (
const isRequestingContextFile = requestUrl === '/context.html'
const isRequestingDebugFile = requestUrl === '/debug.html'
const isRequestingClientContextFile = requestUrl === '/client_with_context.html'
const includedContent = new Map() // file.path -> content
if (isRequestingContextFile || isRequestingDebugFile || isRequestingClientContextFile) {
return filesPromise.then(function (files) {
return filesPromise.then((files) => {
// Read any files.included that will be directly written into HTML before HTML is read.
const contentReads = []
for (const file of files.included) {
const fileType = file.type || path.extname(file.path).substring(1)
if (fileType === 'dom') {
contentReads.push(
readFilePromise(file.path).then((content) => includedContent.set(file.path, content))
)
}
}
return Promise.all(contentReads).then(() => files)
}).then(function (files) {
let fileServer
let requestedFileUrl
log.debug('custom files', customContextFile, customDebugFile, customClientContextFile)
Expand Down Expand Up @@ -181,6 +196,8 @@ function createKarmaMiddleware (

if (fileType === 'css') {
scriptTags.push(`<link type="text/css" href="${filePath}" rel="stylesheet">`)
} else if (fileType === 'dom') {
scriptTags.push(includedContent.get(file.path))
} else if (fileType === 'html') {
scriptTags.push(`<link href="${filePath}" rel="import">`)
} else {
Expand Down Expand Up @@ -224,6 +241,7 @@ createKarmaMiddleware.$inject = [
'filesPromise',
'serveStaticFile',
'serveFile',
'readFilePromise',
'injector',
'config.basePath',
'config.urlRoot',
Expand Down
2 changes: 2 additions & 0 deletions lib/server.js
Expand Up @@ -21,6 +21,7 @@ const plugin = require('./plugin')
const createServeFile = require('./web-server').createServeFile
const createServeStaticFile = require('./web-server').createServeStaticFile
const createFilesPromise = require('./web-server').createFilesPromise
const createReadFilePromise = require('./web-server').createReadFilePromise
const createWebServer = require('./web-server').createWebServer
const preprocessor = require('./preprocessor')
const Launcher = require('./launcher').Launcher
Expand Down Expand Up @@ -78,6 +79,7 @@ class Server extends KarmaEventEmitter {
serveFile: ['factory', createServeFile],
serveStaticFile: ['factory', createServeStaticFile],
filesPromise: ['factory', createFilesPromise],
readFilePromise: ['factory', createReadFilePromise],
socketServer: ['factory', createSocketIoServer],
executor: ['factory', Executor.factory],
// TODO(vojta): remove
Expand Down
23 changes: 21 additions & 2 deletions lib/web-server.js
Expand Up @@ -38,7 +38,25 @@ function createFilesPromise (emitter, fileList) {

return filesPromise
}
createFilesPromise.$inject = ['emitter', 'fileList']

// Bind the filesystem into the injectable file reader function
function createReadFilePromise () {
return (filepath) => {
return new Promise((resolve, reject) => {
fs.readFile(filepath, 'utf8', function (error, data) {
if (error) {
reject(new Error(`Cannot read ${filepath}, got: ${error}`))
} else if (!data) {
reject(new Error(`No content at ${filepath}`))
} else {
resolve(data.split('\n'))
}
})
})
}
}

createReadFilePromise.$inject = []

function createServeStaticFile (config) {
return common.createServeFile(fs, path.normalize(path.join(__dirname, '/../static')), config)
Expand Down Expand Up @@ -106,5 +124,6 @@ module.exports = {
createWebServer,
createServeFile,
createServeStaticFile,
createFilesPromise
createFilesPromise,
createReadFilePromise
}
48 changes: 48 additions & 0 deletions test/unit/middleware/karma.spec.js
Expand Up @@ -12,6 +12,7 @@ const HttpRequestMock = mocks.http.ServerRequest

describe('middleware.karma', () => {
let serveFile
let readFilesDeferred
let filesDeferred
let nextSpy
let response
Expand Down Expand Up @@ -63,6 +64,7 @@ describe('middleware.karma', () => {
filesDeferred.promise,
serveFile,
null,
null,
injector,
'/base/path',
'/__karma__/',
Expand Down Expand Up @@ -119,10 +121,12 @@ describe('middleware.karma', () => {
})

it('should serve client.html', (done) => {
readFilesDeferred = helper.defer()
handler = createKarmaMiddleware(
null,
serveFile,
null,
readFilesDeferred.promise,
injector,
'/base',
'/'
Expand All @@ -138,10 +142,12 @@ describe('middleware.karma', () => {
})

it('should serve /?id=xxx', (done) => {
readFilesDeferred = helper.defer()
handler = createKarmaMiddleware(
null,
serveFile,
null,
readFilesDeferred.promise,
injector,
'/base',
'/'
Expand All @@ -157,10 +163,13 @@ describe('middleware.karma', () => {
})

it('should serve /?x-ua-compatible with replaced values', (done) => {
readFilesDeferred = helper.defer()

handler = createKarmaMiddleware(
null,
serveFile,
null,
readFilesDeferred.promise,
injector,
'/base',
'/'
Expand Down Expand Up @@ -268,6 +277,43 @@ describe('middleware.karma', () => {
callHandlerWith('/__karma__/context.html')
})

it('should serve context.html with included DOM content', (done) => {
const readFilePromise = (path) => {
const cases = {
'/some/abc/a.dom': 'a',
'/some/abc/b_test_dom.html': 'b',
'/some/abc/c': 'c',
'/some/abc/d_test_dom.html': 'd'
}
return Promise.resolve(cases[path] || '?unknown ' + path)
}

filesDeferred = helper.defer()
handler = createKarmaMiddleware(
filesDeferred.promise,
serveFile,
null,
readFilePromise,
injector,
'/base',
'/'
)

includedFiles([
new MockFile('/some/abc/a.dom', 'sha1'),
new MockFile('/some/abc/b_test_dom.html', 'sha2', 'dom'),
new MockFile('/some/abc/c', 'sha3', 'dom')
])

response.once('end', () => {
expect(nextSpy).not.to.have.been.called
expect(response).to.beServedAs(200, 'CONTEXT\na\nb\nc')
done()
})

callHandlerWith('/context.html')
})

it('should serve context.json with the correct paths for all files', (done) => {
includedFiles([
new MockFile('/some/abc/a.css', 'sha1'),
Expand Down Expand Up @@ -422,10 +468,12 @@ describe('middleware.karma', () => {

it('should update handle updated configs', (done) => {
let i = 0
readFilesDeferred = helper.defer()
handler = createKarmaMiddleware(
filesDeferred.promise,
serveFile,
null,
readFilesDeferred.promise,
{
get (val) {
if (val === 'config.client') {
Expand Down
4 changes: 3 additions & 1 deletion test/unit/web-server.spec.js
Expand Up @@ -63,6 +63,7 @@ describe('web-server', () => {
filesPromise: ['factory', m.createFilesPromise],
serveStaticFile: ['factory', m.createServeStaticFile],
serveFile: ['factory', m.createServeFile],
readFilePromise: ['factory', m.createReadFilePromise],
capturedBrowsers: ['value', null],
reporter: ['value', null],
executor: ['value', null],
Expand Down Expand Up @@ -232,7 +233,7 @@ describe('web-server', () => {
filesPromise: ['factory', m.createFilesPromise],
serveStaticFile: ['factory', m.createServeStaticFile],
serveFile: ['factory', m.createServeFile],

readFilePromise: ['factory', m.createReadFilePromise],
capturedBrowsers: ['value', null],
reporter: ['value', null],
executor: ['value', null],
Expand Down Expand Up @@ -277,6 +278,7 @@ describe('web-server', () => {
filesPromise: ['factory', m.createFilesPromise],
serveStaticFile: ['factory', m.createServeStaticFile],
serveFile: ['factory', m.createServeFile],
readFilePromise: ['factory', m.createReadFilePromise],
capturedBrowsers: ['value', null],
reporter: ['value', null],
executor: ['value', null],
Expand Down

0 comments on commit 4651524

Please sign in to comment.