680 lines
19 KiB
JavaScript
680 lines
19 KiB
JavaScript
var arePropertyDescriptorsSupported = function () {
|
||
try {
|
||
Object.defineProperty({}, 'x', {});
|
||
return true;
|
||
} catch (e) { /* this is IE 8. */
|
||
return false;
|
||
}
|
||
};
|
||
var supportsDescriptors = !!Object.defineProperty && arePropertyDescriptorsSupported();
|
||
var functionsHaveNames = function f() {}.name === 'f';
|
||
|
||
var hasSymbols = typeof Symbol === 'function' && typeof Symbol() === 'symbol';
|
||
var ifSymbolsIt = hasSymbols ? it : xit;
|
||
var describeIfGetProto = Object.getPrototypeOf ? describe : xdescribe;
|
||
var describeIfSetProto = Object.setPrototypeOf ? describe : xdescribe;
|
||
var describeIfES5 = supportsDescriptors ? describe : xdescribe;
|
||
var describeIfExtensionsPreventible = Object.preventExtensions ? describe : xdescribe;
|
||
var describeIfGetOwnPropertyNames = Object.getOwnPropertyNames ? describe : xdescribe;
|
||
var ifExtensionsPreventibleIt = Object.preventExtensions ? it : xit;
|
||
var ifES5It = supportsDescriptors ? it : xit;
|
||
var ifFreezeIt = typeof Object.freeze === 'function' ? it : xit;
|
||
var ifFunctionsHaveNamesIt = functionsHaveNames ? it : xit;
|
||
var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it;
|
||
|
||
describe('Reflect', function () {
|
||
if (typeof Reflect === 'undefined') {
|
||
return it('exists', function () {
|
||
expect(this).to.have.property('Reflect');
|
||
});
|
||
}
|
||
|
||
var object = {
|
||
something: 1,
|
||
_value: 0
|
||
};
|
||
|
||
if (supportsDescriptors) {
|
||
/* eslint-disable accessor-pairs */
|
||
Object.defineProperties(object, {
|
||
value: {
|
||
get: function () {
|
||
return this._value;
|
||
}
|
||
},
|
||
|
||
setter: {
|
||
set: function (val) {
|
||
this._value = val;
|
||
}
|
||
},
|
||
|
||
bool: {
|
||
value: true
|
||
}
|
||
});
|
||
/* eslint-enable accessor-pairs */
|
||
}
|
||
|
||
var testXThrow = function (values, func) {
|
||
var checker = function checker(item) {
|
||
try {
|
||
func(item);
|
||
return false;
|
||
} catch (e) {
|
||
return e instanceof TypeError;
|
||
}
|
||
};
|
||
|
||
values.forEach(function (item) {
|
||
expect(item).to.satisfy(checker);
|
||
});
|
||
};
|
||
|
||
var testCallableThrow = testXThrow.bind(null, [null, undefined, 1, 'string', true, [], {}]);
|
||
|
||
var testPrimitiveThrow = testXThrow.bind(null, [null, undefined, 1, 'string', true]);
|
||
|
||
ifShimIt('is on the exported object', function () {
|
||
var exported = require('../');
|
||
expect(exported.Reflect).to.equal(Reflect);
|
||
});
|
||
|
||
describe('.apply()', function () {
|
||
if (typeof Reflect.apply === 'undefined') {
|
||
return it('exists', function () {
|
||
expect(Reflect).to.have.property('apply');
|
||
});
|
||
}
|
||
|
||
it('is a function', function () {
|
||
expect(typeof Reflect.apply).to.equal('function');
|
||
});
|
||
|
||
ifFunctionsHaveNamesIt('has the right name', function () {
|
||
expect(Reflect.apply.name).to.equal('apply');
|
||
});
|
||
|
||
it('throws if target isn’t callable', function () {
|
||
testCallableThrow(function (item) {
|
||
return Reflect.apply(item, null, []);
|
||
});
|
||
});
|
||
|
||
it('works also with redefined apply', function () {
|
||
expect(Reflect.apply(Array.prototype.push, [1, 2], [3, 4, 5])).to.equal(5);
|
||
|
||
var F = function F(a, b, c) {
|
||
return a + b + c;
|
||
};
|
||
|
||
F.apply = false;
|
||
|
||
expect(Reflect.apply(F, null, [1, 2, 3])).to.equal(6);
|
||
|
||
var G = function G(last) {
|
||
return this.x + 'lo' + last;
|
||
};
|
||
|
||
G.apply = function nop() {};
|
||
|
||
expect(Reflect.apply(G, { x: 'yel' }, ['!'])).to.equal('yello!');
|
||
});
|
||
});
|
||
|
||
describe('.construct()', function () {
|
||
if (typeof Reflect.construct === 'undefined') {
|
||
return it('exists', function () {
|
||
expect(Reflect).to.have.property('construct');
|
||
});
|
||
}
|
||
|
||
it('is a function', function () {
|
||
expect(typeof Reflect.construct).to.equal('function');
|
||
});
|
||
|
||
ifFunctionsHaveNamesIt('has the right name', function () {
|
||
expect(Reflect.construct.name).to.equal('construct');
|
||
});
|
||
|
||
it('throws if target isn’t callable', function () {
|
||
testCallableThrow(function (item) {
|
||
return Reflect.apply(item, null, []);
|
||
});
|
||
});
|
||
|
||
it('works also with redefined apply', function () {
|
||
var C = function C(a, b, c) {
|
||
this.qux = [a, b, c].join('|');
|
||
};
|
||
|
||
C.apply = undefined;
|
||
|
||
expect(Reflect.construct(C, ['foo', 'bar', 'baz']).qux).to.equal('foo|bar|baz');
|
||
});
|
||
|
||
it('correctly handles newTarget param', function () {
|
||
var F = function F() {};
|
||
expect(Reflect.construct(function () {}, [], F) instanceof F).to.equal(true);
|
||
});
|
||
});
|
||
|
||
describeIfES5('.defineProperty()', function () {
|
||
if (typeof Reflect.defineProperty === 'undefined') {
|
||
return it('exists', function () {
|
||
expect(Reflect).to.have.property('defineProperty');
|
||
});
|
||
}
|
||
|
||
it('is a function', function () {
|
||
expect(typeof Reflect.defineProperty).to.equal('function');
|
||
});
|
||
|
||
ifFunctionsHaveNamesIt('has the right name', function () {
|
||
expect(Reflect.defineProperty.name).to.equal('defineProperty');
|
||
});
|
||
|
||
it('throws if the target isn’t an object', function () {
|
||
testPrimitiveThrow(function (item) {
|
||
return Reflect.defineProperty(item, 'prop', { value: true });
|
||
});
|
||
});
|
||
|
||
ifExtensionsPreventibleIt('returns false for non-extensible objects', function () {
|
||
var o = Object.preventExtensions({});
|
||
|
||
expect(Reflect.defineProperty(o, 'prop', {})).to.equal(false);
|
||
});
|
||
|
||
it('can return true, even for non-configurable, non-writable properties', function () {
|
||
var o = {};
|
||
var desc = {
|
||
value: 13,
|
||
enumerable: false,
|
||
writable: false,
|
||
configurable: false
|
||
};
|
||
|
||
expect(Reflect.defineProperty(o, 'prop', desc)).to.equal(true);
|
||
|
||
// Defined as non-configurable, but descriptor is identical.
|
||
expect(Reflect.defineProperty(o, 'prop', desc)).to.equal(true);
|
||
|
||
desc.value = 37; // Change
|
||
|
||
expect(Reflect.defineProperty(o, 'prop', desc)).to.equal(false);
|
||
});
|
||
|
||
it('can change from one property type to another, if configurable', function () {
|
||
var o = {};
|
||
|
||
var desc1 = {
|
||
set: function () {},
|
||
configurable: true
|
||
};
|
||
|
||
var desc2 = {
|
||
value: 13,
|
||
configurable: false
|
||
};
|
||
|
||
var desc3 = {
|
||
get: function () {}
|
||
};
|
||
|
||
expect(Reflect.defineProperty(o, 'prop', desc1)).to.equal(true);
|
||
|
||
expect(Reflect.defineProperty(o, 'prop', desc2)).to.equal(true);
|
||
|
||
expect(Reflect.defineProperty(o, 'prop', desc3)).to.equal(false);
|
||
});
|
||
});
|
||
|
||
describe('.deleteProperty()', function () {
|
||
if (typeof Reflect.deleteProperty === 'undefined') {
|
||
return it('exists', function () {
|
||
expect(Reflect).to.have.property('deleteProperty');
|
||
});
|
||
}
|
||
|
||
it('is a function', function () {
|
||
expect(typeof Reflect.deleteProperty).to.equal('function');
|
||
});
|
||
|
||
ifFunctionsHaveNamesIt('has the right name', function () {
|
||
expect(Reflect.deleteProperty.name).to.equal('deleteProperty');
|
||
});
|
||
|
||
it('throws if the target isn’t an object', function () {
|
||
testPrimitiveThrow(function (item) {
|
||
return Reflect.deleteProperty(item, 'prop');
|
||
});
|
||
});
|
||
|
||
ifES5It('returns true for success and false for failure', function () {
|
||
var o = { a: 1 };
|
||
|
||
Object.defineProperty(o, 'b', { value: 2 });
|
||
|
||
expect(o).to.have.property('a');
|
||
expect(o).to.have.property('b');
|
||
expect(o.a).to.equal(1);
|
||
expect(o.b).to.equal(2);
|
||
|
||
expect(Reflect.deleteProperty(o, 'a')).to.equal(true);
|
||
|
||
expect(o).not.to.have.property('a');
|
||
expect(o.b).to.equal(2);
|
||
|
||
expect(Reflect.deleteProperty(o, 'b')).to.equal(false);
|
||
|
||
expect(o).to.have.property('b');
|
||
expect(o.b).to.equal(2);
|
||
|
||
expect(Reflect.deleteProperty(o, 'a')).to.equal(true);
|
||
});
|
||
|
||
it('cannot delete an array’s length property', function () {
|
||
expect(Reflect.deleteProperty([], 'length')).to.equal(false);
|
||
});
|
||
});
|
||
|
||
describeIfES5('.get()', function () {
|
||
if (typeof Reflect.get === 'undefined') {
|
||
return it('exists', function () {
|
||
expect(Reflect).to.have.property('get');
|
||
});
|
||
}
|
||
|
||
it('is a function', function () {
|
||
expect(typeof Reflect.get).to.equal('function');
|
||
});
|
||
|
||
ifFunctionsHaveNamesIt('has the right name', function () {
|
||
expect(Reflect.get.name).to.equal('get');
|
||
});
|
||
|
||
it('throws on null and undefined', function () {
|
||
[null, undefined].forEach(function (item) {
|
||
expect(function () {
|
||
return Reflect.get(item, 'property');
|
||
}).to['throw'](TypeError);
|
||
});
|
||
});
|
||
|
||
it('can retrieve a simple value, from the target', function () {
|
||
var p = { something: 2, bool: false };
|
||
|
||
expect(Reflect.get(object, 'something')).to.equal(1);
|
||
// p has no effect
|
||
expect(Reflect.get(object, 'something', p)).to.equal(1);
|
||
|
||
// Value-defined properties take the target's value,
|
||
// and ignore that of the receiver.
|
||
expect(Reflect.get(object, 'bool', p)).to.equal(true);
|
||
|
||
// Undefined values
|
||
expect(Reflect.get(object, 'undefined_property')).to.equal(undefined);
|
||
});
|
||
|
||
it('will invoke getters on the receiver rather than target', function () {
|
||
var other = { _value: 1337 };
|
||
|
||
expect(Reflect.get(object, 'value', other)).to.equal(1337);
|
||
|
||
// No getter for setter property
|
||
expect(Reflect.get(object, 'setter', other)).to.equal(undefined);
|
||
});
|
||
|
||
it('will search the prototype chain', function () {
|
||
var other = Object.create(object);
|
||
other._value = 17;
|
||
|
||
var yetAnother = { _value: 4711 };
|
||
|
||
expect(Reflect.get(other, 'value', yetAnother)).to.equal(4711);
|
||
|
||
expect(Reflect.get(other, 'bool', yetAnother)).to.equal(true);
|
||
});
|
||
});
|
||
|
||
describeIfES5('.set()', function () {
|
||
if (typeof Reflect.set === 'undefined') {
|
||
return it('exists', function () {
|
||
expect(Reflect).to.have.property('set');
|
||
});
|
||
}
|
||
|
||
it('is a function', function () {
|
||
expect(typeof Reflect.set).to.equal('function');
|
||
});
|
||
|
||
ifFunctionsHaveNamesIt('has the right name', function () {
|
||
expect(Reflect.set.name).to.equal('set');
|
||
});
|
||
|
||
it('throws if the target isn’t an object', function () {
|
||
testPrimitiveThrow(function (item) {
|
||
return Reflect.set(item, 'prop', 'value');
|
||
});
|
||
});
|
||
|
||
it('sets values on receiver', function () {
|
||
var target = {};
|
||
var receiver = {};
|
||
|
||
expect(Reflect.set(target, 'foo', 1, receiver)).to.equal(true);
|
||
|
||
expect('foo' in target).to.equal(false);
|
||
expect(receiver.foo).to.equal(1);
|
||
|
||
expect(Reflect.defineProperty(receiver, 'bar', {
|
||
value: 0,
|
||
writable: true,
|
||
enumerable: false,
|
||
configurable: true
|
||
})).to.equal(true);
|
||
|
||
expect(Reflect.set(target, 'bar', 1, receiver)).to.equal(true);
|
||
expect(receiver.bar).to.equal(1);
|
||
expect(Reflect.getOwnPropertyDescriptor(receiver, 'bar').enumerable).to.equal(false);
|
||
|
||
var out;
|
||
/* eslint-disable accessor-pairs */
|
||
target = Object.create({}, {
|
||
o: {
|
||
set: function () { out = this; }
|
||
}
|
||
});
|
||
/* eslint-enable accessor-pairs */
|
||
|
||
expect(Reflect.set(target, 'o', 17, receiver)).to.equal(true);
|
||
expect(out).to.equal(receiver);
|
||
});
|
||
});
|
||
|
||
describeIfES5('.getOwnPropertyDescriptor()', function () {
|
||
if (typeof Reflect.getOwnPropertyDescriptor === 'undefined') {
|
||
return it('exists', function () {
|
||
expect(Reflect).to.have.property('getOwnPropertyDescriptor');
|
||
});
|
||
}
|
||
|
||
it('is a function', function () {
|
||
expect(typeof Reflect.getOwnPropertyDescriptor).to.equal('function');
|
||
});
|
||
|
||
ifFunctionsHaveNamesIt('has the right name', function () {
|
||
expect(Reflect.getOwnPropertyDescriptor.name).to.equal('getOwnPropertyDescriptor');
|
||
});
|
||
|
||
it('throws if the target isn’t an object', function () {
|
||
testPrimitiveThrow(function (item) {
|
||
return Reflect.getOwnPropertyDescriptor(item, 'prop');
|
||
});
|
||
});
|
||
|
||
it('retrieves property descriptors', function () {
|
||
var obj = { a: 4711 };
|
||
|
||
var desc = Reflect.getOwnPropertyDescriptor(obj, 'a');
|
||
|
||
expect(desc).to.deep.equal({
|
||
value: 4711,
|
||
configurable: true,
|
||
writable: true,
|
||
enumerable: true
|
||
});
|
||
});
|
||
});
|
||
|
||
describeIfGetProto('.getPrototypeOf()', function () {
|
||
if (typeof Reflect.getPrototypeOf === 'undefined') {
|
||
return it('exists', function () {
|
||
expect(Reflect).to.have.property('getPrototypeOf');
|
||
});
|
||
}
|
||
|
||
it('is a function', function () {
|
||
expect(typeof Reflect.getPrototypeOf).to.equal('function');
|
||
});
|
||
|
||
ifFunctionsHaveNamesIt('has the right name', function () {
|
||
expect(Reflect.getPrototypeOf.name).to.equal('getPrototypeOf');
|
||
});
|
||
|
||
it('throws if the target isn’t an object', function () {
|
||
testPrimitiveThrow(function (item) {
|
||
return Reflect.getPrototypeOf(item);
|
||
});
|
||
});
|
||
|
||
it('retrieves prototypes', function () {
|
||
expect(Reflect.getPrototypeOf(Object.create(null))).to.equal(null);
|
||
|
||
expect(Reflect.getPrototypeOf([])).to.equal(Array.prototype);
|
||
});
|
||
});
|
||
|
||
describe('.has()', function () {
|
||
if (typeof Reflect.has === 'undefined') {
|
||
return it('exists', function () {
|
||
expect(Reflect).to.have.property('has');
|
||
});
|
||
}
|
||
|
||
it('is a function', function () {
|
||
expect(typeof Reflect.has).to.equal('function');
|
||
});
|
||
|
||
ifFunctionsHaveNamesIt('has the right name', function () {
|
||
expect(Reflect.has.name).to.equal('has');
|
||
});
|
||
|
||
it('throws if the target isn’t an object', function () {
|
||
testPrimitiveThrow(function (item) {
|
||
return Reflect.has(item, 'prop');
|
||
});
|
||
});
|
||
|
||
it('will detect own properties', function () {
|
||
var target = Object.create ? Object.create(null) : {};
|
||
|
||
expect(Reflect.has(target, 'prop')).to.equal(false);
|
||
|
||
target.prop = undefined;
|
||
expect(Reflect.has(target, 'prop')).to.equal(true);
|
||
|
||
delete target.prop;
|
||
expect(Reflect.has(target, 'prop')).to.equal(false);
|
||
|
||
expect(Reflect.has(Reflect.has, 'length')).to.equal(true);
|
||
});
|
||
|
||
ifES5It('will detect an own accessor property', function () {
|
||
var target = Object.create(null);
|
||
/* eslint-disable accessor-pairs */
|
||
Object.defineProperty(target, 'accessor', {
|
||
set: function () {}
|
||
});
|
||
/* eslint-enable accessor-pairs */
|
||
|
||
expect(Reflect.has(target, 'accessor')).to.equal(true);
|
||
});
|
||
|
||
it('will search the prototype chain', function () {
|
||
var Parent = function () {};
|
||
Parent.prototype.someProperty = undefined;
|
||
|
||
var Child = function () {};
|
||
Child.prototype = new Parent();
|
||
|
||
var target = new Child();
|
||
target.bool = true;
|
||
|
||
expect(Reflect.has(target, 'bool')).to.equal(true);
|
||
expect(Reflect.has(target, 'someProperty')).to.equal(true);
|
||
expect(Reflect.has(target, 'undefinedProperty')).to.equal(false);
|
||
});
|
||
});
|
||
|
||
describeIfExtensionsPreventible('.isExtensible()', function () {
|
||
if (typeof Reflect.isExtensible === 'undefined') {
|
||
return it('exists', function () {
|
||
expect(Reflect).to.have.property('isExtensible');
|
||
});
|
||
}
|
||
|
||
it('is a function', function () {
|
||
expect(typeof Reflect.isExtensible).to.equal('function');
|
||
});
|
||
|
||
ifFunctionsHaveNamesIt('has the right name', function () {
|
||
expect(Reflect.isExtensible.name).to.equal('isExtensible');
|
||
});
|
||
|
||
it('returns true for plain objects', function () {
|
||
expect(Reflect.isExtensible({})).to.equal(true);
|
||
expect(Reflect.isExtensible(Object.preventExtensions({}))).to.equal(false);
|
||
});
|
||
|
||
it('throws if the target isn’t an object', function () {
|
||
testPrimitiveThrow(function (item) {
|
||
return Reflect.isExtensible(item);
|
||
});
|
||
});
|
||
});
|
||
|
||
describeIfGetOwnPropertyNames('.ownKeys()', function () {
|
||
if (typeof Reflect.ownKeys === 'undefined') {
|
||
return it('exists', function () {
|
||
expect(Reflect).to.have.property('ownKeys');
|
||
});
|
||
}
|
||
|
||
it('is a function', function () {
|
||
expect(typeof Reflect.ownKeys).to.equal('function');
|
||
});
|
||
|
||
ifFunctionsHaveNamesIt('has the right name', function () {
|
||
expect(Reflect.ownKeys.name).to.equal('ownKeys');
|
||
});
|
||
|
||
it('throws if the target isn’t an object', function () {
|
||
testPrimitiveThrow(function (item) {
|
||
return Reflect.ownKeys(item);
|
||
});
|
||
});
|
||
|
||
it('should return the same result as Object.getOwnPropertyNames if there are no Symbols', function () {
|
||
var obj = { foo: 1, bar: 2 };
|
||
|
||
obj[1] = 'first';
|
||
|
||
var result = Object.getOwnPropertyNames(obj);
|
||
|
||
// Reflect.ownKeys depends on the implementation of
|
||
// Object.getOwnPropertyNames, at least for non-symbol keys.
|
||
expect(Reflect.ownKeys(obj)).to.deep.equal(result);
|
||
|
||
// We can only be sure of which keys should exist.
|
||
expect(result.sort()).to.deep.equal(['1', 'bar', 'foo']);
|
||
});
|
||
|
||
ifSymbolsIt('symbols come last', function () {
|
||
var s = Symbol();
|
||
|
||
var o = {
|
||
'non-symbol': true
|
||
};
|
||
|
||
o[s] = true;
|
||
|
||
expect(Reflect.ownKeys(o)).to.deep.equal(['non-symbol', s]);
|
||
});
|
||
});
|
||
|
||
describeIfExtensionsPreventible('.preventExtensions()', function () {
|
||
if (typeof Reflect.preventExtensions === 'undefined') {
|
||
return it('exists', function () {
|
||
expect(Reflect).to.have.property('preventExtensions');
|
||
});
|
||
}
|
||
|
||
it('is a function', function () {
|
||
expect(typeof Reflect.preventExtensions).to.equal('function');
|
||
});
|
||
|
||
ifFunctionsHaveNamesIt('has the right name', function () {
|
||
expect(Reflect.preventExtensions.name).to.equal('preventExtensions');
|
||
});
|
||
|
||
it('throws if the target isn’t an object', function () {
|
||
testPrimitiveThrow(function (item) {
|
||
return Reflect.preventExtensions(item);
|
||
});
|
||
});
|
||
|
||
it('prevents extensions on objects', function () {
|
||
var obj = {};
|
||
Reflect.preventExtensions(obj);
|
||
expect(Object.isExtensible(obj)).to.equal(false);
|
||
});
|
||
});
|
||
|
||
describeIfSetProto('.setPrototypeOf()', function () {
|
||
if (typeof Reflect.setPrototypeOf === 'undefined') {
|
||
return it('exists', function () {
|
||
expect(Reflect).to.have.property('setPrototypeOf');
|
||
});
|
||
}
|
||
|
||
it('is a function', function () {
|
||
expect(typeof Reflect.setPrototypeOf).to.equal('function');
|
||
});
|
||
|
||
ifFunctionsHaveNamesIt('has the right name', function () {
|
||
expect(Reflect.setPrototypeOf.name).to.equal('setPrototypeOf');
|
||
});
|
||
|
||
it('throws if the target isn’t an object', function () {
|
||
testPrimitiveThrow(function (item) {
|
||
return Reflect.setPrototypeOf(item, null);
|
||
});
|
||
});
|
||
|
||
it('throws if the prototype is neither object nor null', function () {
|
||
var o = {};
|
||
|
||
[undefined, 1, 'string', true].forEach(function (item) {
|
||
expect(function () {
|
||
return Reflect.setPrototypeOf(o, item);
|
||
}).to['throw'](TypeError);
|
||
});
|
||
});
|
||
|
||
it('can set prototypes, and returns true on success', function () {
|
||
var obj = {};
|
||
|
||
expect(Reflect.setPrototypeOf(obj, Array.prototype)).to.equal(true);
|
||
expect(obj).to.be.an.instanceOf(Array);
|
||
|
||
expect(obj.toString).not.to.equal(undefined);
|
||
expect(Reflect.setPrototypeOf(obj, null)).to.equal(true);
|
||
expect(obj.toString).to.equal(undefined);
|
||
});
|
||
|
||
ifFreezeIt('is returns false on failure', function () {
|
||
var obj = Object.freeze({});
|
||
|
||
expect(Reflect.setPrototypeOf(obj, null)).to.equal(false);
|
||
});
|
||
|
||
it('fails when attempting to create a circular prototype chain', function () {
|
||
var o = {};
|
||
|
||
expect(Reflect.setPrototypeOf(o, o)).to.equal(false);
|
||
});
|
||
});
|
||
});
|