diff --git a/docs/dev/04-public-api.md b/docs/dev/04-public-api.md index 21974dd40..3f810a43c 100644 --- a/docs/dev/04-public-api.md +++ b/docs/dev/04-public-api.md @@ -33,6 +33,14 @@ Trigger a file list refresh. Returns a promise. server.refreshFiles() ``` +### **server.refreshFile(path)** + +Trigger a file refresh. Returns a promise. + +```javascript +server.refreshFile('src/js/module-dep.js') +``` + ### Events The `server` object is an [`EventEmitter`](https://nodejs.org/docs/latest/api/events.html#events_class_events_eventemitter). You can simply listen to events like this: diff --git a/lib/file-list.js b/lib/file-list.js index 02d0bacdc..35f5058e2 100644 --- a/lib/file-list.js +++ b/lib/file-list.js @@ -213,7 +213,7 @@ class FileList { }) } - changeFile (path) { + changeFile (path, force) { const pattern = this._findIncluded(path) const file = this._findFile(path, pattern) @@ -226,14 +226,14 @@ class FileList { fs.statAsync(path), this._refreshing ]).spread((stat) => { - if (stat.mtime <= file.mtime) throw new Promise.CancellationError() + if (!force && stat.mtime <= file.mtime) throw new Promise.CancellationError() file.mtime = stat.mtime return this._preprocess(file) }) .then(() => { log.info('Changed file "%s".', path) - this._emitModified() + this._emitModified(force) return this.files }) .catch(Promise.CancellationError, () => this.files) diff --git a/lib/server.js b/lib/server.js index 426f49e27..dacfdc095 100644 --- a/lib/server.js +++ b/lib/server.js @@ -133,6 +133,10 @@ class Server extends KarmaEventEmitter { return this._fileList ? this._fileList.refresh() : Promise.resolve() } + refreshFile (path) { + return this._fileList ? this._fileList.changeFile(path) : Promise.resolve() + } + _start (config, launcher, preprocess, fileList, capturedBrowsers, executor, done) { if (config.detached) { this._detach(config, done) diff --git a/test/unit/file-list.spec.js b/test/unit/file-list.spec.js index f9eef1d51..3bec4bc68 100644 --- a/test/unit/file-list.spec.js +++ b/test/unit/file-list.spec.js @@ -632,6 +632,23 @@ describe('FileList', () => { }) }) + it('fire "file_list_modified" if force is true even if mtime has not changed', () => { + // MATCH: /some/a.js, /some/b.js, /a.txt + list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess) + + var modified = sinon.stub() + emitter.on('file_list_modified', modified) + + return list.refresh().then((files) => { + // not touching the file, stat will return still the same + modified.reset() + + return list.changeFile('/some/b.js', true).then(() => { + expect(modified).to.have.been.calledOnce + }) + }) + }) + it('does not fire "file_list_modified" if mtime has not changed', () => { // chokidar on fucking windows sometimes fires event multiple times // MATCH: /some/a.js, /some/b.js, /a.txt