summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/AsyncIterator
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/AsyncIterator
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/non262/AsyncIterator')
-rw-r--r--js/src/tests/non262/AsyncIterator/asynciterator.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/constructor-subclassable.js12
-rw-r--r--js/src/tests/non262/AsyncIterator/constructor-throw-when-called-directly.js9
-rw-r--r--js/src/tests/non262/AsyncIterator/constructor-throw-without-new.js9
-rw-r--r--js/src/tests/non262/AsyncIterator/constructor.js9
-rw-r--r--js/src/tests/non262/AsyncIterator/length.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/name.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/proto.js14
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/asIndexedPairs/asIndexedPairs.js25
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/asIndexedPairs/length.js21
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/asIndexedPairs/name.js20
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/async-iterator-helpers-from-other-global.js65
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/clobber-symbol.js50
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/drop/drop-more-than-available.js39
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/drop/drop.js23
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/drop/length.js20
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/drop/name.js20
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/async-writes.js20
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/check-fn-after-getting-iterator.js30
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/coerce-result-to-boolean.js29
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/descriptor.js10
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/error-from-correct-realm.js21
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/fn-not-callable-throws.js26
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/fn-throws-close-iterator.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/interleaving-calls.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/length.js17
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/name.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/next-throws-iterator-not-closed.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/proxy.js46
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/return-true-if-all-match.js16
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/short-circuit-on-false.js21
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/this-not-iterator-throws.js22
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/every/value-throws-iterator-not-closed.js28
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/filter/coerce-result-to-boolean.js25
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/filter/filter.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/filter/length.js21
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/filter/name.js19
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/async-writes.js20
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/check-fn-after-getting-iterator.js28
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/coerce-result-to-boolean.js35
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/descriptor.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/error-from-correct-realm.js21
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/fn-not-callable-throws.js26
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/fn-throws-close-iterator.js26
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/interleaving-calls.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/length.js17
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/name.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/next-throws-iterator-not-closed.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/proxy.js46
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/return-undefined-if-none-match.js16
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/short-circuit-on-match.js21
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/this-not-iterator-throws.js20
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/find/value-throws-iterator-not-closed.js28
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/flatMap/close-iterator-when-inner-complete-throws.js55
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/flatMap/close-iterator-when-inner-next-throws.js50
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/flatMap/close-iterator-when-inner-value-throws.js57
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/flatMap/flatMap.js28
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/flatMap/inner-empty-iterable.js44
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/flatMap/inner-generator.js36
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/flatMap/length.js21
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/flatMap/name.js19
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/flatMap/throw-when-inner-not-iterable.js71
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/forEach/async-writes.js20
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/forEach/check-fn-after-getting-iterator.js27
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/forEach/descriptor.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/forEach/error-from-correct-realm.js21
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/forEach/fn-not-callable-throws.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/forEach/fn-throws-close-iterator.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/forEach/forEach.js11
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/forEach/interleaving-calls.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/forEach/length.js17
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/forEach/name.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/forEach/next-throws-iterator-not-closed.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/forEach/proxy.js44
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/forEach/this-not-iterator-throws.js19
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/forEach/value-throws-iterator-not-closed.js28
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/generator-methods-throw-on-iterator-helpers.js35
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/iterator-helper-methods-throw-on-generators.js12
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-from-other-global.js36
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-handle-empty-iterators.js42
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-interleaved.js59
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-closed-on-call-throws.js49
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-closed-on-yield-throws.js53
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-get-then-throws.js57
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-promise-executor-throws.js53
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-returns-reject.js51
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-then-throws.js57
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-throws.js49
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-value-throws.js54
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-returns-done-generator-finishes.js30
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-multiple-return-close-iterator-once.js64
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-multiple-throw-close-iterator-once.js90
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-mutate-iterator-after-done.js49
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-mutate-iterator.js49
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-not-close-iterator-next-reject.js48
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-pass-through-lastValue.js33
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-pass-value-through-chain.js38
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-proxy-accesses.js68
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-return-closes-iterator.js63
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-return-new-iterator-result.js42
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-closes-iterator-before-next.js58
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-eagerly-on-next-non-callable.js35
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-eagerly-on-non-callable.js40
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-eagerly-on-non-iterator.js31
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-next-done-throws.js53
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-next-not-object.js50
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-on-reentry.js18
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/map/length.js21
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/map/map.js23
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/map/name.js19
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/accumulator-set-to-initial-value.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/async-writes.js20
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/check-fn-after-getting-iterator.js27
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/descriptor.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/empty-iterator-without-initial-value-throws.js9
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/error-from-correct-realm.js21
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/interleaving-calls.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/iterator-empty-return-initial-value.js9
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/iterator-next-return-non-object-throws.js31
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/left-associative.js15
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/length.js17
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/name.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/next-throws-iterator-not-closed.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/no-initial-value-set-accumulator-to-first-value.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/proxy.js44
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/reduce.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/reducer-not-callable-throws.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/reducer-throws-iterator-closed.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/this-not-iterator-throws.js19
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/reduce/value-throws-iterator-not-closed.js28
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/async-writes.js20
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/check-fn-after-getting-iterator.js31
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/coerce-result-to-boolean.js29
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/descriptor.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/error-from-correct-realm.js21
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/fn-not-callable-throws.js28
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/fn-throws-close-iterator.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/interleaving-calls.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/length.js17
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/name.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/next-throws-iterator-not-closed.js23
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/proxy.js46
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/return-false-if-none-match.js16
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/short-circuit-on-true.js20
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/this-not-iterator-throws.js19
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/some/value-throws-iterator-not-closed.js28
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/take-drop-throw-eagerly-on-negative.js30
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/take-drop-throw-eagerly-on-non-integer.js33
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/take/close-iterator-when-none-remaining.js45
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/take/length.js21
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/take/name.js19
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/take/take-more-than-available.js34
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/take/take.js23
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/toArray/async-writes.js20
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/toArray/create-in-current-realm.js22
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/toArray/descriptor.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/toArray/interleaving-calls.js24
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/toArray/iterator-empty.js10
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/toArray/length.js17
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/toArray/name.js13
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/toArray/next-throws.js23
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/toArray/proxy.js44
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/toArray/this-not-iterator-throws.js21
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/toArray/toArray.js22
-rw-r--r--js/src/tests/non262/AsyncIterator/prototype/toArray/value-throws-iterator-not-closed.js33
165 files changed, 4672 insertions, 0 deletions
diff --git a/js/src/tests/non262/AsyncIterator/asynciterator.js b/js/src/tests/non262/AsyncIterator/asynciterator.js
new file mode 100644
index 0000000000..048c3b4392
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/asynciterator.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator')) -- AsyncIterator is not enabled unconditionally
+/*---
+ Property descriptor of AsyncIterator.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(this, 'AsyncIterator');
+assertEq(propDesc.value, AsyncIterator);
+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/AsyncIterator/constructor-subclassable.js b/js/src/tests/non262/AsyncIterator/constructor-subclassable.js
new file mode 100644
index 0000000000..4e8061cfe7
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/constructor-subclassable.js
@@ -0,0 +1,12 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ AsyncIterator constructor can be subclassed.
+---*/
+
+class TestIterator extends AsyncIterator {
+}
+
+assertEq(new TestIterator() instanceof AsyncIterator, true);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/constructor-throw-when-called-directly.js b/js/src/tests/non262/AsyncIterator/constructor-throw-when-called-directly.js
new file mode 100644
index 0000000000..8abc132282
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/constructor-throw-when-called-directly.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ AsyncIterator constructor throws when called directly.
+---*/
+
+assertThrowsInstanceOf(() => new AsyncIterator(), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/constructor-throw-without-new.js b/js/src/tests/non262/AsyncIterator/constructor-throw-without-new.js
new file mode 100644
index 0000000000..699bbed007
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/constructor-throw-without-new.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator')) -- AsyncIterator is not enabled unconditionally
+/*---
+ AsyncIterator constructor throws when called without new.
+---*/
+
+assertThrowsInstanceOf(() => AsyncIterator(), TypeError);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/constructor.js b/js/src/tests/non262/AsyncIterator/constructor.js
new file mode 100644
index 0000000000..e421c4e98b
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/constructor.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator')) -- AsyncIterator is not enabled unconditionally
+/*---
+ The AsyncIterator constructor is a built-in function.
+---*/
+
+assertEq(typeof AsyncIterator, 'function');
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/length.js b/js/src/tests/non262/AsyncIterator/length.js
new file mode 100644
index 0000000000..26803fc44e
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/length.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator')) -- AsyncIterator is not enabled unconditionally
+/*---
+ The "length" property of AsyncIterator
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator, '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/AsyncIterator/name.js b/js/src/tests/non262/AsyncIterator/name.js
new file mode 100644
index 0000000000..d8944341b5
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator')) -- AsyncIterator is not enabled unconditionally
+/*---
+ The "name" property of AsyncIterator
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator, 'name');
+assertEq(propDesc.value, 'AsyncIterator');
+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/AsyncIterator/proto.js b/js/src/tests/non262/AsyncIterator/proto.js
new file mode 100644
index 0000000000..3f19f099c7
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/proto.js
@@ -0,0 +1,14 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator')) -- AsyncIterator is not enabled unconditionally
+/*---
+ The prototype of the AsyncIterator constructor is the intrinsic object %FunctionPrototype%.
+---*/
+
+assertEq(Object.getPrototypeOf(AsyncIterator), Function.prototype);
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator, 'prototype');
+assertEq(propDesc.writable, false);
+assertEq(propDesc.enumerable, false);
+assertEq(propDesc.configurable, false);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/asIndexedPairs/asIndexedPairs.js b/js/src/tests/non262/AsyncIterator/prototype/asIndexedPairs/asIndexedPairs.js
new file mode 100644
index 0000000000..71ae91d602
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/asIndexedPairs/asIndexedPairs.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+
+let iter = gen().asIndexedPairs();
+
+for (const v of [[0, 1], [1, 2], [2, 3]]) {
+ iter.next().then(
+ result => {
+ console.log(result);
+ assertEq(result.done, false);
+ assertEq(result.value[0], v[0]);
+ assertEq(result.value[1], v[1]);
+ }
+ );
+}
+
+iter.next().then(({done}) => assertEq(done, true));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/asIndexedPairs/length.js b/js/src/tests/non262/AsyncIterator/prototype/asIndexedPairs/length.js
new file mode 100644
index 0000000000..6854cd7dd2
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/asIndexedPairs/length.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.asIndexedPairs length value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(AsyncIterator.prototype.asIndexedPairs.length, 0);
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/asIndexedPairs/name.js b/js/src/tests/non262/AsyncIterator/prototype/asIndexedPairs/name.js
new file mode 100644
index 0000000000..c19ac4105e
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/asIndexedPairs/name.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.asIndexedPairs.name value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(AsyncIterator.prototype.asIndexedPairs.name, 'asIndexedPairs');
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/async-iterator-helpers-from-other-global.js b/js/src/tests/non262/AsyncIterator/prototype/async-iterator-helpers-from-other-global.js
new file mode 100644
index 0000000000..f8b8d719cd
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/async-iterator-helpers-from-other-global.js
@@ -0,0 +1,65 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestError extends Error {}
+
+class TestIterator extends AsyncIterator {
+ async next() {
+ return {done: false, value: 'value'};
+ }
+
+ closed = false;
+ async 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", async function*(x) { yield x; }],
+];
+
+const {next: otherNext, return: otherReturn, throw: otherThrow} =
+ Object.getPrototypeOf(otherGlobal.eval("(async function*() {})().map(x => x)"));
+
+(async () => {
+ for (const [method, arg] of methods) {
+ const iterator = new TestIterator();
+ const helper = iterator[method](arg);
+ checkIterResult(await otherNext.call(helper), false, 'value');
+ }
+
+ for (const [method, arg] of methods) {
+ const iterator = new TestIterator();
+ const helper = iterator[method](arg);
+ assertEq(iterator.closed, false);
+ checkIterResult(await otherReturn.call(helper), true, undefined);
+ assertEq(iterator.closed, true);
+ }
+
+ for (const [method, arg] of methods) {
+ const iterator = new TestIterator();
+ const helper = iterator[method](arg);
+ try {
+ await otherThrow.call(helper, new TestError());
+ assertEq(true, false, 'Expected exception');
+ } catch (exc) {
+ assertEq(exc instanceof TestError, true);
+ }
+ checkIterResult(await helper.next(), true, undefined);
+ }
+})();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/clobber-symbol.js b/js/src/tests/non262/AsyncIterator/prototype/clobber-symbol.js
new file mode 100644
index 0000000000..5db6b2276f
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/clobber-symbol.js
@@ -0,0 +1,50 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+//
+
+/*---
+esid: pending
+description: %AsyncIterator.prototype% methods work even if the global Symbol has been clobbered.
+info: >
+ Iterator Helpers proposal 2.1.6
+features: [iterator-helpers, Symbol.asyncIterator]
+---*/
+
+Symbol = undefined;
+assertThrowsInstanceOf(() => Symbol.asyncIterator, TypeError);
+
+async function* gen(value) {
+ yield value;
+}
+
+const lazyMethods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => x),
+ iter => iter.take(1),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(gen),
+];
+
+const strictMethods = [
+ iter => iter.reduce((_, x) => x, undefined),
+ iter => iter.toArray(),
+ iter => iter.forEach(() => undefined),
+ iter => iter.some(x => true),
+ iter => iter.every(x => true),
+ iter => iter.find(x => true),
+];
+
+(async () => {
+ for (const method of lazyMethods) {
+ const {value} = await method(gen('value')).next();
+ assertEq(Array.isArray(value) ? value[1] : value, 'value');
+ }
+
+ for (const method of strictMethods) {
+ await method(gen('value'));
+ }
+})();
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/drop/drop-more-than-available.js b/js/src/tests/non262/AsyncIterator/prototype/drop/drop-more-than-available.js
new file mode 100644
index 0000000000..45e0f91559
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/drop/drop-more-than-available.js
@@ -0,0 +1,39 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.drop returns if the iterator is done.
+info: >
+ Iterator Helpers proposal 2.1.6.5
+ 1. Repeat, while remaining > 0,
+ ...
+ b. Let next be ? Await(? IteratorStep(iterated)).
+ c. If ? IteratorComplete(next) is true, return undefined.
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends AsyncIterator {
+ counter = 0;
+ async next() {
+ return {done: ++this.counter >= 2, value: undefined};
+ }
+}
+
+(async () => {
+ let iter = [1, 2].values().drop(3);
+ let result = await iter.next();
+ assertEq(result.value, undefined);
+ assertEq(result.done, true);
+
+ iter = new TestIterator();
+ let dropped = iter.drop(10);
+ result = await 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/AsyncIterator/prototype/drop/drop.js b/js/src/tests/non262/AsyncIterator/prototype/drop/drop.js
new file mode 100644
index 0000000000..e380d7b7ed
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/drop/drop.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+
+let iter = gen().drop(1);
+
+for (const v of [2, 3]) {
+ iter.next().then(
+ ({done, value}) => {
+ assertEq(done, false);
+ assertEq(value, v);
+ }
+ );
+}
+
+iter.next().then(({done}) => assertEq(done, true));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/drop/length.js b/js/src/tests/non262/AsyncIterator/prototype/drop/length.js
new file mode 100644
index 0000000000..6176622f17
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/drop/length.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.drop length value and descriptor.
+info: >
+features: [iterator-helpers]
+---*/
+
+assertEq(AsyncIterator.prototype.drop.length, 1);
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/drop/name.js b/js/src/tests/non262/AsyncIterator/prototype/drop/name.js
new file mode 100644
index 0000000000..ec0a73416a
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/drop/name.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.drop.name value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(AsyncIterator.prototype.drop.name, 'drop');
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/every/async-writes.js b/js/src/tests/non262/AsyncIterator/prototype/every/async-writes.js
new file mode 100644
index 0000000000..655dfd2624
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/async-writes.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+let x = {a: () => true};
+
+async function* gen() {
+ yield x.a();
+ yield x.a();
+}
+
+gen().every(() => true).then(
+ () => assertEq(true, false, 'expected error'),
+ err => assertEq(err instanceof Error, true),
+);
+
+x.a = () => {
+ throw Error();
+};
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/every/check-fn-after-getting-iterator.js b/js/src/tests/non262/AsyncIterator/prototype/every/check-fn-after-getting-iterator.js
new file mode 100644
index 0000000000..ee147ab14b
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/check-fn-after-getting-iterator.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({done: true});
+ }
+}
+
+async function* gen() {
+ yield 1;
+}
+
+const iter = new Proxy(new TestIterator(), handlerProxy);
+iter.every(1).then(() => assertEq(true, false, 'expected error'), err => assertEq(err instanceof TypeError, true));
+
+assertEq(
+ log.join('\n'),
+ `get: every
+get: next`
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/every/coerce-result-to-boolean.js b/js/src/tests/non262/AsyncIterator/prototype/every/coerce-result-to-boolean.js
new file mode 100644
index 0000000000..35c40d235e
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/coerce-result-to-boolean.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen(value) {
+ yield value;
+}
+const fn = x => x;
+function check(value, expected) {
+ gen(value).every(fn).then(result => assertEq(result, expected));
+}
+
+check(true, true);
+check(1, true);
+check([], true);
+check({}, true);
+check('test', true);
+
+check(false, false);
+check(0, false);
+check('', false);
+check(null, false);
+check(undefined, false);
+check(NaN, false);
+check(-0, false);
+check(0n, false);
+check(createIsHTMLDDA(), false);
+check(Promise.resolve(false), false);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/every/descriptor.js b/js/src/tests/non262/AsyncIterator/prototype/every/descriptor.js
new file mode 100644
index 0000000000..180085cefe
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/descriptor.js
@@ -0,0 +1,10 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/every/error-from-correct-realm.js b/js/src/tests/non262/AsyncIterator/prototype/every/error-from-correct-realm.js
new file mode 100644
index 0000000000..2ff93254ce
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/error-from-correct-realm.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const otherGlobal = newGlobal({newCompartment: true});
+assertEq(TypeError !== otherGlobal.TypeError, true);
+
+async function *gen() {}
+
+gen().every().then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TypeError, true);
+});
+
+otherGlobal.AsyncIterator.prototype.every.call(gen()).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(
+ err instanceof otherGlobal.TypeError,
+ true,
+ 'TypeError comes from the realm of the method.',
+ );
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/every/fn-not-callable-throws.js b/js/src/tests/non262/AsyncIterator/prototype/every/fn-not-callable-throws.js
new file mode 100644
index 0000000000..025c46dfdf
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/fn-not-callable-throws.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function *gen() {
+ yield 1;
+}
+
+function check(fn) {
+ gen().every(fn).then(() => {
+ throw new Error('every should have thrown');
+ },
+ (err) => {
+ assertEq(err instanceof TypeError, true);
+ });
+}
+
+check();
+check(undefined);
+check(null);
+check(0);
+check(false);
+check('');
+check(Symbol(''));
+check({});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/every/fn-throws-close-iterator.js b/js/src/tests/non262/AsyncIterator/prototype/every/fn-throws-close-iterator.js
new file mode 100644
index 0000000000..2a18d2ab45
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/fn-throws-close-iterator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({ done: this.closed });
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = () => { throw new Error(); };
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+iter.every(fn).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof Error, true);
+ assertEq(iter.closed, true);
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/every/interleaving-calls.js b/js/src/tests/non262/AsyncIterator/prototype/every/interleaving-calls.js
new file mode 100644
index 0000000000..8aacdb4316
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/interleaving-calls.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const log = [];
+async function* gen(n) {
+ log.push(`${n}`);
+ yield 1;
+ log.push(`${n}`);
+ yield 2;
+}
+
+Promise.all([gen(1).every(() => true), gen(2).every(() => true)]).then(
+ () => {
+ assertEq(
+ log.join(' '),
+ '1 2 1 2',
+ );
+ },
+ err => {
+ throw err;
+ }
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/every/length.js b/js/src/tests/non262/AsyncIterator/prototype/every/length.js
new file mode 100644
index 0000000000..58d7942018
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/length.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ The `length` property of AsyncIterator.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(AsyncIterator.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/AsyncIterator/prototype/every/name.js b/js/src/tests/non262/AsyncIterator/prototype/every/name.js
new file mode 100644
index 0000000000..086bfb13a6
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ `name` property of AsyncIterator.prototype.every.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/every/next-throws-iterator-not-closed.js b/js/src/tests/non262/AsyncIterator/prototype/every/next-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..98cc850a07
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/next-throws-iterator-not-closed.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestIterator extends AsyncIterator {
+ next() {
+ throw new Error();
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = () => {};
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+iter.every(fn).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof Error, true);
+ assertEq(iter.closed, false);
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/every/proxy.js b/js/src/tests/non262/AsyncIterator/prototype/every/proxy.js
new file mode 100644
index 0000000000..628f143e27
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/proxy.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+// This test checks that %AsyncIterator.prototype%.every only gets the `next` method off of the
+// iterator once, and never accesses the @@asyncIterator 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 AsyncIterator {
+ value = 0;
+ next() {
+ const value = this.value;
+ if (value < 2) {
+ this.value = value + 1;
+ return Promise.resolve({done: false, value});
+ }
+ return Promise.resolve({done: true});
+ }
+}
+
+const iter = new Proxy(new Counter(), handlerProxy);
+iter.every(x => x % 2 == 0).then(value => {
+ assertEq(value, 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/AsyncIterator/prototype/every/return-true-if-all-match.js b/js/src/tests/non262/AsyncIterator/prototype/every/return-true-if-all-match.js
new file mode 100644
index 0000000000..01d0f75d58
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/return-true-if-all-match.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {
+ yield 1;
+ yield 3;
+ yield 5;
+}
+const fn = x => x % 2 == 1;
+
+gen().every(fn).then(result => assertEq(result, true));
+
+async function* empty() {}
+empty().every(x => x).then(result => assertEq(result, true));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/every/short-circuit-on-false.js b/js/src/tests/non262/AsyncIterator/prototype/every/short-circuit-on-false.js
new file mode 100644
index 0000000000..7b2c74d513
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/short-circuit-on-false.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+
+const log = [];
+const fn = value => {
+ log.push(value.toString());
+ return value % 2 == 1;
+};
+
+gen().every(fn).then(result => {
+ assertEq(result, false);
+ assertEq(log.join(','), '1,2');
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/every/this-not-iterator-throws.js b/js/src/tests/non262/AsyncIterator/prototype/every/this-not-iterator-throws.js
new file mode 100644
index 0000000000..ed576c32ec
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/this-not-iterator-throws.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const fn = x => x;
+
+function check(x) {
+ AsyncIterator.prototype.every.call(x, fn).then(
+ () => {
+ throw new Error('check should have been rejected');
+ },
+ err => {
+ assertEq(err instanceof TypeError, true);
+ }
+ );
+}
+
+check();
+check(undefined);
+check({});
+check({next: 0});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/every/value-throws-iterator-not-closed.js b/js/src/tests/non262/AsyncIterator/prototype/every/value-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..423a85ca7b
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/every/value-throws-iterator-not-closed.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestError extends Error {}
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({
+ done: false,
+ get value() {
+ throw new TestError();
+ }
+ });
+ }
+
+ closed = false;
+ return() {
+ closed = true;
+ }
+}
+
+const iterator = new TestIterator();
+assertEq(iterator.closed, false, 'iterator starts unclosed');
+iterator.every(x => x).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iterator.closed, false, 'iterator remains unclosed');
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/filter/coerce-result-to-boolean.js b/js/src/tests/non262/AsyncIterator/prototype/filter/coerce-result-to-boolean.js
new file mode 100644
index 0000000000..23e3a317eb
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/filter/coerce-result-to-boolean.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen(iterable) {
+ yield* iterable;
+}
+
+// All truthy values are kept.
+const truthyValues = [true, 1, [], {}, 'test'];
+(async () => {
+ for await (const value of gen([...truthyValues]).filter(x => x)) {
+ assertEq(truthyValues.shift(), value);
+ }
+})();
+
+// All falsy values are filtered out.
+const falsyValues = [false, 0, '', null, undefined, NaN, -0, 0n, createIsHTMLDDA()];
+gen(falsyValues).filter(x => x).next().then(
+ ({done, value}) => {
+ assertEq(done, true);
+ assertEq(value, undefined);
+ }
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/filter/filter.js b/js/src/tests/non262/AsyncIterator/prototype/filter/filter.js
new file mode 100644
index 0000000000..060e9853f2
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/filter/filter.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+
+let iter = gen().filter(x => x % 2);
+
+for (const v of [1, 3]) {
+ console.log(iter);
+ iter.next().then(
+ ({done, value}) => {
+ assertEq(done, false);
+ assertEq(value, v);
+ }
+ );
+}
+
+iter.next().then(({done}) => assertEq(done, true));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/filter/length.js b/js/src/tests/non262/AsyncIterator/prototype/filter/length.js
new file mode 100644
index 0000000000..7ca14621ff
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/filter/length.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.filter length value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(AsyncIterator.prototype.filter.length, 1);
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/filter/name.js b/js/src/tests/non262/AsyncIterator/prototype/filter/name.js
new file mode 100644
index 0000000000..1a8e030e9a
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/filter/name.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.filter.name value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(AsyncIterator.prototype.filter.name, 'filter');
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/find/async-writes.js b/js/src/tests/non262/AsyncIterator/prototype/find/async-writes.js
new file mode 100644
index 0000000000..6d1707e2fe
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/async-writes.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+let x = {a: () => true};
+
+async function* gen() {
+ yield x.a();
+ yield x.a();
+}
+
+gen().find(() => {}).then(
+ () => assertEq(true, false, 'expected error'),
+ err => assertEq(err instanceof Error, true),
+);
+
+x.a = () => {
+ throw Error();
+};
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/find/check-fn-after-getting-iterator.js b/js/src/tests/non262/AsyncIterator/prototype/find/check-fn-after-getting-iterator.js
new file mode 100644
index 0000000000..579e4f589a
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/check-fn-after-getting-iterator.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({done: true});
+ }
+}
+
+const iter = new Proxy(new TestIterator(), handlerProxy);
+iter.find(1).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TypeError, true);
+ assertEq(
+ log.join('\n'),
+ `get: find
+get: next`
+ );
+});
+
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/find/coerce-result-to-boolean.js b/js/src/tests/non262/AsyncIterator/prototype/find/coerce-result-to-boolean.js
new file mode 100644
index 0000000000..eb89eca840
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/coerce-result-to-boolean.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen(value) {
+ yield value;
+}
+const fn = x => x;
+function check(value, expected) {
+ gen(value).find(fn).then(result => assertEq(result, expected));
+}
+
+check(true, true);
+check(1, 1);
+check('test', 'test');
+
+check(false, undefined);
+check(0, undefined);
+check('', undefined);
+check(null, undefined);
+check(undefined, undefined);
+check(NaN, undefined);
+check(-0, undefined);
+check(0n, undefined);
+check(Promise.resolve(false), undefined);
+
+let array = [];
+check(array, array);
+
+let object = {};
+check(object, object);
+
+const htmlDDA = createIsHTMLDDA();
+check(htmlDDA, undefined);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/find/descriptor.js b/js/src/tests/non262/AsyncIterator/prototype/find/descriptor.js
new file mode 100644
index 0000000000..7b93147d81
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/descriptor.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ Descriptor property of AsyncIterator.prototype.find
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/find/error-from-correct-realm.js b/js/src/tests/non262/AsyncIterator/prototype/find/error-from-correct-realm.js
new file mode 100644
index 0000000000..37c6b4b593
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/error-from-correct-realm.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const otherGlobal = newGlobal({newCompartment: true});
+assertEq(TypeError !== otherGlobal.TypeError, true);
+
+async function *gen() {}
+
+gen().find().then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TypeError, true);
+});
+
+otherGlobal.AsyncIterator.prototype.find.call(gen()).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(
+ err instanceof otherGlobal.TypeError,
+ true,
+ 'TypeError comes from the realm of the method.',
+ );
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/find/fn-not-callable-throws.js b/js/src/tests/non262/AsyncIterator/prototype/find/fn-not-callable-throws.js
new file mode 100644
index 0000000000..c858b812d3
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/fn-not-callable-throws.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function *gen() {
+ yield 1;
+}
+
+function check(fn) {
+ gen().every(fn).then(() => {
+ throw new Error('every should have thrown');
+ },
+ (err) => {
+ assertEq(err instanceof TypeError, true);
+ });
+}
+
+check();
+check(undefined);
+check(null);
+check(0);
+check(false);
+check('');
+check(Symbol(''));
+check({});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/find/fn-throws-close-iterator.js b/js/src/tests/non262/AsyncIterator/prototype/find/fn-throws-close-iterator.js
new file mode 100644
index 0000000000..9544c57d4a
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/fn-throws-close-iterator.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({done: this.closed});
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = () => { throw new Error(); };
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+iter.find(fn).then(() => {
+ throw new Error('promise should be rejected');
+}, err => {
+ assertEq(err instanceof Error, true);
+ assertEq(iter.closed, true);
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/find/interleaving-calls.js b/js/src/tests/non262/AsyncIterator/prototype/find/interleaving-calls.js
new file mode 100644
index 0000000000..d973e8b030
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/interleaving-calls.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const log = [];
+async function* gen(n) {
+ log.push(`${n}`);
+ yield 1;
+ log.push(`${n}`);
+ yield 2;
+}
+
+Promise.all([gen(1).find(() => {}), gen(2).find(() => {})]).then(
+ () => {
+ assertEq(
+ log.join(' '),
+ '1 2 1 2',
+ );
+ },
+ err => {
+ throw err;
+ }
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/find/length.js b/js/src/tests/non262/AsyncIterator/prototype/find/length.js
new file mode 100644
index 0000000000..e207a52898
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/length.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ The `length` property of AsyncIterator.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(AsyncIterator.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/AsyncIterator/prototype/find/name.js b/js/src/tests/non262/AsyncIterator/prototype/find/name.js
new file mode 100644
index 0000000000..21e8fa90f8
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ `name` property of AsyncIterator.prototype.find.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/find/next-throws-iterator-not-closed.js b/js/src/tests/non262/AsyncIterator/prototype/find/next-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..4c5cd3ddbd
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/next-throws-iterator-not-closed.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestIterator extends AsyncIterator {
+ next() {
+ throw new Error();
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = x => x;
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+iter.find(fn).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof Error, true);
+ assertEq(iter.closed, false);
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/find/proxy.js b/js/src/tests/non262/AsyncIterator/prototype/find/proxy.js
new file mode 100644
index 0000000000..4f8a210b45
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/proxy.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+// 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 AsyncIterator {
+ value = 0;
+ next() {
+ const value = this.value;
+ if (value < 2) {
+ this.value = value + 1;
+ return Promise.resolve({done: false, value});
+ }
+ return Promise.resolve({done: true});
+ }
+}
+
+const iter = new Proxy(new Counter(), handlerProxy);
+iter.find(x => x % 2 == 1).then(value => {
+ assertEq(value, 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/AsyncIterator/prototype/find/return-undefined-if-none-match.js b/js/src/tests/non262/AsyncIterator/prototype/find/return-undefined-if-none-match.js
new file mode 100644
index 0000000000..b7dc847036
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/return-undefined-if-none-match.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {
+ yield 1;
+ yield 3;
+ yield 5;
+}
+const fn = x => x % 2 == 0;
+
+gen().find(fn).then(result => assertEq(result, undefined));
+
+async function* empty() {}
+empty().find(x => x).then(result => assertEq(result, undefined));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/find/short-circuit-on-match.js b/js/src/tests/non262/AsyncIterator/prototype/find/short-circuit-on-match.js
new file mode 100644
index 0000000000..4404c53ac1
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/short-circuit-on-match.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+
+const log = [];
+const fn = (value) => {
+ log.push(value.toString());
+ return value % 2 == 0;
+};
+
+gen().find(fn).then(result => {
+ assertEq(result, 2);
+ assertEq(log.join(','), '1,2');
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/find/this-not-iterator-throws.js b/js/src/tests/non262/AsyncIterator/prototype/find/this-not-iterator-throws.js
new file mode 100644
index 0000000000..97c8b142a2
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/this-not-iterator-throws.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const fn = x => x;
+
+function check(x) {
+ AsyncIterator.prototype.find.call(x, fn).then(
+ () => assertEq(true, false, 'expected error'),
+ err => {
+ assertEq(err instanceof TypeError, true);
+ }
+ );
+}
+
+check();
+check(undefined);
+check({});
+check({next: 0});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/find/value-throws-iterator-not-closed.js b/js/src/tests/non262/AsyncIterator/prototype/find/value-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..c639eea5a4
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/find/value-throws-iterator-not-closed.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestError extends Error {}
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({
+ done: false,
+ get value() {
+ throw new TestError();
+ }
+ });
+ }
+
+ closed = false;
+ return() {
+ closed = true;
+ }
+}
+
+const iterator = new TestIterator();
+assertEq(iterator.closed, false, 'iterator starts unclosed');
+iterator.find(x => x).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iterator.closed, false, 'iterator remains unclosed');
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/flatMap/close-iterator-when-inner-complete-throws.js b/js/src/tests/non262/AsyncIterator/prototype/flatMap/close-iterator-when-inner-complete-throws.js
new file mode 100644
index 0000000000..bca8f7c316
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/flatMap/close-iterator-when-inner-complete-throws.js
@@ -0,0 +1,55 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.flatMap closes the iterator when innerComplete throws.
+info: >
+ Iterator Helpers proposal 2.1.6.7
+ 1. Repeat,
+ ...
+ k. Repeat, while innerAlive is true,
+ ...
+ v. Let innerComplete be IteratorComplete(innerNext).
+ vi. IfAbruptCloseAsyncIterator(innerComplete, iterated).
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends AsyncIterator {
+ async next() {
+ return {done: false, value: 0};
+ }
+
+ closed = false;
+ async return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+class TestError extends Error {}
+class InnerIterator extends AsyncIterator {
+ async next() {
+ return {
+ get done() {
+ throw new TestError();
+ }
+ };
+ }
+}
+
+const iter = new TestIterator();
+const mapped = iter.flatMap(x => new InnerIterator());
+
+assertEq(iter.closed, false);
+mapped.next().then(
+ _ => assertEq(true, false, 'Expected reject.'),
+ err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iter.closed, true);
+ }
+);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/flatMap/close-iterator-when-inner-next-throws.js b/js/src/tests/non262/AsyncIterator/prototype/flatMap/close-iterator-when-inner-next-throws.js
new file mode 100644
index 0000000000..d92732e9fd
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/flatMap/close-iterator-when-inner-next-throws.js
@@ -0,0 +1,50 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.flatMap closes the iterator when IteratorNext throws.
+info: >
+ Iterator Helpers proposal 2.1.6.7
+ 1. Repeat,
+ ...
+ k. Repeat, while innerAlive is true,
+ i. Let innerNextPromise be IteratorNext(innerIterator).
+ ii. IfAbruptCloseAsyncIterator(innerNextPromise, iterated).
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends AsyncIterator {
+ async next() {
+ return {done: false, value: 0};
+ }
+
+ closed = false;
+ async return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+class TestError extends Error {}
+class InnerIterator extends AsyncIterator {
+ async next() {
+ throw new TestError();
+ }
+}
+
+const iter = new TestIterator();
+const mapped = iter.flatMap(x => new InnerIterator());
+
+assertEq(iter.closed, false);
+mapped.next().then(
+ _ => assertEq(true, false, 'Expected reject.'),
+ err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iter.closed, true);
+ }
+);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/flatMap/close-iterator-when-inner-value-throws.js b/js/src/tests/non262/AsyncIterator/prototype/flatMap/close-iterator-when-inner-value-throws.js
new file mode 100644
index 0000000000..97a82ec0bb
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/flatMap/close-iterator-when-inner-value-throws.js
@@ -0,0 +1,57 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.flatMap closes the iterator when innerValue throws.
+info: >
+ Iterator Helpers proposal 2.1.6.7
+ 1. Repeat,
+ ...
+ k. Repeat, while innerAlive is true,
+ ...
+ viii. Else,
+ 1. Let innerValue be IteratorValue(innerNext).
+ 2. IfAbruptCloseAsyncIterator(innerValue, iterated).
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends AsyncIterator {
+ async next() {
+ return {done: false, value: 0};
+ }
+
+ closed = false;
+ async return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+class TestError extends Error {}
+class InnerIterator extends AsyncIterator {
+ async next() {
+ return {
+ done: false,
+ get value() {
+ throw new TestError();
+ },
+ };
+ }
+}
+
+const iter = new TestIterator();
+const mapped = iter.flatMap(x => new InnerIterator());
+
+assertEq(iter.closed, false);
+mapped.next().then(
+ _ => assertEq(true, false, 'Expected reject.'),
+ err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iter.closed, true);
+ }
+);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/flatMap/flatMap.js b/js/src/tests/non262/AsyncIterator/prototype/flatMap/flatMap.js
new file mode 100644
index 0000000000..dbd17cb33b
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/flatMap/flatMap.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+
+async function* inner(x) {
+ yield x;
+ yield x + 1;
+}
+
+let iter = gen().flatMap(x => inner(x));
+
+for (const v of [1, 2, 2, 3, 3, 4]) {
+ iter.next().then(
+ ({done, value}) => {
+ assertEq(done, false);
+ assertEq(value, v);
+ }
+ );
+}
+
+iter.next().then(({done}) => assertEq(done, true));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/flatMap/inner-empty-iterable.js b/js/src/tests/non262/AsyncIterator/prototype/flatMap/inner-empty-iterable.js
new file mode 100644
index 0000000000..3da588f444
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/flatMap/inner-empty-iterable.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.flatMap skips empty inner iterables.
+info: >
+ Iterator Helpers proposal 2.1.6.7
+ 1. Repeat,
+ ...
+ k. Repeat, while innerAlive is true,
+ ...
+ v. Let innerComplete be IteratorComplete(innerNext).
+ ...
+ vii. If innerComplete is true, set innerAlive to false.
+features: [iterator-helpers]
+---*/
+
+async function* gen(values) {
+ yield* values;
+}
+
+(async () => {
+ let iter = gen([0, 1, 2, 3]).flatMap(x => x % 2 ? gen([]) : gen([x]));
+
+ for (const expected of [0, 2]) {
+ const result = await iter.next();
+ assertEq(result.value, expected);
+ assertEq(result.done, false);
+ }
+
+ let result = await iter.next();
+ assertEq(result.value, undefined);
+ assertEq(result.done, true);
+
+ iter = gen([0, 1, 2, 3]).flatMap(x => gen([]));
+ result = await iter.next();
+ assertEq(result.value, undefined);
+ assertEq(result.done, true);
+})();
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/flatMap/inner-generator.js b/js/src/tests/non262/AsyncIterator/prototype/flatMap/inner-generator.js
new file mode 100644
index 0000000000..08c0dfbba7
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/flatMap/inner-generator.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.flatMap innerIterator can be a generator.
+info: >
+ Iterator Helpers proposal 2.1.6.7
+features: [iterator-helpers]
+---*/
+
+async function* gen() {
+ yield 1;
+ yield 2;
+}
+
+(async () => {
+ const iter = gen().flatMap(async function*(x) {
+ yield x;
+ yield* [x + 1, x + 2];
+ });
+
+ for (const expected of [1, 2, 3, 2, 3, 4]) {
+ const result = await iter.next();
+ assertEq(result.value, expected);
+ assertEq(result.done, false);
+ }
+
+ const result = await iter.next();
+ assertEq(result.value, undefined);
+ assertEq(result.done, true);
+})();
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/flatMap/length.js b/js/src/tests/non262/AsyncIterator/prototype/flatMap/length.js
new file mode 100644
index 0000000000..4e6862cd41
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/flatMap/length.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.flatMap length value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(AsyncIterator.prototype.flatMap.length, 1);
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/flatMap/name.js b/js/src/tests/non262/AsyncIterator/prototype/flatMap/name.js
new file mode 100644
index 0000000000..2aeebe0f85
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/flatMap/name.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.flatMap.name value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(AsyncIterator.prototype.flatMap.name, 'flatMap');
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/flatMap/throw-when-inner-not-iterable.js b/js/src/tests/non262/AsyncIterator/prototype/flatMap/throw-when-inner-not-iterable.js
new file mode 100644
index 0000000000..e854a8c8ae
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/flatMap/throw-when-inner-not-iterable.js
@@ -0,0 +1,71 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.flatMap closes the iterator and throws when mapped isn't iterable.
+info: >
+ Iterator Helpers proposal 2.1.6.7
+ 1. Repeat,
+ ...
+ h. Let innerIterator be GetIterator(mapped, async).
+ i. IfAbruptCloseAsyncIterator(innerIterator, iterated).
+features: [iterator-helpers]
+---*/
+
+class NotIterable {
+ async next() {
+ return {done: true};
+ }
+}
+
+class InvalidIterable {
+ [Symbol.asyncIterator]() {
+ return {};
+ }
+}
+
+class TestIterator extends AsyncIterator {
+ async next() {
+ return {done: false, value: 0};
+ }
+
+ closed = false;
+ async return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+const nonIterables = [
+ new NotIterable(),
+ new InvalidIterable(),
+ undefined,
+ null,
+ 0,
+ false,
+ Symbol(''),
+ 0n,
+ {},
+];
+
+(async () => {
+ for (const value of nonIterables) {
+ const iter = new TestIterator();
+ const mapped = iter.flatMap(x => value);
+
+ assertEq(iter.closed, false);
+ console.log("here!");
+ try {
+ await mapped.next();
+ assertEq(true, false, 'Expected reject');
+ } catch (exc) {
+ assertEq(exc instanceof TypeError, true);
+ }
+ assertEq(iter.closed, true);
+ }
+})();
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/forEach/async-writes.js b/js/src/tests/non262/AsyncIterator/prototype/forEach/async-writes.js
new file mode 100644
index 0000000000..25c4302ade
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/forEach/async-writes.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+let x = {a: () => true};
+
+async function* gen() {
+ yield x.a();
+ yield x.a();
+}
+
+gen().forEach(() => {}).then(
+ () => assertEq(true, false, 'expected error'),
+ err => assertEq(err instanceof Error, true),
+);
+
+x.a = () => {
+ throw Error();
+};
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/forEach/check-fn-after-getting-iterator.js b/js/src/tests/non262/AsyncIterator/prototype/forEach/check-fn-after-getting-iterator.js
new file mode 100644
index 0000000000..bcf77e56d1
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/forEach/check-fn-after-getting-iterator.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({done: true});
+ }
+}
+
+const iter = new Proxy(new TestIterator(), handlerProxy);
+iter.forEach(1).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TypeError, true);
+ assertEq(
+ log.join('\n'),
+ `get: forEach
+get: next`
+ );
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/forEach/descriptor.js b/js/src/tests/non262/AsyncIterator/prototype/forEach/descriptor.js
new file mode 100644
index 0000000000..8825422a28
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/forEach/descriptor.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ Descriptor property of AsyncIterator.prototype.forEach
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/forEach/error-from-correct-realm.js b/js/src/tests/non262/AsyncIterator/prototype/forEach/error-from-correct-realm.js
new file mode 100644
index 0000000000..32797fe750
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/forEach/error-from-correct-realm.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const otherGlobal = newGlobal({newCompartment: true});
+assertEq(TypeError !== otherGlobal.TypeError, true);
+
+async function *gen() {}
+
+gen().forEach().then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TypeError, true);
+});
+
+otherGlobal.AsyncIterator.prototype.forEach.call(gen()).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(
+ err instanceof otherGlobal.TypeError,
+ true,
+ 'TypeError comes from the realm of the method.',
+ );
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/forEach/fn-not-callable-throws.js b/js/src/tests/non262/AsyncIterator/prototype/forEach/fn-not-callable-throws.js
new file mode 100644
index 0000000000..c70e336bff
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/forEach/fn-not-callable-throws.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function *gen() {}
+
+function check(fn) {
+ gen().forEach(fn).then(() => {
+ throw new Error('every should have thrown');
+ },
+ (err) => {
+ assertEq(err instanceof TypeError, true);
+ });
+}
+
+check();
+check(undefined);
+check(null);
+check(0);
+check(false);
+check('');
+check(Symbol(''));
+check({});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/forEach/fn-throws-close-iterator.js b/js/src/tests/non262/AsyncIterator/prototype/forEach/fn-throws-close-iterator.js
new file mode 100644
index 0000000000..4e7d60412e
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/forEach/fn-throws-close-iterator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({ done: this.closed });
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = () => { throw new Error(); };
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+iter.forEach(fn).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof Error, true);
+ assertEq(iter.closed, true);
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/forEach/forEach.js b/js/src/tests/non262/AsyncIterator/prototype/forEach/forEach.js
new file mode 100644
index 0000000000..2109be5fd6
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/forEach/forEach.js
@@ -0,0 +1,11 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+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/AsyncIterator/prototype/forEach/interleaving-calls.js b/js/src/tests/non262/AsyncIterator/prototype/forEach/interleaving-calls.js
new file mode 100644
index 0000000000..c8c47bde45
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/forEach/interleaving-calls.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const log = [];
+async function* gen(n) {
+ log.push(`${n}`);
+ yield 1;
+ log.push(`${n}`);
+ yield 2;
+}
+
+Promise.all([gen(1).forEach(() => {}), gen(2).forEach(() => {})]).then(
+ () => {
+ assertEq(
+ log.join(' '),
+ '1 2 1 2',
+ );
+ },
+ err => {
+ throw err;
+ }
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/forEach/length.js b/js/src/tests/non262/AsyncIterator/prototype/forEach/length.js
new file mode 100644
index 0000000000..5e59af9fea
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/forEach/length.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ The `length` property of AsyncIterator.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(AsyncIterator.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/AsyncIterator/prototype/forEach/name.js b/js/src/tests/non262/AsyncIterator/prototype/forEach/name.js
new file mode 100644
index 0000000000..3053c3967f
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/forEach/name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ `name` property of AsyncIterator.prototype.forEach.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/forEach/next-throws-iterator-not-closed.js b/js/src/tests/non262/AsyncIterator/prototype/forEach/next-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..0c72c700e2
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/forEach/next-throws-iterator-not-closed.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestIterator extends AsyncIterator {
+ next() {
+ throw new Error();
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = () => {};
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+iter.forEach(fn).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof Error, true);
+ assertEq(iter.closed, false);
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/forEach/proxy.js b/js/src/tests/non262/AsyncIterator/prototype/forEach/proxy.js
new file mode 100644
index 0000000000..bab7a2e864
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/forEach/proxy.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+// 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 AsyncIterator {
+ value = 0;
+ next() {
+ const value = this.value;
+ if (value < 2) {
+ this.value = value + 1;
+ return Promise.resolve({done: false, value});
+ }
+ return Promise.resolve({done: true});
+ }
+}
+
+const iter = new Proxy(new Counter(), handlerProxy);
+iter.forEach(x => x).then(() => {
+ 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/AsyncIterator/prototype/forEach/this-not-iterator-throws.js b/js/src/tests/non262/AsyncIterator/prototype/forEach/this-not-iterator-throws.js
new file mode 100644
index 0000000000..c92536fbe6
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/forEach/this-not-iterator-throws.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const fn = x => x;
+function check(x) {
+ AsyncIterator.prototype.forEach.call(x, fn).then(
+ () => assertEq(true, false, 'expected error'),
+ err => {
+ assertEq(err instanceof TypeError, true);
+ }
+ );
+}
+
+check();
+check(undefined);
+check({});
+check({next: 0});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/forEach/value-throws-iterator-not-closed.js b/js/src/tests/non262/AsyncIterator/prototype/forEach/value-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..8611a0100f
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/forEach/value-throws-iterator-not-closed.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestError extends Error {}
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({
+ done: false,
+ get value() {
+ throw new TestError();
+ }
+ });
+ }
+
+ closed = false;
+ return() {
+ closed = true;
+ }
+}
+
+const iterator = new TestIterator();
+assertEq(iterator.closed, false, 'iterator starts unclosed');
+iterator.forEach(x => x).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iterator.closed, false, 'iterator remains unclosed');
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/generator-methods-throw-on-iterator-helpers.js b/js/src/tests/non262/AsyncIterator/prototype/generator-methods-throw-on-iterator-helpers.js
new file mode 100644
index 0000000000..0e5b6ac0b5
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/generator-methods-throw-on-iterator-helpers.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const asyncGeneratorProto = Object.getPrototypeOf(
+ Object.getPrototypeOf(
+ (async function *() {})()
+ )
+);
+
+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 => (async function*() {})()),
+];
+
+for (const method of methods) {
+ const iteratorHelper = method((async function*() {})());
+ asyncGeneratorProto.next.call(iteratorHelper).then(
+ _ => assertEq(true, false, 'Expected reject'),
+ err => assertEq(err instanceof TypeError, true),
+ );
+ asyncGeneratorProto.return.call(iteratorHelper).then(
+ _ => assertEq(true, false, 'Expected reject'),
+ err => assertEq(err instanceof TypeError, true),
+ );
+ asyncGeneratorProto.throw.call(iteratorHelper).then(
+ _ => assertEq(true, false, 'Expected reject'),
+ err => assertEq(err instanceof TypeError, true),
+ );
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/iterator-helper-methods-throw-on-generators.js b/js/src/tests/non262/AsyncIterator/prototype/iterator-helper-methods-throw-on-generators.js
new file mode 100644
index 0000000000..f79fb7d842
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/iterator-helper-methods-throw-on-generators.js
@@ -0,0 +1,12 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function *gen() { yield 'value'; }
+
+const asyncIteratorHelperProto = Object.getPrototypeOf(gen().map(x => x));
+
+assertThrowsInstanceOf(() => asyncIteratorHelperProto.next.call(gen()), TypeError);
+assertThrowsInstanceOf(() => asyncIteratorHelperProto.return.call(gen()), TypeError);
+assertThrowsInstanceOf(() => asyncIteratorHelperProto.throw.call(gen()), TypeError);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-from-other-global.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-from-other-global.js
new file mode 100644
index 0000000000..8b7a945fd5
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-from-other-global.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen(values) {
+ yield* values;
+}
+
+const otherAsyncIteratorProto = newGlobal({newCompartment: true}).AsyncIterator.prototype;
+
+const methods = [
+ ["map", x => x],
+ ["filter", x => true],
+ ["take", Infinity],
+ ["drop", 0],
+ ["asIndexedPairs", undefined],
+ ["flatMap", x => gen([x])],
+];
+
+(async () => {
+ for (const [method, arg] of methods) {
+ const iterator = gen([1, 2, 3]);
+ const helper = otherAsyncIteratorProto[method].call(iterator, arg);
+
+ for (const expected of [1, 2, 3]) {
+ const {done, value} = await helper.next();
+ assertEq(done, false);
+ assertEq(Array.isArray(value) ? value[1] : value, expected);
+ }
+
+ const {done, value} = await helper.next();
+ assertEq(done, true);
+ assertEq(value, undefined);
+ }
+})();
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-handle-empty-iterators.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-handle-empty-iterators.js
new file mode 100644
index 0000000000..b1bd426dd8
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-handle-empty-iterators.js
@@ -0,0 +1,42 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods handle empty iterators.
+info: >
+ Iterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class EmptyIterator extends AsyncIterator {
+ async next() {
+ return {done: true};
+ }
+}
+
+async function* gen() {}
+
+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 => gen()),
+];
+
+for (const method of methods) {
+ for (const iterator of [new EmptyIterator(), gen()]) {
+ method(iterator).next().then(
+ ({done, value}) => {
+ assertEq(done, true);
+ assertEq(value, undefined);
+ }
+ );
+ }
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-interleaved.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-interleaved.js
new file mode 100644
index 0000000000..98c2a2b680
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-interleaved.js
@@ -0,0 +1,59 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% method calls can be interleaved.
+info: >
+ Iterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends AsyncIterator {
+ value = 0;
+ async next() {
+ return {done: false, value: this.value++};
+ }
+}
+
+function unwrapResult(value) {
+ // Unwrap the asIndexedPair return values.
+ while (Array.isArray(value)) {
+ value = value[1];
+ }
+ return value;
+}
+
+function check({done, value}, expectedDone, expectedValue) {
+ assertEq(done, expectedDone);
+ assertEq(unwrapResult(value), expectedValue);
+}
+
+const methods = [
+ ['map', x => x],
+ ['filter', x => true],
+ ['take', Infinity],
+ ['drop', 0],
+ ['asIndexedPairs', undefined],
+ ['flatMap', async function*(x) { yield x; }],
+];
+
+(async () => {
+ for (const [firstMethod, firstArg] of methods) {
+ for (const [secondMethod, secondArg] of methods) {
+ const iterator = new TestIterator();
+
+ const firstHelper = iterator[firstMethod](firstArg);
+ const secondHelper = iterator[secondMethod](secondArg);
+
+ check(await firstHelper.next(), false, 0);
+ check(await secondHelper.next(), false, 1);
+ check(await firstHelper.next(), false, 2);
+ check(await secondHelper.next(), false, 3);
+ }
+ }
+})();
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-closed-on-call-throws.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-closed-on-call-throws.js
new file mode 100644
index 0000000000..1a52d113f9
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-closed-on-call-throws.js
@@ -0,0 +1,49 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods close the iterator if callback throws.
+info: >
+ AsyncIterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+class TestAsyncIterator extends AsyncIterator {
+ async next() {
+ return {done: false, value: 1};
+ }
+
+ closed = false;
+ async 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 TestAsyncIterator();
+ assertEq(iter.closed, false);
+ method(iter).next().then(
+ _ => assertEq(true, false, 'Expected reject'),
+ err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iter.closed, true);
+ },
+ );
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
+
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-closed-on-yield-throws.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-closed-on-yield-throws.js
new file mode 100644
index 0000000000..bec857eb33
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-closed-on-yield-throws.js
@@ -0,0 +1,53 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods close the iterator if `yield` throws.
+info: >
+ AsyncIterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+class TestAsyncIterator extends AsyncIterator {
+ async next() {
+ return {done: false, value: 1};
+ }
+
+ closed = false;
+ async return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+async function* gen(x) { yield x; }
+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(gen),
+];
+
+for (const method of methods) {
+ const iterator = new TestAsyncIterator();
+ const iteratorHelper = method(iterator);
+
+ assertEq(iterator.closed, false);
+ iteratorHelper.next().then(
+ _ => iteratorHelper.throw(new TestError()).then(
+ _ => assertEq(true, false, 'Expected reject'),
+ err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iterator.closed, true);
+ },
+ ),
+ );
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-get-then-throws.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-get-then-throws.js
new file mode 100644
index 0000000000..a9c8a6ebca
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-get-then-throws.js
@@ -0,0 +1,57 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods don't close the iterator if getting `then` throws.
+info: >
+ AsyncIterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+
+class TestIterator extends AsyncIterator {
+ next() {
+ return {
+ get then() {
+ throw new TestError();
+ }
+ };
+ }
+
+ closed = false;
+ async return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+const methods = [
+ ["map", x => x],
+ ["filter", x => true],
+ ["take", Infinity],
+ ["drop", 0],
+ ["asIndexedPairs", undefined],
+ ["flatMap", async function*(x) { yield x; }],
+];
+
+(async () => {
+ for (const [method, arg] of methods) {
+ const iterator = new TestIterator();
+ assertEq(iterator.closed, false);
+
+ try {
+ await iterator[method](arg).next();
+ assertEq(true, false, 'Expected exception');
+ } catch(err) {
+ console.log(err);
+ assertEq(err instanceof TestError, true);
+ }
+ assertEq(iterator.closed, false);
+ }
+})();
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-promise-executor-throws.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-promise-executor-throws.js
new file mode 100644
index 0000000000..838c381b17
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-promise-executor-throws.js
@@ -0,0 +1,53 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods don't close the iterator if executor of Promise returned by `.next` throws.
+info: >
+ AsyncIterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+class TestIterator extends AsyncIterator {
+ next() {
+ return new Promise((resolve, reject) => {
+ throw new TestError();
+ });
+ }
+
+ closed = false;
+ async return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+const methods = [
+ ["map", x => x],
+ ["filter", x => true],
+ ["take", Infinity],
+ ["drop", 0],
+ ["asIndexedPairs", undefined],
+ ["flatMap", async function*(x) { yield x; }],
+];
+
+(async () => {
+ for (const [method, arg] of methods) {
+ const iterator = new TestIterator();
+ assertEq(iterator.closed, false);
+
+ try {
+ await iterator[method](arg).next();
+ assertEq(true, false, 'Expected exception');
+ } catch(err) {
+ assertEq(err instanceof TestError, true);
+ }
+ assertEq(iterator.closed, false);
+ }
+})();
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-returns-reject.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-returns-reject.js
new file mode 100644
index 0000000000..65eede2a6b
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-returns-reject.js
@@ -0,0 +1,51 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods don't close the iterator if `.next` returns a rejected Promise.
+info: >
+ AsyncIterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.reject(new TestError());
+ }
+
+ closed = false;
+ async return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+const methods = [
+ ["map", x => x],
+ ["filter", x => true],
+ ["take", Infinity],
+ ["drop", 0],
+ ["asIndexedPairs", undefined],
+ ["flatMap", async function*(x) { yield x; }],
+];
+
+(async () => {
+ for (const [method, arg] of methods) {
+ const iterator = new TestIterator();
+ assertEq(iterator.closed, false);
+
+ try {
+ await iterator[method](arg).next();
+ assertEq(true, false, 'Expected exception');
+ } catch(err) {
+ assertEq(err instanceof TestError, true);
+ }
+ assertEq(iterator.closed, false);
+ }
+})();
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-then-throws.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-then-throws.js
new file mode 100644
index 0000000000..609a49c3c7
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-then-throws.js
@@ -0,0 +1,57 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods don't close the iterator if `then` returned by `next` throws.
+info: >
+ AsyncIterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+
+class TestIterator extends AsyncIterator {
+ next() {
+ return {
+ then() {
+ throw new TestError();
+ }
+ };
+ }
+
+ closed = false;
+ async return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+const methods = [
+ ["map", x => x],
+ ["filter", x => true],
+ ["take", Infinity],
+ ["drop", 0],
+ ["asIndexedPairs", undefined],
+ ["flatMap", async function*(x) { yield x; }],
+];
+
+(async () => {
+ for (const [method, arg] of methods) {
+ const iterator = new TestIterator();
+ assertEq(iterator.closed, false);
+
+ try {
+ await iterator[method](arg).next();
+ assertEq(true, false, 'Expected exception');
+ } catch(err) {
+ console.log(err);
+ assertEq(err instanceof TestError, true);
+ }
+ assertEq(iterator.closed, false);
+ }
+})();
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-throws.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-throws.js
new file mode 100644
index 0000000000..ff42a3f7b6
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-next-throws.js
@@ -0,0 +1,49 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods don't close the iterator if `.next` call throws.
+info: >
+ AsyncIterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+class TestAsyncIterator extends AsyncIterator {
+ next() {
+ throw new TestError();
+ }
+
+ closed = false;
+ async return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+async function* gen(x) { yield x; }
+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(gen),
+];
+
+for (const method of methods) {
+ const iterator = new TestAsyncIterator();
+ assertEq(iterator.closed, false);
+ method(iterator).next().then(
+ _ => assertEq(true, false, 'Expected reject'),
+ err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iterator.closed, false);
+ },
+ );
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-value-throws.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-value-throws.js
new file mode 100644
index 0000000000..1578070553
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-not-closed-on-value-throws.js
@@ -0,0 +1,54 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods don't close the iterator if `value` throws.
+info: >
+ AsyncIterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+class TestAsyncIterator extends AsyncIterator {
+ async next() {
+ return {
+ get value() {
+ throw new TestError();
+ }
+ };
+ }
+
+ closed = false;
+ async return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+const iterator = new TestAsyncIterator();
+
+async function* gen(x) { yield x; }
+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(gen),
+];
+
+for (const method of methods) {
+ assertEq(iterator.closed, false);
+ method(iterator).next().then(
+ _ => assertEq(true, false, 'Expected reject'),
+ err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iterator.closed, false);
+ },
+ );
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-returns-done-generator-finishes.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-returns-done-generator-finishes.js
new file mode 100644
index 0000000000..d7e2be8f5d
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-iterator-returns-done-generator-finishes.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestIterator extends AsyncIterator {
+ async next() {
+ return {done: true, value: 'value'};
+ }
+}
+
+async function* gen(x) { yield x; }
+
+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(gen),
+];
+
+(async () => {
+ for (const method of methods) {
+ const iterator = method(new TestIterator());
+ const {done, value} = await iterator.next();
+ assertEq(done, true);
+ assertEq(value, undefined);
+ }
+})();
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-multiple-return-close-iterator-once.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-multiple-return-close-iterator-once.js
new file mode 100644
index 0000000000..4ccb6fd4b1
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-multiple-return-close-iterator-once.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Calling `.return()` on a lazy %AsyncIterator.prototype% method multiple times closes the source iterator once.
+info: >
+ Iterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends AsyncIterator {
+ async next() {
+ return {done: false, value: 1};
+ }
+
+ closeCount = 0;
+ async return(value) {
+ this.closeCount++;
+ return {done: true, value};
+ }
+}
+
+async function* gen(x) { yield x; }
+
+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(gen),
+];
+
+(async () => {
+ // Call `return` after stepping the iterator once:
+ for (const method of methods) {
+ const iter = new TestIterator();
+ const iterHelper = method(iter);
+
+ await iterHelper.next();
+ assertEq(iter.closeCount, 0);
+ await iterHelper.return();
+ assertEq(iter.closeCount, 1);
+ await 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);
+ await iterHelper.return();
+ assertEq(iter.closeCount, 1);
+ await iterHelper.return();
+ assertEq(iter.closeCount, 1);
+ }
+})();
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-multiple-throw-close-iterator-once.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-multiple-throw-close-iterator-once.js
new file mode 100644
index 0000000000..45e88be26a
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-multiple-throw-close-iterator-once.js
@@ -0,0 +1,90 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Calling `throw` on a lazy %AsyncIterator.prototype% method multiple times closes the source iterator once.
+info: >
+ Iterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+
+class TestIterator extends AsyncIterator {
+ async next() {
+ return {done: false, value: 1};
+ }
+
+ closeCount = 0;
+ async return(value) {
+ this.closeCount++;
+ return {done: true, value};
+ }
+}
+
+async function* gen(x) { yield x; }
+
+const methods = [
+ iter => iter.map(x => x),
+ iter => iter.filter(x => true),
+ iter => iter.take(Infinity),
+ iter => iter.drop(0),
+ iter => iter.asIndexedPairs(),
+ iter => iter.flatMap(gen),
+];
+
+(async () => {
+ // Call `throw` after stepping the iterator once:
+ for (const method of methods) {
+ const iter = new TestIterator();
+ const iterHelper = method(iter);
+
+ await iterHelper.next()
+ assertEq(iter.closeCount, 0);
+
+ try {
+ await iterHelper.throw(new TestError());
+ assertEq(true, false, 'Expected reject');
+ } catch (exc) {
+ assertEq(exc instanceof TestError, true);
+ }
+ assertEq(iter.closeCount, 1);
+
+ try {
+ await iterHelper.throw(new TestError());
+ assertEq(true, false, 'Expected reject');
+ } catch (exc) {
+ assertEq(exc instanceof TestError, true);
+ }
+ 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);
+
+ try {
+ await iterHelper.throw(new TestError());
+ assertEq(true, false, 'Expected reject');
+ } catch (exc) {
+ assertEq(exc instanceof TestError, true);
+ }
+ assertEq(iter.closeCount, 1);
+
+ try {
+ await iterHelper.throw(new TestError());
+ assertEq(true, false, 'Expected reject');
+ } catch (exc) {
+ assertEq(exc instanceof TestError, true);
+ }
+ assertEq(iter.closeCount, 1);
+ }
+})();
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-mutate-iterator-after-done.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-mutate-iterator-after-done.js
new file mode 100644
index 0000000000..b9a37234a8
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-mutate-iterator-after-done.js
@@ -0,0 +1,49 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+//
+
+/*---
+esid: pending
+description: %AsyncIterator.prototype% methods ignore iterator mutation if already done.
+info: >
+ Iterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends AsyncIterator {
+ values = [1, 2];
+ async next() {
+ if (this.values.length == 0)
+ return {done: true};
+ return {done: false, value: this.values.shift()};
+ }
+}
+
+function check({done, value}, expectedDone, expectedValue) {
+ assertEq(done, expectedDone);
+ assertEq(Array.isArray(value) ? value[1] : value, expectedValue);
+}
+
+const methods = [
+ ['map', x => x],
+ ['filter', x => true],
+ ['take', Infinity],
+ ['drop', 0],
+ ['asIndexedPairs', undefined],
+ ['flatMap', async function*(x) { yield x; }],
+];
+
+for (const [method, arg] of methods) {
+ (async () => {
+ const iter = new TestIterator();
+ const iterHelper = iter[method](arg);
+ check(await iterHelper.next(), false, 1);
+ check(await iterHelper.next(), false, 2);
+ check(await iterHelper.next(), true, undefined);
+ iter.values.push(3);
+ check(await iterHelper.next(), true, undefined);
+ })();
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-mutate-iterator.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-mutate-iterator.js
new file mode 100644
index 0000000000..876990d945
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-mutate-iterator.js
@@ -0,0 +1,49 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+//
+
+/*---
+esid: pending
+description: %AsyncIterator.prototype% methods work properly if the iterator has been mutated.
+info: >
+ Iterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends AsyncIterator {
+ values = [1, 2];
+ async next() {
+ if (this.values.length == 0)
+ return {done: true};
+ return {done: false, value: this.values.shift()};
+ }
+}
+
+function check({done, value}, expectedDone, expectedValue) {
+ assertEq(done, expectedDone);
+ assertEq(Array.isArray(value) ? value[1] : value, expectedValue);
+}
+
+const methods = [
+ ['map', x => x],
+ ['filter', x => true],
+ ['take', Infinity],
+ ['drop', 0],
+ ['asIndexedPairs', undefined],
+ ['flatMap', async function*(x) { yield x; }],
+];
+
+for (const [method, arg] of methods) {
+ (async () => {
+ const iter = new TestIterator();
+ const iterHelper = iter[method](arg);
+ check(await iterHelper.next(), false, 1);
+ check(await iterHelper.next(), false, 2);
+ iter.values.push(3);
+ check(await iterHelper.next(), false, 3);
+ check(await iterHelper.next(), true, undefined);
+ })();
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-not-close-iterator-next-reject.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-not-close-iterator-next-reject.js
new file mode 100644
index 0000000000..43d84ae17d
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-not-close-iterator-next-reject.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods don't close the iterator if `next` returns rejected promise.
+info: >
+ AsyncIterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.reject('rejection');
+ }
+
+ closed = false;
+ async return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+async function* gen(x) { yield x; }
+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(gen),
+];
+
+for (const method of methods) {
+ const iterator = new TestIterator();
+ assertEq(iterator.closed, false);
+ method(iterator).next().then(
+ _ => assertEq(true, false, 'Expected reject'),
+ err => {
+ assertEq(err, 'rejection');
+ assertEq(iterator.closed, false);
+ },
+ );
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-pass-through-lastValue.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-pass-through-lastValue.js
new file mode 100644
index 0000000000..40da229ca6
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-pass-through-lastValue.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestAsyncIterator extends AsyncIterator {
+ async 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 TestAsyncIterator();
+ const iteratorHelper = method(iterator);
+ iteratorHelper.next().then(
+ _ => iteratorHelper.next('last value').then(
+ ({done, value}) => {
+ assertEq(done, false);
+ // Unwrap the return value from asIndexedPairs.
+ assertEq(Array.isArray(value) ? value[1] : value, 'last value');
+ }
+ ),
+ );
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
+
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-pass-value-through-chain.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-pass-value-through-chain.js
new file mode 100644
index 0000000000..8b5506ee97
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-pass-value-through-chain.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestAsyncIterator extends AsyncIterator {
+ async 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 TestAsyncIterator();
+ const iteratorChain = outerMethod(innerMethod(iterator));
+ iteratorChain.next().then(
+ _ => iteratorChain.next('last value').then(
+ ({done, value}) => {
+ assertEq(done, false);
+ // Unwrap the asIndexedPair return values.
+ while (Array.isArray(value)) {
+ value = value[1];
+ }
+ assertEq(value, 'last value');
+ }
+ ),
+ );
+ }
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
+
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-proxy-accesses.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-proxy-accesses.js
new file mode 100644
index 0000000000..5892a41e5b
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-proxy-accesses.js
@@ -0,0 +1,68 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods access specified properties only.
+info: >
+ Iterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+let log;
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args.filter(x => typeof x != 'object').map(x => x.toString())}`);
+ return Reflect[key](...args);
+ },
+});
+
+class TestIterator extends AsyncIterator {
+ value = 0;
+ async next() {
+ if (this.value < 1)
+ return new Proxy({done: false, value: this.value++}, handlerProxy);
+ return new Proxy({done: true, value: undefined}, handlerProxy);
+ }
+}
+
+const methods = [
+ ['map', x => x],
+ ['filter', x => true],
+ ['take', 4],
+ ['drop', 0],
+ ['asIndexedPairs', undefined],
+ ['flatMap', async function*(x) { yield x; }],
+];
+
+(async () => {
+ for (const [method, argument] of methods) {
+ log = [];
+ const iteratorProxy = new Proxy(new TestIterator(), handlerProxy);
+ const iteratorHelper = iteratorProxy[method](argument);
+
+ await iteratorHelper.next();
+ await iteratorHelper.next();
+ const {done} = await iteratorHelper.next();
+ assertEq(done, true);
+ assertEq(
+ log.join('\n'),
+ `get: ${method}
+get: next
+get: value
+get: value
+set: value,1
+getOwnPropertyDescriptor: value
+defineProperty: value
+get: then
+get: done
+get: value
+get: value
+get: then
+get: done`
+ );
+ }
+})();
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-return-closes-iterator.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-return-closes-iterator.js
new file mode 100644
index 0000000000..98a0902b75
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-return-closes-iterator.js
@@ -0,0 +1,63 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Calling `return` on a lazy %AsyncIterator.prototype% method closes the source iterator.
+info: >
+ Iterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends AsyncIterator {
+ async next() {
+ return {done: false, value: 1};
+ }
+
+ closed = false;
+ async return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+async function* gen(x) { yield x; }
+
+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(gen),
+];
+
+for (const method of methods) {
+ const iter = new TestIterator();
+ const iterHelper = method(iter);
+
+ iterHelper.next().then(() => {
+ assertEq(iter.closed, false);
+ iterHelper.return(0).then(({done, value}) => {
+ assertEq(iter.closed, true);
+ assertEq(done, true);
+ assertEq(value, 0);
+ });
+ });
+}
+
+for (const method of methods) {
+ const iter = new TestIterator();
+ const iterHelper = method(iter);
+
+ assertEq(iter.closed, false);
+ iterHelper.return(0).then(({done, value}) => {
+ assertEq(iter.closed, true);
+ assertEq(done, true);
+ assertEq(value, 0);
+ });
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-return-new-iterator-result.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-return-new-iterator-result.js
new file mode 100644
index 0000000000..02cae2740d
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-return-new-iterator-result.js
@@ -0,0 +1,42 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy Iterator Helper methods return new iterator result objects.
+info: >
+ Iterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+const iterResult = {done: false, value: 1, testProperty: 'test'};
+class TestIterator extends AsyncIterator {
+ async next() {
+ return iterResult;
+ }
+}
+
+async function* gen(x) { yield x; }
+
+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(gen),
+];
+
+// Call `return` before stepping the iterator:
+for (const method of methods) {
+ const iter = new TestIterator();
+ const iterHelper = method(iter);
+ iterHelper.next().then(result => {
+ assertEq(result == iterResult, false);
+ assertEq(result.testProperty, undefined);
+ });
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-closes-iterator-before-next.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-closes-iterator-before-next.js
new file mode 100644
index 0000000000..4e9d9f6421
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-closes-iterator-before-next.js
@@ -0,0 +1,58 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Calling `throw` on a lazy %AsyncIterator.prototype% method closes the source iterator.
+info: >
+ Iterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+
+class TestIterator extends AsyncIterator {
+ async next() {
+ return {done: false, value: 1};
+ }
+
+ closed = false;
+ async return(value) {
+ this.closed = true;
+ return {done: true, value};
+ }
+}
+
+async function* gen(x) { yield x; }
+
+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(gen),
+];
+
+for (const method of methods) {
+ const iter = new TestIterator();
+ const iterHelper = method(iter);
+
+ assertEq(iter.closed, false);
+ iterHelper.throw(new TestError()).then(
+ _ => assertEq(true, false, 'Expected reject.'),
+ err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iter.closed, true);
+
+ iterHelper.next().then(({done, value}) => {
+ assertEq(done, true);
+ assertEq(value, undefined);
+ });
+ },
+ );
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-eagerly-on-next-non-callable.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-eagerly-on-next-non-callable.js
new file mode 100644
index 0000000000..489887d020
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-eagerly-on-next-non-callable.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods throw eagerly when `next` is non-callable.
+info: >
+ Iterator Helpers proposal 1.1.1
+features: [iterator-helpers]
+---*/
+
+async function* gen(x) { yield x; }
+const methods = [
+ next => AsyncIterator.prototype.map.bind({next}, x => x),
+ next => AsyncIterator.prototype.filter.bind({next}, x => x),
+ next => AsyncIterator.prototype.take.bind({next}, 1),
+ next => AsyncIterator.prototype.drop.bind({next}, 0),
+ next => AsyncIterator.prototype.asIndexedPairs.bind({next}),
+ next => AsyncIterator.prototype.flatMap.bind({next}, gen),
+];
+
+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/AsyncIterator/prototype/lazy-methods-throw-eagerly-on-non-callable.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-eagerly-on-non-callable.js
new file mode 100644
index 0000000000..d8a9b390fa
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-eagerly-on-non-callable.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods throw eagerly when passed non-callables.
+info: >
+ Iterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+async function* gen() {}
+
+const methods = [
+ (iter, fn) => iter.map(fn),
+ (iter, fn) => iter.filter(fn),
+ (iter, fn) => iter.flatMap(fn),
+];
+
+for (const method of methods) {
+ assertThrowsInstanceOf(() => method(AsyncIterator.prototype, 0), TypeError);
+ assertThrowsInstanceOf(() => method(AsyncIterator.prototype, false), TypeError);
+ assertThrowsInstanceOf(() => method(AsyncIterator.prototype, undefined), TypeError);
+ assertThrowsInstanceOf(() => method(AsyncIterator.prototype, null), TypeError);
+ assertThrowsInstanceOf(() => method(AsyncIterator.prototype, ''), TypeError);
+ assertThrowsInstanceOf(() => method(AsyncIterator.prototype, Symbol('')), TypeError);
+ assertThrowsInstanceOf(() => method(AsyncIterator.prototype, {}), TypeError);
+
+ assertThrowsInstanceOf(() => method(gen(), 0), TypeError);
+ assertThrowsInstanceOf(() => method(gen(), false), TypeError);
+ assertThrowsInstanceOf(() => method(gen(), undefined), TypeError);
+ assertThrowsInstanceOf(() => method(gen(), null), TypeError);
+ assertThrowsInstanceOf(() => method(gen(), ''), TypeError);
+ assertThrowsInstanceOf(() => method(gen(), Symbol('')), TypeError);
+ assertThrowsInstanceOf(() => method(gen(), {}), TypeError);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-eagerly-on-non-iterator.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-eagerly-on-non-iterator.js
new file mode 100644
index 0000000000..1a61f5001a
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-eagerly-on-non-iterator.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods throw eagerly when called on non-iterators.
+info: >
+ AsyncIterator Helpers proposal 1.1.1
+features: [iterator-helpers]
+---*/
+
+async function* gen(x) { yield x; }
+
+const methods = [
+ iter => AsyncIterator.prototype.map.bind(iter, x => x),
+ iter => AsyncIterator.prototype.filter.bind(iter, x => x),
+ iter => AsyncIterator.prototype.take.bind(iter, 1),
+ iter => AsyncIterator.prototype.drop.bind(iter, 0),
+ iter => AsyncIterator.prototype.asIndexedPairs.bind(iter),
+ iter => AsyncIterator.prototype.flatMap.bind(iter, gen),
+];
+
+for (const method of methods) {
+ for (const value of [undefined, null, 0, false, '', Symbol(''), {}, []]) {
+ assertThrowsInstanceOf(method(value), TypeError);
+ }
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-next-done-throws.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-next-done-throws.js
new file mode 100644
index 0000000000..276e59fc86
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-next-done-throws.js
@@ -0,0 +1,53 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods throw if `next.done` throws.
+info: >
+ AsyncIterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestError extends Error {}
+class TestAsyncIterator extends AsyncIterator {
+ async next() {
+ return {
+ get done() {
+ throw new TestError();
+ }
+ };
+ }
+
+ closed = false;
+ async return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+async function* gen(x) { yield x; }
+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(gen),
+];
+
+for (const method of methods) {
+ const iterator = new TestAsyncIterator();
+ assertEq(iterator.closed, false);
+ method(iterator).next().then(
+ _ => assertEq(true, false, 'Expected reject'),
+ err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iterator.closed, false);
+ },
+ );
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-next-not-object.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-next-not-object.js
new file mode 100644
index 0000000000..bb38a67000
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-next-not-object.js
@@ -0,0 +1,50 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: Lazy %AsyncIterator.prototype% methods throw if `next` call returns a non-object.
+info: >
+ Iterator Helpers proposal 2.1.6
+features: [iterator-helpers]
+---*/
+
+class TestAsyncIterator extends AsyncIterator {
+ async next(value) {
+ return value;
+ }
+
+ closed = false;
+ async return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+async function* gen(x) { yield x; }
+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(gen),
+];
+
+for (const method of methods) {
+ for (const value of [undefined, null, 0, false, '', Symbol('')]) {
+ const iterator = new TestAsyncIterator();
+ assertEq(iterator.closed, false);
+ method(iterator).next(value).then(
+ _ => assertEq(true, false, 'Expected reject'),
+ err => {
+ assertEq(err instanceof TypeError, true);
+ assertEq(iterator.closed, false);
+ },
+ );
+ }
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-on-reentry.js b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-on-reentry.js
new file mode 100644
index 0000000000..d7a582c6c1
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/lazy-methods-throw-on-reentry.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen(x) { yield x; }
+
+const methods = ['map', 'filter', 'flatMap'];
+
+for (const method of methods) {
+ const iter = gen('value');
+ const iterHelper = iter[method](x => iterHelper.next());
+ iterHelper.next().then(
+ _ => assertEq(true, false, 'Expected reject.'),
+ err => assertEq(err instanceof TypeError, true),
+ );
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
+
diff --git a/js/src/tests/non262/AsyncIterator/prototype/map/length.js b/js/src/tests/non262/AsyncIterator/prototype/map/length.js
new file mode 100644
index 0000000000..4bd55f92e0
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/map/length.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.map length value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(AsyncIterator.prototype.map.length, 1);
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/map/map.js b/js/src/tests/non262/AsyncIterator/prototype/map/map.js
new file mode 100644
index 0000000000..b3adb5cd6c
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/map/map.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+
+const iter = gen().map(x => x**2);
+
+for (const v of [1, 4, 9]) {
+ iter.next().then(
+ ({done, value}) => {
+ assertEq(done, false);
+ assertEq(value, v);
+ }
+ );
+}
+
+iter.next().then(({done}) => assertEq(done, true));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/map/name.js b/js/src/tests/non262/AsyncIterator/prototype/map/name.js
new file mode 100644
index 0000000000..efb7181966
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/map/name.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.map.name value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(AsyncIterator.prototype.map.name, 'map');
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/reduce/accumulator-set-to-initial-value.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/accumulator-set-to-initial-value.js
new file mode 100644
index 0000000000..943094aabc
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/accumulator-set-to-initial-value.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const reducer = (acc, _) => acc;
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+
+gen().reduce(reducer, 0).then(value => assertEq(value, 0));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/async-writes.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/async-writes.js
new file mode 100644
index 0000000000..2328cc3521
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/async-writes.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+let x = {a: () => true};
+
+async function* gen() {
+ yield x.a();
+ yield x.a();
+}
+
+gen().reduce(() => {}, 0).then(
+ () => assertEq(true, false, 'expected error'),
+ err => assertEq(err instanceof Error, true),
+);
+
+x.a = () => {
+ throw Error();
+};
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/check-fn-after-getting-iterator.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/check-fn-after-getting-iterator.js
new file mode 100644
index 0000000000..4a5484f786
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/check-fn-after-getting-iterator.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({ done: this.closed });
+ }
+}
+
+const iter = new Proxy(new TestIterator(), handlerProxy);
+iter.reduce(1).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TypeError, true);
+ assertEq(
+ log.join('\n'),
+ `get: reduce
+get: next`
+ );
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/descriptor.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/descriptor.js
new file mode 100644
index 0000000000..6472c1a14d
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/descriptor.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ Descriptor property of AsyncIterator.prototype.reduce
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/reduce/empty-iterator-without-initial-value-throws.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/empty-iterator-without-initial-value-throws.js
new file mode 100644
index 0000000000..c54fccba20
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/empty-iterator-without-initial-value-throws.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {}
+gen().reduce((x, y) => x + y).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TypeError, true);
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/error-from-correct-realm.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/error-from-correct-realm.js
new file mode 100644
index 0000000000..16c0ac51a9
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/error-from-correct-realm.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const otherGlobal = newGlobal({newCompartment: true});
+assertEq(TypeError !== otherGlobal.TypeError, true);
+
+async function *gen() {}
+
+gen().reduce().then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TypeError, true);
+});
+
+otherGlobal.AsyncIterator.prototype.reduce.call(gen()).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(
+ err instanceof otherGlobal.TypeError,
+ true,
+ 'TypeError comes from the realm of the method.',
+ );
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/interleaving-calls.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/interleaving-calls.js
new file mode 100644
index 0000000000..8961c69903
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/interleaving-calls.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const log = [];
+async function* gen(n) {
+ log.push(`${n}`);
+ yield 1;
+ log.push(`${n}`);
+ yield 2;
+}
+
+Promise.all([gen(1).reduce(() => {}, 0), gen(2).reduce(() => {}, 0)]).then(
+ () => {
+ assertEq(
+ log.join(' '),
+ '1 2 1 2',
+ );
+ },
+ err => {
+ throw err;
+ }
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/iterator-empty-return-initial-value.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/iterator-empty-return-initial-value.js
new file mode 100644
index 0000000000..b664d25729
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/iterator-empty-return-initial-value.js
@@ -0,0 +1,9 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const reducer = (x, y) => 0;
+async function *gen() {}
+
+gen().reduce(reducer, 1).then(result => assertEq(result, 1));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/iterator-next-return-non-object-throws.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/iterator-next-return-non-object-throws.js
new file mode 100644
index 0000000000..57c244d603
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/iterator-next-return-non-object-throws.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestIterator extends AsyncIterator {
+ constructor(value) {
+ super();
+ this.value = value;
+ }
+
+ next() {
+ return Promise.resolve(this.value);
+ }
+}
+
+const sum = (x, y) => x + y;
+function check(value) {
+ const iter = new TestIterator(value);
+ iter.reduce(sum).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TypeError, true);
+ });
+}
+
+check();
+check(undefined);
+check(null);
+check(0);
+check(false);
+check('');
+check(Symbol(''));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/left-associative.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/left-associative.js
new file mode 100644
index 0000000000..91147a1fba
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/left-associative.js
@@ -0,0 +1,15 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+
+gen().reduce((x, y) => `(${x}+${y})`, 0)
+ .then(result => assertEq(result, '(((0+1)+2)+3)'));
+gen().reduce((x, y) => `(${x}+${y})`)
+ .then(result => assertEq(result, '((1+2)+3)'));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/length.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/length.js
new file mode 100644
index 0000000000..022df65164
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/length.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ The `length` property of AsyncIterator.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(AsyncIterator.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/AsyncIterator/prototype/reduce/name.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/name.js
new file mode 100644
index 0000000000..aada19b46d
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ `name` property of AsyncIterator.prototype.reduce.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/reduce/next-throws-iterator-not-closed.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/next-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..796cdb1895
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/next-throws-iterator-not-closed.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestIterator extends AsyncIterator {
+ next() {
+ throw new Error();
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const sum = (x, y) => x + y;
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+iter.reduce(sum).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof Error, true);
+ assertEq(iter.closed, false);
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/no-initial-value-set-accumulator-to-first-value.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/no-initial-value-set-accumulator-to-first-value.js
new file mode 100644
index 0000000000..0e480dbe4a
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/no-initial-value-set-accumulator-to-first-value.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const reducer = (acc, _) => acc;
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+
+gen().reduce(reducer).then(result => assertEq(result, 1));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/proxy.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/proxy.js
new file mode 100644
index 0000000000..b1e6d52495
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/proxy.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+// 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 AsyncIterator {
+ value = 0;
+ next() {
+ const value = this.value;
+ if (value < 2) {
+ this.value = value + 1;
+ return Promise.resolve({done: false, value});
+ }
+ return Promise.resolve({done: true});
+ }
+}
+
+const iter = new Proxy(new Counter(), handlerProxy);
+iter.reduce((x, y) => x + y).then(() => {
+ 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/AsyncIterator/prototype/reduce/reduce.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/reduce.js
new file mode 100644
index 0000000000..d2382e4d53
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/reduce.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const reducer = (acc, value) => acc + value;
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+
+gen().reduce(reducer, 0).then(result => assertEq(result, 6));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/reducer-not-callable-throws.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/reducer-not-callable-throws.js
new file mode 100644
index 0000000000..c7fb2005d8
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/reducer-not-callable-throws.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function *gen() {}
+
+function check(fn) {
+ gen().reduce(fn).then(() => {
+ throw new Error('every should have thrown');
+ },
+ err => {
+ assertEq(err instanceof TypeError, true);
+ });
+}
+
+check();
+check(undefined);
+check(null);
+check(0);
+check(false);
+check('');
+check(Symbol(''));
+check({});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/reducer-throws-iterator-closed.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/reducer-throws-iterator-closed.js
new file mode 100644
index 0000000000..2a55a89850
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/reducer-throws-iterator-closed.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({ 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);
+iter.reduce(reducer).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof Error, true);
+ assertEq(iter.closed, true);
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/this-not-iterator-throws.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/this-not-iterator-throws.js
new file mode 100644
index 0000000000..7f95920fbd
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/this-not-iterator-throws.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const sum = (x, y) => x + y;
+function check(x) {
+ AsyncIterator.prototype.reduce.call(x, sum).then(
+ () => assertEq(true, false, 'expected error'),
+ err => {
+ assertEq(err instanceof TypeError, true);
+ }
+ );
+}
+
+check();
+check(undefined);
+check({});
+check({next: 0});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/reduce/value-throws-iterator-not-closed.js b/js/src/tests/non262/AsyncIterator/prototype/reduce/value-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..bfe4a9213f
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/reduce/value-throws-iterator-not-closed.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestError extends Error {}
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({
+ done: false,
+ get value() {
+ throw new TestError();
+ }
+ });
+ }
+
+ closed = false;
+ return() {
+ closed = true;
+ }
+}
+
+const iterator = new TestIterator();
+assertEq(iterator.closed, false, 'iterator starts unclosed');
+iterator.reduce((x, y) => x + y, 0).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iterator.closed, false, 'iterator remains unclosed');
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/some/async-writes.js b/js/src/tests/non262/AsyncIterator/prototype/some/async-writes.js
new file mode 100644
index 0000000000..384bf2e115
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/async-writes.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+let x = {a: () => true};
+
+async function* gen() {
+ yield x.a();
+ yield x.a();
+}
+
+gen().some(() => {}).then(
+ () => assertEq(true, false, 'expected error'),
+ err => assertEq(err instanceof Error, true),
+);
+
+x.a = () => {
+ throw Error();
+};
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/some/check-fn-after-getting-iterator.js b/js/src/tests/non262/AsyncIterator/prototype/some/check-fn-after-getting-iterator.js
new file mode 100644
index 0000000000..41dd30bee0
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/check-fn-after-getting-iterator.js
@@ -0,0 +1,31 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+const log = [];
+const handlerProxy = new Proxy({}, {
+ get: (target, key, receiver) => (...args) => {
+ log.push(`${key}: ${args[1]?.toString()}`);
+ return Reflect[key](...args);
+ },
+});
+
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({done: true});
+ }
+}
+
+async function* gen() {
+ yield 1;
+}
+
+const iter = new Proxy(new TestIterator(), handlerProxy);
+iter.some(1).then(() => assertEq(true, false, 'expected error'), err => assertEq(err instanceof TypeError, true));
+
+assertEq(
+ log.join('\n'),
+ `get: some
+get: next`
+);
+
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/some/coerce-result-to-boolean.js b/js/src/tests/non262/AsyncIterator/prototype/some/coerce-result-to-boolean.js
new file mode 100644
index 0000000000..8b56511040
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/coerce-result-to-boolean.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen(value) {
+ yield value;
+}
+const fn = x => x;
+function check(value, expected) {
+ gen(value).some(fn).then(result => assertEq(result, expected));
+}
+
+check(true, true);
+check(1, true);
+check([], true);
+check({}, true);
+check('test', true);
+
+check(false, false);
+check(0, false);
+check('', false);
+check(null, false);
+check(undefined, false);
+check(NaN, false);
+check(-0, false);
+check(0n, false);
+check(createIsHTMLDDA(), false);
+check(Promise.resolve(false), false);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/some/descriptor.js b/js/src/tests/non262/AsyncIterator/prototype/some/descriptor.js
new file mode 100644
index 0000000000..d9f5ef8fb7
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/descriptor.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ Descriptor property of AsyncIterator.prototype.some
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/some/error-from-correct-realm.js b/js/src/tests/non262/AsyncIterator/prototype/some/error-from-correct-realm.js
new file mode 100644
index 0000000000..bb4b637c1a
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/error-from-correct-realm.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const otherGlobal = newGlobal({newCompartment: true});
+assertEq(TypeError !== otherGlobal.TypeError, true);
+
+async function *gen() {}
+
+gen().some().then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TypeError, true);
+});
+
+otherGlobal.AsyncIterator.prototype.some.call(gen()).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(
+ err instanceof otherGlobal.TypeError,
+ true,
+ 'TypeError comes from the realm of the method.',
+ );
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/some/fn-not-callable-throws.js b/js/src/tests/non262/AsyncIterator/prototype/some/fn-not-callable-throws.js
new file mode 100644
index 0000000000..74a11ceebf
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/fn-not-callable-throws.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function *gen() {
+ yield 1;
+}
+
+function check(fn) {
+ gen().some(fn).then(
+ () => {
+ throw new Error('every should have thrown');
+ },
+ err => {
+ assertEq(err instanceof TypeError, true);
+ }
+ );
+}
+
+check();
+check(undefined);
+check(null);
+check(0);
+check(false);
+check('');
+check(Symbol(''));
+check({});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/some/fn-throws-close-iterator.js b/js/src/tests/non262/AsyncIterator/prototype/some/fn-throws-close-iterator.js
new file mode 100644
index 0000000000..bdf5119f57
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/fn-throws-close-iterator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({ done: this.closed });
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = () => { throw new Error(); };
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+iter.some(fn).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof Error, true);
+ assertEq(iter.closed, true);
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/some/interleaving-calls.js b/js/src/tests/non262/AsyncIterator/prototype/some/interleaving-calls.js
new file mode 100644
index 0000000000..d5882b9532
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/interleaving-calls.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const log = [];
+async function* gen(n) {
+ log.push(`${n}`);
+ yield 1;
+ log.push(`${n}`);
+ yield 2;
+}
+
+Promise.all([gen(1).some(() => {}), gen(2).some(() => {})]).then(
+ () => {
+ assertEq(
+ log.join(' '),
+ '1 2 1 2',
+ );
+ },
+ err => {
+ throw err;
+ }
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/some/length.js b/js/src/tests/non262/AsyncIterator/prototype/some/length.js
new file mode 100644
index 0000000000..ce86dc8b2f
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/length.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ The `length` property of AsyncIterator.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(AsyncIterator.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/AsyncIterator/prototype/some/name.js b/js/src/tests/non262/AsyncIterator/prototype/some/name.js
new file mode 100644
index 0000000000..f2e84a139c
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ `name` property of AsyncIterator.prototype.some.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/some/next-throws-iterator-not-closed.js b/js/src/tests/non262/AsyncIterator/prototype/some/next-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..89574e0f8e
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/next-throws-iterator-not-closed.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestIterator extends AsyncIterator {
+ next() {
+ throw new Error();
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const fn = () => {};
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+iter.some(fn).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof Error, true);
+ assertEq(iter.closed, false);
+});
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/some/proxy.js b/js/src/tests/non262/AsyncIterator/prototype/some/proxy.js
new file mode 100644
index 0000000000..6ae089ae38
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/proxy.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+// 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 AsyncIterator {
+ value = 0;
+ next() {
+ const value = this.value;
+ if (value < 2) {
+ this.value = value + 1;
+ return Promise.resolve({done: false, value});
+ }
+ return Promise.resolve({done: true});
+ }
+}
+
+const iter = new Proxy(new Counter(), handlerProxy);
+iter.some(x => x % 2 == 1).then(value => {
+ assertEq(value, 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/AsyncIterator/prototype/some/return-false-if-none-match.js b/js/src/tests/non262/AsyncIterator/prototype/some/return-false-if-none-match.js
new file mode 100644
index 0000000000..118436d70b
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/return-false-if-none-match.js
@@ -0,0 +1,16 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {
+ yield 1;
+ yield 3;
+ yield 5;
+}
+const fn = x => x % 2 == 0;
+
+gen().some(fn).then(result => assertEq(result, false));
+
+async function* empty() {}
+empty().some(x => x).then(result => assertEq(result, false));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/some/short-circuit-on-true.js b/js/src/tests/non262/AsyncIterator/prototype/some/short-circuit-on-true.js
new file mode 100644
index 0000000000..3d7250b9a2
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/short-circuit-on-true.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+const log = [];
+const fn = (value) => {
+ log.push(value.toString());
+ return value % 2 == 0;
+};
+
+gen().some(fn).then(result => {
+ assertEq(result, true);
+ assertEq(log.join(','), '1,2');
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/some/this-not-iterator-throws.js b/js/src/tests/non262/AsyncIterator/prototype/some/this-not-iterator-throws.js
new file mode 100644
index 0000000000..1233fc371c
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/this-not-iterator-throws.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const fn = x => x;
+function check(x) {
+ AsyncIterator.prototype.some.call(x, fn).then(
+ () => assertEq(true, false, 'expected error'),
+ err => {
+ assertEq(err instanceof TypeError, true);
+ }
+ );
+}
+
+check();
+check(undefined);
+check({});
+check({next: 0});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/some/value-throws-iterator-not-closed.js b/js/src/tests/non262/AsyncIterator/prototype/some/value-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..f7a344eea4
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/some/value-throws-iterator-not-closed.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestError extends Error {}
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({
+ done: false,
+ get value() {
+ throw new TestError();
+ }
+ });
+ }
+
+ closed = false;
+ return() {
+ closed = true;
+ }
+}
+
+const iterator = new TestIterator();
+assertEq(iterator.closed, false, 'iterator starts unclosed');
+iterator.some(x => x).then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iterator.closed, false, 'iterator remains unclosed');
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/take-drop-throw-eagerly-on-negative.js b/js/src/tests/non262/AsyncIterator/prototype/take-drop-throw-eagerly-on-negative.js
new file mode 100644
index 0000000000..f21c78e650
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/take-drop-throw-eagerly-on-negative.js
@@ -0,0 +1,30 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: `take` and `drop` throw eagerly when passed negative numbers, after rounding towards 0.
+info: >
+ Iterator Helpers proposal 2.1.6.4 and 2.1.6.5
+features: [iterator-helpers]
+---*/
+
+async function* gen() {}
+const iter = gen();
+const methods = [
+ value => iter.take(value),
+ value => iter.drop(value),
+];
+
+for (const method of methods) {
+ assertThrowsInstanceOf(() => method(-1), RangeError);
+ assertThrowsInstanceOf(() => method(-Infinity), RangeError);
+
+ // Both -0 and -0.9 round towards 0.
+ method(-0);
+ method(-0.9);
+}
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/take-drop-throw-eagerly-on-non-integer.js b/js/src/tests/non262/AsyncIterator/prototype/take-drop-throw-eagerly-on-non-integer.js
new file mode 100644
index 0000000000..a81b407afc
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/take-drop-throw-eagerly-on-non-integer.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: `take` and `drop` throw eagerly when passed values that can't be converted to numbers.
+info: >
+ Iterator Helpers proposal 2.1.6.4 and 2.1.6.5
+features: [iterator-helpers]
+---*/
+
+async function* gen() {}
+const iter = gen();
+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/AsyncIterator/prototype/take/close-iterator-when-none-remaining.js b/js/src/tests/non262/AsyncIterator/prototype/take/close-iterator-when-none-remaining.js
new file mode 100644
index 0000000000..6ae3e34b5d
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/take/close-iterator-when-none-remaining.js
@@ -0,0 +1,45 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.take closes the iterator when remaining is 0.
+info: >
+ Iterator Helpers proposal 2.1.6.4
+features: [iterator-helpers]
+---*/
+
+class TestIterator extends AsyncIterator {
+ async next() {
+ return {done: false, value: 'value'};
+ }
+
+ closed = false;
+ async return() {
+ this.closed = true;
+ return {done: true};
+ }
+}
+
+const iter = new TestIterator();
+const iterTake = iter.take(1);
+
+iterTake.next().then(
+ ({done, value}) => {
+ assertEq(done, false);
+ assertEq(value, 'value');
+ assertEq(iter.closed, false);
+
+ iterTake.next().then(
+ ({done, value}) => {
+ assertEq(done, true);
+ assertEq(value, undefined);
+ assertEq(iter.closed, true);
+ }
+ );
+ }
+);
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/take/length.js b/js/src/tests/non262/AsyncIterator/prototype/take/length.js
new file mode 100644
index 0000000000..0daf649a58
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/take/length.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.take length value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(AsyncIterator.prototype.take.length, 1);
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/take/name.js b/js/src/tests/non262/AsyncIterator/prototype/take/name.js
new file mode 100644
index 0000000000..6d126390fb
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/take/name.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.take.name value and descriptor.
+info: >
+ 17 ECMAScript Standard Built-in Objects
+features: [iterator-helpers]
+---*/
+
+assertEq(AsyncIterator.prototype.take.name, 'take');
+
+const propertyDescriptor = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/take/take-more-than-available.js b/js/src/tests/non262/AsyncIterator/prototype/take/take-more-than-available.js
new file mode 100644
index 0000000000..65355704ae
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/take/take-more-than-available.js
@@ -0,0 +1,34 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+//
+//
+/*---
+esid: pending
+description: %AsyncIterator.prototype%.take returns if the iterator is done.
+info: >
+ Iterator Helpers proposal 2.1.6.4
+ 2. Repeat,
+ ...
+ c. Let next be ? Await(? IteratorNext(iterated, lastValue)).
+ d. If ? IteratorComplete(next) is false, return undefined.
+features: [iterator-helpers]
+---*/
+
+async function* gen(values) {
+ yield* values;
+}
+
+(async () => {
+ const iter = gen([1, 2]).take(10);
+ for (const expected of [1, 2]) {
+ const result = await iter.next();
+ assertEq(result.value, expected);
+ assertEq(result.done, false);
+ }
+ const result = await iter.next();
+ assertEq(result.value, undefined);
+ assertEq(result.done, true);
+})();
+
+if (typeof reportCompare == 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/take/take.js b/js/src/tests/non262/AsyncIterator/prototype/take/take.js
new file mode 100644
index 0000000000..a734da8c2c
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/take/take.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+
+let iter = gen().take(2);
+
+for (const v of [1, 2]) {
+ iter.next().then(
+ ({done, value}) => {
+ assertEq(done, false);
+ assertEq(value, v);
+ }
+ );
+}
+
+iter.next().then(({done}) => assertEq(done, true));
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/toArray/async-writes.js b/js/src/tests/non262/AsyncIterator/prototype/toArray/async-writes.js
new file mode 100644
index 0000000000..8246d8d4ed
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/toArray/async-writes.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+let x = {a: () => true};
+
+async function* gen() {
+ yield x.a();
+ yield x.a();
+}
+
+gen().toArray().then(
+ () => assertEq(true, false, 'expected error'),
+ err => assertEq(err instanceof Error, true),
+);
+
+x.a = () => {
+ throw Error();
+};
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/toArray/create-in-current-realm.js b/js/src/tests/non262/AsyncIterator/prototype/toArray/create-in-current-realm.js
new file mode 100644
index 0000000000..6f0b69f8ad
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/toArray/create-in-current-realm.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const otherGlobal = newGlobal({newCompartment: true});
+
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+
+gen().toArray().then(array => {
+ assertEq(array instanceof Array, true);
+ assertEq(array instanceof otherGlobal.Array, false);
+});
+
+otherGlobal.AsyncIterator.prototype.toArray.call(gen()).then(array => {
+ 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/AsyncIterator/prototype/toArray/descriptor.js b/js/src/tests/non262/AsyncIterator/prototype/toArray/descriptor.js
new file mode 100644
index 0000000000..58c7a13872
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/toArray/descriptor.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ Descriptor property of AsyncIterator.prototype.toArray
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/toArray/interleaving-calls.js b/js/src/tests/non262/AsyncIterator/prototype/toArray/interleaving-calls.js
new file mode 100644
index 0000000000..88e3fcd5e8
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/toArray/interleaving-calls.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+const log = [];
+async function* gen(n) {
+ log.push(`${n}`);
+ yield 1;
+ log.push(`${n}`);
+ yield 2;
+}
+
+Promise.all([gen(1).toArray(), gen(2).toArray()]).then(
+ () => {
+ assertEq(
+ log.join(' '),
+ '1 2 1 2',
+ );
+ },
+ err => {
+ throw err;
+ }
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/toArray/iterator-empty.js b/js/src/tests/non262/AsyncIterator/prototype/toArray/iterator-empty.js
new file mode 100644
index 0000000000..d8eec0454d
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/toArray/iterator-empty.js
@@ -0,0 +1,10 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {}
+gen().toArray().then(array => {
+ assertEq(Array.isArray(array), true);
+ assertEq(array.length, 0);
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/toArray/length.js b/js/src/tests/non262/AsyncIterator/prototype/toArray/length.js
new file mode 100644
index 0000000000..f0467d5fc3
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/toArray/length.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ The `length` property of AsyncIterator.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(AsyncIterator.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/AsyncIterator/prototype/toArray/name.js b/js/src/tests/non262/AsyncIterator/prototype/toArray/name.js
new file mode 100644
index 0000000000..63cdf4c201
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/toArray/name.js
@@ -0,0 +1,13 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+/*---
+ `name` property of AsyncIterator.prototype.toArray.
+---*/
+
+const propDesc = Reflect.getOwnPropertyDescriptor(AsyncIterator.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/AsyncIterator/prototype/toArray/next-throws.js b/js/src/tests/non262/AsyncIterator/prototype/toArray/next-throws.js
new file mode 100644
index 0000000000..d998f83e83
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/toArray/next-throws.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestIterator extends AsyncIterator {
+ next() {
+ throw new Error();
+ }
+
+ closed = false;
+ return() {
+ this.closed = true;
+ }
+}
+
+const iter = new TestIterator();
+
+assertEq(iter.closed, false);
+iter.toArray().then(() => assertEq(true, false, 'expected error'), err => {
+ assertEq(err instanceof Error, true);
+ assertEq(iter.closed, false);
+});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/toArray/proxy.js b/js/src/tests/non262/AsyncIterator/prototype/toArray/proxy.js
new file mode 100644
index 0000000000..b82af6628e
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/toArray/proxy.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+//
+// 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 AsyncIterator {
+ value = 0;
+ next() {
+ const value = this.value;
+ if (value < 2) {
+ this.value = value + 1;
+ return Promise.resolve({done: false, value});
+ }
+ return Promise.resolve({done: true});
+ }
+}
+
+const iter = new Proxy(new Counter(), handlerProxy);
+iter.toArray().then(() => {
+ 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/AsyncIterator/prototype/toArray/this-not-iterator-throws.js b/js/src/tests/non262/AsyncIterator/prototype/toArray/this-not-iterator-throws.js
new file mode 100644
index 0000000000..9846c33ee5
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/toArray/this-not-iterator-throws.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+
+function check(x) {
+ AsyncIterator.prototype.toArray.call(x).then(
+ () => {
+ throw new Error('check should have been rejected');
+ },
+ err => {
+ assertEq(err instanceof TypeError, true);
+ }
+ );
+}
+
+check();
+check(undefined);
+check({});
+check({next: 0});
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);
diff --git a/js/src/tests/non262/AsyncIterator/prototype/toArray/toArray.js b/js/src/tests/non262/AsyncIterator/prototype/toArray/toArray.js
new file mode 100644
index 0000000000..0a91e4d95d
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/toArray/toArray.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+async function* gen() {
+ yield 1;
+ yield 2;
+ yield 3;
+}
+assertEq(Array.isArray(gen()), false);
+
+gen().toArray().then(array => {
+ 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/AsyncIterator/prototype/toArray/value-throws-iterator-not-closed.js b/js/src/tests/non262/AsyncIterator/prototype/toArray/value-throws-iterator-not-closed.js
new file mode 100644
index 0000000000..a00f780185
--- /dev/null
+++ b/js/src/tests/non262/AsyncIterator/prototype/toArray/value-throws-iterator-not-closed.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('AsyncIterator'))
+
+class TestError extends Error {}
+class TestIterator extends AsyncIterator {
+ next() {
+ return Promise.resolve({
+ done: false,
+ get value() {
+ throw new TestError();
+ }
+ });
+ }
+
+ closed = false;
+ return() {
+ closed = true;
+ }
+}
+
+const iterator = new TestIterator();
+assertEq(iterator.closed, false, 'iterator starts unclosed');
+iterator.toArray().then(
+ () => {
+ throw new Error('toArray should have thrown');
+ },
+ err => {
+ assertEq(err instanceof TestError, true);
+ assertEq(iterator.closed, false, 'iterator remains unclosed');
+ }
+);
+
+if (typeof reportCompare === 'function')
+ reportCompare(0, 0);