summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/Iterator
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/tests/non262/Iterator
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/non262/Iterator')
-rw-r--r--js/src/tests/non262/Iterator/constructor-subclassable.js12
-rw-r--r--js/src/tests/non262/Iterator/constructor-throw-when-called-directly.js9
-rw-r--r--js/src/tests/non262/Iterator/constructor-throw-without-new.js9
-rw-r--r--js/src/tests/non262/Iterator/constructor.js9
-rw-r--r--js/src/tests/non262/Iterator/from/Iterator.from-descriptor.js12
-rw-r--r--js/src/tests/non262/Iterator/from/Iterator.from-length.js17
-rw-r--r--js/src/tests/non262/Iterator/from/Iterator.from-name.js13
-rw-r--r--js/src/tests/non262/Iterator/from/call-from-with-different-this.js18
-rw-r--r--js/src/tests/non262/Iterator/from/iterator-not-callable-throws.js13
-rw-r--r--js/src/tests/non262/Iterator/from/modify-next.js15
-rw-r--r--js/src/tests/non262/Iterator/from/modify-return.js22
-rw-r--r--js/src/tests/non262/Iterator/from/modify-throw.js18
-rw-r--r--js/src/tests/non262/Iterator/from/o-not-object-throws.js13
-rw-r--r--js/src/tests/non262/Iterator/from/proxy-not-wrapped.js34
-rw-r--r--js/src/tests/non262/Iterator/from/proxy-wrap-next.js30
-rw-r--r--js/src/tests/non262/Iterator/from/proxy-wrap-return.js31
-rw-r--r--js/src/tests/non262/Iterator/from/proxy-wrap-throw.js31
-rw-r--r--js/src/tests/non262/Iterator/from/return-iterator-if-iterable.js25
-rw-r--r--js/src/tests/non262/Iterator/from/return-wrapper-if-not-iterable.js28
-rw-r--r--js/src/tests/non262/Iterator/from/return-wrapper-if-not-iterator-instance.js24
-rw-r--r--js/src/tests/non262/Iterator/from/wrap-functions-on-other-global.js31
-rw-r--r--js/src/tests/non262/Iterator/from/wrap-method-with-non-wrap-this-throws.js42
-rw-r--r--js/src/tests/non262/Iterator/from/wrap-new-global.js9
-rw-r--r--js/src/tests/non262/Iterator/from/wrap-next-forwards-value.js18
-rw-r--r--js/src/tests/non262/Iterator/from/wrap-next-not-object-throws.js14
-rw-r--r--js/src/tests/non262/Iterator/from/wrap-return-closes-iterator.js33
-rw-r--r--js/src/tests/non262/Iterator/from/wrap-throw.js45
-rw-r--r--js/src/tests/non262/Iterator/iterator.js13
-rw-r--r--js/src/tests/non262/Iterator/length.js13
-rw-r--r--js/src/tests/non262/Iterator/name.js13
-rw-r--r--js/src/tests/non262/Iterator/proto.js17
-rw-r--r--js/src/tests/non262/Iterator/prototype/asIndexedPairs/asIndexedPairs.js15
-rw-r--r--js/src/tests/non262/Iterator/prototype/asIndexedPairs/length.js21
-rw-r--r--js/src/tests/non262/Iterator/prototype/asIndexedPairs/name.js19
-rw-r--r--js/src/tests/non262/Iterator/prototype/drop/drop-more-than-available.js37
-rw-r--r--js/src/tests/non262/Iterator/prototype/drop/drop.js26
-rw-r--r--js/src/tests/non262/Iterator/prototype/drop/length.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/drop/name.js19
-rw-r--r--js/src/tests/non262/Iterator/prototype/every/check-fn-after-getting-iterator.js26
-rw-r--r--js/src/tests/non262/Iterator/prototype/every/coerce-result-to-boolean.js23
-rw-r--r--js/src/tests/non262/Iterator/prototype/every/descriptor.js13
-rw-r--r--js/src/tests/non262/Iterator/prototype/every/error-from-correct-realm.js16
-rw-r--r--js/src/tests/non262/Iterator/prototype/every/fn-not-callable-throws.js15
-rw-r--r--js/src/tests/non262/Iterator/prototype/every/fn-throws-close-iterator.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/every/length.js17
-rw-r--r--js/src/tests/non262/Iterator/prototype/every/name.js13
-rw-r--r--js/src/tests/non262/Iterator/prototype/every/next-throws-iterator-not-closed.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/every/proxy.js44
-rw-r--r--js/src/tests/non262/Iterator/prototype/every/return-true-if-all-match.js11
-rw-r--r--js/src/tests/non262/Iterator/prototype/every/short-circuit-on-false.js14
-rw-r--r--js/src/tests/non262/Iterator/prototype/every/this-not-iterator-throws.js9
-rw-r--r--js/src/tests/non262/Iterator/prototype/every/value-throws-iterator-not-closed.js25
-rw-r--r--js/src/tests/non262/Iterator/prototype/filter/coerce-result-to-boolean.js16
-rw-r--r--js/src/tests/non262/Iterator/prototype/filter/filter.js14
-rw-r--r--js/src/tests/non262/Iterator/prototype/filter/length.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/filter/name.js19
-rw-r--r--js/src/tests/non262/Iterator/prototype/find/check-fn-after-getting-iterator.js26
-rw-r--r--js/src/tests/non262/Iterator/prototype/find/coerce-result-to-boolean.js27
-rw-r--r--js/src/tests/non262/Iterator/prototype/find/descriptor.js13
-rw-r--r--js/src/tests/non262/Iterator/prototype/find/error-from-correct-realm.js16
-rw-r--r--js/src/tests/non262/Iterator/prototype/find/fn-not-callable-throws.js15
-rw-r--r--js/src/tests/non262/Iterator/prototype/find/fn-throws-close-iterator.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/find/length.js17
-rw-r--r--js/src/tests/non262/Iterator/prototype/find/name.js13
-rw-r--r--js/src/tests/non262/Iterator/prototype/find/next-throws-iterator-not-closed.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/find/proxy.js44
-rw-r--r--js/src/tests/non262/Iterator/prototype/find/return-undefined-if-none-match.js11
-rw-r--r--js/src/tests/non262/Iterator/prototype/find/short-circuit-on-match.js14
-rw-r--r--js/src/tests/non262/Iterator/prototype/find/this-not-iterator-throws.js9
-rw-r--r--js/src/tests/non262/Iterator/prototype/find/value-throws-iterator-not-closed.js25
-rw-r--r--js/src/tests/non262/Iterator/prototype/flatMap/close-iterator-when-inner-complete-throws.js49
-rw-r--r--js/src/tests/non262/Iterator/prototype/flatMap/close-iterator-when-inner-next-throws.js45
-rw-r--r--js/src/tests/non262/Iterator/prototype/flatMap/close-iterator-when-inner-value-throws.js52
-rw-r--r--js/src/tests/non262/Iterator/prototype/flatMap/flatMap.js12
-rw-r--r--js/src/tests/non262/Iterator/prototype/flatMap/inner-empty-iterable.js38
-rw-r--r--js/src/tests/non262/Iterator/prototype/flatMap/inner-generator.js29
-rw-r--r--js/src/tests/non262/Iterator/prototype/flatMap/length.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/flatMap/name.js19
-rw-r--r--js/src/tests/non262/Iterator/prototype/flatMap/throw-when-inner-not-iterable.js64
-rw-r--r--js/src/tests/non262/Iterator/prototype/forEach/check-fn-after-getting-iterator.js26
-rw-r--r--js/src/tests/non262/Iterator/prototype/forEach/descriptor.js13
-rw-r--r--js/src/tests/non262/Iterator/prototype/forEach/error-from-correct-realm.js16
-rw-r--r--js/src/tests/non262/Iterator/prototype/forEach/fn-not-callable-throws.js15
-rw-r--r--js/src/tests/non262/Iterator/prototype/forEach/fn-throws-close-iterator.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/forEach/forEach.js11
-rw-r--r--js/src/tests/non262/Iterator/prototype/forEach/length.js17
-rw-r--r--js/src/tests/non262/Iterator/prototype/forEach/name.js13
-rw-r--r--js/src/tests/non262/Iterator/prototype/forEach/next-throws-iterator-not-closed.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/forEach/proxy.js44
-rw-r--r--js/src/tests/non262/Iterator/prototype/forEach/this-not-iterator-throws.js9
-rw-r--r--js/src/tests/non262/Iterator/prototype/forEach/value-throws-iterator-not-closed.js25
-rw-r--r--js/src/tests/non262/Iterator/prototype/generator-methods-throw-on-iterator-helpers.js16
-rw-r--r--js/src/tests/non262/Iterator/prototype/iterator-helper-methods-throw-on-generators.js14
-rw-r--r--js/src/tests/non262/Iterator/prototype/iterator-helpers-from-other-global.js64
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-from-other-global.js31
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-handle-empty-iterators.js40
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-interleaved.js62
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-closed-on-call-throws.js44
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-closed-on-yield-throws.js45
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-not-closed-on-next-throws.js44
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-not-closed-on-value-throws.js48
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-returns-done-generator-finishes.js27
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-multiple-return-close-iterator-once.js60
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-multiple-throw-close-iterator-once.js62
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-pass-through-lastValue.js29
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-pass-value-through-chain.js33
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-proxy-accesses.js70
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-reentry-not-close-iterator.js43
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-return-closes-iterator.js58
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-return-new-iterator-result.js39
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-throw-closes-iterator-before-next.js50
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-throw-eagerly-on-next-non-callable.js34
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-throw-eagerly-on-non-callable.js38
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-throw-eagerly-on-non-iterator.js34
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-throw-next-done-throws.js47
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-throw-next-not-object.js44
-rw-r--r--js/src/tests/non262/Iterator/prototype/lazy-methods-throw-on-reentry.js18
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/call-next-on-iterator-while-iterating.js24
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/clobber-symbol.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/interleaved-map-calls.js23
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/length.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/map.js28
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/mapper-not-callable-throw.js33
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/mutate-iterator-after-done.js23
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/mutate-iterator.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/name.js19
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/output-at-generator-end.js26
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/pass-lastValue-to-next.js43
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/proxy-abrupt-completion-in-iteratorValue.js55
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/proxy-abrupt-completion-in-yield.js62
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/proxy-abrupt-completion.js54
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/proxy-accesses.js94
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/reenter-map-generator-from-mapper.js15
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/this-not-iterator-throw.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/this-value-array-throws.js14
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/throw-when-iterator-returns-non-object.js24
-rw-r--r--js/src/tests/non262/Iterator/prototype/map/values-pass-through-chained-maps-to-next.js43
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/accumulator-set-to-initial-value.js9
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/check-fn-after-getting-iterator.js26
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/descriptor.js13
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/empty-iterator-without-initial-value-throws.js7
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/error-from-correct-realm.js16
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/iterator-empty-return-initial-value.js9
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/iterator-next-return-non-object-throws.js30
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/left-associative.js7
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/length.js17
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/name.js13
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/next-throws-iterator-not-closed.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/no-initial-value-set-accumulator-to-first-value.js9
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/proxy.js44
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/reduce.js9
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/reducer-not-callable-throws.js20
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/reducer-throws-iterator-closed.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/this-not-iterator-throws.js9
-rw-r--r--js/src/tests/non262/Iterator/prototype/reduce/value-throws-iterator-not-closed.js25
-rw-r--r--js/src/tests/non262/Iterator/prototype/some/check-fn-after-getting-iterator.js26
-rw-r--r--js/src/tests/non262/Iterator/prototype/some/coerce-result-to-boolean.js23
-rw-r--r--js/src/tests/non262/Iterator/prototype/some/descriptor.js13
-rw-r--r--js/src/tests/non262/Iterator/prototype/some/error-from-correct-realm.js16
-rw-r--r--js/src/tests/non262/Iterator/prototype/some/fn-not-callable-throws.js15
-rw-r--r--js/src/tests/non262/Iterator/prototype/some/fn-throws-close-iterator.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/some/length.js17
-rw-r--r--js/src/tests/non262/Iterator/prototype/some/name.js13
-rw-r--r--js/src/tests/non262/Iterator/prototype/some/next-throws-iterator-not-closed.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/some/proxy.js44
-rw-r--r--js/src/tests/non262/Iterator/prototype/some/return-false-if-none-match.js11
-rw-r--r--js/src/tests/non262/Iterator/prototype/some/short-circuit-on-true.js14
-rw-r--r--js/src/tests/non262/Iterator/prototype/some/this-not-iterator-throws.js9
-rw-r--r--js/src/tests/non262/Iterator/prototype/some/value-throws-iterator-not-closed.js25
-rw-r--r--js/src/tests/non262/Iterator/prototype/take-drop-throw-eagerly-on-negative.js30
-rw-r--r--js/src/tests/non262/Iterator/prototype/take-drop-throw-eagerly-on-non-integer.js32
-rw-r--r--js/src/tests/non262/Iterator/prototype/take/close-iterator-when-none-remaining.js40
-rw-r--r--js/src/tests/non262/Iterator/prototype/take/length.js22
-rw-r--r--js/src/tests/non262/Iterator/prototype/take/name.js19
-rw-r--r--js/src/tests/non262/Iterator/prototype/take/take-more-than-available.js52
-rw-r--r--js/src/tests/non262/Iterator/prototype/take/take.js26
-rw-r--r--js/src/tests/non262/Iterator/prototype/toArray/create-in-current-realm.js14
-rw-r--r--js/src/tests/non262/Iterator/prototype/toArray/descriptor.js13
-rw-r--r--js/src/tests/non262/Iterator/prototype/toArray/iterator-empty.js10
-rw-r--r--js/src/tests/non262/Iterator/prototype/toArray/length.js17
-rw-r--r--js/src/tests/non262/Iterator/prototype/toArray/name.js13
-rw-r--r--js/src/tests/non262/Iterator/prototype/toArray/next-throws.js14
-rw-r--r--js/src/tests/non262/Iterator/prototype/toArray/proxy.js44
-rw-r--r--js/src/tests/non262/Iterator/prototype/toArray/this-not-iterator-throws.js8
-rw-r--r--js/src/tests/non262/Iterator/prototype/toArray/toArray.js17
-rw-r--r--js/src/tests/non262/Iterator/prototype/toArray/value-throws-iterator-not-closed.js25
186 files changed, 4703 insertions, 0 deletions
diff --git a/js/src/tests/non262/Iterator/constructor-subclassable.js b/js/src/tests/non262/Iterator/constructor-subclassable.js
new file mode 100644
index 0000000000..9f65c65ad0
--- /dev/null
+++ b/js/src/tests/non262/Iterator/constructor-subclassable.js
@@ -0,0 +1,12 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Iterator constructor can be subclassed.
+---*/
+
+class TestIterator extends Iterator {
+}
+
+assertEq(new TestIterator() instanceof Iterator, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/constructor-throw-when-called-directly.js b/js/src/tests/non262/Iterator/constructor-throw-when-called-directly.js
new file mode 100644
index 0000000000..2b49b2d4ba
--- /dev/null
+++ b/js/src/tests/non262/Iterator/constructor-throw-when-called-directly.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Iterator constructor throws when called directly.
+---*/
+
+assertThrowsInstanceOf(() => new Iterator(), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/constructor-throw-without-new.js b/js/src/tests/non262/Iterator/constructor-throw-without-new.js
new file mode 100644
index 0000000000..85497fcd63
--- /dev/null
+++ b/js/src/tests/non262/Iterator/constructor-throw-without-new.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Iterator constructor throws when called without new.
+---*/
+
+assertThrowsInstanceOf(() => Iterator(), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/constructor.js b/js/src/tests/non262/Iterator/constructor.js
new file mode 100644
index 0000000000..56d8271e82
--- /dev/null
+++ b/js/src/tests/non262/Iterator/constructor.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ The Iterator constructor is a built-in function.
+---*/
+
+assertEq(typeof Iterator, 'function');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/Iterator.from-descriptor.js b/js/src/tests/non262/Iterator/from/Iterator.from-descriptor.js
new file mode 100644
index 0000000000..19bdde852b
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/Iterator.from-descriptor.js
@@ -0,0 +1,12 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Descriptor property of Iterator.from
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator, 'from');
+assertEq(propDesc.writable, true);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/Iterator.from-length.js b/js/src/tests/non262/Iterator/from/Iterator.from-length.js
new file mode 100644
index 0000000000..0833538da1
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/Iterator.from-length.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ The `length` property of Iterator.from.
+info: |
+ ES7 section 17: Unless otherwise specified, the length property of a built-in
+ Function object has the attributes { [[Writable]]: false, [[Enumerable]]:
+ false, [[Configurable]]: true }.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.from, 'length');
+assertEq(propDesc.value, 1);
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/Iterator.from-name.js b/js/src/tests/non262/Iterator/from/Iterator.from-name.js
new file mode 100644
index 0000000000..6f48d3e891
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/Iterator.from-name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ `name` property of Iterator.from.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.from, 'name');
+assertEq(propDesc.value, 'from');
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/call-from-with-different-this.js b/js/src/tests/non262/Iterator/from/call-from-with-different-this.js
new file mode 100644
index 0000000000..90328d117d
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/call-from-with-different-this.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const iter = {
+ next: () => ({done: false, value: 0}),
+};
+const wrap = Iterator.from.call(undefined, iter);
+
+const result = wrap.next();
+assertEq(result.done, false);
+assertEq(result.value, 0);
+
+const returnResult = wrap.return(1);
+assertEq(returnResult.done, true);
+assertEq(returnResult.value, 1);
+
+assertThrowsInstanceOf(() => wrap.throw(new Error()), Error);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/iterator-not-callable-throws.js b/js/src/tests/non262/Iterator/from/iterator-not-callable-throws.js
new file mode 100644
index 0000000000..a7c98f9e2a
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/iterator-not-callable-throws.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Iterator.from throws when called with an object with a non-callable @@iterator property.
+---*/
+
+assertThrowsInstanceOf(() => Iterator.from({ [Symbol.iterator]: 0 }), TypeError);
+assertThrowsInstanceOf(() => Iterator.from({ [Symbol.iterator]: false }), TypeError);
+assertThrowsInstanceOf(() => Iterator.from({ [Symbol.iterator]: "" }), TypeError);
+assertThrowsInstanceOf(() => Iterator.from({ [Symbol.iterator]: {} }), TypeError);
+assertThrowsInstanceOf(() => Iterator.from({ [Symbol.iterator]: Symbol('') }), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/modify-next.js b/js/src/tests/non262/Iterator/from/modify-next.js
new file mode 100644
index 0000000000..d347abd2cd
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/modify-next.js
@@ -0,0 +1,15 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const iter = {
+ next: () => ({ done: false, value: 0 }),
+};
+
+const wrap = Iterator.from(iter);
+
+iter.next = () => ({ done: true, value: undefined });
+
+let {done, value} = wrap.next();
+assertEq(done, false);
+assertEq(value, 0);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/modify-return.js b/js/src/tests/non262/Iterator/from/modify-return.js
new file mode 100644
index 0000000000..733eec69d7
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/modify-return.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const iter = {
+ next: () => ({ done: false, value: 0 }),
+ return: (value) => ({ done: true, value }),
+};
+
+const wrap = Iterator.from(iter);
+
+let {done, value} = wrap.return(1);
+assertEq(done, true);
+assertEq(value, 1);
+
+iter.return = () => { throw new Error(); };
+assertThrowsInstanceOf(wrap.return, Error);
+
+iter.return = null;
+let nullResult = wrap.return(2);
+assertEq(nullResult.done, true);
+assertEq(nullResult.value, 2);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/modify-throw.js b/js/src/tests/non262/Iterator/from/modify-throw.js
new file mode 100644
index 0000000000..0db7cf6f61
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/modify-throw.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const iter = {
+ next: () => ({ done: false, value: 0 }),
+ throw: (value) => ({ done: true, value }),
+};
+
+const wrap = Iterator.from(iter);
+
+let {done, value} = wrap.throw(0);
+assertEq(done, true);
+assertEq(value, 0);
+
+class TestError extends Error {}
+iter.throw = () => { throw new TestError(); };
+assertThrowsInstanceOf(() => wrap.throw(), TestError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/o-not-object-throws.js b/js/src/tests/non262/Iterator/from/o-not-object-throws.js
new file mode 100644
index 0000000000..3e6c00e59a
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/o-not-object-throws.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Iterator.from throws when called with a non-object.
+---*/
+
+assertThrowsInstanceOf(() => Iterator.from(undefined), TypeError);
+assertThrowsInstanceOf(() => Iterator.from(null), TypeError);
+assertThrowsInstanceOf(() => Iterator.from(0), TypeError);
+assertThrowsInstanceOf(() => Iterator.from(false), TypeError);
+assertThrowsInstanceOf(() => Iterator.from(Symbol('')), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/proxy-not-wrapped.js b/js/src/tests/non262/Iterator/from/proxy-not-wrapped.js
new file mode 100644
index 0000000000..df38e0fc86
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/proxy-not-wrapped.js
@@ -0,0 +1,34 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+
+ const item = Reflect[key](...args);
+ if (typeof item === 'function')
+ return (...args) => new Proxy(item.apply(receiver, args), handlerProxy);
+ return item;
+ },
+});
+
+class Iter extends Iterator {
+ [Symbol.iterator]() {
+ return this;
+ }
+ next() {
+ return { done: false, value: 0 };
+ }
+}
+const iter = new Iter();
+const proxy = new Proxy(iter, handlerProxy);
+const wrap = Iterator.from(proxy);
+
+assertEq(
+ log.join('\n'),
+ `get: Symbol(Symbol.iterator)
+get: next
+getPrototypeOf: undefined`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/proxy-wrap-next.js b/js/src/tests/non262/Iterator/from/proxy-wrap-next.js
new file mode 100644
index 0000000000..7630535402
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/proxy-wrap-next.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1].toString()}`);
+
+ const item = Reflect[key](...args);
+ if (typeof item === 'function')
+ return item.bind(receiver);
+ return item;
+ },
+});
+const iter = new Proxy({
+ next: () => ({ done: false, value: 0 }),
+}, handlerProxy);
+
+const wrap = Iterator.from(iter);
+// Call next multiple times. Should not call `get` on proxy.
+wrap.next();
+wrap.next();
+wrap.next();
+
+assertEq(
+ log.join('\n'),
+ `get: Symbol(Symbol.iterator)
+get: next`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/proxy-wrap-return.js b/js/src/tests/non262/Iterator/from/proxy-wrap-return.js
new file mode 100644
index 0000000000..34caeb2176
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/proxy-wrap-return.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1].toString()}`);
+
+ const item = Reflect[key](...args);
+ if (typeof item === 'function')
+ return item.bind(receiver);
+ return item;
+ },
+});
+const iter = new Proxy({
+ next: () => ({ done: false, value: 0 }),
+ return: (value) => ({ done: true, value }),
+}, handlerProxy);
+
+const wrap = Iterator.from(iter);
+wrap.return();
+wrap.return();
+
+assertEq(
+ log.join('\n'),
+ `get: Symbol(Symbol.iterator)
+get: next
+get: return
+get: return`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/proxy-wrap-throw.js b/js/src/tests/non262/Iterator/from/proxy-wrap-throw.js
new file mode 100644
index 0000000000..92a51f4a26
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/proxy-wrap-throw.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1].toString()}`);
+
+ const item = Reflect[key](...args);
+ if (typeof item === 'function')
+ return item.bind(receiver);
+ return item;
+ },
+});
+const iter = new Proxy({
+ next: () => ({ done: false, value: 0 }),
+ throw: (value) => ({ done: true, value }),
+}, handlerProxy);
+
+const wrap = Iterator.from(iter);
+wrap.throw();
+wrap.throw();
+
+assertEq(
+ log.join('\n'),
+ `get: Symbol(Symbol.iterator)
+get: next
+get: throw
+get: throw`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/return-iterator-if-iterable.js b/js/src/tests/non262/Iterator/from/return-iterator-if-iterable.js
new file mode 100644
index 0000000000..e83e25185d
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/return-iterator-if-iterable.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Iterator.from returns O if it is iterable, an iterator, and an instance of Iterator.
+---*/
+
+class TestIterator extends Iterator {
+ [Symbol.iterator]() {
+ return this;
+ }
+
+ next() {
+ return { done: false, value: this.value++ };
+ }
+
+ value = 0;
+}
+
+const iter = new TestIterator();
+assertEq(iter, Iterator.from(iter));
+
+const arrayIter = [1, 2, 3][Symbol.iterator]();
+assertEq(arrayIter, Iterator.from(arrayIter));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/return-wrapper-if-not-iterable.js b/js/src/tests/non262/Iterator/from/return-wrapper-if-not-iterable.js
new file mode 100644
index 0000000000..09b974f327
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/return-wrapper-if-not-iterable.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Iterator.from returns an iterator wrapper if O is not an iterable.
+---*/
+
+class TestIterator {
+ next() {
+ return { done: false, value: 0 };
+ }
+}
+
+const iter = new TestIterator();
+assertEq(
+ Symbol.iterator in iter,
+ false,
+ 'iter is not an iterable.'
+);
+
+const wrapper = Iterator.from(iter);
+assertEq(iter !== wrapper, true);
+assertEq(
+ Symbol.iterator in wrapper,
+ true,
+ 'wrapper is an iterable.'
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/return-wrapper-if-not-iterator-instance.js b/js/src/tests/non262/Iterator/from/return-wrapper-if-not-iterator-instance.js
new file mode 100644
index 0000000000..4045801277
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/return-wrapper-if-not-iterator-instance.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Iterator.from returns an iterator wrapper if O is not an instance of Iterator.
+---*/
+
+class TestIterator {
+ [Symbol.iterator]() {
+ return this;
+ }
+
+ next() {
+ return { done: false, value: 0 };
+ }
+}
+
+const iter = new TestIterator();
+assertEq(iter instanceof Iterator, false);
+
+const wrapper = Iterator.from(iter);
+assertEq(iter !== wrapper, true);
+assertEq(wrapper instanceof Iterator, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/wrap-functions-on-other-global.js b/js/src/tests/non262/Iterator/from/wrap-functions-on-other-global.js
new file mode 100644
index 0000000000..186e4e62d0
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/wrap-functions-on-other-global.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+class TestError extends Error {}
+
+function checkIterResult({done, value}, expectedDone, expectedValue) {
+ assertEq(done, expectedDone);
+ assertEq(value, expectedValue);
+}
+
+const iter = {
+ next(value) {
+ return {done: false, value: arguments.length};
+ },
+ return() {
+ throw new TestError();
+ },
+ throw: (value) => ({done: true, value}),
+};
+const thisWrap = Iterator.from(iter);
+const otherGlobal = newGlobal({newCompartment: true});
+const otherWrap = otherGlobal.Iterator.from(iter);
+
+checkIterResult(thisWrap.next.call(otherWrap), false, 0);
+checkIterResult(thisWrap.next.call(otherWrap, 'value'), false, 1);
+
+assertThrowsInstanceOf(thisWrap.return.bind(otherWrap), TestError);
+
+checkIterResult(thisWrap.throw.call(otherWrap, 'value'), true, 'value');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/wrap-method-with-non-wrap-this-throws.js b/js/src/tests/non262/Iterator/from/wrap-method-with-non-wrap-this-throws.js
new file mode 100644
index 0000000000..7ff8539923
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/wrap-method-with-non-wrap-this-throws.js
@@ -0,0 +1,42 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+// All methods on %WrapForValidIteratorPrototype% require an [[Iterated]]
+// internal slot on the `this` object.
+
+class TestIterator {
+ next() {
+ return {
+ done: false,
+ value: 0,
+ };
+ }
+}
+
+const nextMethod = Iterator.from(new TestIterator()).next;
+assertThrowsInstanceOf(() => nextMethod.call(undefined), TypeError);
+assertThrowsInstanceOf(() => nextMethod.call(null), TypeError);
+assertThrowsInstanceOf(() => nextMethod.call(0), TypeError);
+assertThrowsInstanceOf(() => nextMethod.call(false), TypeError);
+assertThrowsInstanceOf(() => nextMethod.call('test'), TypeError);
+assertThrowsInstanceOf(() => nextMethod.call(Object(1)), TypeError);
+assertThrowsInstanceOf(() => nextMethod.call({}), TypeError);
+
+const returnMethod = Iterator.from(new TestIterator()).next;
+assertThrowsInstanceOf(() => returnMethod.call(undefined), TypeError);
+assertThrowsInstanceOf(() => returnMethod.call(null), TypeError);
+assertThrowsInstanceOf(() => returnMethod.call(0), TypeError);
+assertThrowsInstanceOf(() => returnMethod.call(false), TypeError);
+assertThrowsInstanceOf(() => returnMethod.call('test'), TypeError);
+assertThrowsInstanceOf(() => returnMethod.call(Object(1)), TypeError);
+assertThrowsInstanceOf(() => returnMethod.call({}), TypeError);
+
+const throwMethod = Iterator.from(new TestIterator()).next;
+assertThrowsInstanceOf(() => throwMethod.call(undefined), TypeError);
+assertThrowsInstanceOf(() => throwMethod.call(null), TypeError);
+assertThrowsInstanceOf(() => throwMethod.call(0), TypeError);
+assertThrowsInstanceOf(() => throwMethod.call(false), TypeError);
+assertThrowsInstanceOf(() => throwMethod.call('test'), TypeError);
+assertThrowsInstanceOf(() => throwMethod.call(Object(1)), TypeError);
+assertThrowsInstanceOf(() => throwMethod.call({}), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/wrap-new-global.js b/js/src/tests/non262/Iterator/from/wrap-new-global.js
new file mode 100644
index 0000000000..a9a26b41b0
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/wrap-new-global.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const otherGlobal = newGlobal({newCompartment: true});
+
+const iter = [1, 2, 3].values();
+assertEq(iter, Iterator.from(iter));
+assertEq(iter !== otherGlobal.Iterator.from(iter), true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/wrap-next-forwards-value.js b/js/src/tests/non262/Iterator/from/wrap-next-forwards-value.js
new file mode 100644
index 0000000000..095ddd692a
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/wrap-next-forwards-value.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+class Iter {
+ next(value) {
+ this.v = value;
+ return { done: false, value };
+ }
+}
+
+const iter = new Iter();
+const wrap = Iterator.from(iter);
+assertEq(iter !== wrap, true);
+
+assertEq(iter.v, undefined);
+wrap.next(1);
+assertEq(iter.v, 1);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/wrap-next-not-object-throws.js b/js/src/tests/non262/Iterator/from/wrap-next-not-object-throws.js
new file mode 100644
index 0000000000..0e5b559f3b
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/wrap-next-not-object-throws.js
@@ -0,0 +1,14 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const iter = (value) => Iterator.from({
+ next: () => value,
+});
+
+assertThrowsInstanceOf(() => iter(undefined).next(), TypeError);
+assertThrowsInstanceOf(() => iter(null).next(), TypeError);
+assertThrowsInstanceOf(() => iter(0).next(), TypeError);
+assertThrowsInstanceOf(() => iter(false).next(), TypeError);
+assertThrowsInstanceOf(() => iter('test').next(), TypeError);
+assertThrowsInstanceOf(() => iter(Symbol('')).next(), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/wrap-return-closes-iterator.js b/js/src/tests/non262/Iterator/from/wrap-return-closes-iterator.js
new file mode 100644
index 0000000000..22518871f3
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/wrap-return-closes-iterator.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+class Iter {
+ next() {
+ if (this.closed)
+ return { done: true, value: undefined };
+ return { done: false, value: 0 };
+ }
+
+ return(value) {
+ this.closed = true;
+ return { done: true, value };
+ }
+}
+
+const iter = new Iter();
+const wrap = Iterator.from(iter);
+assertEq(iter.closed, undefined);
+
+let result = wrap.next();
+assertEq(result.done, false);
+assertEq(result.value, 0);
+
+result = wrap.return(1);
+assertEq(result.done, true);
+assertEq(result.value, 1);
+
+assertEq(iter.closed, true);
+result = wrap.next();
+assertEq(result.done, true);
+assertEq(result.value, undefined);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/from/wrap-throw.js b/js/src/tests/non262/Iterator/from/wrap-throw.js
new file mode 100644
index 0000000000..ffe17c80e8
--- /dev/null
+++ b/js/src/tests/non262/Iterator/from/wrap-throw.js
@@ -0,0 +1,45 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+class Iter {
+ next() {
+ return { done: false, value: 0 };
+ }
+}
+
+const iter = new Iter();
+const wrap = Iterator.from(iter);
+
+assertThrowsInstanceOf(() => wrap.throw(new Error()), Error);
+assertThrows(() => wrap.throw());
+assertThrows(() => wrap.throw(1));
+
+class IterThrowNull {
+ next() {
+ return { done: false, value: 0 };
+ }
+ throw = null;
+}
+
+const iterNull = new IterThrowNull();
+const wrapNull = Iterator.from(iter);
+
+assertThrowsInstanceOf(() => wrapNull.throw(new Error()), Error);
+assertThrows(() => wrapNull.throw());
+assertThrows(() => wrapNull.throw(1));
+
+class IterWithThrow {
+ next() {
+ return { done: false, value: 0 };
+ }
+
+ throw(value) {
+ return value;
+ }
+}
+
+const iterWithThrow = new IterWithThrow();
+const wrapWithThrow = Iterator.from(iterWithThrow);
+
+assertEq(wrapWithThrow.throw(1), 1);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/iterator.js b/js/src/tests/non262/Iterator/iterator.js
new file mode 100644
index 0000000000..ad48fc2061
--- /dev/null
+++ b/js/src/tests/non262/Iterator/iterator.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Property descriptor of Iterator.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(this, 'Iterator');
+assertEq(propDesc.value, Iterator);
+assertEq(propDesc.writable, true);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/length.js b/js/src/tests/non262/Iterator/length.js
new file mode 100644
index 0000000000..07d1e4f804
--- /dev/null
+++ b/js/src/tests/non262/Iterator/length.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ The "length" property of Iterator
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator, 'length');
+assertEq(propDesc.value, 0);
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/name.js b/js/src/tests/non262/Iterator/name.js
new file mode 100644
index 0000000000..c11e570228
--- /dev/null
+++ b/js/src/tests/non262/Iterator/name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ The "name" property of Iterator
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator, 'name');
+assertEq(propDesc.value, 'Iterator');
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/proto.js b/js/src/tests/non262/Iterator/proto.js
new file mode 100644
index 0000000000..2ab92641e7
--- /dev/null
+++ b/js/src/tests/non262/Iterator/proto.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ The prototype of the Iterator constructor is the intrinsic object %FunctionPrototype%.
+---*/
+
+assertEq(Object.getPrototypeOf(Iterator), Function.prototype);
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator, 'prototype');
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, false);
+
+// Make sure @@toStringTag hasn't been set.
+assertEq(Symbol.toStringTag in propDesc.value, false);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/asIndexedPairs/asIndexedPairs.js b/js/src/tests/non262/Iterator/prototype/asIndexedPairs/asIndexedPairs.js
new file mode 100644
index 0000000000..42dfb6aaca
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/asIndexedPairs/asIndexedPairs.js
@@ -0,0 +1,15 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+let iter = [1, 2, 3].values().asIndexedPairs();
+
+for (const v of [[0, 1], [1, 2], [2, 3]]) {
+ let result = iter.next();
+ assertEq(result.done, false);
+ assertEq(result.value[0], v[0]);
+ assertEq(result.value[1], v[1]);
+}
+
+assertEq(iter.next().done, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/asIndexedPairs/length.js b/js/src/tests/non262/Iterator/prototype/asIndexedPairs/length.js
new file mode 100644
index 0000000000..4ec7ce238c
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/asIndexedPairs/length.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: %Iterator.prototype%.asIndexedPairs length value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(Iterator.prototype.asIndexedPairs.length, 0);
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(Iterator.prototype.asIndexedPairs, 'length');
+assertEq(propertyDescriptor.value, 0);
+assertEq(propertyDescriptor.enumerable, false);
+assertEq(propertyDescriptor.writable, false);
+assertEq(propertyDescriptor.configurable, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/asIndexedPairs/name.js b/js/src/tests/non262/Iterator/prototype/asIndexedPairs/name.js
new file mode 100644
index 0000000000..74d31d7905
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/asIndexedPairs/name.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+/*---
+esid: pending
+description: %Iterator.prototype%.asIndexedPairs.name value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(Iterator.prototype.asIndexedPairs.name, 'asIndexedPairs');
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(Iterator.prototype.asIndexedPairs, 'name');
+assertEq(propertyDescriptor.value, 'asIndexedPairs');
+assertEq(propertyDescriptor.enumerable, false);
+assertEq(propertyDescriptor.writable, false);
+assertEq(propertyDescriptor.configurable, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/drop/drop-more-than-available.js b/js/src/tests/non262/Iterator/prototype/drop/drop-more-than-available.js
new file mode 100644
index 0000000000..230ebb8faf
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/drop/drop-more-than-available.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: %Iterator.prototype%.drop returns if the iterator is done.
+info: >
+ Iterator Helpers proposal 2.1.5.5
+ 1. Repeat, while remaining > 0,
+ ...
+ b. Let next be ? IteratorStep(iterated).
+ c. If next is false, return undefined.
+features: [iterator-helpers]
+---*/
+
+let iter = [1, 2].values().drop(3);
+let result = iter.next();
+assertEq(result.value, undefined);
+assertEq(result.done, true);
+
+class TestIterator extends Iterator {
+ counter = 0;
+ next() {
+ return {done: ++this.counter >= 2, value: undefined};
+ }
+}
+
+iter = new TestIterator();
+let dropped = iter.drop(10);
+result = dropped.next();
+assertEq(result.value, undefined);
+assertEq(result.done, true);
+assertEq(iter.counter, 2);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/drop/drop.js b/js/src/tests/non262/Iterator/prototype/drop/drop.js
new file mode 100644
index 0000000000..2bacd45196
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/drop/drop.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+/*---
+esid: pending
+description: Smoketest of %Iterator.prototype%.drop.
+info: >
+ Iterator Helpers proposal 2.1.5.5
+features: [iterator-helpers]
+---*/
+
+let iter = [1, 2, 3].values().drop(1);
+
+for (const v of [2, 3]) {
+ let result = iter.next();
+ assertEq(result.done, false);
+ assertEq(result.value, v);
+}
+
+assertEq(iter.next().done, true);
+
+// `drop`, when called without arguments, has a limit of undefined,
+// which converts to 0.
+assertEq(['test'].values().drop().next().value, 'test');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/drop/length.js b/js/src/tests/non262/Iterator/prototype/drop/length.js
new file mode 100644
index 0000000000..d7dbcefcc5
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/drop/length.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: %Iterator.prototype%.drop length value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+includes: [propertyHelper.js]
+features: [Symbol.iterator]
+---*/
+
+assertEq(Iterator.prototype.drop.length, 1);
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(Iterator.prototype.drop, 'length');
+assertEq(propertyDescriptor.value, 1);
+assertEq(propertyDescriptor.enumerable, false);
+assertEq(propertyDescriptor.writable, false);
+assertEq(propertyDescriptor.configurable, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/drop/name.js b/js/src/tests/non262/Iterator/prototype/drop/name.js
new file mode 100644
index 0000000000..06c904a21c
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/drop/name.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+/*---
+esid: pending
+description: %Iterator.prototype%.drop.name value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(Iterator.prototype.drop.name, 'drop');
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(Iterator.prototype.drop, 'name');
+assertEq(propertyDescriptor.value, 'drop');
+assertEq(propertyDescriptor.enumerable, false);
+assertEq(propertyDescriptor.writable, false);
+assertEq(propertyDescriptor.configurable, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/every/check-fn-after-getting-iterator.js b/js/src/tests/non262/Iterator/prototype/every/check-fn-after-getting-iterator.js
new file mode 100644
index 0000000000..4c7305ad5c
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/every/check-fn-after-getting-iterator.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: true};
+ }
+}
+
+const iter = new Proxy(new TestIterator(), handlerProxy);
+assertThrowsInstanceOf(() => iter.every(1), TypeError);
+
+assertEq(
+ log.join('\n'),
+ `get: every
+get: next`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/every/coerce-result-to-boolean.js b/js/src/tests/non262/Iterator/prototype/every/coerce-result-to-boolean.js
new file mode 100644
index 0000000000..4af9650ab8
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/every/coerce-result-to-boolean.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const fn = (value) => value;
+assertEq([true].values().every(fn), true);
+assertEq([1].values().every(fn), true);
+assertEq([[]].values().every(fn), true);
+assertEq([{}].values().every(fn), true);
+assertEq(['test'].values().every(fn), true);
+
+assertEq([false].values().every(fn), false);
+assertEq([0].values().every(fn), false);
+assertEq([''].values().every(fn), false);
+assertEq([null].values().every(fn), false);
+assertEq([undefined].values().every(fn), false);
+assertEq([NaN].values().every(fn), false);
+assertEq([-0].values().every(fn), false);
+assertEq([0n].values().every(fn), false);
+
+const htmlDDA = createIsHTMLDDA();
+assertEq([htmlDDA].values().every(fn), false);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/every/descriptor.js b/js/src/tests/non262/Iterator/prototype/every/descriptor.js
new file mode 100644
index 0000000000..e11eca28f3
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/every/descriptor.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Descriptor property of Iterator.prototype.every
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype, 'every');
+assertEq(typeof propDesc.value, 'function');
+assertEq(propDesc.writable, true);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/every/error-from-correct-realm.js b/js/src/tests/non262/Iterator/prototype/every/error-from-correct-realm.js
new file mode 100644
index 0000000000..7b24a631bb
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/every/error-from-correct-realm.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const otherGlobal = newGlobal({newCompartment: true});
+assertEq(TypeError !== otherGlobal.TypeError, true);
+
+const iter = [].values();
+
+assertThrowsInstanceOf(() => iter.every(), TypeError);
+assertThrowsInstanceOf(
+ otherGlobal.Iterator.prototype.every.bind(iter),
+ otherGlobal.TypeError,
+ 'TypeError comes from the realm of the method.',
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/every/fn-not-callable-throws.js b/js/src/tests/non262/Iterator/prototype/every/fn-not-callable-throws.js
new file mode 100644
index 0000000000..6b4328180c
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/every/fn-not-callable-throws.js
@@ -0,0 +1,15 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const iter = [].values();
+
+assertThrowsInstanceOf(() => iter.every(), TypeError);
+assertThrowsInstanceOf(() => iter.every(undefined), TypeError);
+assertThrowsInstanceOf(() => iter.every(null), TypeError);
+assertThrowsInstanceOf(() => iter.every(0), TypeError);
+assertThrowsInstanceOf(() => iter.every(false), TypeError);
+assertThrowsInstanceOf(() => iter.every(''), TypeError);
+assertThrowsInstanceOf(() => iter.every(Symbol('')), TypeError);
+assertThrowsInstanceOf(() => iter.every({}), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/every/fn-throws-close-iterator.js b/js/src/tests/non262/Iterator/prototype/every/fn-throws-close-iterator.js
new file mode 100644
index 0000000000..e3df75e2df
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/every/fn-throws-close-iterator.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestIterator extends Iterator {
+ next() {
+ return { done: this.closed };
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = () => { throw new Error(); };
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+assertThrowsInstanceOf(() => iter.every(fn), Error);
+assertEq(iter.closed, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/every/length.js b/js/src/tests/non262/Iterator/prototype/every/length.js
new file mode 100644
index 0000000000..8ef8ecbc7f
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/every/length.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ The `length` property of Iterator.prototype.every.
+info: |
+ ES7 section 17: Unless otherwise specified, the length property of a built-in
+ Function object has the attributes { [[Writable]]: false, [[Enumerable]]:
+ false, [[Configurable]]: true }.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype.every, 'length');
+assertEq(propDesc.value, 1);
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/every/name.js b/js/src/tests/non262/Iterator/prototype/every/name.js
new file mode 100644
index 0000000000..7a75da9771
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/every/name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ `name` property of Iterator.prototype.every.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype.every, 'name');
+assertEq(propDesc.value, 'every');
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/every/next-throws-iterator-not-closed.js b/js/src/tests/non262/Iterator/prototype/every/next-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..56a3dae169
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/every/next-throws-iterator-not-closed.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestIterator extends Iterator {
+ next() {
+ throw new Error();
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = () => {};
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+assertThrowsInstanceOf(() => iter.every(fn), Error);
+assertEq(iter.closed, false);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/every/proxy.js b/js/src/tests/non262/Iterator/prototype/every/proxy.js
new file mode 100644
index 0000000000..c3a5b27770
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/every/proxy.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+//
+// This test checks that %Iterator.prototype%.every only gets the `next` method off of the
+// iterator once, and never accesses the @@iterator property.
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class Counter extends Iterator {
+ value = 0;
+ next() {
+ const value = this.value;
+ if (value < 2) {
+ this.value = value + 1;
+ return {done: false, value};
+ }
+ return {done: true};
+ }
+}
+
+const iter = new Proxy(new Counter(), handlerProxy);
+assertEq(iter.every(x => x % 2 == 0), false);
+
+assertEq(
+ log.join('\n'),
+ `get: every
+get: next
+get: value
+set: value
+getOwnPropertyDescriptor: value
+defineProperty: value
+get: value
+set: value
+getOwnPropertyDescriptor: value
+defineProperty: value
+get: return`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/every/return-true-if-all-match.js b/js/src/tests/non262/Iterator/prototype/every/return-true-if-all-match.js
new file mode 100644
index 0000000000..894219d29e
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/every/return-true-if-all-match.js
@@ -0,0 +1,11 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const iter = [1, 3, 5].values();
+const fn = (value) => value % 2 == 1;
+
+assertEq(iter.every(fn), true);
+
+assertEq([].values().every(x => x), true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/every/short-circuit-on-false.js b/js/src/tests/non262/Iterator/prototype/every/short-circuit-on-false.js
new file mode 100644
index 0000000000..15b144a4a4
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/every/short-circuit-on-false.js
@@ -0,0 +1,14 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const iter = [1, 2, 3].values();
+const log = [];
+const fn = (value) => {
+ log.push(value.toString());
+ return value % 2 == 1;
+};
+
+assertEq(iter.every(fn), false);
+assertEq(log.join(','), '1,2');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/every/this-not-iterator-throws.js b/js/src/tests/non262/Iterator/prototype/every/this-not-iterator-throws.js
new file mode 100644
index 0000000000..5796c8524e
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/every/this-not-iterator-throws.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const fn = x => x;
+assertThrowsInstanceOf(Iterator.prototype.every.bind(undefined, fn), TypeError);
+assertThrowsInstanceOf(Iterator.prototype.every.bind({}, fn), TypeError);
+assertThrowsInstanceOf(Iterator.prototype.every.bind({next: 0}, fn), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/every/value-throws-iterator-not-closed.js b/js/src/tests/non262/Iterator/prototype/every/value-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..61fe29b7a1
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/every/value-throws-iterator-not-closed.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestError extends Error {}
+class TestIterator extends Iterator {
+ next() {
+ return new Proxy({done: false}, {get: (target, key, receiver) => {
+ if (key === 'value')
+ throw new TestError();
+ return 0;
+ }});
+ }
+
+ closed = false;
+ return() {
+ closed = true;
+ }
+}
+
+const iterator = new TestIterator();
+assertEq(iterator.closed, false, 'iterator starts unclosed');
+assertThrowsInstanceOf(() => iterator.every(x => x), TestError);
+assertEq(iterator.closed, false, 'iterator remains unclosed');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/filter/coerce-result-to-boolean.js b/js/src/tests/non262/Iterator/prototype/filter/coerce-result-to-boolean.js
new file mode 100644
index 0000000000..a3d16bcdfa
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/filter/coerce-result-to-boolean.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+// All truthy values are kept.
+const truthyValues = [true, 1, [], {}, 'test'];
+for (const value of [...truthyValues].values().filter(x => x)) {
+ assertEq(truthyValues.shift(), value);
+}
+
+// All falsy values are filtered out.
+const falsyValues = [false, 0, '', null, undefined, NaN, -0, 0n, createIsHTMLDDA()];
+const result = falsyValues.values().filter(x => x).next();
+assertEq(result.done, true);
+assertEq(result.value, undefined);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/filter/filter.js b/js/src/tests/non262/Iterator/prototype/filter/filter.js
new file mode 100644
index 0000000000..1d148cb82b
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/filter/filter.js
@@ -0,0 +1,14 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+let iter = [1, 2, 3].values().filter(x => x % 2);
+
+for (const v of [1, 3]) {
+ let result = iter.next();
+ assertEq(result.done, false);
+ assertEq(result.value, v);
+}
+
+assertEq(iter.next().done, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/filter/length.js b/js/src/tests/non262/Iterator/prototype/filter/length.js
new file mode 100644
index 0000000000..c1fad91b1d
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/filter/length.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: %Iterator.prototype%.filter length value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+includes: [propertyHelper.js]
+features: [Symbol.iterator]
+---*/
+
+assertEq(Iterator.prototype.filter.length, 1);
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(Iterator.prototype.filter, 'length');
+assertEq(propertyDescriptor.value, 1);
+assertEq(propertyDescriptor.enumerable, false);
+assertEq(propertyDescriptor.writable, false);
+assertEq(propertyDescriptor.configurable, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/filter/name.js b/js/src/tests/non262/Iterator/prototype/filter/name.js
new file mode 100644
index 0000000000..b278220225
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/filter/name.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+/*---
+esid: pending
+description: %Iterator.prototype%.filter.name value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(Iterator.prototype.filter.name, 'filter');
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(Iterator.prototype.filter, 'name');
+assertEq(propertyDescriptor.value, 'filter');
+assertEq(propertyDescriptor.enumerable, false);
+assertEq(propertyDescriptor.writable, false);
+assertEq(propertyDescriptor.configurable, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/find/check-fn-after-getting-iterator.js b/js/src/tests/non262/Iterator/prototype/find/check-fn-after-getting-iterator.js
new file mode 100644
index 0000000000..0417360cc9
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/find/check-fn-after-getting-iterator.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: true};
+ }
+}
+
+const iter = new Proxy(new TestIterator(), handlerProxy);
+assertThrowsInstanceOf(() => iter.find(1), TypeError);
+
+assertEq(
+ log.join('\n'),
+ `get: find
+get: next`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/find/coerce-result-to-boolean.js b/js/src/tests/non262/Iterator/prototype/find/coerce-result-to-boolean.js
new file mode 100644
index 0000000000..7818e5a58d
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/find/coerce-result-to-boolean.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const fn = (value) => value;
+assertEq([true].values().find(fn), true);
+assertEq([1].values().find(fn), 1);
+assertEq(['test'].values().find(fn), 'test');
+
+assertEq([false].values().find(fn), undefined);
+assertEq([0].values().find(fn), undefined);
+assertEq([''].values().find(fn), undefined);
+assertEq([null].values().find(fn), undefined);
+assertEq([undefined].values().find(fn), undefined);
+assertEq([NaN].values().find(fn), undefined);
+assertEq([-0].values().find(fn), undefined);
+assertEq([0n].values().find(fn), undefined);
+
+let array = [];
+assertEq([array].values().find(fn), array);
+
+let object = {};
+assertEq([object].values().find(fn), object);
+
+const htmlDDA = createIsHTMLDDA();
+assertEq([htmlDDA].values().find(fn), undefined);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/find/descriptor.js b/js/src/tests/non262/Iterator/prototype/find/descriptor.js
new file mode 100644
index 0000000000..45699dff85
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/find/descriptor.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Descriptor property of Iterator.prototype.find
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype, 'find');
+assertEq(typeof propDesc.value, 'function');
+assertEq(propDesc.writable, true);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/find/error-from-correct-realm.js b/js/src/tests/non262/Iterator/prototype/find/error-from-correct-realm.js
new file mode 100644
index 0000000000..b34408e853
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/find/error-from-correct-realm.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const otherGlobal = newGlobal({newCompartment: true});
+assertEq(TypeError !== otherGlobal.TypeError, true);
+
+const iter = [].values();
+
+assertThrowsInstanceOf(() => iter.find(), TypeError);
+assertThrowsInstanceOf(
+ otherGlobal.Iterator.prototype.find.bind(iter),
+ otherGlobal.TypeError,
+ 'TypeError comes from the realm of the method.',
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/find/fn-not-callable-throws.js b/js/src/tests/non262/Iterator/prototype/find/fn-not-callable-throws.js
new file mode 100644
index 0000000000..33d18b49cc
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/find/fn-not-callable-throws.js
@@ -0,0 +1,15 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const iter = [].values();
+
+assertThrowsInstanceOf(() => iter.find(), TypeError);
+assertThrowsInstanceOf(() => iter.find(undefined), TypeError);
+assertThrowsInstanceOf(() => iter.find(null), TypeError);
+assertThrowsInstanceOf(() => iter.find(0), TypeError);
+assertThrowsInstanceOf(() => iter.find(false), TypeError);
+assertThrowsInstanceOf(() => iter.find(''), TypeError);
+assertThrowsInstanceOf(() => iter.find(Symbol('')), TypeError);
+assertThrowsInstanceOf(() => iter.find({}), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/find/fn-throws-close-iterator.js b/js/src/tests/non262/Iterator/prototype/find/fn-throws-close-iterator.js
new file mode 100644
index 0000000000..1393bee356
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/find/fn-throws-close-iterator.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestIterator extends Iterator {
+ next() {
+ return { done: this.closed };
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = (value) => { throw new Error(); };
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+assertThrowsInstanceOf(() => iter.find(fn), Error);
+assertEq(iter.closed, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/find/length.js b/js/src/tests/non262/Iterator/prototype/find/length.js
new file mode 100644
index 0000000000..b182ca0e78
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/find/length.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ The `length` property of Iterator.prototype.find.
+info: |
+ ES7 section 17: Unless otherwise specified, the length property of a built-in
+ Function object has the attributes { [[Writable]]: false, [[Enumerable]]:
+ false, [[Configurable]]: true }.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype.find, 'length');
+assertEq(propDesc.value, 1);
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/find/name.js b/js/src/tests/non262/Iterator/prototype/find/name.js
new file mode 100644
index 0000000000..36d903b44c
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/find/name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ `name` property of Iterator.prototype.find.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype.find, 'name');
+assertEq(propDesc.value, 'find');
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/find/next-throws-iterator-not-closed.js b/js/src/tests/non262/Iterator/prototype/find/next-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..13c3195654
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/find/next-throws-iterator-not-closed.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestIterator extends Iterator {
+ next() {
+ throw new Error();
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = x => x;
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+assertThrowsInstanceOf(() => iter.find(fn), Error);
+assertEq(iter.closed, false);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/find/proxy.js b/js/src/tests/non262/Iterator/prototype/find/proxy.js
new file mode 100644
index 0000000000..c24d787710
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/find/proxy.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+//
+// This test checks that %Iterator.prototype%.find only gets the `next` method off of the
+// iterator once, and never accesses the @@iterator property.
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class Counter extends Iterator {
+ value = 0;
+ next() {
+ const value = this.value;
+ if (value < 2) {
+ this.value = value + 1;
+ return {done: false, value};
+ }
+ return {done: true};
+ }
+}
+
+const iter = new Proxy(new Counter(), handlerProxy);
+assertEq(iter.find(x => x % 2 == 1), 1);
+
+assertEq(
+ log.join('\n'),
+ `get: find
+get: next
+get: value
+set: value
+getOwnPropertyDescriptor: value
+defineProperty: value
+get: value
+set: value
+getOwnPropertyDescriptor: value
+defineProperty: value
+get: return`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/find/return-undefined-if-none-match.js b/js/src/tests/non262/Iterator/prototype/find/return-undefined-if-none-match.js
new file mode 100644
index 0000000000..3e7364fa95
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/find/return-undefined-if-none-match.js
@@ -0,0 +1,11 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const iter = [1, 3, 5].values();
+const fn = (value) => value % 2 == 0;
+
+assertEq(iter.find(fn), undefined);
+
+assertEq([].values().find(x => x), undefined);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/find/short-circuit-on-match.js b/js/src/tests/non262/Iterator/prototype/find/short-circuit-on-match.js
new file mode 100644
index 0000000000..8ce7c5a354
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/find/short-circuit-on-match.js
@@ -0,0 +1,14 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const iter = [1, 2, 3].values();
+const log = [];
+const fn = (value) => {
+ log.push(value.toString());
+ return value % 2 == 0;
+};
+
+assertEq(iter.find(fn), 2);
+assertEq(log.join(','), '1,2');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/find/this-not-iterator-throws.js b/js/src/tests/non262/Iterator/prototype/find/this-not-iterator-throws.js
new file mode 100644
index 0000000000..8e1d446705
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/find/this-not-iterator-throws.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const fn = x => x;
+assertThrowsInstanceOf(Iterator.prototype.find.bind(undefined, fn), TypeError);
+assertThrowsInstanceOf(Iterator.prototype.find.bind({}, fn), TypeError);
+assertThrowsInstanceOf(Iterator.prototype.find.bind({next: 0}, fn), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/find/value-throws-iterator-not-closed.js b/js/src/tests/non262/Iterator/prototype/find/value-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..23873c618a
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/find/value-throws-iterator-not-closed.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestError extends Error {}
+class TestIterator extends Iterator {
+ next() {
+ return new Proxy({done: false}, {get: (target, key, receiver) => {
+ if (key === 'value')
+ throw new TestError();
+ return 0;
+ }});
+ }
+
+ closed = false;
+ return() {
+ closed = true;
+ }
+}
+
+const iterator = new TestIterator();
+assertEq(iterator.closed, false, 'iterator starts unclosed');
+assertThrowsInstanceOf(() => iterator.find(x => x), TestError);
+assertEq(iterator.closed, false, 'iterator remains unclosed');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/flatMap/close-iterator-when-inner-complete-throws.js b/js/src/tests/non262/Iterator/prototype/flatMap/close-iterator-when-inner-complete-throws.js
new file mode 100644
index 0000000000..3a0bfcf167
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/flatMap/close-iterator-when-inner-complete-throws.js
@@ -0,0 +1,49 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: %Iterator.prototype%.flatMap closes the iterator when innerComplete throws.
+info: >
+ Iterator Helpers proposal 2.1.5.7
+ 1. Repeat,
+ ...
+ i. Repeat, while innerAlive is true,
+ iii. Let innerComplete be IteratorComplete(innerNext).
+ iv. IfAbruptCloseIterator(innerComplete, iterated).
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: false, value: 0};
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+class TestError extends Error {}
+class InnerIterator extends Iterator {
+ next() {
+ return {
+ get done() {
+ throw new TestError();
+ }
+ };
+ }
+}
+
+const iter = new TestIterator();
+const mapped = iter.flatMap(x => new InnerIterator());
+
+assertEq(iter.closed, false);
+assertThrowsInstanceOf(() => mapped.next(), TestError);
+assertEq(iter.closed, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/flatMap/close-iterator-when-inner-next-throws.js b/js/src/tests/non262/Iterator/prototype/flatMap/close-iterator-when-inner-next-throws.js
new file mode 100644
index 0000000000..a8f70497f7
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/flatMap/close-iterator-when-inner-next-throws.js
@@ -0,0 +1,45 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: %Iterator.prototype%.flatMap closes the iterator when innerNext throws.
+info: >
+ Iterator Helpers proposal 2.1.5.7
+ 1. Repeat,
+ ...
+ i. Repeat, while innerAlive is true,
+ i. Let innerNext be IteratorNext(innerIterator).
+ ii. IfAbruptCloseIterator(innerNext, iterated).
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: false, value: 0};
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+class TestError extends Error {}
+class InnerIterator extends Iterator {
+ next() {
+ throw new TestError();
+ }
+}
+
+const iter = new TestIterator();
+const mapped = iter.flatMap(x => new InnerIterator());
+
+assertEq(iter.closed, false);
+assertThrowsInstanceOf(() => mapped.next(), TestError);
+assertEq(iter.closed, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/flatMap/close-iterator-when-inner-value-throws.js b/js/src/tests/non262/Iterator/prototype/flatMap/close-iterator-when-inner-value-throws.js
new file mode 100644
index 0000000000..3b2f26b401
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/flatMap/close-iterator-when-inner-value-throws.js
@@ -0,0 +1,52 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: %Iterator.prototype%.flatMap closes the iterator when innerValue throws.
+info: >
+ Iterator Helpers proposal 2.1.5.7
+ 1. Repeat,
+ ...
+ i. Repeat, while innerAlive is true,
+ ...
+ vi. Else,
+ 1. Let innerValue be IteratorValue(innerNext).
+ 2. IfAbruptCloseIterator(innerValue, iterated).
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: false, value: 0};
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+class TestError extends Error {}
+class InnerIterator extends Iterator {
+ next() {
+ return {
+ done: false,
+ get value() {
+ throw new TestError();
+ },
+ };
+ }
+}
+
+const iter = new TestIterator();
+const mapped = iter.flatMap(x => new InnerIterator());
+
+assertEq(iter.closed, false);
+assertThrowsInstanceOf(() => mapped.next(), TestError);
+assertEq(iter.closed, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/flatMap/flatMap.js b/js/src/tests/non262/Iterator/prototype/flatMap/flatMap.js
new file mode 100644
index 0000000000..6acce22593
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/flatMap/flatMap.js
@@ -0,0 +1,12 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+let iter = [1, 2, 3].values().flatMap(x => [x, x + 1]);
+for (const v of [1, 2, 2, 3, 3, 4]) {
+ let result = iter.next();
+ assertEq(result.done, false);
+ assertEq(result.value, v);
+}
+assertEq(iter.next().done, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/flatMap/inner-empty-iterable.js b/js/src/tests/non262/Iterator/prototype/flatMap/inner-empty-iterable.js
new file mode 100644
index 0000000000..24fcc85c2c
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/flatMap/inner-empty-iterable.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: %Iterator.prototype%.flatMap skips empty inner iterables.
+info: >
+ Iterator Helpers proposal 2.1.5.7
+ 1. Repeat,
+ ...
+ i. Repeat, while innerAlive is true,
+ ...
+ iii. Let innerComplete be IteratorComplete(innerNext).
+ ...
+ v. If innerComplete is true, set innerAlive to false.
+features: [iterator-helpers]
+---*/
+
+let iter = [0, 1, 2, 3].values().flatMap(x => x % 2 ? [] : [x]);
+
+for (const expected of [0, 2]) {
+ const result = iter.next();
+ assertEq(result.value, expected);
+ assertEq(result.done, false);
+}
+
+let result = iter.next();
+assertEq(result.value, undefined);
+assertEq(result.done, true);
+
+iter = [0, 1, 2, 3].values().flatMap(x => []);
+result = iter.next();
+assertEq(result.value, undefined);
+assertEq(result.done, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/flatMap/inner-generator.js b/js/src/tests/non262/Iterator/prototype/flatMap/inner-generator.js
new file mode 100644
index 0000000000..9589027b4b
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/flatMap/inner-generator.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: %Iterator.prototype%.flatMap innerIterator can be a generator.
+info: >
+ Iterator Helpers proposal 2.1.5.7
+features: [iterator-helpers]
+---*/
+
+const iter = [1, 2].values().flatMap(function*(x) {
+ yield x;
+ yield* [x + 1, x + 2];
+});
+
+for (const expected of [1, 2, 3, 2, 3, 4]) {
+ const result = iter.next();
+ assertEq(result.value, expected);
+ assertEq(result.done, false);
+}
+
+const result = iter.next();
+assertEq(result.value, undefined);
+assertEq(result.done, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/flatMap/length.js b/js/src/tests/non262/Iterator/prototype/flatMap/length.js
new file mode 100644
index 0000000000..d5f8a5021f
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/flatMap/length.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: %Iterator.prototype%.flatMap length value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+includes: [propertyHelper.js]
+features: [Symbol.iterator]
+---*/
+
+assertEq(Iterator.prototype.flatMap.length, 1);
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(Iterator.prototype.flatMap, 'length');
+assertEq(propertyDescriptor.value, 1);
+assertEq(propertyDescriptor.enumerable, false);
+assertEq(propertyDescriptor.writable, false);
+assertEq(propertyDescriptor.configurable, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/flatMap/name.js b/js/src/tests/non262/Iterator/prototype/flatMap/name.js
new file mode 100644
index 0000000000..6cc6b98ef0
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/flatMap/name.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+/*---
+esid: pending
+description: %Iterator.prototype%.flatMap.name value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(Iterator.prototype.flatMap.name, 'flatMap');
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(Iterator.prototype.flatMap, 'name');
+assertEq(propertyDescriptor.value, 'flatMap');
+assertEq(propertyDescriptor.enumerable, false);
+assertEq(propertyDescriptor.writable, false);
+assertEq(propertyDescriptor.configurable, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/flatMap/throw-when-inner-not-iterable.js b/js/src/tests/non262/Iterator/prototype/flatMap/throw-when-inner-not-iterable.js
new file mode 100644
index 0000000000..eb581936e1
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/flatMap/throw-when-inner-not-iterable.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: %Iterator.prototype%.flatMap closes the iterator and throws when mapped isn't iterable.
+info: >
+ Iterator Helpers proposal 2.1.5.7
+ 1. Repeat,
+ ...
+ f. Let innerIterator be GetIterator(mapped, sync).
+ g. IfAbruptCloseIterator(innerIterator, iterated).
+features: [iterator-helpers]
+---*/
+
+class NotIterable {
+ next() {
+ return {done: true};
+ }
+}
+
+class InvalidIterable {
+ [Symbol.iterator]() {
+ return {};
+ }
+}
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: false, value: 0};
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+const nonIterables = [
+ new NotIterable(),
+ new InvalidIterable(),
+ undefined,
+ null,
+ 0,
+ false,
+ Symbol(''),
+ 0n,
+ {},
+];
+
+for (const value of nonIterables) {
+ const iter = new TestIterator();
+ const mapped = iter.flatMap(x => value);
+
+ assertEq(iter.closed, false);
+ assertThrowsInstanceOf(() => mapped.next(), TypeError);
+ assertEq(iter.closed, true);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
+
diff --git a/js/src/tests/non262/Iterator/prototype/forEach/check-fn-after-getting-iterator.js b/js/src/tests/non262/Iterator/prototype/forEach/check-fn-after-getting-iterator.js
new file mode 100644
index 0000000000..2291c04664
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/forEach/check-fn-after-getting-iterator.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: true};
+ }
+}
+
+const iter = new Proxy(new TestIterator(), handlerProxy);
+assertThrowsInstanceOf(() => iter.forEach(1), TypeError);
+
+assertEq(
+ log.join('\n'),
+ `get: forEach
+get: next`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/forEach/descriptor.js b/js/src/tests/non262/Iterator/prototype/forEach/descriptor.js
new file mode 100644
index 0000000000..b33be1e435
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/forEach/descriptor.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Descriptor property of Iterator.prototype.forEach
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype, 'forEach');
+assertEq(typeof propDesc.value, 'function');
+assertEq(propDesc.writable, true);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/forEach/error-from-correct-realm.js b/js/src/tests/non262/Iterator/prototype/forEach/error-from-correct-realm.js
new file mode 100644
index 0000000000..38c8e9bb5c
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/forEach/error-from-correct-realm.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const otherGlobal = newGlobal({newCompartment: true});
+assertEq(TypeError !== otherGlobal.TypeError, true);
+
+const iter = [].values();
+
+assertThrowsInstanceOf(() => iter.forEach(), TypeError);
+assertThrowsInstanceOf(
+ otherGlobal.Iterator.prototype.forEach.bind(iter),
+ otherGlobal.TypeError,
+ 'TypeError comes from the realm of the method.',
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/forEach/fn-not-callable-throws.js b/js/src/tests/non262/Iterator/prototype/forEach/fn-not-callable-throws.js
new file mode 100644
index 0000000000..473789a6a2
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/forEach/fn-not-callable-throws.js
@@ -0,0 +1,15 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const iter = [].values();
+
+assertThrowsInstanceOf(() => iter.forEach(), TypeError);
+assertThrowsInstanceOf(() => iter.forEach(undefined), TypeError);
+assertThrowsInstanceOf(() => iter.forEach(null), TypeError);
+assertThrowsInstanceOf(() => iter.forEach(0), TypeError);
+assertThrowsInstanceOf(() => iter.forEach(false), TypeError);
+assertThrowsInstanceOf(() => iter.forEach(''), TypeError);
+assertThrowsInstanceOf(() => iter.forEach(Symbol('')), TypeError);
+assertThrowsInstanceOf(() => iter.forEach({}), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/forEach/fn-throws-close-iterator.js b/js/src/tests/non262/Iterator/prototype/forEach/fn-throws-close-iterator.js
new file mode 100644
index 0000000000..1703673f0d
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/forEach/fn-throws-close-iterator.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestIterator extends Iterator {
+ next() {
+ return { done: this.closed };
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = () => { throw new Error(); };
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+assertThrowsInstanceOf(() => iter.forEach(fn), Error);
+assertEq(iter.closed, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/forEach/forEach.js b/js/src/tests/non262/Iterator/prototype/forEach/forEach.js
new file mode 100644
index 0000000000..62ddce6eb7
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/forEach/forEach.js
@@ -0,0 +1,11 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const log = [];
+const fn = (value) => log.push(value);
+const iter = [1, 2, 3].values();
+
+assertEq(iter.forEach(fn), undefined);
+assertEq(log.join(','), '1,2,3');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/forEach/length.js b/js/src/tests/non262/Iterator/prototype/forEach/length.js
new file mode 100644
index 0000000000..9f2f9134f8
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/forEach/length.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ The `length` property of Iterator.prototype.forEach.
+info: |
+ ES7 section 17: Unless otherwise specified, the length property of a built-in
+ Function object has the attributes { [[Writable]]: false, [[Enumerable]]:
+ false, [[Configurable]]: true }.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype.forEach, 'length');
+assertEq(propDesc.value, 1);
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/forEach/name.js b/js/src/tests/non262/Iterator/prototype/forEach/name.js
new file mode 100644
index 0000000000..7c4964e696
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/forEach/name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ `name` property of Iterator.prototype.forEach.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype.forEach, 'name');
+assertEq(propDesc.value, 'forEach');
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/forEach/next-throws-iterator-not-closed.js b/js/src/tests/non262/Iterator/prototype/forEach/next-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..042b6d660c
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/forEach/next-throws-iterator-not-closed.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestIterator extends Iterator {
+ next() {
+ throw new Error();
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = () => {};
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+assertThrowsInstanceOf(() => iter.forEach(fn), Error);
+assertEq(iter.closed, false);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/forEach/proxy.js b/js/src/tests/non262/Iterator/prototype/forEach/proxy.js
new file mode 100644
index 0000000000..9d50aed9fe
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/forEach/proxy.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+//
+// This test checks that %Iterator.prototype%.forEach only gets the `next` method off of the
+// iterator once, and never accesses the @@iterator property.
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class Counter extends Iterator {
+ value = 0;
+ next() {
+ const value = this.value;
+ if (value < 2) {
+ this.value = value + 1;
+ return {done: false, value};
+ }
+ return {done: true};
+ }
+}
+
+const iter = new Proxy(new Counter(), handlerProxy);
+iter.forEach(x => x);
+
+assertEq(
+ log.join('\n'),
+ `get: forEach
+get: next
+get: value
+set: value
+getOwnPropertyDescriptor: value
+defineProperty: value
+get: value
+set: value
+getOwnPropertyDescriptor: value
+defineProperty: value
+get: value`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/forEach/this-not-iterator-throws.js b/js/src/tests/non262/Iterator/prototype/forEach/this-not-iterator-throws.js
new file mode 100644
index 0000000000..d47ba38960
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/forEach/this-not-iterator-throws.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const fn = x => x;
+assertThrowsInstanceOf(Iterator.prototype.forEach.bind(undefined, fn), TypeError);
+assertThrowsInstanceOf(Iterator.prototype.forEach.bind({}, fn), TypeError);
+assertThrowsInstanceOf(Iterator.prototype.forEach.bind({next: 0}, fn), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/forEach/value-throws-iterator-not-closed.js b/js/src/tests/non262/Iterator/prototype/forEach/value-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..28f1d64113
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/forEach/value-throws-iterator-not-closed.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestError extends Error {}
+class TestIterator extends Iterator {
+ next() {
+ return new Proxy({done: false}, {get: (target, key, receiver) => {
+ if (key === 'value')
+ throw new TestError();
+ return 0;
+ }});
+ }
+
+ closed = false;
+ return() {
+ closed = true;
+ }
+}
+
+const iterator = new TestIterator();
+assertEq(iterator.closed, false, 'iterator starts unclosed');
+assertThrowsInstanceOf(() => iterator.forEach(x => x), TestError);
+assertEq(iterator.closed, false, 'iterator remains unclosed');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/generator-methods-throw-on-iterator-helpers.js b/js/src/tests/non262/Iterator/prototype/generator-methods-throw-on-iterator-helpers.js
new file mode 100644
index 0000000000..f684be43fb
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/generator-methods-throw-on-iterator-helpers.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+const generatorProto = Object.getPrototypeOf(
+ Object.getPrototypeOf(
+ (function *() {})()
+ )
+);
+
+const iteratorHelper = [0].values().map(x => x);
+
+assertThrowsInstanceOf(() => generatorProto.next.call(iteratorHelper), TypeError);
+assertThrowsInstanceOf(() => generatorProto.return.call(iteratorHelper), TypeError);
+assertThrowsInstanceOf(() => generatorProto.throw.call(iteratorHelper), TypeError);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/iterator-helper-methods-throw-on-generators.js b/js/src/tests/non262/Iterator/prototype/iterator-helper-methods-throw-on-generators.js
new file mode 100644
index 0000000000..e074d7e580
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/iterator-helper-methods-throw-on-generators.js
@@ -0,0 +1,14 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+const iteratorHelperProto = Object.getPrototypeOf([].values().map(x => x));
+
+function *gen() {
+ yield 1;
+}
+
+assertThrowsInstanceOf(() => iteratorHelperProto.next.call(gen()), TypeError);
+assertThrowsInstanceOf(() => iteratorHelperProto.return.call(gen()), TypeError);
+assertThrowsInstanceOf(() => iteratorHelperProto.throw.call(gen()), TypeError);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/iterator-helpers-from-other-global.js b/js/src/tests/non262/Iterator/prototype/iterator-helpers-from-other-global.js
new file mode 100644
index 0000000000..d18bd8f00f
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/iterator-helpers-from-other-global.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+class TestError extends Error {}
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: false, value: 'value'};
+ }
+
+ closed = false;
+ return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+function checkIterResult({done, value}, expectedDone, expectedValue) {
+ assertEq(done, expectedDone);
+ assertEq(Array.isArray(value) ? value[1] : value, expectedValue);
+}
+
+const otherGlobal = newGlobal({newCompartment: true});
+
+const methods = [
+ ["map", x => x],
+ ["filter", x => true],
+ ["take", Infinity],
+ ["drop", 0],
+ ["asIndexedPairs", undefined],
+ ["flatMap", x => [x]],
+];
+
+for (const [method, arg] of methods) {
+ const {next: otherNext} = Object.getPrototypeOf(
+ new otherGlobal.Array().values()[method](arg)
+ );
+ const iterator = new TestIterator();
+ const helper = iterator[method](arg);
+ checkIterResult(otherNext.call(helper), false, 'value');
+}
+
+for (const [method, arg] of methods) {
+ const {return: otherReturn} = Object.getPrototypeOf(
+ new otherGlobal.Array().values()[method](arg)
+ );
+ const iterator = new TestIterator();
+ const helper = iterator[method](arg);
+ assertEq(iterator.closed, false);
+ checkIterResult(otherReturn.call(helper), true, undefined);
+ assertEq(iterator.closed, true);
+}
+
+for (const [method, arg] of methods) {
+ const {throw: otherThrow} = Object.getPrototypeOf(
+ new otherGlobal.Array().values()[method](arg)
+ );
+ const iterator = new TestIterator();
+ const helper = iterator[method](arg);
+ assertThrowsInstanceOf(otherThrow.bind(helper, new TestError()), TestError);
+ checkIterResult(helper.next(), true, undefined);
+}
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-from-other-global.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-from-other-global.js
new file mode 100644
index 0000000000..e6235ed171
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-from-other-global.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+const otherIteratorProto = newGlobal({newCompartment: true}).Iterator.prototype;
+
+const methods = [
+ ["map", x => x],
+ ["filter", x => true],
+ ["take", Infinity],
+ ["drop", 0],
+ ["asIndexedPairs", undefined],
+ ["flatMap", x => [x]],
+];
+
+// Use the lazy Iterator methods from another global on an iterator from this global.
+for (const [method, arg] of methods) {
+ const iterator = [1, 2, 3].values();
+ const helper = otherIteratorProto[method].call(iterator, arg);
+
+ for (const expected of [1, 2, 3]) {
+ const {done, value} = helper.next();
+ assertEq(done, false);
+ assertEq(Array.isArray(value) ? value[1] : value, expected);
+ }
+
+ const {done, value} = helper.next();
+ assertEq(done, true);
+ assertEq(value, undefined);
+}
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-handle-empty-iterators.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-handle-empty-iterators.js
new file mode 100644
index 0000000000..e6df2758ad
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-handle-empty-iterators.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %Iterator.prototype% methods handle empty iterators.
+info: >
+ Iterator Helpers proposal 2.1.5
+features: [iterator-helpers]
+---*/
+
+class EmptyIterator extends Iterator {
+ next() {
+ return {done: true};
+ }
+}
+
+const emptyIterator1 = new EmptyIterator();
+const emptyIterator2 = [].values();
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => x),
+ iter => iter.take(1),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(x => [x]),
+];
+
+for (const method of methods) {
+ for (const iterator of [emptyIterator1, emptyIterator2]) {
+ const result = method(iterator).next();
+ assertEq(result.done, true);
+ assertEq(result.value, undefined);
+ }
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-interleaved.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-interleaved.js
new file mode 100644
index 0000000000..0edc3cd467
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-interleaved.js
@@ -0,0 +1,62 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %Iterator.prototype% method calls can be interleaved.
+info: >
+ Iterator Helpers proposal 2.1.5
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends Iterator {
+ value = 0;
+ next() {
+ return {done: false, value: this.value++};
+ }
+}
+
+function unwrapResult(result) {
+ // Unwrap the asIndexedPair return values.
+ while (Array.isArray(result.value)) {
+ result.value = result.value[1];
+ }
+ return result;
+}
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => true),
+ iter => iter.take(2),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(x => [x]),
+];
+
+for (const firstMethod of methods) {
+ for (const secondMethod of methods) {
+ const iterator = new TestIterator();
+ const firstHelper = firstMethod(iterator);
+ const secondHelper = secondMethod(iterator);
+
+ let firstResult = unwrapResult(firstHelper.next());
+ assertEq(firstResult.done, false);
+ assertEq(firstResult.value, 0);
+
+ let secondResult = unwrapResult(secondHelper.next());
+ assertEq(secondResult.done, false);
+ assertEq(secondResult.value, 1);
+
+ firstResult = unwrapResult(firstHelper.next());
+ assertEq(firstResult.done, false);
+ assertEq(firstResult.value, 2);
+
+ secondResult = unwrapResult(secondHelper.next());
+ assertEq(secondResult.done, false);
+ assertEq(secondResult.value, 3);
+ }
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-closed-on-call-throws.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-closed-on-call-throws.js
new file mode 100644
index 0000000000..f81e9280ce
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-closed-on-call-throws.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %Iterator.prototype% methods close the iterator if callback throws.
+info: >
+ Iterator Helpers proposal 2.1.5
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+class TestIterator extends Iterator {
+ next() {
+ return {done: false, value: 1};
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+function fn() {
+ throw new TestError();
+}
+const methods = [
+ iter => iter.map(fn),
+ iter => iter.filter(fn),
+ iter => iter.flatMap(fn),
+];
+
+for (const method of methods) {
+ const iter = new TestIterator();
+ assertEq(iter.closed, false);
+ assertThrowsInstanceOf(() => method(iter).next(), TestError);
+ assertEq(iter.closed, true);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
+
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-closed-on-yield-throws.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-closed-on-yield-throws.js
new file mode 100644
index 0000000000..361b800404
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-closed-on-yield-throws.js
@@ -0,0 +1,45 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %Iterator.prototype% methods close the iterator if `yield` throws.
+info: >
+ Iterator Helpers proposal 2.1.5
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+class TestIterator extends Iterator {
+ next() {
+ return {done: false, value: 1};
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => true),
+ iter => iter.take(1),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(x => [x]),
+];
+
+for (const method of methods) {
+ const iterator = new TestIterator();
+ assertEq(iterator.closed, false);
+ const iteratorHelper = method(iterator);
+ iteratorHelper.next();
+ assertThrowsInstanceOf(() => iteratorHelper.throw(new TestError()), TestError);
+ assertEq(iterator.closed, true);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-not-closed-on-next-throws.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-not-closed-on-next-throws.js
new file mode 100644
index 0000000000..4aceacebb6
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-not-closed-on-next-throws.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %Iterator.prototype% methods don't close the iterator if `.next` call throws.
+info: >
+ Iterator Helpers proposal 2.1.5
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+class TestIterator extends Iterator {
+ next() {
+ throw new TestError();
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+const iterator = new TestIterator();
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => x),
+ iter => iter.take(1),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(x => [x]),
+];
+
+for (const method of methods) {
+ assertEq(iterator.closed, false);
+ assertThrowsInstanceOf(() => method(iterator).next(), TestError);
+ assertEq(iterator.closed, false);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-not-closed-on-value-throws.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-not-closed-on-value-throws.js
new file mode 100644
index 0000000000..1ca88ca9b5
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-not-closed-on-value-throws.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %Iterator.prototype% methods don't close the iterator if `value` throws.
+info: >
+ Iterator Helpers proposal 2.1.5
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+class TestIterator extends Iterator {
+ next() {
+ return {
+ get value() {
+ throw new TestError();
+ }
+ };
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+const iterator = new TestIterator();
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => x),
+ iter => iter.take(1),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(x => [x]),
+];
+
+for (const method of methods) {
+ assertEq(iterator.closed, false);
+ assertThrowsInstanceOf(() => method(iterator).next(), TestError);
+ assertEq(iterator.closed, false);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-returns-done-generator-finishes.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-returns-done-generator-finishes.js
new file mode 100644
index 0000000000..d6b3f14277
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-iterator-returns-done-generator-finishes.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: true, value: 'value'};
+ }
+}
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => true),
+ iter => iter.take(1),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(x => [x]),
+];
+
+for (const method of methods) {
+ const iterator = method(new TestIterator());
+ const result = iterator.next();
+ assertEq(result.done, true);
+ assertEq(result.value, undefined);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
+
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-multiple-return-close-iterator-once.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-multiple-return-close-iterator-once.js
new file mode 100644
index 0000000000..34c165b86d
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-multiple-return-close-iterator-once.js
@@ -0,0 +1,60 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Calling `.return()` on a lazy %Iterator.prototype% method multiple times closes the source iterator once.
+info: >
+ Iterator Helpers proposal 2.1.5
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: false, value: 1};
+ }
+
+ closeCount = 0;
+ return(value) {
+ this.closeCount++;
+ return {done: true, value};
+ }
+}
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => x),
+ iter => iter.take(1),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(x => [x]),
+];
+
+// Call `return` after stepping the iterator once:
+for (const method of methods) {
+ const iter = new TestIterator();
+ const iterHelper = method(iter);
+ iterHelper.next();
+
+ assertEq(iter.closeCount, 0);
+ iterHelper.return();
+ assertEq(iter.closeCount, 1);
+ iterHelper.return();
+ assertEq(iter.closeCount, 1);
+}
+
+// Call `return` before stepping the iterator:
+for (const method of methods) {
+ const iter = new TestIterator();
+ const iterHelper = method(iter);
+
+ assertEq(iter.closeCount, 0);
+ iterHelper.return();
+ assertEq(iter.closeCount, 1);
+ iterHelper.return();
+ assertEq(iter.closeCount, 1);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-multiple-throw-close-iterator-once.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-multiple-throw-close-iterator-once.js
new file mode 100644
index 0000000000..6c044cbd89
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-multiple-throw-close-iterator-once.js
@@ -0,0 +1,62 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Calling `.throw()` on a lazy %Iterator.prototype% method multiple times closes the source iterator once.
+info: >
+ Iterator Helpers proposal 2.1.5
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: false, value: 1};
+ }
+
+ closeCount = 0;
+ return(value) {
+ this.closeCount++;
+ return {done: true, value};
+ }
+}
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => x),
+ iter => iter.take(1),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(x => [x]),
+];
+
+// Call `throw` after stepping the iterator once:
+for (const method of methods) {
+ const iter = new TestIterator();
+ const iterHelper = method(iter);
+ iterHelper.next();
+
+ assertEq(iter.closeCount, 0);
+ assertThrowsInstanceOf(() => iterHelper.throw(new TestError()), TestError);
+ assertEq(iter.closeCount, 1);
+ assertThrowsInstanceOf(() => iterHelper.throw(new TestError()), TestError);
+ assertEq(iter.closeCount, 1);
+}
+
+// Call `throw` before stepping the iterator:
+for (const method of methods) {
+ const iter = new TestIterator();
+ const iterHelper = method(iter);
+
+ assertEq(iter.closeCount, 0);
+ assertThrowsInstanceOf(() => iterHelper.throw(new TestError()), TestError);
+ assertEq(iter.closeCount, 1);
+ assertThrowsInstanceOf(() => iterHelper.throw(new TestError()), TestError);
+ assertEq(iter.closeCount, 1);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-pass-through-lastValue.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-pass-through-lastValue.js
new file mode 100644
index 0000000000..a7195b38e4
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-pass-through-lastValue.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+class TestIterator extends Iterator {
+ next(value) {
+ return {done: false, value};
+ }
+}
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => true),
+ iter => iter.take(2),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+];
+
+for (const method of methods) {
+ const iterator = new TestIterator();
+ const iteratorHelper = method(iterator);
+ iteratorHelper.next();
+ let result = iteratorHelper.next('last value');
+ assertEq(result.done, false);
+ // Array.isArray is used to make sure we unwrap asIndexedPairs results.
+ assertEq(Array.isArray(result.value) ? result.value[1] : result.value, 'last value');
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
+
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-pass-value-through-chain.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-pass-value-through-chain.js
new file mode 100644
index 0000000000..553e6934f7
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-pass-value-through-chain.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+class TestIterator extends Iterator {
+ next(value) {
+ return {done: false, value};
+ }
+}
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => true),
+ iter => iter.take(2),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+];
+
+for (const outerMethod of methods) {
+ for (const innerMethod of methods) {
+ const iterator = new TestIterator();
+ const iteratorChain = outerMethod(innerMethod(iterator));
+ iteratorChain.next();
+ let result = iteratorChain.next('last value');
+ assertEq(result.done, false);
+ // Unwrap the asIndexedPair return values.
+ while (Array.isArray(result.value)) {
+ result.value = result.value[1];
+ }
+ assertEq(result.value, 'last value');
+ }
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-proxy-accesses.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-proxy-accesses.js
new file mode 100644
index 0000000000..d391a4f199
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-proxy-accesses.js
@@ -0,0 +1,70 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: Lazy %Iterator.prototype% methods access specified properties only.
+info: >
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends Iterator {
+ value = 0;
+ next() {
+ if (this.value < 2)
+ return { done: false, value: this.value++ };
+ return { done: true, value: undefined };
+ }
+}
+
+const handlerProxy = log => new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ const target = args[0];
+ const item = Reflect[key](...args);
+
+ log.push(`${key}: ${args.filter(x => typeof x != 'object').map(x => x.toString())}`);
+
+ return item;
+ },
+});
+
+const methods = [
+ [iter => iter.map(x => x), 'map'],
+ [iter => iter.filter(x => true), 'filter'],
+ [iter => iter.take(4), 'take'],
+ [iter => iter.drop(0), 'drop'],
+ [iter => iter.asIndexedPairs(), 'asIndexedPairs'],
+ [iter => iter.flatMap(x => [x]), 'flatMap'],
+];
+
+for (const method of methods) {
+ const log = [];
+ const iteratorProxy = new Proxy(new TestIterator(), handlerProxy(log));
+ const iteratorHelper = method[0](iteratorProxy);
+ const methodName = method[1];
+
+ iteratorHelper.next();
+ iteratorHelper.next();
+ iteratorHelper.next();
+ assertEq(iteratorHelper.next().done, true);
+
+ assertEq(
+ log.join('\n'),
+ `get: ${methodName}
+get: next
+get: value
+get: value
+getOwnPropertyDescriptor: value
+defineProperty: value
+set: value,1
+get: value
+get: value
+getOwnPropertyDescriptor: value
+defineProperty: value
+set: value,2
+get: value`
+ )
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-reentry-not-close-iterator.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-reentry-not-close-iterator.js
new file mode 100644
index 0000000000..da1e4c8c29
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-reentry-not-close-iterator.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+const methods = [
+ [iter => iter.map, x => x],
+ [iter => iter.filter, x => true],
+ [iter => iter.flatMap, x => [x]],
+];
+
+for (const method of methods) {
+ const iter = [1, 2, 3].values();
+ const iterMethod = method[0](iter);
+ let iterHelper;
+ let reentered = false;
+ iterHelper = iterMethod.call(iter, x => {
+ if (x == 2) {
+ // Reenter the currently running generator.
+ reentered = true;
+ assertThrowsInstanceOf(() => iterHelper.next(), TypeError);
+ }
+ return method[1](x);
+ });
+
+ let result = iterHelper.next();
+ assertEq(result.value, 1);
+ assertEq(result.done, false);
+
+ assertEq(reentered, false);
+ result = iterHelper.next();
+ assertEq(reentered, true);
+ assertEq(result.value, 2);
+ assertEq(result.done, false);
+
+ result = iterHelper.next();
+ assertEq(result.value, 3);
+ assertEq(result.done, false);
+
+ result = iterHelper.next();
+ assertEq(result.value, undefined);
+ assertEq(result.done, true);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-return-closes-iterator.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-return-closes-iterator.js
new file mode 100644
index 0000000000..45fa3105df
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-return-closes-iterator.js
@@ -0,0 +1,58 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Calling `.return()` on a lazy %Iterator.prototype% method closes the source iterator.
+info: >
+ Iterator Helpers proposal 2.1.5
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: false, value: 1};
+ }
+
+ closed = false;
+ return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => x),
+ iter => iter.take(1),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(x => [x]),
+];
+
+for (const method of methods) {
+ const iter = new TestIterator();
+ const iterHelper = method(iter);
+ iterHelper.next();
+
+ assertEq(iter.closed, false);
+ const result = iterHelper.return(0);
+ assertEq(iter.closed, true);
+ assertEq(result.done, true);
+ assertEq(result.value, 0);
+}
+
+for (const method of methods) {
+ const iter = new TestIterator();
+ const iterHelper = method(iter);
+
+ assertEq(iter.closed, false);
+ const result = iterHelper.return(0);
+ assertEq(iter.closed, true);
+ assertEq(result.done, true);
+ assertEq(result.value, 0);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-return-new-iterator-result.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-return-new-iterator-result.js
new file mode 100644
index 0000000000..407782fae5
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-return-new-iterator-result.js
@@ -0,0 +1,39 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy Iterator Helper methods return new iterator result objects.
+info: >
+ Iterator Helpers proposal 2.1.5
+features: [iterator-helpers]
+---*/
+
+const iterResult = {done: false, value: 1, testProperty: 'test'};
+class TestIterator extends Iterator {
+ next() {
+ return iterResult;
+ }
+}
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => true),
+ iter => iter.take(1),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(x => [x]),
+];
+
+// Call `return` before stepping the iterator:
+for (const method of methods) {
+ const iter = new TestIterator();
+ const iterHelper = method(iter);
+ const result = iterHelper.next();
+ assertEq(result == iterResult, false);
+ assertEq(result.testProperty, undefined);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-closes-iterator-before-next.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-closes-iterator-before-next.js
new file mode 100644
index 0000000000..d3197fc107
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-closes-iterator-before-next.js
@@ -0,0 +1,50 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Calling `.throw()` on a lazy %Iterator.prototype% method closes the source iterator.
+info: >
+ Iterator Helpers proposal 2.1.5
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: false, value: 1};
+ }
+
+ closed = false;
+ return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => x),
+ iter => iter.take(1),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(x => [x]),
+];
+
+for (const method of methods) {
+ const iter = new TestIterator();
+ const iterHelper = method(iter);
+
+ assertEq(iter.closed, false);
+ assertThrowsInstanceOf(() => iterHelper.throw(new TestError()), TestError);
+ assertEq(iter.closed, true);
+
+ const result = iterHelper.next();
+ assertEq(result.done, true);
+ assertEq(result.value, undefined);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-eagerly-on-next-non-callable.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-eagerly-on-next-non-callable.js
new file mode 100644
index 0000000000..22d9bbd48a
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-eagerly-on-next-non-callable.js
@@ -0,0 +1,34 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %Iterator.prototype% methods throw eagerly when `next` is non-callable.
+info: >
+ Iterator Helpers proposal 1.1.1
+features: [iterator-helpers]
+---*/
+
+const methods = [
+ next => Iterator.prototype.map.bind({next}, x => x),
+ next => Iterator.prototype.filter.bind({next}, x => x),
+ next => Iterator.prototype.take.bind({next}, 1),
+ next => Iterator.prototype.drop.bind({next}, 0),
+ next => Iterator.prototype.asIndexedPairs.bind({next}),
+ next => Iterator.prototype.flatMap.bind({next}, x => [x]),
+];
+
+for (const method of methods) {
+ assertThrowsInstanceOf(method(0), TypeError);
+ assertThrowsInstanceOf(method(false), TypeError);
+ assertThrowsInstanceOf(method(undefined), TypeError);
+ assertThrowsInstanceOf(method(null), TypeError);
+ assertThrowsInstanceOf(method(''), TypeError);
+ assertThrowsInstanceOf(method(Symbol('')), TypeError);
+ assertThrowsInstanceOf(method({}), TypeError);
+ assertThrowsInstanceOf(method([]), TypeError);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-eagerly-on-non-callable.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-eagerly-on-non-callable.js
new file mode 100644
index 0000000000..7c31a21a38
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-eagerly-on-non-callable.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %Iterator.prototype% methods throw eagerly when passed non-callables.
+info: >
+ Iterator Helpers proposal 2.1.5
+features: [iterator-helpers]
+---*/
+
+const methods = [
+ (iter, fn) => iter.map(fn),
+ (iter, fn) => iter.filter(fn),
+ (iter, fn) => iter.flatMap(fn),
+];
+
+for (const method of methods) {
+ assertThrowsInstanceOf(() => method(Iterator.prototype, 0), TypeError);
+ assertThrowsInstanceOf(() => method(Iterator.prototype, false), TypeError);
+ assertThrowsInstanceOf(() => method(Iterator.prototype, undefined), TypeError);
+ assertThrowsInstanceOf(() => method(Iterator.prototype, null), TypeError);
+ assertThrowsInstanceOf(() => method(Iterator.prototype, ''), TypeError);
+ assertThrowsInstanceOf(() => method(Iterator.prototype, Symbol('')), TypeError);
+ assertThrowsInstanceOf(() => method(Iterator.prototype, {}), TypeError);
+
+ assertThrowsInstanceOf(() => method([].values(), 0), TypeError);
+ assertThrowsInstanceOf(() => method([].values(), false), TypeError);
+ assertThrowsInstanceOf(() => method([].values(), undefined), TypeError);
+ assertThrowsInstanceOf(() => method([].values(), null), TypeError);
+ assertThrowsInstanceOf(() => method([].values(), ''), TypeError);
+ assertThrowsInstanceOf(() => method([].values(), Symbol('')), TypeError);
+ assertThrowsInstanceOf(() => method([].values(), {}), TypeError);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-eagerly-on-non-iterator.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-eagerly-on-non-iterator.js
new file mode 100644
index 0000000000..dad38237f1
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-eagerly-on-non-iterator.js
@@ -0,0 +1,34 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %Iterator.prototype% methods throw eagerly when called on non-iterators.
+info: >
+ Iterator Helpers proposal 1.1.1
+features: [iterator-helpers]
+---*/
+
+const methods = [
+ iter => Iterator.prototype.map.bind(iter, x => x),
+ iter => Iterator.prototype.filter.bind(iter, x => x),
+ iter => Iterator.prototype.take.bind(iter, 1),
+ iter => Iterator.prototype.drop.bind(iter, 0),
+ iter => Iterator.prototype.asIndexedPairs.bind(iter),
+ iter => Iterator.prototype.flatMap.bind(iter, x => [x]),
+];
+
+for (const method of methods) {
+ assertThrowsInstanceOf(method(undefined), TypeError);
+ assertThrowsInstanceOf(method(null), TypeError);
+ assertThrowsInstanceOf(method(0), TypeError);
+ assertThrowsInstanceOf(method(false), TypeError);
+ assertThrowsInstanceOf(method(''), TypeError);
+ assertThrowsInstanceOf(method(Symbol('')), TypeError);
+ assertThrowsInstanceOf(method({}), TypeError);
+ assertThrowsInstanceOf(method([]), TypeError);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-next-done-throws.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-next-done-throws.js
new file mode 100644
index 0000000000..72669beabc
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-next-done-throws.js
@@ -0,0 +1,47 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %Iterator.prototype% methods throw if `next.done` throws.
+info: >
+ Iterator Helpers proposal 2.1.5
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+class TestIterator extends Iterator {
+ next() {
+ return {
+ get done() {
+ throw new TestError();
+ }
+ };
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => x),
+ iter => iter.take(1),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(x => [x]),
+];
+
+for (const method of methods) {
+ const iterator = new TestIterator();
+ assertEq(iterator.closed, false);
+ assertThrowsInstanceOf(() => method(iterator).next(), TestError);
+ assertEq(iterator.closed, false);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-next-not-object.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-next-not-object.js
new file mode 100644
index 0000000000..1d70ed1d62
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-next-not-object.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %Iterator.prototype% methods throw if `next` call returns a non-object.
+info: >
+ Iterator Helpers proposal 2.1.5
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends Iterator {
+ next(value) {
+ return value;
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => x),
+ iter => iter.take(1),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(x => [x]),
+];
+
+for (const method of methods) {
+ for (const value of [undefined, null, 0, false, '', Symbol('')]) {
+ const iterator = new TestIterator();
+ assertEq(iterator.closed, false);
+ assertThrowsInstanceOf(() => method(iterator).next(value), TypeError);
+ assertEq(iterator.closed, false);
+ }
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-on-reentry.js b/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-on-reentry.js
new file mode 100644
index 0000000000..1095842f55
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/lazy-methods-throw-on-reentry.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+const methods = [
+ iter => iter.map,
+ iter => iter.filter,
+ iter => iter.flatMap,
+];
+
+for (const method of methods) {
+ const iter = [1].values();
+ const iterMethod = method(iter);
+ let iterHelper;
+ iterHelper = iterMethod.call(iter, x => iterHelper.next());
+ assertThrowsInstanceOf(() => iterHelper.next(), TypeError);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/call-next-on-iterator-while-iterating.js b/js/src/tests/non262/Iterator/prototype/map/call-next-on-iterator-while-iterating.js
new file mode 100644
index 0000000000..a5a10120a0
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/call-next-on-iterator-while-iterating.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+/*---
+esid: pending
+description: Call next on an iterator that is being iterated over.
+info:
+features: [iterator-helpers]
+---*/
+
+const iterator = [1, 2, 3].values()
+const items = [];
+
+for (const item of iterator.map(x => x ** 2)) {
+ const nextItem = iterator.next();
+ items.push(item, nextItem.value);
+}
+
+assertEq(items[0], 1);
+assertEq(items[1], 2);
+assertEq(items[2], 9);
+assertEq(items[3], undefined);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/clobber-symbol.js b/js/src/tests/non262/Iterator/prototype/map/clobber-symbol.js
new file mode 100644
index 0000000000..8d5b2721e1
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/clobber-symbol.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+//
+//
+
+/*---
+esid: pending
+description: %Iterator.prototype%.map works even if the global Symbol has been clobbered..
+info:
+features: [iterator-helpers, Symbol, Symbol.iterator]
+---*/
+
+Symbol = undefined;
+assertThrowsInstanceOf(() => Symbol.iterator, TypeError);
+
+const iterator = [0].values();
+assertEq(
+ iterator.map(x => x + 1).next().value, 1,
+ '`%Iterator.prototype%.map` still works after Symbol has been clobbered'
+);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/interleaved-map-calls.js b/js/src/tests/non262/Iterator/prototype/map/interleaved-map-calls.js
new file mode 100644
index 0000000000..3253e06192
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/interleaved-map-calls.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: Interleaved %Iterator.prototype%.map calls on the same iterator.
+info:
+features: [iterator-helpers]
+---*/
+
+const iterator = [1, 2, 3].values();
+const mapped1 = iterator.map(x => x);
+const mapped2 = iterator.map(x => 0);
+
+assertEq(mapped1.next().value, 1);
+assertEq(mapped2.next().value, 0);
+assertEq(mapped1.next().value, 3);
+
+assertEq(mapped1.next().done, true);
+assertEq(mapped2.next().done, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/length.js b/js/src/tests/non262/Iterator/prototype/map/length.js
new file mode 100644
index 0000000000..d6bc1ca774
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/length.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: %Iterator.prototype%.map length value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+includes: [propertyHelper.js]
+features: [Symbol.iterator]
+---*/
+
+assertEq(Iterator.prototype.map.length, 1);
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(Iterator.prototype.map, 'length');
+assertEq(propertyDescriptor.value, 1);
+assertEq(propertyDescriptor.enumerable, false);
+assertEq(propertyDescriptor.writable, false);
+assertEq(propertyDescriptor.configurable, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/map.js b/js/src/tests/non262/Iterator/prototype/map/map.js
new file mode 100644
index 0000000000..2cf5267be7
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/map.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+/*---
+esid: pending
+description: %Iterator.prototype%.map value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+const map = Reflect.getOwnPropertyDescriptor(Iterator.prototype, 'map');
+
+assertEq(
+ Iterator.prototype.map, map.value,
+ 'The value of `%Iterator.prototype%.map` is the same as the value in the property descriptor.'
+);
+
+assertEq(
+ typeof map.value, 'function',
+ '%Iterator.prototype%.map is a function.'
+);
+
+assertEq(map.enumerable, false);
+assertEq(map.writable, true);
+assertEq(map.configurable, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/mapper-not-callable-throw.js b/js/src/tests/non262/Iterator/prototype/map/mapper-not-callable-throw.js
new file mode 100644
index 0000000000..334e0fd8f9
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/mapper-not-callable-throw.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: Eagerly throw TypeError when `mapper` is not callable.
+info:
+features: [iterator-helpers]
+---*/
+
+assertThrowsInstanceOf(() => Iterator.prototype.map(undefined), TypeError);
+assertThrowsInstanceOf(() => [].values().map(undefined), TypeError);
+
+assertThrowsInstanceOf(() => Iterator.prototype.map(null), TypeError);
+assertThrowsInstanceOf(() => [].values().map(null), TypeError);
+
+assertThrowsInstanceOf(() => Iterator.prototype.map(0), TypeError);
+assertThrowsInstanceOf(() => [].values().map(0), TypeError);
+
+assertThrowsInstanceOf(() => Iterator.prototype.map(false), TypeError);
+assertThrowsInstanceOf(() => [].values().map(false), TypeError);
+
+assertThrowsInstanceOf(() => Iterator.prototype.map({}), TypeError);
+assertThrowsInstanceOf(() => [].values().map({}), TypeError);
+
+assertThrowsInstanceOf(() => Iterator.prototype.map(''), TypeError);
+assertThrowsInstanceOf(() => [].values().map(''), TypeError);
+
+assertThrowsInstanceOf(() => Iterator.prototype.map(Symbol('')), TypeError);
+assertThrowsInstanceOf(() => [].values().map(Symbol('')), TypeError);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/mutate-iterator-after-done.js b/js/src/tests/non262/Iterator/prototype/map/mutate-iterator-after-done.js
new file mode 100644
index 0000000000..b38158d73a
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/mutate-iterator-after-done.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: Mutate an iterator after it has been mapped and returned done.
+info:
+features: [iterator-helpers]
+---*/
+
+const array = [1, 2, 3];
+const iterator = [1, 2, 3].values().map(x => x * 2);
+
+assertEq(iterator.next().value, 2);
+assertEq(iterator.next().value, 4);
+assertEq(iterator.next().value, 6);
+assertEq(iterator.next().done, true);
+
+array.push(4);
+assertEq(iterator.next().done, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/mutate-iterator.js b/js/src/tests/non262/Iterator/prototype/map/mutate-iterator.js
new file mode 100644
index 0000000000..b1cc52fae5
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/mutate-iterator.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: Mutate an iterator after it has been mapped.
+info:
+features: [iterator-helpers]
+---*/
+
+const array = [1, 2, 3];
+const iterator = array.values().map(x => x * 2);
+array.push(4);
+
+assertEq(iterator.next().value, 2);
+assertEq(iterator.next().value, 4);
+assertEq(iterator.next().value, 6);
+assertEq(iterator.next().value, 8);
+assertEq(iterator.next().done, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/name.js b/js/src/tests/non262/Iterator/prototype/map/name.js
new file mode 100644
index 0000000000..3ba024d6e7
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/name.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+/*---
+esid: pending
+description: %Iterator.prototype%.map.name value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(Iterator.prototype.map.name, 'map');
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(Iterator.prototype.map, 'name');
+assertEq(propertyDescriptor.value, 'map');
+assertEq(propertyDescriptor.enumerable, false);
+assertEq(propertyDescriptor.writable, false);
+assertEq(propertyDescriptor.configurable, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/output-at-generator-end.js b/js/src/tests/non262/Iterator/prototype/map/output-at-generator-end.js
new file mode 100644
index 0000000000..69ef04a7b2
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/output-at-generator-end.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: %Iterator.prototype%.map outputs correct value at end of iterator.
+info:
+features: [iterator-helpers]
+---*/
+
+const iterator = [0].values().map(x => x);
+
+const iterRecord = iterator.next();
+assertEq(iterRecord.done, false);
+assertEq(iterRecord.value, 0);
+
+let endRecord = iterator.next();
+assertEq(endRecord.done, true);
+assertEq(endRecord.value, undefined);
+
+endRecord = iterator.next();
+assertEq(endRecord.done, true);
+assertEq(endRecord.value, undefined);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/pass-lastValue-to-next.js b/js/src/tests/non262/Iterator/prototype/map/pass-lastValue-to-next.js
new file mode 100644
index 0000000000..deb31e2aa2
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/pass-lastValue-to-next.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: %Iterator.prototype%.map passes lastValue to the `next` call.
+info: >
+ Iterator Helpers Proposal 2.1.5.2
+features: [iterator-helpers]
+---*/
+
+let nextWasPassed;
+
+const iteratorWhereNextTakesValue = Object.setPrototypeOf({
+ next: function(value) {
+ nextWasPassed = value;
+
+ if (this.value < 3)
+ return { done: false, value: this.value++ };
+ return { done: true, value: undefined };
+ },
+ value: 0,
+}, Iterator.prototype);
+
+const mappedIterator = iteratorWhereNextTakesValue.map(x => x);
+
+assertEq(mappedIterator.next(1).value, 0);
+assertEq(nextWasPassed, undefined);
+
+assertEq(mappedIterator.next(2).value, 1);
+assertEq(nextWasPassed, 2);
+
+assertEq(mappedIterator.next(3).value, 2);
+assertEq(nextWasPassed, 3);
+
+assertEq(mappedIterator.next(4).done, true);
+assertEq(nextWasPassed, 4);
+
+// assertEq(mappedIterator.next(5).done, true);
+// assertEq(nextWasPassed, 4);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/proxy-abrupt-completion-in-iteratorValue.js b/js/src/tests/non262/Iterator/prototype/map/proxy-abrupt-completion-in-iteratorValue.js
new file mode 100644
index 0000000000..f50bd0da10
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/proxy-abrupt-completion-in-iteratorValue.js
@@ -0,0 +1,55 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: %Iterator.prototype%.map does not call return when IteratorValue returns an abrupt completion.
+info: >
+features: [iterator-helpers]
+---*/
+
+const handlerProxy = log => new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ const target = args[0];
+ const item = Reflect[key](...args);
+
+ log.push(`${key}: ${args.filter(x => typeof x != 'object').map(x => x.toString())}`);
+
+ switch (typeof item) {
+ case 'function': return item.bind(new Proxy(target, handlerProxy(log)));
+ case 'object': return new Proxy(item, handlerProxy(log));
+ default: return item;
+ }
+ },
+});
+
+const log = [];
+const iterator = Object.setPrototypeOf({
+ next: function() {
+ throw 'error';
+ return { done: false, value: 0 };
+ },
+ return: function(value) {
+ log.push('close iterator');
+ return { done: true, value };
+ },
+}, Iterator.prototype);
+const iteratorProxy = new Proxy(iterator, handlerProxy(log));
+const mappedProxy = iteratorProxy.map(x => x);
+
+try {
+ mappedProxy.next();
+} catch (exc) {
+ assertEq(exc, 'error');
+}
+
+console.log(log.join('\n'));
+
+assertEq(
+ log.join('\n'),
+`get: map
+get: next`
+);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/proxy-abrupt-completion-in-yield.js b/js/src/tests/non262/Iterator/prototype/map/proxy-abrupt-completion-in-yield.js
new file mode 100644
index 0000000000..4d4854da36
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/proxy-abrupt-completion-in-yield.js
@@ -0,0 +1,62 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: %Iterator.prototype%.map calls return when yield throws.
+info: >
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+
+class TestIterator extends Iterator {
+ constructor(log) {
+ super();
+ this.log = log;
+ }
+
+ next() {
+ return {done: false, value: 0};
+ }
+
+ return(value) {
+ log.push('close iterator');
+ return {done: true, value};
+ }
+}
+
+const handlerProxy = log => new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ const target = args[0];
+ const item = Reflect[key](...args);
+
+ log.push(`${key}: ${args.filter(x => typeof x != 'object').map(x => x.toString())}`);
+
+ switch (typeof item) {
+ case 'function': return item.bind(new Proxy(target, handlerProxy(log)));
+ case 'object': return new Proxy(item, handlerProxy(log));
+ default: return item;
+ }
+ },
+});
+
+const log = [];
+const iterator = new TestIterator(log);
+const iteratorProxy = new Proxy(iterator, handlerProxy(log));
+const mappedProxy = iteratorProxy.map(x => x);
+
+mappedProxy.next();
+assertThrowsInstanceOf(() => mappedProxy.throw(new TestError()), TestError);
+mappedProxy.next();
+
+assertEq(
+ log.join('\n'),
+`get: map
+get: next
+get: return
+close iterator`
+);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/proxy-abrupt-completion.js b/js/src/tests/non262/Iterator/prototype/map/proxy-abrupt-completion.js
new file mode 100644
index 0000000000..ea0e10bdb4
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/proxy-abrupt-completion.js
@@ -0,0 +1,54 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: %Iterator.prototype%.map accesses specified properties only.
+info: >
+features: [iterator-helpers]
+---*/
+
+const handlerProxy = log => new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ const target = args[0];
+ const item = Reflect[key](...args);
+
+ log.push(`${key}: ${args.filter(x => typeof x != 'object').map(x => x.toString())}`);
+
+ switch (typeof item) {
+ case 'function': return item.bind(new Proxy(target, handlerProxy(log)));
+ case 'object': return new Proxy(item, handlerProxy(log));
+ default: return item;
+ }
+ },
+});
+
+const log = [];
+const iterator = Object.setPrototypeOf({
+ next: function() {
+ return { done: false, value: 0 };
+ },
+ return: function(value) {
+ log.push('close iterator');
+ return { done: true, value };
+ },
+}, Iterator.prototype);
+const iteratorProxy = new Proxy(iterator, handlerProxy(log));
+const mappedProxy = iteratorProxy.map(x => { throw 'error'; });
+
+try {
+ mappedProxy.next();
+} catch (exc) {
+ assertEq(exc, 'error');
+}
+
+assertEq(
+ log.join('\n'),
+`get: map
+get: next
+get: return
+close iterator`
+);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/proxy-accesses.js b/js/src/tests/non262/Iterator/prototype/map/proxy-accesses.js
new file mode 100644
index 0000000000..ba6dfd7ece
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/proxy-accesses.js
@@ -0,0 +1,94 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: %Iterator.prototype%.map accesses specified properties only.
+info: >
+features: [iterator-helpers]
+---*/
+
+const handlerProxy = log => new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ const target = args[0];
+ const item = Reflect[key](...args);
+
+ log.push(`${key}: ${args.filter(x => typeof x != 'object').map(x => x.toString())}`);
+
+ switch (typeof item) {
+ case 'function': return item.bind(new Proxy(target, handlerProxy(log)));
+ case 'object': return new Proxy(item, handlerProxy(log));
+ default: return item;
+ }
+ },
+});
+
+const log = [];
+const iterator = Object.setPrototypeOf({
+ next: function() {
+ if (this.value < 3)
+ return { done: false, value: this.value++ };
+ return { done: true, value: undefined };
+ },
+ value: 0,
+}, Iterator.prototype);
+const iteratorProxy = new Proxy(iterator, handlerProxy(log));
+const mappedProxy = iteratorProxy.map(x => x);
+
+for (const item of mappedProxy) {
+}
+
+assertEq(
+ log.join('\n'),
+`get: map
+get: next
+get: value
+get: value
+getOwnPropertyDescriptor: value
+has: enumerable
+get: enumerable
+has: configurable
+get: configurable
+has: value
+get: value
+has: writable
+get: writable
+has: get
+has: set
+defineProperty: value
+set: value,1
+get: value
+get: value
+getOwnPropertyDescriptor: value
+has: enumerable
+get: enumerable
+has: configurable
+get: configurable
+has: value
+get: value
+has: writable
+get: writable
+has: get
+has: set
+defineProperty: value
+set: value,2
+get: value
+get: value
+getOwnPropertyDescriptor: value
+has: enumerable
+get: enumerable
+has: configurable
+get: configurable
+has: value
+get: value
+has: writable
+get: writable
+has: get
+has: set
+defineProperty: value
+set: value,3
+get: value`
+);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/reenter-map-generator-from-mapper.js b/js/src/tests/non262/Iterator/prototype/map/reenter-map-generator-from-mapper.js
new file mode 100644
index 0000000000..b7a0d56d5c
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/reenter-map-generator-from-mapper.js
@@ -0,0 +1,15 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+// Re-entering the map() generator from the called mapper fails.
+
+let iterator;
+function mapper(x) {
+ let n = iterator.next();
+ return x;
+}
+iterator = [0].values().map(mapper);
+
+assertThrowsInstanceOf(iterator.next, TypeError);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/this-not-iterator-throw.js b/js/src/tests/non262/Iterator/prototype/map/this-not-iterator-throw.js
new file mode 100644
index 0000000000..aaed1f2617
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/this-not-iterator-throw.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: Eagerly throw TypeError when `this` is not an iterator.
+info:
+features: [iterator-helpers]
+---*/
+
+const mapper = (x) => x;
+
+assertThrowsInstanceOf(() => Iterator.prototype.map.call(undefined, mapper), TypeError);
+assertThrowsInstanceOf(() => Iterator.prototype.map.call(null, mapper), TypeError);
+assertThrowsInstanceOf(() => Iterator.prototype.map.call(0, mapper), TypeError);
+assertThrowsInstanceOf(() => Iterator.prototype.map.call(false, mapper), TypeError);
+assertThrowsInstanceOf(() => Iterator.prototype.map.call({}, mapper), TypeError);
+assertThrowsInstanceOf(() => Iterator.prototype.map.call('', mapper), TypeError);
+assertThrowsInstanceOf(() => Iterator.prototype.map.call(new Symbol(''), mapper), TypeError);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/this-value-array-throws.js b/js/src/tests/non262/Iterator/prototype/map/this-value-array-throws.js
new file mode 100644
index 0000000000..d8573bb3ce
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/this-value-array-throws.js
@@ -0,0 +1,14 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: TypeError is thrown if `this` is an Array.
+info:
+features: [Symbol.iterator]
+---*/
+
+assertThrowsInstanceOf(() => Iterator.prototype.map.call([], x => x), TypeError);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/throw-when-iterator-returns-non-object.js b/js/src/tests/non262/Iterator/prototype/map/throw-when-iterator-returns-non-object.js
new file mode 100644
index 0000000000..287507a2f6
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/throw-when-iterator-returns-non-object.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: Throw TypeError if `next` call returns non-object.
+info:
+features: [iterator-helpers]
+---*/
+
+const iterator = returnValue => Object.setPrototypeOf({
+ next: () => returnValue,
+}, Iterator.prototype);
+const mapper = x => x;
+
+assertThrowsInstanceOf(() => iterator(undefined).map(mapper).next(), TypeError);
+assertThrowsInstanceOf(() => iterator(null).map(mapper).next(), TypeError);
+assertThrowsInstanceOf(() => iterator(0).map(mapper).next(), TypeError);
+assertThrowsInstanceOf(() => iterator(false).map(mapper).next(), TypeError);
+assertThrowsInstanceOf(() => iterator('').map(mapper).next(), TypeError);
+assertThrowsInstanceOf(() => iterator(Symbol()).map(mapper).next(), TypeError);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/map/values-pass-through-chained-maps-to-next.js b/js/src/tests/non262/Iterator/prototype/map/values-pass-through-chained-maps-to-next.js
new file mode 100644
index 0000000000..d49daebb87
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/map/values-pass-through-chained-maps-to-next.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: Multiple chained %Iterator.prototype%.map calls pass `lastValue` to the iterator's `next` call.
+info: >
+ Iterator Helpers Proposal 2.1.5.2
+features: [iterator-helpers]
+---*/
+
+let nextWasPassed;
+
+const iteratorWhereNextTakesValue = Object.setPrototypeOf({
+ next: function(value) {
+ nextWasPassed = value;
+
+ if (this.value < 3)
+ return { done: false, value: this.value++ };
+ return { done: true, value: undefined };
+ },
+ value: 0,
+}, Iterator.prototype);
+
+const mappedIterator = iteratorWhereNextTakesValue.map(x => 2 * x).map(x => 1 + x);
+
+assertEq(mappedIterator.next(1).value, 1);
+assertEq(nextWasPassed, undefined);
+
+assertEq(mappedIterator.next(2).value, 3);
+assertEq(nextWasPassed, 2);
+
+assertEq(mappedIterator.next(3).value, 5);
+assertEq(nextWasPassed, 3);
+
+assertEq(mappedIterator.next(4).done, true);
+assertEq(nextWasPassed, 4);
+
+assertEq(mappedIterator.next(5).done, true);
+assertEq(nextWasPassed, 4);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/accumulator-set-to-initial-value.js b/js/src/tests/non262/Iterator/prototype/reduce/accumulator-set-to-initial-value.js
new file mode 100644
index 0000000000..4395e1c7d4
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/accumulator-set-to-initial-value.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const reducer = (acc, value) => acc;
+const iterator = [1, 2, 3].values();
+
+assertEq(iterator.reduce(reducer, 0), 0);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/check-fn-after-getting-iterator.js b/js/src/tests/non262/Iterator/prototype/reduce/check-fn-after-getting-iterator.js
new file mode 100644
index 0000000000..4e4852326a
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/check-fn-after-getting-iterator.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: true};
+ }
+}
+
+const iter = new Proxy(new TestIterator(), handlerProxy);
+assertThrowsInstanceOf(() => iter.reduce(1), TypeError);
+
+assertEq(
+ log.join('\n'),
+ `get: reduce
+get: next`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/descriptor.js b/js/src/tests/non262/Iterator/prototype/reduce/descriptor.js
new file mode 100644
index 0000000000..0fb0ff01b3
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/descriptor.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Descriptor property of Iterator.prototype.reduce
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype, 'reduce');
+assertEq(typeof propDesc.value, 'function');
+assertEq(propDesc.writable, true);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/empty-iterator-without-initial-value-throws.js b/js/src/tests/non262/Iterator/prototype/reduce/empty-iterator-without-initial-value-throws.js
new file mode 100644
index 0000000000..d8e0a595cf
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/empty-iterator-without-initial-value-throws.js
@@ -0,0 +1,7 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const iter = [].values();
+assertThrowsInstanceOf(() => iter.reduce((x, y) => x + y), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/error-from-correct-realm.js b/js/src/tests/non262/Iterator/prototype/reduce/error-from-correct-realm.js
new file mode 100644
index 0000000000..96634ba62b
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/error-from-correct-realm.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const otherGlobal = newGlobal({newCompartment: true});
+assertEq(TypeError !== otherGlobal.TypeError, true);
+
+const iter = [].values();
+
+assertThrowsInstanceOf(() => iter.reduce(), TypeError);
+assertThrowsInstanceOf(
+ otherGlobal.Iterator.prototype.reduce.bind(iter),
+ otherGlobal.TypeError,
+ 'TypeError comes from the realm of the method.',
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/iterator-empty-return-initial-value.js b/js/src/tests/non262/Iterator/prototype/reduce/iterator-empty-return-initial-value.js
new file mode 100644
index 0000000000..30c15a48fe
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/iterator-empty-return-initial-value.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const reducer = (x, y) => 0;
+const iterator = [].values();
+
+assertEq(iterator.reduce(reducer, 1), 1);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/iterator-next-return-non-object-throws.js b/js/src/tests/non262/Iterator/prototype/reduce/iterator-next-return-non-object-throws.js
new file mode 100644
index 0000000000..d77789f04a
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/iterator-next-return-non-object-throws.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestIterator extends Iterator {
+ constructor(value) {
+ super();
+ this.value = value;
+ }
+
+ next() {
+ return this.value;
+ }
+}
+
+const sum = (x, y) => x + y;
+
+let iter = new TestIterator(undefined);
+assertThrowsInstanceOf(() => iter.reduce(sum), TypeError);
+iter = new TestIterator(null);
+assertThrowsInstanceOf(() => iter.reduce(sum), TypeError);
+iter = new TestIterator(0);
+assertThrowsInstanceOf(() => iter.reduce(sum), TypeError);
+iter = new TestIterator(false);
+assertThrowsInstanceOf(() => iter.reduce(sum), TypeError);
+iter = new TestIterator('');
+assertThrowsInstanceOf(() => iter.reduce(sum), TypeError);
+iter = new TestIterator(Symbol(''));
+assertThrowsInstanceOf(() => iter.reduce(sum), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/left-associative.js b/js/src/tests/non262/Iterator/prototype/reduce/left-associative.js
new file mode 100644
index 0000000000..a6208504b6
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/left-associative.js
@@ -0,0 +1,7 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+assertEq([1, 2, 3].values().reduce((x, y) => `(${x}+${y})`, 0), '(((0+1)+2)+3)');
+assertEq([1, 2, 3].values().reduce((x, y) => `(${x}+${y})`), '((1+2)+3)');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/length.js b/js/src/tests/non262/Iterator/prototype/reduce/length.js
new file mode 100644
index 0000000000..0780e684a8
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/length.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ The `length` property of Iterator.prototype.reduce.
+info: |
+ ES7 section 17: Unless otherwise specified, the length property of a built-in
+ Function object has the attributes { [[Writable]]: false, [[Enumerable]]:
+ false, [[Configurable]]: true }.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype.reduce, 'length');
+assertEq(propDesc.value, 1);
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/name.js b/js/src/tests/non262/Iterator/prototype/reduce/name.js
new file mode 100644
index 0000000000..1269bb4b52
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ `name` property of Iterator.prototype.reduce.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype.reduce, 'name');
+assertEq(propDesc.value, 'reduce');
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/next-throws-iterator-not-closed.js b/js/src/tests/non262/Iterator/prototype/reduce/next-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..0fbeb995f1
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/next-throws-iterator-not-closed.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestIterator extends Iterator {
+ next() {
+ throw new Error();
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const sum = (x, y) => x + y;
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+assertThrowsInstanceOf(() => iter.reduce(sum), Error);
+assertEq(iter.closed, false);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/no-initial-value-set-accumulator-to-first-value.js b/js/src/tests/non262/Iterator/prototype/reduce/no-initial-value-set-accumulator-to-first-value.js
new file mode 100644
index 0000000000..a2b0008e6a
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/no-initial-value-set-accumulator-to-first-value.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const reducer = (acc, value) => acc;
+const iterator = [1, 2, 3].values();
+
+assertEq(iterator.reduce(reducer), 1);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/proxy.js b/js/src/tests/non262/Iterator/prototype/reduce/proxy.js
new file mode 100644
index 0000000000..34569cf044
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/proxy.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+//
+// This test checks that %Iterator.prototype%.reduce only gets the `next` method off of the
+// iterator once, and never accesses the @@iterator property.
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class Counter extends Iterator {
+ value = 0;
+ next() {
+ const value = this.value;
+ if (value < 2) {
+ this.value = value + 1;
+ return {done: false, value};
+ }
+ return {done: true};
+ }
+}
+
+const iter = new Proxy(new Counter(), handlerProxy);
+iter.reduce((x, y) => x + y);
+
+assertEq(
+ log.join('\n'),
+ `get: reduce
+get: next
+get: value
+set: value
+getOwnPropertyDescriptor: value
+defineProperty: value
+get: value
+set: value
+getOwnPropertyDescriptor: value
+defineProperty: value
+get: value`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/reduce.js b/js/src/tests/non262/Iterator/prototype/reduce/reduce.js
new file mode 100644
index 0000000000..d824da211d
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/reduce.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const reducer = (acc, value) => acc + value;
+const iterator = [1, 2, 3].values();
+
+assertEq(iterator.reduce(reducer, 0), 6);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/reducer-not-callable-throws.js b/js/src/tests/non262/Iterator/prototype/reduce/reducer-not-callable-throws.js
new file mode 100644
index 0000000000..c33e5e4f9c
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/reducer-not-callable-throws.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestIterator extends Iterator {
+ next() {
+ return { done: false, value: 0 };
+ }
+}
+
+const iter = new TestIterator();
+assertThrowsInstanceOf(() => iter.reduce(), TypeError);
+assertThrowsInstanceOf(() => iter.reduce(undefined), TypeError);
+assertThrowsInstanceOf(() => iter.reduce(null), TypeError);
+assertThrowsInstanceOf(() => iter.reduce(0), TypeError);
+assertThrowsInstanceOf(() => iter.reduce(false), TypeError);
+assertThrowsInstanceOf(() => iter.reduce(''), TypeError);
+assertThrowsInstanceOf(() => iter.reduce(Symbol('')), TypeError);
+assertThrowsInstanceOf(() => iter.reduce({}), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/reducer-throws-iterator-closed.js b/js/src/tests/non262/Iterator/prototype/reduce/reducer-throws-iterator-closed.js
new file mode 100644
index 0000000000..592fa80d17
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/reducer-throws-iterator-closed.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestIterator extends Iterator {
+ next() {
+ return { done: this.closed, value: undefined };
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const reducer = (x, y) => { throw new Error(); };
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+assertThrowsInstanceOf(() => iter.reduce(reducer), Error);
+assertEq(iter.closed, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/this-not-iterator-throws.js b/js/src/tests/non262/Iterator/prototype/reduce/this-not-iterator-throws.js
new file mode 100644
index 0000000000..d4804c51e2
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/this-not-iterator-throws.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const sum = (x, y) => x + y;
+assertThrowsInstanceOf(Iterator.prototype.reduce.bind(undefined, sum), TypeError);
+assertThrowsInstanceOf(Iterator.prototype.reduce.bind({}, sum), TypeError);
+assertThrowsInstanceOf(Iterator.prototype.reduce.bind({next: 0}, sum), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/reduce/value-throws-iterator-not-closed.js b/js/src/tests/non262/Iterator/prototype/reduce/value-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..7b43eedcc6
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/reduce/value-throws-iterator-not-closed.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestError extends Error {}
+class TestIterator extends Iterator {
+ next() {
+ return new Proxy({done: false}, {get: (target, key, receiver) => {
+ if (key === 'value')
+ throw new TestError();
+ return 0;
+ }});
+ }
+
+ closed = false;
+ return() {
+ closed = true;
+ }
+}
+
+const iterator = new TestIterator();
+assertEq(iterator.closed, false, 'iterator starts unclosed');
+assertThrowsInstanceOf(() => iterator.reduce((x, y) => x + y, 0), TestError);
+assertEq(iterator.closed, false, 'iterator remains unclosed');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/some/check-fn-after-getting-iterator.js b/js/src/tests/non262/Iterator/prototype/some/check-fn-after-getting-iterator.js
new file mode 100644
index 0000000000..f81f660916
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/some/check-fn-after-getting-iterator.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: true};
+ }
+}
+
+const iter = new Proxy(new TestIterator(), handlerProxy);
+assertThrowsInstanceOf(() => iter.some(1), TypeError);
+
+assertEq(
+ log.join('\n'),
+ `get: some
+get: next`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/some/coerce-result-to-boolean.js b/js/src/tests/non262/Iterator/prototype/some/coerce-result-to-boolean.js
new file mode 100644
index 0000000000..5bebdb06ea
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/some/coerce-result-to-boolean.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const fn = (value) => value;
+assertEq([true].values().some(fn), true);
+assertEq([1].values().some(fn), true);
+assertEq([[]].values().some(fn), true);
+assertEq([{}].values().some(fn), true);
+assertEq(['test'].values().some(fn), true);
+
+assertEq([false].values().some(fn), false);
+assertEq([0].values().some(fn), false);
+assertEq([''].values().some(fn), false);
+assertEq([null].values().some(fn), false);
+assertEq([undefined].values().some(fn), false);
+assertEq([NaN].values().some(fn), false);
+assertEq([-0].values().some(fn), false);
+assertEq([0n].values().some(fn), false);
+
+const htmlDDA = createIsHTMLDDA();
+assertEq([htmlDDA].values().some(fn), false);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/some/descriptor.js b/js/src/tests/non262/Iterator/prototype/some/descriptor.js
new file mode 100644
index 0000000000..dfafc4aa5f
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/some/descriptor.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Descriptor property of Iterator.prototype.some
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype, 'some');
+assertEq(typeof propDesc.value, 'function');
+assertEq(propDesc.writable, true);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/some/error-from-correct-realm.js b/js/src/tests/non262/Iterator/prototype/some/error-from-correct-realm.js
new file mode 100644
index 0000000000..ba68c6e7c1
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/some/error-from-correct-realm.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const otherGlobal = newGlobal({newCompartment: true});
+assertEq(TypeError !== otherGlobal.TypeError, true);
+
+const iter = [].values();
+
+assertThrowsInstanceOf(() => iter.some(), TypeError);
+assertThrowsInstanceOf(
+ otherGlobal.Iterator.prototype.some.bind(iter),
+ otherGlobal.TypeError,
+ 'TypeError comes from the realm of the method.',
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/some/fn-not-callable-throws.js b/js/src/tests/non262/Iterator/prototype/some/fn-not-callable-throws.js
new file mode 100644
index 0000000000..52be15391f
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/some/fn-not-callable-throws.js
@@ -0,0 +1,15 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const iter = [].values();
+
+assertThrowsInstanceOf(() => iter.some(), TypeError);
+assertThrowsInstanceOf(() => iter.some(undefined), TypeError);
+assertThrowsInstanceOf(() => iter.some(null), TypeError);
+assertThrowsInstanceOf(() => iter.some(0), TypeError);
+assertThrowsInstanceOf(() => iter.some(false), TypeError);
+assertThrowsInstanceOf(() => iter.some(''), TypeError);
+assertThrowsInstanceOf(() => iter.some(Symbol('')), TypeError);
+assertThrowsInstanceOf(() => iter.some({}), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/some/fn-throws-close-iterator.js b/js/src/tests/non262/Iterator/prototype/some/fn-throws-close-iterator.js
new file mode 100644
index 0000000000..bbe751e175
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/some/fn-throws-close-iterator.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestIterator extends Iterator {
+ next() {
+ return { done: this.closed };
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = () => { throw new Error(); };
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+assertThrowsInstanceOf(() => iter.some(fn), Error);
+assertEq(iter.closed, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/some/length.js b/js/src/tests/non262/Iterator/prototype/some/length.js
new file mode 100644
index 0000000000..c9d1f986f6
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/some/length.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ The `length` property of Iterator.prototype.some.
+info: |
+ ES7 section 17: Unless otherwise specified, the length property of a built-in
+ Function object has the attributes { [[Writable]]: false, [[Enumerable]]:
+ false, [[Configurable]]: true }.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype.some, 'length');
+assertEq(propDesc.value, 1);
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/some/name.js b/js/src/tests/non262/Iterator/prototype/some/name.js
new file mode 100644
index 0000000000..679e75460c
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/some/name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ `name` property of Iterator.prototype.some.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype.some, 'name');
+assertEq(propDesc.value, 'some');
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/some/next-throws-iterator-not-closed.js b/js/src/tests/non262/Iterator/prototype/some/next-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..4bdf372908
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/some/next-throws-iterator-not-closed.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestIterator extends Iterator {
+ next() {
+ throw new Error();
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = () => {};
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+assertThrowsInstanceOf(() => iter.some(fn), Error);
+assertEq(iter.closed, false);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/some/proxy.js b/js/src/tests/non262/Iterator/prototype/some/proxy.js
new file mode 100644
index 0000000000..a444a2d5cb
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/some/proxy.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+//
+// This test checks that %Iterator.prototype%.some only gets the `next` method off of the
+// iterator once, and never accesses the @@iterator property.
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class Counter extends Iterator {
+ value = 0;
+ next() {
+ const value = this.value;
+ if (value < 2) {
+ this.value = value + 1;
+ return {done: false, value};
+ }
+ return {done: true};
+ }
+}
+
+const iter = new Proxy(new Counter(), handlerProxy);
+assertEq(iter.some(x => x % 2 == 1), true);
+
+assertEq(
+ log.join('\n'),
+ `get: some
+get: next
+get: value
+set: value
+getOwnPropertyDescriptor: value
+defineProperty: value
+get: value
+set: value
+getOwnPropertyDescriptor: value
+defineProperty: value
+get: return`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/some/return-false-if-none-match.js b/js/src/tests/non262/Iterator/prototype/some/return-false-if-none-match.js
new file mode 100644
index 0000000000..00fab94245
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/some/return-false-if-none-match.js
@@ -0,0 +1,11 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const iter = [1, 3, 5].values();
+const fn = (value) => value % 2 == 0;
+
+assertEq(iter.some(fn), false);
+
+assertEq([].values().some(x => x), false);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/some/short-circuit-on-true.js b/js/src/tests/non262/Iterator/prototype/some/short-circuit-on-true.js
new file mode 100644
index 0000000000..4f0d67bf09
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/some/short-circuit-on-true.js
@@ -0,0 +1,14 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const iter = [1, 2, 3].values();
+const log = [];
+const fn = (value) => {
+ log.push(value.toString());
+ return value % 2 == 0;
+};
+
+assertEq(iter.some(fn), true);
+assertEq(log.join(','), '1,2');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/some/this-not-iterator-throws.js b/js/src/tests/non262/Iterator/prototype/some/this-not-iterator-throws.js
new file mode 100644
index 0000000000..0659ec037e
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/some/this-not-iterator-throws.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const fn = x => x;
+assertThrowsInstanceOf(Iterator.prototype.some.bind(undefined, fn), TypeError);
+assertThrowsInstanceOf(Iterator.prototype.some.bind({}, fn), TypeError);
+assertThrowsInstanceOf(Iterator.prototype.some.bind({next: 0}, fn), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/some/value-throws-iterator-not-closed.js b/js/src/tests/non262/Iterator/prototype/some/value-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..87bf5df033
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/some/value-throws-iterator-not-closed.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestError extends Error {}
+class TestIterator extends Iterator {
+ next() {
+ return new Proxy({done: false}, {get: (target, key, receiver) => {
+ if (key === 'value')
+ throw new TestError();
+ return 0;
+ }});
+ }
+
+ closed = false;
+ return() {
+ closed = true;
+ }
+}
+
+const iterator = new TestIterator();
+assertEq(iterator.closed, false, 'iterator starts unclosed');
+assertThrowsInstanceOf(() => iterator.some(x => x), TestError);
+assertEq(iterator.closed, false, 'iterator remains unclosed');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/take-drop-throw-eagerly-on-negative.js b/js/src/tests/non262/Iterator/prototype/take-drop-throw-eagerly-on-negative.js
new file mode 100644
index 0000000000..b870e31e72
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/take-drop-throw-eagerly-on-negative.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: `take` and `drop` throw eagerly when passed negative numbers, after rounding towards 0.
+info: >
+ Iterator Helpers proposal 2.1.5.4 and 2.1.5.5
+features: [iterator-helpers]
+---*/
+
+const iter = [].values();
+const methods = [
+ value => iter.take(value),
+ value => iter.drop(value),
+];
+
+for (const method of methods) {
+ assertThrowsInstanceOf(() => method(-1), RangeError);
+ assertThrowsInstanceOf(() => method(-Infinity), RangeError);
+
+ method(NaN);
+ method(-NaN);
+ method(-0);
+ method(-0.9);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/take-drop-throw-eagerly-on-non-integer.js b/js/src/tests/non262/Iterator/prototype/take-drop-throw-eagerly-on-non-integer.js
new file mode 100644
index 0000000000..3e1333ab37
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/take-drop-throw-eagerly-on-non-integer.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: `take` and `drop` throw eagerly when passed values that can't be converted to numbers.
+info: >
+ Iterator Helpers proposal 2.1.5.4 and 2.1.5.5
+features: [iterator-helpers]
+---*/
+
+const iter = [].values();
+const methods = [
+ value => iter.take(value),
+ value => iter.drop(value),
+];
+
+const objectWithToPrimitive = {
+ [Symbol.toPrimitive]() {
+ return {};
+ }
+};
+
+for (const method of methods) {
+ assertThrowsInstanceOf(() => method(0n), TypeError);
+ assertThrowsInstanceOf(() => method(Symbol('')), TypeError);
+ assertThrowsInstanceOf(() => method(objectWithToPrimitive), TypeError);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/take/close-iterator-when-none-remaining.js b/js/src/tests/non262/Iterator/prototype/take/close-iterator-when-none-remaining.js
new file mode 100644
index 0000000000..1c78db378b
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/take/close-iterator-when-none-remaining.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: %Iterator.prototype%.take closes the iterator when remaining is 0.
+info: >
+ Iterator Helpers proposal 2.1.5.4
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends Iterator {
+ next() {
+ return {done: false, value: 1};
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+const iter = new TestIterator();
+const iterTake = iter.take(1);
+
+let result = iterTake.next();
+assertEq(result.done, false);
+assertEq(result.value, 1);
+assertEq(iter.closed, false);
+
+result = iterTake.next();
+assertEq(result.done, true);
+assertEq(result.value, undefined);
+assertEq(iter.closed, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
+
diff --git a/js/src/tests/non262/Iterator/prototype/take/length.js b/js/src/tests/non262/Iterator/prototype/take/length.js
new file mode 100644
index 0000000000..4e5efa6cea
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/take/length.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+//
+
+/*---
+esid: pending
+description: %Iterator.prototype%.take length value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+includes: [propertyHelper.js]
+features: [Symbol.iterator]
+---*/
+
+assertEq(Iterator.prototype.take.length, 1);
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(Iterator.prototype.take, 'length');
+assertEq(propertyDescriptor.value, 1);
+assertEq(propertyDescriptor.enumerable, false);
+assertEq(propertyDescriptor.writable, false);
+assertEq(propertyDescriptor.configurable, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/take/name.js b/js/src/tests/non262/Iterator/prototype/take/name.js
new file mode 100644
index 0000000000..87f75b63dd
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/take/name.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+/*---
+esid: pending
+description: %Iterator.prototype%.take.name value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(Iterator.prototype.take.name, 'take');
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(Iterator.prototype.take, 'name');
+assertEq(propertyDescriptor.value, 'take');
+assertEq(propertyDescriptor.enumerable, false);
+assertEq(propertyDescriptor.writable, false);
+assertEq(propertyDescriptor.configurable, true);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/take/take-more-than-available.js b/js/src/tests/non262/Iterator/prototype/take/take-more-than-available.js
new file mode 100644
index 0000000000..b9d07b6122
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/take/take-more-than-available.js
@@ -0,0 +1,52 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator'))
+
+//
+//
+/*---
+esid: pending
+description: %Iterator.prototype%.take returns if the iterator is done.
+info: >
+ Iterator Helpers proposal 2.1.5.4
+ 2. Repeat,
+ ...
+ c. Let next be ? IteratorStep(iterated, lastValue).
+ d. If next is false, return undefined.
+features: [iterator-helpers]
+---*/
+
+let iter = [1, 2].values().take(3);
+for (const expected of [1, 2]) {
+ const result = iter.next();
+ assertEq(result.value, expected);
+ assertEq(result.done, false);
+}
+let result = iter.next();
+assertEq(result.value, undefined);
+assertEq(result.done, true);
+
+class TestIterator extends Iterator {
+ counter = 0;
+ next() {
+ return {done: ++this.counter >= 2, value: undefined};
+ }
+
+ closed = false;
+ return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+iter = new TestIterator();
+let taken = iter.take(10);
+for (const value of taken) {
+ assertEq(value, undefined);
+}
+result = taken.next();
+assertEq(result.value, undefined);
+assertEq(result.done, true);
+assertEq(iter.counter, 2);
+assertEq(iter.closed, false);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/take/take.js b/js/src/tests/non262/Iterator/prototype/take/take.js
new file mode 100644
index 0000000000..d94671c664
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/take/take.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+/*---
+esid: pending
+description: Smoketest of %Iterator.prototype%.take.
+info: >
+ Iterator Helpers proposal 2.1.5.4
+features: [iterator-helpers]
+---*/
+
+let iter = [1, 2, 3].values().take(2);
+
+for (const v of [1, 2]) {
+ let result = iter.next();
+ assertEq(result.done, false);
+ assertEq(result.value, v);
+}
+
+assertEq(iter.next().done, true);
+
+// `take`, when called without arguments, has a limit of undefined,
+// which converts to 0.
+assertEq(['test'].values().take().next().done, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/toArray/create-in-current-realm.js b/js/src/tests/non262/Iterator/prototype/toArray/create-in-current-realm.js
new file mode 100644
index 0000000000..850729e5e3
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/toArray/create-in-current-realm.js
@@ -0,0 +1,14 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const otherGlobal = newGlobal({newCompartment: true});
+
+let array = [1, 2, 3].values().toArray();
+assertEq(array instanceof Array, true);
+assertEq(array instanceof otherGlobal.Array, false);
+
+array = otherGlobal.Iterator.prototype.toArray.call([1, 2, 3].values());
+assertEq(array instanceof Array, false);
+assertEq(array instanceof otherGlobal.Array, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/toArray/descriptor.js b/js/src/tests/non262/Iterator/prototype/toArray/descriptor.js
new file mode 100644
index 0000000000..8daa56fd4a
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/toArray/descriptor.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ Descriptor property of Iterator.prototype.toArray
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype, 'toArray');
+assertEq(typeof propDesc.value, 'function');
+assertEq(propDesc.writable, true);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/toArray/iterator-empty.js b/js/src/tests/non262/Iterator/prototype/toArray/iterator-empty.js
new file mode 100644
index 0000000000..97c14f0d06
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/toArray/iterator-empty.js
@@ -0,0 +1,10 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const iter = [].values();
+const array = iter.toArray();
+
+assertEq(Array.isArray(array), true);
+assertEq(array.length, 0);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/toArray/length.js b/js/src/tests/non262/Iterator/prototype/toArray/length.js
new file mode 100644
index 0000000000..493a225ce7
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/toArray/length.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ The `length` property of Iterator.prototype.toArray.
+info: |
+ ES7 section 17: Unless otherwise specified, the length property of a built-in
+ Function object has the attributes { [[Writable]]: false, [[Enumerable]]:
+ false, [[Configurable]]: true }.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype.toArray, 'length');
+assertEq(propDesc.value, 0);
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/toArray/name.js b/js/src/tests/non262/Iterator/prototype/toArray/name.js
new file mode 100644
index 0000000000..b382c3a3a6
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/toArray/name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+/*---
+ `name` property of Iterator.prototype.toArray.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(Iterator.prototype.toArray, 'name');
+assertEq(propDesc.value, 'toArray');
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/toArray/next-throws.js b/js/src/tests/non262/Iterator/prototype/toArray/next-throws.js
new file mode 100644
index 0000000000..c93ecdd324
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/toArray/next-throws.js
@@ -0,0 +1,14 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestIterator extends Iterator {
+ next() {
+ throw new Error();
+ }
+}
+
+const iter = new TestIterator();
+
+assertThrowsInstanceOf(() => iter.toArray(), Error);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/toArray/proxy.js b/js/src/tests/non262/Iterator/prototype/toArray/proxy.js
new file mode 100644
index 0000000000..83024eeb8a
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/toArray/proxy.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+//
+// This test checks that %Iterator.prototype%.toArray only gets the `next` method off of the
+// iterator once, and never accesses the @@iterator property.
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class Counter extends Iterator {
+ value = 0;
+ next() {
+ const value = this.value;
+ if (value < 2) {
+ this.value = value + 1;
+ return {done: false, value};
+ }
+ return {done: true};
+ }
+}
+
+const iter = new Proxy(new Counter(), handlerProxy);
+const array = iter.toArray();
+
+assertEq(
+ log.join('\n'),
+ `get: toArray
+get: next
+get: value
+set: value
+getOwnPropertyDescriptor: value
+defineProperty: value
+get: value
+set: value
+getOwnPropertyDescriptor: value
+defineProperty: value
+get: value`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/toArray/this-not-iterator-throws.js b/js/src/tests/non262/Iterator/prototype/toArray/this-not-iterator-throws.js
new file mode 100644
index 0000000000..1442d22557
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/toArray/this-not-iterator-throws.js
@@ -0,0 +1,8 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+assertThrowsInstanceOf(Iterator.prototype.toArray.bind(undefined), TypeError);
+assertThrowsInstanceOf(Iterator.prototype.toArray.bind({}), TypeError);
+assertThrowsInstanceOf(Iterator.prototype.toArray.bind({next: 0}), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/toArray/toArray.js b/js/src/tests/non262/Iterator/prototype/toArray/toArray.js
new file mode 100644
index 0000000000..29c99525fb
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/toArray/toArray.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+const iter = [1, 2, 3].values();
+assertEq(Array.isArray(iter), false);
+
+const array = iter.toArray();
+assertEq(Array.isArray(array), true);
+assertEq(array.length, 3);
+
+const expected = [1, 2, 3];
+for (const item of array) {
+ const expect = expected.shift();
+ assertEq(item, expect);
+}
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/Iterator/prototype/toArray/value-throws-iterator-not-closed.js b/js/src/tests/non262/Iterator/prototype/toArray/value-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..ca56de8a66
--- /dev/null
+++ b/js/src/tests/non262/Iterator/prototype/toArray/value-throws-iterator-not-closed.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('Iterator')) -- Iterator is not enabled unconditionally
+
+class TestError extends Error {}
+class TestIterator extends Iterator {
+ next() {
+ return new Proxy({done: false}, {get: (target, key, receiver) => {
+ if (key === 'value')
+ throw new TestError();
+ return 0;
+ }});
+ }
+
+ closed = false;
+ return() {
+ closed = true;
+ }
+}
+
+const iterator = new TestIterator();
+assertEq(iterator.closed, false, 'iterator starts unclosed');
+assertThrowsInstanceOf(() => iterator.toArray(), TestError);
+assertEq(iterator.closed, false, 'iterator remains unclosed');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);