June 27, 2019
TestsSource
- What can we proxy?
- How does the handler work
- an async setter
- helper, learning, trying out
Source Code
The source code we wrote during the event.
proxies.spec.js
import assert from 'assert';
describe('What can we proxy?', () => {
it('an empty object, is proxyable', () => {
assert.doesNotThrow(() => { new Proxy({}, {}); });
});
it('undefined, is NOT proxyable', () => {
assert.throws(() => { new Proxy(undefined, {}); }, TypeError);
});
it('the number literal, is NOT proxyable', () => {
assert.throws(() => { new Proxy(42, {}); }, TypeError);
});
it('the `Number(42)` object, is NOT proxyable', () => {
assert.throws(() => { new Proxy(Number(42), {}); }, TypeError);
});
it('the `new Number(42)` object, is NOT proxyable', () => {
assert.doesNotThrow(() => { new Proxy(new Number(42), {}); });
});
it('the `[]`, is proxyable', () => {
assert.doesNotThrow(() => { new Proxy([], {}); });
});
it('the `new Promise()`, is proxyable', () => {
assert.doesNotThrow(() => { new Proxy(new Promise(() => {}), {}); });
});
it('the `function()`, is proxyable', () => {
assert.doesNotThrow(() => { new Proxy(function() {}, {}); });
});
it('a class, is proxyable', () => {
const aClass = class {};
assert.doesNotThrow(() => { new Proxy(aClass, {}); });
});
it('a string, is proxyable', () => {
assert.throws(() => { new Proxy('', {}); }, TypeError);
});
});
describe('How does the handler work', () => {
it('make an object immutable', () => {
class OurError extends Error {}
const handler = {
set: function() { throw new OurError(); }
};
const p = new Proxy({x: 1}, handler);
assert.throws(() => p.x = 2, OurError);
});
it('a set handler throws if it is empty', () => {
const handler = {
set: function() { }
};
const p = new Proxy({x: 1}, handler);
assert.throws(() => p.x = 2, TypeError);
});
it('a set handler returns truthy value does not throw', () => {
const handler = {
set: function() { return true; }
};
const p = new Proxy({x: 1}, handler);
assert.doesNotThrow(() => p.x = 2);
});
it('updating the target property and throw an error, but still set the value', () => {
const handler = {
set: function(obj, prop, value) { obj[prop] = value; return false; }
};
const p = new Proxy({x: 1}, handler);
assert.throws(() => p.x = 2);
assert.equal(p.x, 2);
});
describe('an async setter', () => {
it('make set handler async, does not throw', () => {
const handler = {
set: async function(obj, prop, value) {
await Promise.resolve(value);
return true;
}
};
const p = new Proxy({x: 1}, handler);
assert.doesNotThrow(() => p.x = 2);
assert.equal(p.x, 1);
});
it('set the value before a Promise-await', () => {
const handler = {
set: async function(obj, prop, value) {
obj[prop] = value;
await Promise.resolve(value);
return true;
}
};
const p = new Proxy({x: 1}, handler);
assert.doesNotThrow(() => p.x = 2);
assert.equal(p.x, 2);
});
it('set the value after a Promise-await', () => {
const handler = {
set: async function(obj, prop, value) {
await Promise.resolve(value);
obj[prop] = value;
return true;
}
};
const p = new Proxy({x: 1}, handler);
assert.doesNotThrow(() => p.x = 2);
assert.equal(p.x, 1);
});
it('set the value and return a promise, works because its truthy', () => {
const handler = {
set: function(obj, prop, value) {
obj[prop] = value;
return Promise.resolve('');
}
};
const p = new Proxy({x: 1}, handler);
assert.doesNotThrow(() => p.x = 2);
assert.equal(p.x, 2);
});
it('a promise inside the setter changes the value', () => {
const handler = {
set: function(obj, prop, value) {
obj[prop] = value; // change to 2
new Promise(
(resolve) => { obj[prop] = value + 1; resolve(); }
); // change to 3
return true;
}
};
const p = new Proxy({x: 1}, handler);
assert.doesNotThrow(() => p.x = 2);
assert.equal(p.x, 3);
});
it('a promise inside the setter changes the value, after a timeout', () => {
const handler = {
set: function(obj, prop, value) {
obj[prop] = value; // change to 2
new Promise(
(resolve) => {
setTimeout(() => {obj[prop] = value + 1; resolve(); }, 0);
}
); // change to 3
return true;
}
};
const p = new Proxy({x: 1}, handler);
assert.doesNotThrow(() => p.x = 2);
assert.equal(p.x, 2);
});
it('a promise inside the setter changes the value, after a timeout - and extended testing', (done) => {
const handler = {
set: function(obj, prop, value) {
obj[prop] = value; // change to 2
new Promise(
(resolve) => {
setTimeout(() => {obj[prop] = value + 1; resolve(); }, 0);
}
); // change to 3
return true;
}
};
const p = new Proxy({x: 1}, handler);
assert.doesNotThrow(() => p.x = 2);
assert.equal(p.x, 2);
setTimeout(() => { assert.equal(p.x, 3); done(); }, 0);
});
});
});
describe('', () => {
it('what is `p.this`?', () => {
});
it('nested properties work too', () => {
const handler = {};
const p = new Proxy({x: { y: 2}}, handler);
assert.equal(p.x.y, 2);
});
it('what does a get-handler receive as a parameter for nested props', () => {
let whatProp = '';
const handler = {
get: (obj, prop) => { whatProp = prop; return obj[prop]; }
};
const p = new Proxy({x: { y: 2}}, handler);
const _ =p.x.y;
assert.equal(whatProp, 'x');
});
it('what does a get-handler receive as a parameter for nested props', () => {
let whatArgs = '';
const handler = {
get: (obj, prop, args) => { whatArgs = args; return obj[prop]; }
};
const p = new Proxy({x: { y: 2}}, handler);
const _ =p.x.y;
assert.equal(whatArgs, p);
});
it('modify nested objects', () => {
const handler = {
get: () => { return {y: 42}; }
};
const p = new Proxy({x: { y: 2}}, handler);
const fourtytwo = p.x.y;
assert.equal(fourtytwo, 42);
});
it('nesting proxies', () => {
const x = new Proxy({ y: 2}, { get: () => 1 });
const p = {x};
const fourtytwo = p.x.y;
assert.equal(fourtytwo, 1);
});
});
describe('helper, learning, trying out', () => {
it('typeof `Number(42)`', () => {
assert.equal(typeof Number(42), 'number');
});
it('typeof `new Number(42)`', () => {
assert.equal(typeof new Number(42), 'object');
});
it('instanceof `new Number(42)` is "Number"', () => {
assert(new Number(42) instanceof Number);
});
});