1 /* Any copyright is dedicated to the Public Domain.
2 * http://creativecommons.org/licenses/publicdomain/ */
4 // Reflect.set does property assignment.
5 // With three arguments, this is pretty straightforward.
7 assertEq(Reflect.set(obj, "prop", "value"), true);
8 assertEq(obj.prop, "value");
11 // === Various targets
13 // It can assign array elements.
14 var arr = ["duck", "duck", "duck"];
15 assertEq(Reflect.set(arr, 2, "goose"), true);
16 assertEq(arr[2], "goose");
18 // It can extend an array.
19 assertEq(Reflect.set(arr, 3, "Model T"), true);
20 assertEq(arr.length, 4);
22 // It can truncate an array.
23 assertEq(Reflect.set(arr, "length", 1), true);
24 assertDeepEq(arr, ["duck"]);
26 // It won't assign to non-writable properties of String objects.
27 var str = new String("hello");
28 assertEq(Reflect.set(str, "0", "y"), false);
29 assertEq(str[0], "h");
30 assertEq(Reflect.set(str, "length", 700), false);
31 assertEq(str.length, 5);
35 // The optional fourth argument is the receiver, which [[Set]] methods use for
38 // On ordinary objects, if the property has a setter, the receiver is passed as
39 // the this-value to the setter.
45 assertEq(this, expected);
48 for (expected of [obj, {}, [], 37.3]) {
49 assertEq(Reflect.set(obj, "prop", 32, expected), true);
52 // If the property doesn't already exist, it is defined on the receiver.
55 assertEq(Reflect.set(obj, "prop", 47, obj2), true);
56 assertDeepEq(obj, {});
57 assertDeepEq(Reflect.getOwnPropertyDescriptor(obj2, "prop"),
58 {value: 47, writable: true, enumerable: true, configurable: true});
60 // If the property doesn't already exist, and the receiver isn't an object, return false.
61 for (var v of SOME_PRIMITIVE_VALUES) {
62 assertEq(Reflect.set({}, "x", 0, v), false);
65 // Receiver defaults to the target.
69 var proxy = new Proxy(obj, {
74 assertEq(r, expectedReceiver); // not obj
80 expectedReceiver = proxy;
81 assertEq(Reflect.set(proxy, "key", "value"), true);
84 // But not if explicitly present and undefined.
86 expectedReceiver = undefined;
87 assertEq(Reflect.set(proxy, "key", "value", undefined), true);
90 // Reflect.set can be used as fallback behavior in a proxy handler .set()
97 assertEq(this, proxy); // not obj!
100 proxy = new Proxy(obj, {
105 return Reflect.set(t, k, v, r);
109 assertEq(Reflect.set(proxy, "prop", "value"), true);
113 // === Cross-compartment wrapper behavior.
115 // When calling a cross-compartment wrapper, receiver is rewrapped for the
116 // target compartment.
118 if (!("assertEq" in g))
119 g.assertEq = assertEq; // necessary in the browser
125 assertEq(this, receiver);
126 assertEq(v, "xyzzy");
133 assertEq(Reflect.set(g.obj, "x", "xyzzy", g.receiver), true);
136 // ...even when receiver is from a different compartment than target.
138 g.receiver = receiver;
140 assertEq(Reflect.set(g.obj, "x", "xyzzy", receiver), true);
143 // ...even when receiver is a primtive value, even undefined.
144 for (receiver of SOME_PRIMITIVE_VALUES) {
145 g.receiver = receiver;
147 assertEq(Reflect.set(g.obj, "x", "xyzzy", receiver), true);
152 // === Less than 3 arguments
154 // With two arguments, the value is assumed to be undefined.
156 assertEq(Reflect.set(obj, "size"), true);
157 assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "size"),
158 {value: undefined, writable: true, enumerable: true, configurable: true});
160 // With just one argument, the key is "undefined".
162 assertEq(Reflect.set(obj), true);
163 assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "undefined"),
164 {value: undefined, writable: true, enumerable: true, configurable: true});
166 // For the no argument-case, see target.js.
171 // Non-writable data property
173 Reflect.defineProperty(obj, "x", {value: 0, writable: false});
174 assertEq(Reflect.set(obj, "x", 1), false);
177 // The same, but inherited from a prototype
178 var obj2 = Object.create(obj);
179 assertEq(Reflect.set(obj2, "x", 1), false);
180 assertEq(obj2.hasOwnProperty("x"), false);
185 var desc = {get: () => 12, set: undefined, enumerable: false, configurable: true};
186 Reflect.defineProperty(obj, "y", desc);
187 assertEq(Reflect.set(obj, "y", 13), false);
188 assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "y"), desc);
190 // The same, but inherited from a prototype
191 obj2 = Object.create(obj);
192 assertEq(Reflect.set(obj2, "y", 1), false);
193 assertEq(obj2.hasOwnProperty("y"), false);
194 assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "y"), desc);
196 // Proxy set handler returns a false value
197 for (var no of [false, ""]) {
200 var proxy = new Proxy(obj, {
210 assertEq(Reflect.set(proxy, "x", 33), false);
212 assertEq("x" in obj, false);
215 // Proxy handler method throws
217 proxy = new Proxy(obj, {
218 set(t, k, v, r) { throw "i don't like " + v; }
220 assertThrowsValue(() => Reflect.set(proxy, "food", "cheese"), "i don't like cheese");
222 // If a Proxy set handler breaks the object invariants, it's a TypeError.
223 for (obj of [{a: 0}, {get a() { return 0; }}]) {
225 proxy = new Proxy(obj, {
226 set(t, k, v, r) { return true; }
228 assertThrowsInstanceOf(() => Reflect.set(proxy, "a", "b"), TypeError);
231 // Per spec, this should first call p.[[Set]]("0", 42, a) and
232 // then (since p has no own properties) a.[[Set]]("0", 42, a).
233 // The latter should not define a property on p.
234 var a = [0, 1, 2, 3];
235 var p = Object.create(a);
236 Reflect.set(p, "0", 42, a);
237 assertEq(p.hasOwnProperty("0"), false);
238 assertDeepEq(Reflect.getOwnPropertyDescriptor(a, "0"),
239 {value: 42, writable: true, enumerable: true, configurable: true});
241 // Test behavior of ordinary objects' [[Set]] method (ES6 9.1.9).
242 // On an ordinary object, if the property key isn't present, [[Set]] calls
243 // receiver.[[GetOwnProperty]]() and then receiver.[[DefineProperty]]().
246 var proxyTarget = {};
247 var existingDescriptor, expected, defineResult;
248 var receiver = new Proxy(proxyTarget, {
249 getOwnPropertyDescriptor(t, k) {
251 return existingDescriptor;
253 defineProperty(t, k, desc) {
255 assertEq(t, proxyTarget);
257 assertDeepEq(desc, expected);
261 existingDescriptor = undefined;
262 expected = {value: 5, writable: true, enumerable: true, configurable: true};
263 for (var defineResult of [true, false]) {
265 assertEq(Reflect.set(obj, "prop", 5, receiver), defineResult);
269 existingDescriptor = {value: 7, writable: true, enumerable: false, configurable: true};
270 expected = {value: 4};
271 for (var defineResult of [true, false]) {
273 assertEq(Reflect.set(obj, "prop", 4, receiver), defineResult);
278 // For more Reflect.set tests, see target.js and propertyKeys.js.