Skip to content

Commit 4651524

Browse files
authoredOct 12, 2018
feat(server): .dom files include HTML tags in page. (#3178)
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.
1 parent 5cc4089 commit 4651524

File tree

6 files changed

+105
-12
lines changed

6 files changed

+105
-12
lines changed
 

Diff for: ‎docs/config/02-files.md

+11-7
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ Each pattern is either a simple string or an object with the following propertie
3434
* `js`
3535
* `dart`
3636
* `module`
37+
* `dom`
38+
* **Description.** The type determines the mechanism for including the file. The `css` and `html` types
39+
create `link` elements; the `js`, `dart`, and `module` elements create `script` elements. The `dom` type
40+
includes the file content in the page, used, for example, to test components combinging HTML and JS.
3741

3842
### `watched`
3943
* **Type.** Boolean
@@ -46,17 +50,17 @@ Each pattern is either a simple string or an object with the following propertie
4650
* **Description.** Should the files be included in the browser using
4751
`<script>` tag? Use `false` if you want to load them manually, eg.
4852
using [Require.js](../plus/requirejs.html).
49-
53+
5054
If a file is covered by multiple patterns with different `include` properties, the most specific pattern takes
5155
precedence over the other.
52-
53-
The specificity of the pattern is defined as a six-tuple, where larger tuple implies lesser specificity:
56+
57+
The specificity of the pattern is defined as a six-tuple, where larger tuple implies lesser specificity:
5458
*(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>)*.
55-
Tuples are compared lexicographically.
56-
57-
The *n<sub>glob parts</sub>* is the number of patterns after the bracket sections are expanded. E.g. the
59+
Tuples are compared lexicographically.
60+
61+
The *n<sub>glob parts</sub>* is the number of patterns after the bracket sections are expanded. E.g. the
5862
the pattern *{0...9}* will yield *n<sub>glob parts</sub>=10*. The rest of the tuple is decided as the least
59-
specific of each expanded pattern.
63+
specific of each expanded pattern.
6064

6165
### `served`
6266
* **Type.** Boolean

Diff for: ‎lib/middleware/karma.js

+20-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ const FILE_TYPES = [
3030
'html',
3131
'js',
3232
'dart',
33-
'module'
33+
'module',
34+
'dom'
3435
]
3536

3637
function filePathToUrlPath (filePath, basePath, urlRoot, proxyPath) {
@@ -64,6 +65,7 @@ function createKarmaMiddleware (
6465
filesPromise,
6566
serveStaticFile,
6667
serveFile,
68+
readFilePromise,
6769
injector,
6870
basePath,
6971
urlRoot,
@@ -133,8 +135,21 @@ function createKarmaMiddleware (
133135
const isRequestingContextFile = requestUrl === '/context.html'
134136
const isRequestingDebugFile = requestUrl === '/debug.html'
135137
const isRequestingClientContextFile = requestUrl === '/client_with_context.html'
138+
const includedContent = new Map() // file.path -> content
136139
if (isRequestingContextFile || isRequestingDebugFile || isRequestingClientContextFile) {
137-
return filesPromise.then(function (files) {
140+
return filesPromise.then((files) => {
141+
// Read any files.included that will be directly written into HTML before HTML is read.
142+
const contentReads = []
143+
for (const file of files.included) {
144+
const fileType = file.type || path.extname(file.path).substring(1)
145+
if (fileType === 'dom') {
146+
contentReads.push(
147+
readFilePromise(file.path).then((content) => includedContent.set(file.path, content))
148+
)
149+
}
150+
}
151+
return Promise.all(contentReads).then(() => files)
152+
}).then(function (files) {
138153
let fileServer
139154
let requestedFileUrl
140155
log.debug('custom files', customContextFile, customDebugFile, customClientContextFile)
@@ -181,6 +196,8 @@ function createKarmaMiddleware (
181196

182197
if (fileType === 'css') {
183198
scriptTags.push(`<link type="text/css" href="${filePath}" rel="stylesheet">`)
199+
} else if (fileType === 'dom') {
200+
scriptTags.push(includedContent.get(file.path))
184201
} else if (fileType === 'html') {
185202
scriptTags.push(`<link href="${filePath}" rel="import">`)
186203
} else {
@@ -224,6 +241,7 @@ createKarmaMiddleware.$inject = [
224241
'filesPromise',
225242
'serveStaticFile',
226243
'serveFile',
244+
'readFilePromise',
227245
'injector',
228246
'config.basePath',
229247
'config.urlRoot',

Diff for: ‎lib/server.js

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const plugin = require('./plugin')
2121
const createServeFile = require('./web-server').createServeFile
2222
const createServeStaticFile = require('./web-server').createServeStaticFile
2323
const createFilesPromise = require('./web-server').createFilesPromise
24+
const createReadFilePromise = require('./web-server').createReadFilePromise
2425
const createWebServer = require('./web-server').createWebServer
2526
const preprocessor = require('./preprocessor')
2627
const Launcher = require('./launcher').Launcher
@@ -78,6 +79,7 @@ class Server extends KarmaEventEmitter {
7879
serveFile: ['factory', createServeFile],
7980
serveStaticFile: ['factory', createServeStaticFile],
8081
filesPromise: ['factory', createFilesPromise],
82+
readFilePromise: ['factory', createReadFilePromise],
8183
socketServer: ['factory', createSocketIoServer],
8284
executor: ['factory', Executor.factory],
8385
// TODO(vojta): remove

Diff for: ‎lib/web-server.js

+21-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,25 @@ function createFilesPromise (emitter, fileList) {
3838

3939
return filesPromise
4040
}
41-
createFilesPromise.$inject = ['emitter', 'fileList']
41+
42+
// Bind the filesystem into the injectable file reader function
43+
function createReadFilePromise () {
44+
return (filepath) => {
45+
return new Promise((resolve, reject) => {
46+
fs.readFile(filepath, 'utf8', function (error, data) {
47+
if (error) {
48+
reject(new Error(`Cannot read ${filepath}, got: ${error}`))
49+
} else if (!data) {
50+
reject(new Error(`No content at ${filepath}`))
51+
} else {
52+
resolve(data.split('\n'))
53+
}
54+
})
55+
})
56+
}
57+
}
58+
59+
createReadFilePromise.$inject = []
4260

4361
function createServeStaticFile (config) {
4462
return common.createServeFile(fs, path.normalize(path.join(__dirname, '/../static')), config)
@@ -106,5 +124,6 @@ module.exports = {
106124
createWebServer,
107125
createServeFile,
108126
createServeStaticFile,
109-
createFilesPromise
127+
createFilesPromise,
128+
createReadFilePromise
110129
}

Diff for: ‎test/unit/middleware/karma.spec.js

+48
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const HttpRequestMock = mocks.http.ServerRequest
1212

1313
describe('middleware.karma', () => {
1414
let serveFile
15+
let readFilesDeferred
1516
let filesDeferred
1617
let nextSpy
1718
let response
@@ -63,6 +64,7 @@ describe('middleware.karma', () => {
6364
filesDeferred.promise,
6465
serveFile,
6566
null,
67+
null,
6668
injector,
6769
'/base/path',
6870
'/__karma__/',
@@ -119,10 +121,12 @@ describe('middleware.karma', () => {
119121
})
120122

121123
it('should serve client.html', (done) => {
124+
readFilesDeferred = helper.defer()
122125
handler = createKarmaMiddleware(
123126
null,
124127
serveFile,
125128
null,
129+
readFilesDeferred.promise,
126130
injector,
127131
'/base',
128132
'/'
@@ -138,10 +142,12 @@ describe('middleware.karma', () => {
138142
})
139143

140144
it('should serve /?id=xxx', (done) => {
145+
readFilesDeferred = helper.defer()
141146
handler = createKarmaMiddleware(
142147
null,
143148
serveFile,
144149
null,
150+
readFilesDeferred.promise,
145151
injector,
146152
'/base',
147153
'/'
@@ -157,10 +163,13 @@ describe('middleware.karma', () => {
157163
})
158164

159165
it('should serve /?x-ua-compatible with replaced values', (done) => {
166+
readFilesDeferred = helper.defer()
167+
160168
handler = createKarmaMiddleware(
161169
null,
162170
serveFile,
163171
null,
172+
readFilesDeferred.promise,
164173
injector,
165174
'/base',
166175
'/'
@@ -268,6 +277,43 @@ describe('middleware.karma', () => {
268277
callHandlerWith('/__karma__/context.html')
269278
})
270279

280+
it('should serve context.html with included DOM content', (done) => {
281+
const readFilePromise = (path) => {
282+
const cases = {
283+
'/some/abc/a.dom': 'a',
284+
'/some/abc/b_test_dom.html': 'b',
285+
'/some/abc/c': 'c',
286+
'/some/abc/d_test_dom.html': 'd'
287+
}
288+
return Promise.resolve(cases[path] || '?unknown ' + path)
289+
}
290+
291+
filesDeferred = helper.defer()
292+
handler = createKarmaMiddleware(
293+
filesDeferred.promise,
294+
serveFile,
295+
null,
296+
readFilePromise,
297+
injector,
298+
'/base',
299+
'/'
300+
)
301+
302+
includedFiles([
303+
new MockFile('/some/abc/a.dom', 'sha1'),
304+
new MockFile('/some/abc/b_test_dom.html', 'sha2', 'dom'),
305+
new MockFile('/some/abc/c', 'sha3', 'dom')
306+
])
307+
308+
response.once('end', () => {
309+
expect(nextSpy).not.to.have.been.called
310+
expect(response).to.beServedAs(200, 'CONTEXT\na\nb\nc')
311+
done()
312+
})
313+
314+
callHandlerWith('/context.html')
315+
})
316+
271317
it('should serve context.json with the correct paths for all files', (done) => {
272318
includedFiles([
273319
new MockFile('/some/abc/a.css', 'sha1'),
@@ -422,10 +468,12 @@ describe('middleware.karma', () => {
422468

423469
it('should update handle updated configs', (done) => {
424470
let i = 0
471+
readFilesDeferred = helper.defer()
425472
handler = createKarmaMiddleware(
426473
filesDeferred.promise,
427474
serveFile,
428475
null,
476+
readFilesDeferred.promise,
429477
{
430478
get (val) {
431479
if (val === 'config.client') {

Diff for: ‎test/unit/web-server.spec.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ describe('web-server', () => {
6363
filesPromise: ['factory', m.createFilesPromise],
6464
serveStaticFile: ['factory', m.createServeStaticFile],
6565
serveFile: ['factory', m.createServeFile],
66+
readFilePromise: ['factory', m.createReadFilePromise],
6667
capturedBrowsers: ['value', null],
6768
reporter: ['value', null],
6869
executor: ['value', null],
@@ -232,7 +233,7 @@ describe('web-server', () => {
232233
filesPromise: ['factory', m.createFilesPromise],
233234
serveStaticFile: ['factory', m.createServeStaticFile],
234235
serveFile: ['factory', m.createServeFile],
235-
236+
readFilePromise: ['factory', m.createReadFilePromise],
236237
capturedBrowsers: ['value', null],
237238
reporter: ['value', null],
238239
executor: ['value', null],
@@ -277,6 +278,7 @@ describe('web-server', () => {
277278
filesPromise: ['factory', m.createFilesPromise],
278279
serveStaticFile: ['factory', m.createServeStaticFile],
279280
serveFile: ['factory', m.createServeFile],
281+
readFilePromise: ['factory', m.createReadFilePromise],
280282
capturedBrowsers: ['value', null],
281283
reporter: ['value', null],
282284
executor: ['value', null],

0 commit comments

Comments
 (0)
Please sign in to comment.