diff --git a/src/index.js b/src/index.js index 9b0b180..c39b100 100644 --- a/src/index.js +++ b/src/index.js @@ -56,17 +56,18 @@ export default function gawk(value, parent) { } else { // gawk it! gawked = new Proxy(value, { - set: (target, prop, value) => { + set: (target, prop, newValue) => { if (prop === '__gawk__') { throw new Error('Cannot override property \'__gawk__\''); } - // console.log('setting', prop, value); + // console.log('setting', prop, newValue); let changed = true; + const desc = Object.getOwnPropertyDescriptor(target, prop); - if (Object.prototype.hasOwnProperty.call(target, prop)) { - changed = target[prop] !== value; + if (desc) { + changed = target[prop] !== newValue; const parents = isGawked(target[prop]) && target[prop].__gawk__.parents; if (parents) { parents.delete(gawked); @@ -74,12 +75,15 @@ export default function gawk(value, parent) { target[prop].__gawk__.parents = null; } } - if (!Array.isArray(target) || prop !== 'length') { + + // if the destination property has a setter, then we can't assume we need to + // fire a delete + if (typeof desc.set !== 'function' && (!Array.isArray(target) || prop !== 'length')) { delete target[prop]; } } - target[prop] = gawk(value, gawked); + target[prop] = gawk(newValue, gawked); if (changed) { notify(gawked); diff --git a/test/test-watch.js b/test/test-watch.js index dd7e2b2..b363460 100644 --- a/test/test-watch.js +++ b/test/test-watch.js @@ -644,4 +644,29 @@ describe('gawk.unwatch()', () => { expect(gobj.__gawk__.previous).to.be.null; }); + + it('should notify when a getter/setter property is changed', () => { + const obj = Object.defineProperty({}, 'foo', { + configurable: true, + enumerable: true, + get() { + return this._foo; + }, + set(value) { + this._foo = value.toUpperCase(); + } + }); + + obj.foo = 'bar'; + + const gobj = gawk(obj); + expect(gobj.foo).to.equal('BAR'); + + const callback = spy(); + gawk.watch(gobj, callback); + + gobj.foo = 'baz'; + expect(callback).to.be.calledOnce; + expect(gobj.foo).to.equal('BAZ'); + }); });