Skip to content

Commit

Permalink
test(gulp): Fixed test debugging.
Browse files Browse the repository at this point in the history
test: Added test for revoking the proxy.
fix: Improved property descriptor handling.
  • Loading branch information
cb1kenobi committed Nov 18, 2020
1 parent 97834c7 commit 07107f0
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 18 deletions.
3 changes: 2 additions & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ function runTests(cover) {
args.push(path.join(mocha, 'bin', 'mocha'));

// add --inspect
if (process.argv.indexOf('--inspect') !== -1 || process.argv.indexOf('--inspect-brk') !== -1) {
const { argv } = process;
if (argv.includes('--debug') || argv.includes('--inspect') || argv.includes('--inspect-brk')) {
args.push('--inspect-brk');
}

Expand Down
31 changes: 24 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@ export default function gawk(value, parent) {
const desc = Object.getOwnPropertyDescriptor(target, prop);

if (desc) {
if (desc.writable === false) {
// if both writable and configurable are false, then returning anything
// will cause an error because without proxies, setting a non-writable
// property has no effect, but attempting to set a proxied non-writable
// property is a TypeError
return true;
}

changed = target[prop] !== newValue;
const parents = isGawked(target[prop]) && target[prop].__gawk__.parents;
if (parents) {
Expand All @@ -104,13 +112,20 @@ export default function gawk(value, parent) {

// 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];
if (typeof desc.set === 'function') {
target[prop] = gawk(newValue, gawked);

} else {
if (!Array.isArray(target) || prop !== 'length') {
delete target[prop];
}
desc.value = gawk(newValue, gawked);
Object.defineProperty(target, prop, desc);
}
} else {
target[prop] = gawk(newValue, gawked);
}

target[prop] = gawk(newValue, gawked);

if (changed) {
notify(gawked);
}
Expand Down Expand Up @@ -182,7 +197,7 @@ export default function gawk(value, parent) {
},

/**
* Removes the proxy from this object.
* Makes this gawked proxy unusable.
*/
revoke: revocable.revoke
}
Expand All @@ -191,9 +206,11 @@ export default function gawk(value, parent) {
// gawk any object properties
for (const key of Reflect.ownKeys(gawked)) {
if (key !== '__gawk__' && gawked[key] && typeof gawked[key] === 'object') {
// desc should always be an object since we know the key exists
const desc = Object.getOwnPropertyDescriptor(gawked, key);
if (!desc || desc.configurable !== false) {
gawked[key] = gawk(gawked[key], gawked);
if (desc && desc.configurable !== false) {
desc.value = gawk(gawked[key], gawked);
Object.defineProperty(gawked, key, desc);
}
}
}
Expand Down
120 changes: 110 additions & 10 deletions test/test-object.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import gawk, { isGawked } from '../dist/index';

import { EventEmitter } from 'events';
import { expect } from 'chai';

const version = require('./../package.json').version;

Expand Down Expand Up @@ -256,6 +257,84 @@ describe('set property', () => {
expect(Object.getOwnPropertySymbols(gobj)).to.deep.equal([ id ]);
expect(gobj[id]).to.equal('bar');
});

it('should set an object with a configurable, enumerable, writable property', () => {
const obj = {
foo: 'bar'
};

Object.defineProperty(obj, 'baz', {
configurable: true,
enumerable: true,
value: {
pow: 'wiz'
},
writable: true
});

const gobj = gawk(obj);
expect(JSON.parse(JSON.stringify(gobj))).to.deep.equal({ foo: 'bar', baz: { pow: 'wiz' } });
expect(gobj.foo).to.equal('bar');
expect(gobj.baz).to.deep.equal({ pow: 'wiz' });
expect(gobj.baz.pow).to.equal('wiz');

gobj.baz = 'bam';
expect(JSON.parse(JSON.stringify(gobj))).to.deep.equal({ foo: 'bar', baz: 'bam' });
expect(gobj.foo).to.equal('bar');
expect(gobj.baz).to.equal('bam');
});

it('should set an object with a configurable, enumerable, read-only property', () => {
const obj = {
foo: 'bar'
};

Object.defineProperty(obj, 'baz', {
configurable: true,
enumerable: true,
value: {
pow: 'wiz'
},
writable: false
});

const gobj = gawk(obj);
expect(JSON.parse(JSON.stringify(gobj))).to.deep.equal({ foo: 'bar', baz: { pow: 'wiz' } });
expect(gobj.foo).to.equal('bar');
expect(gobj.baz).to.deep.equal({ pow: 'wiz' });
expect(gobj.baz.pow).to.equal('wiz');

gobj.baz = 'bam';
expect(JSON.parse(JSON.stringify(gobj))).to.deep.equal({ foo: 'bar', baz: { pow: 'wiz' } });
expect(gobj.foo).to.equal('bar');
expect(gobj.baz).to.deep.equal({ pow: 'wiz' });
expect(gobj.baz.pow).to.equal('wiz');
});

it('should set an object with a non-configurable, non-enumerable, read-only property', () => {
const obj = {
foo: 'bar'
};

Object.defineProperty(obj, 'baz', {
configurable: false,
enumerable: false,
value: {
pow: 'wiz'
},
writable: false
});

const gobj = gawk(obj);
expect(JSON.parse(JSON.stringify(gobj))).to.deep.equal({ foo: 'bar' });
expect(gobj.foo).to.equal('bar');
expect(gobj.baz).to.deep.equal({ pow: 'wiz' });
expect(gobj.baz.pow).to.equal('wiz');

expect(() => {
gobj.baz = 'bam';
}).to.throw(TypeError, /'set' on proxy/);
});
});

describe('delete property', () => {
Expand Down Expand Up @@ -486,22 +565,43 @@ describe('gawk.mergeDeep()', () => {
expect(isGawked(gobj.foo.biz)).to.be.true;
expect(gobj.foo.biz.__gawk__.parents.has(gobj.foo)).to.be.true;
});
});

it('should gawk an object with a non-configurable, non-enumerable property', () => {
describe('revoke', () => {
it('should revoke the proxy', () => {
const obj = {
foo: 'bar'
foo: {
bar: 'baz'
}
};

Object.defineProperty(obj, 'baz', {
value: {
pow: 'wiz'
const gobj = gawk(obj);

expect(gobj).to.not.equal(obj);
expect(gobj).to.deep.equal(obj);

gobj.foo.bar = 'wiz';
expect(gobj).to.deep.equal({
foo: {
bar: 'wiz'
}
});
expect(obj).to.deep.equal({
foo: {
bar: 'wiz'
}
});

const gobj = gawk(obj);
expect(JSON.parse(JSON.stringify(gobj))).to.deep.equal({ foo: 'bar' });
expect(gobj.foo).to.equal('bar');
expect(gobj.baz).to.deep.equal({ pow: 'wiz' });
expect(gobj.baz.pow).to.equal('wiz');
gobj.__gawk__.revoke();

expect(() => {
gobj.foo.bar = 'bam';
}).to.throw(TypeError, 'Cannot perform \'get\' on a proxy that has been revoked');

expect(obj).to.deep.equal({
foo: {
bar: 'wiz'
}
});
});
});

0 comments on commit 07107f0

Please sign in to comment.