diff --git a/.gitignore b/.gitignore index 2f9af78..050868b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ coverage/ -npm-*.log \ No newline at end of file +npm-*.log +debug.log diff --git a/index.js b/index.js index e593f02..99ac4c2 100644 --- a/index.js +++ b/index.js @@ -80,18 +80,22 @@ class RefreshingConfig extends EventEmitter { } apply(patches) { - // Snapshot the properties/name and apply the patches. If a changed property is still present, + // Snapshot the property names and apply the patches. If a changed property is still present, // it was changed so set. If it is now missing, delete it. - const newValues = Object.assign({}, this.values); - patch.apply(newValues, patches); - const affected = this._getAffectedProperties(patches); - return Q.all(affected.map(key => { - if (newValues[key] === undefined) { - return this.delete(key); - } else { - return this.set(key, newValues[key]); - } - })); + return this.refreshIfNeeded().then(() => { + const oldKeys = Object.getOwnPropertyNames(this.values); + patch.apply(this.values, patches); + const affected = this._getAffectedProperties(patches); + return Q.all(affected.map(key => { + if (this.values[key] !== undefined) { + return this.set(key, this.values[key]); + } + if (oldKeys.includes(key)) { + return this.delete(key); + } + return Q(); + })); + }); } _getAffectedProperties(patches) { diff --git a/test/index-test.js b/test/index-test.js index ff1de54..3b92dcd 100644 --- a/test/index-test.js +++ b/test/index-test.js @@ -1,7 +1,7 @@ +const chai = require('chai'); const clone = require('clone'); const events = require('events'); const Q = require('q'); -const chai = require('chai'); const sinon = require('sinon'); chai.should(); @@ -204,6 +204,27 @@ describe('RefreshingConfig', () => { target.withExtension(null).should.equal(target); target.withExtension({}).should.equal(target); }); + it('applies patches correctly', () => { + const store = { + getAll: sinon.stub().returns(Q({ foo: 'bar', test: 42 })), + set: sinon.stub().returns(Q()), + delete: sinon.stub().returns(Q()) + }; + const target = new config.RefreshingConfig(store); + const patches = [ + { op: 'add', path: '/first', value: 'value' }, + { op: 'replace', path: '/foo', value: 'fred' }, + { op: 'remove', path: '/test' }, + { op: 'remove', path: '/test2' } + ]; + return target.apply(patches).then(() => { + store.set.calledTwice.should.be.true; + store.set.firstCall.calledWith('first', 'value').should.be.true; + store.set.secondCall.calledWith('foo', 'fred').should.be.true; + store.delete.calledOnce.should.be.true; + store.delete.firstCall.calledWith('test').should.be.true; + }); + }); }); describe('AlwaysRefreshPolicy', () => {