diff --git a/lib/reload.js b/lib/reload.js index e741f5b..26494b8 100644 --- a/lib/reload.js +++ b/lib/reload.js @@ -52,12 +52,12 @@ ReloadJSON.prototype.read = function (path) { var data; if (err) { - // If a error occurs the loader needs to be invalidated. + // If an error occurs the loader needs to be invalidated. files[path] = null; return self.emit('error', err); } - // Once loaded store data in in cache and configure a watch on the + // Once loaded store data in cache and configure a watch on the // file so that it can be reloaded when it is changed. data = args[0]; files[path] = data @@ -84,16 +84,16 @@ ReloadJSON.prototype.configureWatch = function (path) { }); // Make sure old data is not used again - watch.on('change', function (filename) { + watch.on('change', function (event, filename) { self.files[path] = null; - self.emit('change', filename); + self.emit('change', event, filename); }); // Trigger a new read of the file after a debounce timeout, it's // possible a read was started in the meantime in that case no read is // triggered from the watch. - watch.on('change', debounce(function () { - if (!self.files[path]) { + watch.on('change', debounce(function (ev) { + if (ev === 'change' && !self.files[path]) { self.read(path); } }, 10)); @@ -104,7 +104,7 @@ ReloadJSON.prototype.configureWatch = function (path) { } // Load json from the specified path. The result is cached and multiple request -// is consolidated into on. +// is consolidated into a single file read. ReloadJSON.prototype.load = function (path, callback) { var self = this, files = this.files, diff --git a/package.json b/package.json index f7df387..0d75c51 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "mocha": "^2.1.0", "rewire": "^2.1.0", "sinon": "^1.10.3", - "touch": "0.0.3" + "touch": "0.0.3", + "rimraf": "~2.3.2" } } diff --git a/test/component/reload.coffee b/test/component/reload.coffee index 47669ba..bf6c675 100644 --- a/test/component/reload.coffee +++ b/test/component/reload.coffee @@ -1,21 +1,37 @@ +fs = require 'fs' +os = require 'os' +rimraf = require 'rimraf' path = require 'path' touch = require 'touch' +sinon = require 'sinon' describe "reload-json", -> Reload = require '../../lib/reload' - base = path.join process.cwd(), 'test/data/' + base = path.join os.tmpdir(), 'reload-json-test' + filepath = path.join base, 'test.json' reload = null + errorcb = null - beforeEach -> + before (done) -> + fs.mkdir base, done + + after (done) -> + rimraf base, done + + beforeEach (done) -> + errorcb = sinon.stub() reload = new Reload + reload.on 'error', errorcb + fs.writeFile filepath, JSON.stringify(file: 'test.json'), (err) -> + done() it "returns the same data when reading the same file", (done) -> - filepath = path.join base, 'test.json' readOne = null readTwo = null verify = -> assert.strictEqual readOne, readTwo + assert.notCalled errorcb done() reload.load filepath, (err, data) -> @@ -28,8 +44,7 @@ describe "reload-json", -> readTwo = data verify() if readOne - it "reads new data immediatly after the file is changed", (done) -> - filepath = path.join base, 'test.json' + it "reads new data immediately after the file is changed", (done) -> reload.load filepath, (err, readOne) -> assert.isNull err @@ -39,4 +54,41 @@ describe "reload-json", -> reload.load filepath, (err, readTwo) -> assert.isNull err assert.notStrictEqual readOne, readTwo + assert.notCalled errorcb + done() + + it "does not use cached value after file is removed", (done) -> + reload.load filepath, (err, readOne) -> + assert.isNull err + + fs.unlink filepath, (err) -> + assert.isNull err + + reload.load filepath, (err, readTwo) -> + assert.isNull readTwo + assert.instanceOf err, Error done() + + it "does not trigger reload when file is removed", (done) -> + reload.load filepath, (err, readOne) -> + assert.isNull err + + fs.unlink filepath, (err) -> + assert.isNull err + assert.notCalled errorcb + + setTimeout (-> + assert.notCalled errorcb + done() + ), 25 + + it "reads new data when file is replaced", (done) -> + tmppath = path.join base, 'new.json' + fs.writeFile tmppath, JSON.stringify(file: 'new.json'), (err) -> + reload.load filepath, (err, readOne) -> + assert.isNull err + fs.rename tmppath, filepath, (err) -> + assert.isNull err + reload.load filepath, (err, readTwo) -> + assert.propertyVal readTwo, 'file', 'new.json' + done() diff --git a/test/data/test.json b/test/data/test.json deleted file mode 100644 index 1983d4d..0000000 --- a/test/data/test.json +++ /dev/null @@ -1 +0,0 @@ -{"file": "test.json"} diff --git a/test/unit/reload.coffee b/test/unit/reload.coffee index e362426..822ab4c 100644 --- a/test/unit/reload.coffee +++ b/test/unit/reload.coffee @@ -56,14 +56,16 @@ describe "reload-json", -> reload.read 'foo' describe "#configureWatch", -> - it "configures a filesystem watch", -> + it "configures a filesystem watch", (done) -> reload.configureWatch 'foo' - assert.calledOnce fsMock.watch - assert.calledWith fsMock.watch, 'foo' + process.nextTick -> + assert.calledOnce fsMock.watch + assert.calledWith fsMock.watch, 'foo' + done() it "triggers a read on change", (done) -> reload.configureWatch 'foo' - watch.emit 'change' + watch.emit 'change', 'change', 'foo' setTimeout (-> assert.calledOnce fsMock.readFile @@ -73,7 +75,7 @@ describe "reload-json", -> it "checks if a read is in progress before triggering", (done) -> reload.configureWatch 'foo' - watch.emit 'change' + watch.emit 'change', 'change', 'foo' setTimeout (-> reload.files['foo'] = {} @@ -86,11 +88,11 @@ describe "reload-json", -> it "forwards change event", (done) -> reload.configureWatch 'foo' - reload.on 'change', (filename) -> + reload.on 'change', (ev, filename) -> assert.equal filename, 'foo' done() - watch.emit 'change', 'foo' + watch.emit 'change', 'change', 'foo' it "forwards any error that occurs", (done) -> err = new Error 'dummy-error'