Bug 1929040 - [wpt-sync] Update web-platform-tests to d4fb35c4980b6581ce0535b2dac71cb...
[gecko.git] / dom / bindings / test / test_observablearray_proxyhandler.html
blob00ef7c26b4e72bda1a7ca05e13f646c0837db305
1 <!-- Any copyright is dedicated to the Public Domain.
2 - http://creativecommons.org/publicdomain/zero/1.0/ -->
3 <!DOCTYPE HTML>
4 <html>
5 <head>
6 <title>Test Observable Array Type</title>
7 <script src="/tests/SimpleTest/SimpleTest.js"></script>
8 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
9 </head>
10 <body>
11 <script>
12 /* global TestInterfaceObservableArray */
14 add_task(async function init() {
15 await SpecialPowers.pushPrefEnv({set: [["dom.expose_test_interfaces", true]]});
16 });
18 add_task(function testObservableArrayExoticObjects_defineProperty() {
19 let setCallbackCount = 0;
20 let deleteCallbackCount = 0;
21 let setCallbackTests = null;
22 let deleteCallbackTests = null;
24 let m = new TestInterfaceObservableArray({
25 setBooleanCallback(value, index) {
26 setCallbackCount++;
27 if (typeof setCallbackTests === 'function') {
28 setCallbackTests(value, index);
31 deleteBooleanCallback(value, index) {
32 deleteCallbackCount++;
33 if (typeof deleteCallbackTests === 'function') {
34 deleteCallbackTests(value, index);
37 });
38 m.observableArrayBoolean = [true, true, true];
40 let b = m.observableArrayBoolean;
41 ok(Array.isArray(b), "observable array should be an array type");
42 is(b.length, 3, "length of observable array should be 0");
44 // Test length
46 // [descriptor, shouldThrow, expectedResult]
47 // Invalid descriptor
48 [{configurable: true, value: 0}, false, false],
49 [{enumerable: true, value: 0}, false, false],
50 [{writable: false, value: 0}, false, false],
51 [{get: ()=>{}}, false, false],
52 [{set: ()=>{}}, false, false],
53 [{get: ()=>{}, set: ()=>{}}, false, false],
54 [{get: ()=>{}, value: 0}, true],
55 // Invalid length value
56 [{value: 1.9}, true],
57 [{value: "invalid"}, true],
58 [{value: {}}, true],
59 // length value should not greater than current length
60 [{value: b.length + 1}, false, false],
61 // descriptor without value
62 [{configurable: false, enumerable: false, writable: true}, false, true],
63 // Success
64 [{value: b.length}, false, true],
65 [{value: b.length - 1}, false, true],
66 [{value: 0}, false, true],
67 ].forEach(function([descriptor, shouldThrow, expectedResult]) {
68 // Initialize
69 let oldLen = b.length;
70 let oldValues = b.slice();
71 let deleteCallbackIndex = oldLen - 1;
72 let success = expectedResult && "value" in descriptor;
73 setCallbackCount = 0;
74 deleteCallbackCount = 0;
75 setCallbackTests = null;
76 deleteCallbackTests = function(_value, _index) {
77 is(_value, oldValues[deleteCallbackIndex], "deleteCallbackTests: test value argument");
78 is(_index, deleteCallbackIndex, "deleteCallbackTests: test index argument");
79 deleteCallbackIndex--;
82 // Test
83 info(`defining "length" property with ${JSON.stringify(descriptor)}`);
84 try {
85 is(Reflect.defineProperty(b, "length", descriptor), expectedResult,
86 `Reflect.defineProperty should return ${expectedResult}`);
87 ok(!shouldThrow, "Reflect.defineProperty should not throw");
88 } catch(e) {
89 ok(shouldThrow, `Reflect.defineProperty throws ${e}`);
91 is(setCallbackCount, 0, "setCallback count");
92 is(deleteCallbackCount, success ? oldLen - descriptor.value : 0, "deleteCallback count");
93 isDeeply(b, success ? oldValues.slice(0, descriptor.value) : oldValues, "property values");
94 is(b.length, success ? descriptor.value : oldLen, "length of observable array");
95 });
97 // Test indexed value
99 // [index, descriptor, shouldThrow, expectedResult]
100 // Invalid descriptor
101 [0, {configurable: false, value: true}, false, false],
102 [0, {enumerable: false, value: true}, false, false],
103 [0, {writable: false, value: true}, false, false],
104 [0, {get: ()=>{}}, false, false],
105 [0, {set: ()=>{}}, false, false],
106 [0, {get: ()=>{}, set: ()=>{}}, false, false],
107 [0, {get: ()=>{}, value: true}, true],
108 // Index could not greater than last index + 1.
109 [b.length + 1, {configurable: true, enumerable: true, value: true}, false, false],
110 // descriptor without value
111 [b.length, {configurable: true, enumerable: true}, false, true],
112 // Success
113 [b.length, {configurable: true, enumerable: true, value: true}, false, true],
114 [b.length + 1, {configurable: true, enumerable: true, value: true}, false, true],
115 ].forEach(function([index, descriptor, shouldThrow, expectedResult]) {
116 // Initialize
117 let oldLen = b.length;
118 let oldValue = b[index];
119 let success = expectedResult && "value" in descriptor;
120 setCallbackCount = 0;
121 deleteCallbackCount = 0;
122 setCallbackTests = function(_value, _index) {
123 is(_value, descriptor.value, "setCallbackTests: test value argument");
124 is(_index, index, "setCallbackTests: test index argument");
126 deleteCallbackTests = function(_value, _index) {
127 is(_value, oldValue, "deleteCallbackTests: test value argument");
128 is(_index, index, "deleteCallbackTests: test index argument");
131 // Test
132 info(`defining ${index} property with ${JSON.stringify(descriptor)}`);
133 try {
134 is(Reflect.defineProperty(b, index, descriptor), expectedResult,
135 `Reflect.defineProperty should return ${expectedResult}`);
136 ok(!shouldThrow, "Reflect.defineProperty should not throw");
137 } catch(e) {
138 ok(shouldThrow, `Reflect.defineProperty throws ${e}`);
140 is(setCallbackCount, success ? 1 : 0, "setCallback count");
141 is(deleteCallbackCount, (oldLen > index) ? 1 : 0, "deleteCallback count");
142 is(b[index], success ? descriptor.value : oldValue, "property value");
143 is(b.length, success ? Math.max(index + 1, oldLen) : oldLen, "length of observable array");
146 // Test other property
148 // [property, descriptor, shouldThrow, expectedResult]
149 ["prop1", {configurable: false, value: "value1"}, false, true],
150 ["prop1", {configurable: true, value: "value2"}, false, false],
151 ["prop2", {enumerable: false, value: 5}, false, true],
152 ["prop3", {enumerable: false, value: []}, false, true],
153 ["prop4", {enumerable: false, value: {}}, false, true],
154 ["prop5", {get: ()=>{}, value: true}, true, false],
155 ["prop6", {get: ()=>{}, set: ()=>{}}, false, true],
156 ].forEach(function([property, descriptor, shouldThrow, expectedResult]) {
157 // Initialize
158 let oldValue = b[property];
159 let oldLen = b.length;
160 setCallbackCount = 0;
161 deleteCallbackCount = 0;
162 setCallbackTests = null;
163 deleteCallbackTests = null;
165 // Test
166 info(`defining ${property} property with ${JSON.stringify(descriptor)}`);
167 try {
168 is(Reflect.defineProperty(b, property, descriptor), expectedResult,
169 `Reflect.defineProperty should return ${expectedResult}`);
170 ok(!shouldThrow, "Reflect.defineProperty should not throw");
171 } catch(e) {
172 ok(shouldThrow, `Reflect.defineProperty throws ${e}`);
174 is(setCallbackCount, 0, "setCallback count");
175 is(deleteCallbackCount, 0, "deleteCallback count");
176 is(b[property], expectedResult ? descriptor.value : oldValue, "property value");
177 is(b.length, oldLen, "length of observable array");
181 add_task(function testObservableArrayExoticObjects_defineProperty_callback_throw() {
182 let setCallbackCount = 0;
183 let deleteCallbackCount = 0;
185 const minLen = 3;
186 let m = new TestInterfaceObservableArray({
187 setBooleanCallback(value) {
188 setCallbackCount++;
189 if (value) {
190 throw new Error("setBooleanCallback");
193 deleteBooleanCallback(value, index) {
194 deleteCallbackCount++;
195 if (index < minLen) {
196 throw new Error("deleteBooleanCallback");
200 m.observableArrayBoolean = [false, false, false, false, false];
202 let b = m.observableArrayBoolean;
203 ok(Array.isArray(b), "observable array should be an array type");
204 is(b.length, 5, "length of observable array should be 3");
206 // Test length
208 // [length, shouldThrow]
209 [b.length, false],
210 [b.length - 1, false],
211 [0, true],
212 ].forEach(function([length, shouldThrow]) {
213 // Initialize
214 let oldValues = b.slice();
215 let oldLen = b.length;
216 let descriptor = {value: length};
217 setCallbackCount = 0;
218 deleteCallbackCount = 0;
220 // Test
221 info(`defining "length" property with ${JSON.stringify(descriptor)}`);
222 try {
223 ok(Reflect.defineProperty(b, "length", descriptor),
224 "Reflect.defineProperty should return true");
225 ok(!shouldThrow, "Reflect.defineProperty should not throw");
226 } catch(e) {
227 ok(shouldThrow, `Reflect.defineProperty throws ${e}`);
229 is(setCallbackCount, 0, "setCallback count");
230 is(deleteCallbackCount, oldLen - (shouldThrow ? minLen - 1 : length), "deleteCallback count");
231 isDeeply(b, oldValues.slice(0, shouldThrow ? minLen : length), "property values");
232 is(b.length, shouldThrow ? minLen : length, "length of observable array");
235 // Test indexed value
237 // [index, value, shouldThrow]
238 [b.length, true, true],
239 [b.length, false, false],
240 [b.length + 1, false, false],
241 [b.length + 1, true, true],
242 [0, true, true],
243 [0, false, true],
244 ].forEach(function([index, value, shouldThrow]) {
245 // Initialize
246 let oldValue = b[index];
247 let oldLen = b.length;
248 let descriptor = {configurable: true, enumerable: true, value};
249 setCallbackCount = 0;
250 deleteCallbackCount = 0;
252 // Test
253 info(`defining ${index} property with ${JSON.stringify(descriptor)}`);
254 try {
255 ok(Reflect.defineProperty(b, index, descriptor), "Reflect.defineProperty should return true");
256 ok(!shouldThrow, "Reflect.defineProperty should not throw");
257 } catch(e) {
258 ok(shouldThrow, `Reflect.defineProperty throws ${e}`);
260 is(setCallbackCount, (index < minLen) ? 0 : 1, "setCallback count");
261 is(deleteCallbackCount, (oldLen > index) ? 1 : 0, "deleteCallback count");
262 is(b[index], shouldThrow ? oldValue : value, "property value");
263 is(b.length, shouldThrow ? oldLen : Math.max(oldLen, index + 1), "length of observable array");
266 // Test other property
268 // [property, descriptor, expectedResult]
269 ["prop1", {configurable: false, value: "value1"}, true],
270 ["prop1", {configurable: true, value: "value2"}, false],
271 ["prop2", {enumerable: false, value: 5}, true],
272 ["prop3", {enumerable: false, value: []}, true],
273 ["prop4", {enumerable: false, value: {}}, true],
274 ].forEach(function([property, descriptor, expectedResult]) {
275 // Initialize
276 let oldValue = b[property];
277 let oldLen = b.length;
278 setCallbackCount = 0;
279 deleteCallbackCount = 0;
281 // Test
282 info(`defining ${property} property with ${JSON.stringify(descriptor)}`);
283 try {
284 is(Reflect.defineProperty(b, property, descriptor), expectedResult,
285 `Reflect.defineProperty should return ${expectedResult}`);
286 ok(true, "Reflect.defineProperty should not throw");
287 } catch(e) {
288 ok(false, `Reflect.defineProperty throws ${e}`);
290 is(setCallbackCount, 0, "setCallback count");
291 is(deleteCallbackCount, 0, "deleteCallback count");
292 is(b[property], expectedResult ? descriptor.value : oldValue, "property value");
293 is(b.length, oldLen, "length of observable array");
297 add_task(function testObservableArrayExoticObjects_deleteProperty() {
298 let setCallbackCount = 0;
299 let deleteCallbackCount = 0;
300 let deleteCallbackTests = null;
302 let m = new TestInterfaceObservableArray({
303 setBooleanCallback() {
304 setCallbackCount++;
306 deleteBooleanCallback(value, index) {
307 deleteCallbackCount++;
308 if (typeof deleteCallbackTests === 'function') {
309 deleteCallbackTests(value, index);
313 m.observableArrayBoolean = [true, true];
315 let b = m.observableArrayBoolean;
316 ok(Array.isArray(b), "observable array should be an array type");
317 is(b.length, 2, "length of observable array should be 2");
319 // Test length
320 setCallbackCount = 0;
321 deleteCallbackCount = 0;
322 info("deleting length property");
323 ok(!Reflect.deleteProperty(b, "length"), "test result of deleting length property");
324 is(setCallbackCount, 0, "setCallback should not be called");
325 is(deleteCallbackCount, 0, "deleteCallback should not be called");
326 is(b.length, 2, "length should still be 2");
328 // Test indexed value
330 // [index, expectedResult]
331 [2, false],
332 [0, false],
333 [1, true],
334 ].forEach(function([index, expectedResult]) {
335 // Initialize
336 let oldLen = b.length;
337 let oldValue = b[index];
338 setCallbackCount = 0;
339 deleteCallbackCount = 0;
340 deleteCallbackTests = function(_value, _index) {
341 is(_value, oldValue, "deleteCallbackTests: test value argument");
342 is(_index, index, "deleteCallbackTests: test index argument");
345 // Test
346 info(`deleting ${index} property`);
347 is(Reflect.deleteProperty(b, index), expectedResult,
348 `Reflect.deleteProperty should return ${expectedResult}`);
349 is(setCallbackCount, 0, "setCallback count");
350 is(deleteCallbackCount, expectedResult ? 1 : 0, "deleteCallback count");
351 is(b[index], expectedResult ? undefined : oldValue, "property value");
352 is(b.length, expectedResult ? oldLen - 1 : oldLen,
353 "length of observable array");
356 // Test other property
358 // [property, value]
359 ["prop1", "value1"],
360 ["prop2", 5],
361 ["prop3", []],
362 ["prop4", {}],
363 ].forEach(function([property, value]) {
364 // Initialize
365 b[property] = value;
366 let oldLen = b.length;
367 setCallbackCount = 0;
368 deleteCallbackCount = 0;
369 deleteCallbackTests = null;
371 // Test
372 info(`deleting ${property} property`);
373 is(b[property], value, `property value should be ${value} before deleting`);
374 ok(Reflect.deleteProperty(b, property), "Reflect.deleteProperty should return true");
375 is(setCallbackCount, 0, "setCallback count");
376 is(deleteCallbackCount, 0, "deleteCallback count");
377 is(b[property], undefined, "property value should be undefined after deleting");
378 is(b.length, oldLen, "length of observable array");
382 add_task(function testObservableArrayExoticObjects_deleteProperty_callback_throw() {
383 let setCallbackCount = 0;
384 let deleteCallbackCount = 0;
386 let m = new TestInterfaceObservableArray({
387 setBooleanCallback() {
388 setCallbackCount++;
390 deleteBooleanCallback(value) {
391 deleteCallbackCount++;
392 if (value) {
393 throw new Error("deleteBooleanCallback");
397 m.observableArrayBoolean = [true, false];
399 let b = m.observableArrayBoolean;
400 ok(Array.isArray(b), "observable array should be an array type");
401 is(b.length, 2, "length of observable array should be 2");
403 // Test indexed value
404 let index = b.length;
405 while (index--) {
406 // Initialize
407 let oldValue = b[index];
408 let oldLen = b.length;
409 setCallbackCount = 0;
410 deleteCallbackCount = 0;
412 // Test
413 info(`deleting index ${index}`);
414 try {
415 ok(Reflect.deleteProperty(b, index), "Reflect.deleteProperty should return true");
416 ok(!oldValue, "Reflect.deleteProperty should not throw");
417 } catch(e) {
418 ok(oldValue, `Reflect.deleteProperty throws ${e}`);
420 is(setCallbackCount, 0, "setCallback count");
421 is(deleteCallbackCount, 1, "deleteCallback count");
422 is(b[index], oldValue ? oldValue : undefined, "property value");
423 is(b.length, oldValue ? oldLen : oldLen - 1, "length of observable array");
426 // Test other property
428 // [property, value]
429 ["prop1", "value1"],
430 ["prop2", 5],
431 ["prop3", []],
432 ["prop4", {}],
433 ["prop5", false],
434 ].forEach(function([property, value]) {
435 // Initialize
436 b[property] = value;
437 let oldLen = b.length;
438 setCallbackCount = 0;
439 deleteCallbackCount = 0;
441 // Test
442 info(`deleting ${property} property`);
443 is(b[property], value, `property value should be ${JSON.stringify(value)} before deleting`);
444 try {
445 ok(Reflect.deleteProperty(b, property), `Reflect.deleteProperty should return true`);
446 ok(true, "Reflect.deleteProperty should not throw");
447 } catch(e) {
448 ok(false, `Reflect.deleteProperty throws ${e}`);
450 is(setCallbackCount, 0, "setCallback count");
451 is(deleteCallbackCount, 0, "deleteCallback count");
452 is(b[property], undefined, `property value should be undefined after deleting`);
453 is(b.length, oldLen, "length of observable array");
457 add_task(function testObservableArrayExoticObjects_get() {
458 let m = new TestInterfaceObservableArray();
459 m.observableArrayBoolean = [true, false];
461 let b = m.observableArrayBoolean;
462 ok(Array.isArray(b), "observable array should be an array type");
463 is(b.length, 2, "length of observable array should be 2");
465 // Test length
466 is(Reflect.get(b, "length"), 2, "test result of getting length property");
468 // Test indexed value
469 is(Reflect.get(b, 0), true, "test result of getting index 0");
470 is(Reflect.get(b, 1), false, "test result of getting index 1");
471 is(Reflect.get(b, 2), undefined, "test result of getting index 2");
473 // Test other property
475 // [property, value]
476 ["prop1", "value1"],
477 ["prop2", 5],
478 ["prop3", []],
479 ["prop4", {}],
480 ].forEach(function([property, value]) {
481 is(Reflect.get(b, property), undefined, `test ${property} property before setting property value`);
482 b[property] = value;
483 is(Reflect.get(b, property), value, `test ${property} property after setting property value`);
487 add_task(function testObservableArrayExoticObjects_getOwnPropertyDescriptor() {
488 function TestDescriptor(object, property, exist, configurable, enumerable,
489 writable, value) {
490 let descriptor = Reflect.getOwnPropertyDescriptor(object, property);
491 if (!exist) {
492 is(descriptor, undefined, `descriptor of ${property} property should be undefined`);
493 return;
496 is(descriptor.configurable, configurable, `test descriptor of ${property} property (configurable)`);
497 is(descriptor.enumerable, enumerable, `test descriptor of ${property} property (enumerable)`);
498 is(descriptor.writable, writable, `test descriptor of ${property} property (writable)`);
499 is(descriptor.value, value, `test descriptor of ${property} property (value)`);
502 let m = new TestInterfaceObservableArray();
503 m.observableArrayBoolean = [true, false];
505 let b = m.observableArrayBoolean;
506 ok(Array.isArray(b), "observable array should be an array type");
507 is(b.length, 2, "length of observable array should be 2");
509 // Test length
510 TestDescriptor(b, "length", true, false /* configurable */,
511 false /* enumerable */, true /* writable */ , 2 /* value */);
513 // Test indexed value
514 TestDescriptor(b, 0, true, true /* configurable */, true /* enumerable */,
515 true /* writable */ , true /* value */);
516 TestDescriptor(b, 1, true, true /* configurable */, true /* enumerable */,
517 true /* writable */ , false /* value */);
518 TestDescriptor(b, 2, false);
520 // Test other property
522 // [property, value, configurable, enumerable, writable]
523 ["prop1", "value1", true, true, true],
524 ["prop2", 5, true, true, false],
525 ["prop3", [], true, false, false],
526 ["prop4", {}, false, false, false],
527 ].forEach(function([property, value, configurable, enumerable, writable]) {
528 Object.defineProperty(b, property, {
529 value,
530 configurable,
531 enumerable,
532 writable,
534 TestDescriptor(b, property, true, configurable, enumerable, writable , value);
538 add_task(function testObservableArrayExoticObjects_has() {
539 let m = new TestInterfaceObservableArray();
540 m.observableArrayBoolean = [true, false];
542 let b = m.observableArrayBoolean;
543 ok(Array.isArray(b), "observable array should be an array type");
544 is(b.length, 2, "length of observable array should be 2");
546 // Test length
547 ok(Reflect.has(b, "length"), `test length property`);
549 // Test indexed value
550 ok(Reflect.has(b, 0), `test 0 property`);
551 ok(Reflect.has(b, 1), `test 1 property`);
552 ok(!Reflect.has(b, 2), `test 2 property`);
554 // Test other property
556 // [property, value]
557 ["prop1", "value1"],
558 ["prop2", 5],
559 ["prop3", []],
560 ["prop4", {}],
561 ].forEach(function([property, value]) {
562 ok(!Reflect.has(b, property), `test ${property} property before setting property value`);
563 b[property] = value;
564 ok(Reflect.has(b, property), `test ${property} property after setting property value`);
568 add_task(function testObservableArrayExoticObjects_ownKeys() {
569 let m = new TestInterfaceObservableArray();
570 m.observableArrayBoolean = [true, false];
572 let b = m.observableArrayBoolean;
573 ok(Array.isArray(b), "observable array should be an array type");
574 is(b.length, 2, "length of observable array should be 2");
576 // Add other properties
577 b.prop1 = "value1";
578 b.prop2 = 5;
579 b.prop3 = [];
580 b.prop4 = {};
582 let keys = Reflect.ownKeys(b);
583 SimpleTest.isDeeply(keys, ["0", "1", "length", "prop1", "prop2", "prop3", "prop4"], `test property keys`);
586 add_task(function testObservableArrayExoticObjects_preventExtensions() {
587 let m = new TestInterfaceObservableArray();
588 let b = m.observableArrayBoolean;
589 ok(Array.isArray(b), "observable array should be an array type");
590 is(b.length, 0, "length of observable array should be 0");
592 // Test preventExtensions
593 ok(Reflect.isExtensible(b), "test isExtensible before preventExtensions");
594 ok(!Reflect.preventExtensions(b), "test preventExtensions");
595 ok(Reflect.isExtensible(b), "test isExtensible after preventExtensions");
598 add_task(function testObservableArrayExoticObjects_set() {
599 let setCallbackCount = 0;
600 let deleteCallbackCount = 0;
601 let setCallbackTests = null;
602 let deleteCallbackTests = null;
604 let m = new TestInterfaceObservableArray({
605 setBooleanCallback(value, index) {
606 setCallbackCount++;
607 if (typeof setCallbackTests === 'function') {
608 setCallbackTests(value, index);
611 deleteBooleanCallback(value, index) {
612 deleteCallbackCount++;
613 if (typeof deleteCallbackTests === 'function') {
614 deleteCallbackTests(value, index);
618 m.observableArrayBoolean = [true, true, true];
620 let b = m.observableArrayBoolean;
621 ok(Array.isArray(b), "observable array should be an array type");
622 is(b.length, 3, "length of observable array should be 3");
624 // Test length
626 // [length, shouldThrow, expectedResult]
627 // Invalid length value
628 [1.9, true],
629 ['invalid', true],
630 [{}, true],
631 // length value should not greater than current length
632 [b.length + 1, false, false],
633 // Success
634 [b.length, false, true],
635 [b.length - 1, false, true],
636 [0, false, true],
637 ].forEach(function([length, shouldThrow, expectedResult]) {
638 // Initialize
639 let oldLen = b.length;
640 let oldValues = b.slice();
641 setCallbackCount = 0;
642 deleteCallbackCount = 0;
643 setCallbackTests = null;
644 let deleteCallbackIndex = oldLen - 1;
645 deleteCallbackTests = function(_value, _index) {
646 is(_value, oldValues[deleteCallbackIndex], "deleteCallbackTests: test value argument");
647 is(_index, deleteCallbackIndex, "deleteCallbackTests: test index argument");
648 deleteCallbackIndex--;
651 // Test
652 info(`setting "length" property value to ${length}`);
653 try {
654 is(Reflect.set(b, "length", length), expectedResult, `Reflect.set should return ${expectedResult}`);
655 ok(!shouldThrow, "Reflect.set should not throw");
656 } catch(e) {
657 ok(shouldThrow, `Reflect.set throws ${e}`);
659 is(setCallbackCount, 0, "setCallback count");
660 is(deleteCallbackCount, expectedResult ? oldLen - length : 0, "deleteCallback count");
661 isDeeply(b, expectedResult ? oldValues.slice(0, length) : oldValues, "property values");
662 is(b.length, expectedResult ? length : oldLen, "length of observable array");
665 // Test indexed value
667 // [index, value, shouldThrow, expectedResult]
668 // Index could not greater than last index.
669 [b.length + 1, true, false, false],
670 // Success
671 [b.length, true, false, true],
672 [b.length + 1, true, false, true],
673 ].forEach(function([index, value, shouldThrow, expectedResult]) {
674 // Initialize
675 let oldLen = b.length;
676 let oldValue = b[index];
677 setCallbackCount = 0;
678 deleteCallbackCount = 0;
679 setCallbackTests = function(_value, _index) {
680 is(_value, value, "setCallbackTests: test value argument");
681 is(_index, index, "setCallbackTests: test index argument");
683 deleteCallbackTests = function(_value, _index) {
684 is(_value, oldValue, "deleteCallbackTests: test value argument");
685 is(_index, index, "deleteCallbackTests: test index argument");
688 // Test
689 info(`setting ${index} property to ${value}`);
690 try {
691 is(Reflect.set(b, index, value), expectedResult, `Reflect.set should return ${expectedResult}`);
692 ok(!shouldThrow, "Reflect.set should not throw");
693 } catch(e) {
694 ok(shouldThrow, `Reflect.set throws ${e}`);
696 is(setCallbackCount, expectedResult ? 1 : 0, "setCallback count");
697 is(deleteCallbackCount, (oldLen > index) ? 1 : 0, "deleteCallback count");
698 is(b[index], expectedResult ? value : oldValue, "property value");
699 is(b.length, expectedResult ? Math.max(index + 1, oldLen) : oldLen, "length of observable array");
702 // Test other property
704 // [property, value]
705 ["prop1", "value1"],
706 ["prop1", "value2"],
707 ["prop2", 5],
708 ["prop3", []],
709 ["prop4", {}],
710 ].forEach(function([property, value]) {
711 // Initialize
712 let oldLen = b.length;
713 setCallbackCount = 0;
714 deleteCallbackCount = 0;
715 setCallbackTests = null;
716 deleteCallbackTests = null;
718 // Test
719 info(`setting ${property} property to ${value}`);
720 ok(Reflect.set(b, property, value), "Reflect.defineProperty should return true");
721 is(setCallbackCount, 0, "setCallback count");
722 is(deleteCallbackCount, 0, "deleteCallback count");
723 is(b[property], value, "property value");
724 is(b.length, oldLen, "length of observable array");
728 add_task(function testObservableArrayExoticObjects_set_callback_throw() {
729 let setCallbackCount = 0;
730 let deleteCallbackCount = 0;
732 const minLen = 3;
733 let m = new TestInterfaceObservableArray({
734 setBooleanCallback(value) {
735 setCallbackCount++;
736 if (value) {
737 throw new Error("setBooleanCallback");
740 deleteBooleanCallback(value, index) {
741 deleteCallbackCount++;
742 if (index < minLen) {
743 throw new Error("deleteBooleanCallback");
747 m.observableArrayBoolean = [false, false, false, false, false];
749 let b = m.observableArrayBoolean;
750 ok(Array.isArray(b), "observable array should be an array type");
751 is(b.length, 5, "length of observable array should be 3");
753 // Test length
755 // [value, shouldThrow]
756 [b.length, false],
757 [b.length - 1, false],
758 [0, true],
759 ].forEach(function([length, shouldThrow]) {
760 // Initialize
761 let oldValues = b.slice();
762 let oldLen = b.length;
763 setCallbackCount = 0;
764 deleteCallbackCount = 0;
766 // Test
767 info(`setting "length" property to ${length}`);
768 try {
769 ok(Reflect.set(b, "length", length), "Reflect.set should return true");
770 ok(!shouldThrow, `Reflect.set should not throw`);
771 } catch(e) {
772 ok(shouldThrow, `Reflect.set throws ${e}`);
774 is(setCallbackCount, 0, "setCallback should not be called");
775 is(deleteCallbackCount, oldLen - (shouldThrow ? minLen - 1 : length), "deleteCallback count");
776 isDeeply(b, oldValues.slice(0, shouldThrow ? minLen : length), "property values");
777 is(b.length, shouldThrow ? minLen : length, "length of observable array");
780 // Test indexed value
782 // [index, value, shouldThrow]
783 [b.length, true, true],
784 [b.length, false, false],
785 [b.length + 1, false, false],
786 [b.length + 1, true, true],
787 [0, false, true],
788 [0, true, true],
789 ].forEach(function([index, value, shouldThrow]) {
790 // Initialize
791 let oldValue = b[index];
792 let oldLen = b.length;
793 setCallbackCount = 0;
794 deleteCallbackCount = 0;
796 // Test
797 info(`setting ${index} property to ${value}`);
798 try {
799 ok(Reflect.set(b, index, value), "Reflect.set should return true");
800 ok(!shouldThrow, `Reflect.set should not throw`);
801 } catch(e) {
802 ok(shouldThrow, `Reflect.set throws ${e}`);
804 is(setCallbackCount, (index < minLen) ? 0 : 1, "setCallback count");
805 is(deleteCallbackCount, (oldLen > index) ? 1 : 0, "deleteCallback count");
806 is(b[index], shouldThrow ? oldValue : value, "property value");
807 is(b.length, shouldThrow ? oldLen : Math.max(oldLen, index + 1), "length of observable array");
810 // Test other property
812 ["prop1", "value1"],
813 ["prop1", "value2"],
814 ["prop2", 5],
815 ["prop3", []],
816 ["prop4", {}],
817 ].forEach(function([property, value]) {
818 // Initialize
819 let oldLen = b.length;
820 setCallbackCount = 0;
821 deleteCallbackCount = 0;
823 // Test
824 info(`setting ${property} property to ${JSON.stringify(value)}`);
825 try {
826 ok(Reflect.set(b, property, value), "Reflect.set should return true");
827 ok(true, `Reflect.set should not throw`);
828 } catch(e) {
829 ok(false, `Reflect.set throws ${e}`);
831 is(setCallbackCount, 0, "setCallback should not be called");
832 is(deleteCallbackCount, 0, "deleteCallback should be called");
833 is(b[property], value, "property value");
834 is(b.length, oldLen, "length of observable array");
838 add_task(function testObservableArrayExoticObjects_invalidtype() {
839 let m = new TestInterfaceObservableArray();
840 let i = m.observableArrayInterface;
841 ok(Array.isArray(i), "Observable array should be an array type");
842 is(i.length, 0, "length should be 0");
844 [true, "invalid"].forEach(function(value) {
845 SimpleTest.doesThrow(() => {
846 let descriptor = {configurable: true, enumerable: true, writable: true, value};
847 Reflect.defineProperty(i, i.length, descriptor);
848 }, `defining ${i.length} property with ${JSON.stringify(value)} should throw`);
850 SimpleTest.doesThrow(() => {
851 Reflect.set(i, i.length, value);
852 }, `setting ${i.length} property to ${JSON.stringify(value)} should throw`);
855 is(i.length, 0, "length should still be 0");
857 </script>
858 </body>
859 </html>