Array.fromAsync: Tests for mapfn and thisArg arguments

- normal case with synchronous and asynchronous mapfn
- a non-callable value is passed as mapfn
- behaviour of various values of thisArg in strict and sloppy mode
- mapfn result is awaited once per iteration
- iterator is closed when mapfn throws
This commit is contained in:
Philip Chimento 2022-11-23 12:36:02 -08:00 committed by Ms2ger
parent ba1e51c8e7
commit c4d8f01d3d
19 changed files with 687 additions and 0 deletions

View File

@ -0,0 +1,35 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
An asynchronous mapping function is applied to each (awaited) item of an
arraylike.
info: |
3.k.vii.4. If _mapping_ is *true*, then
a. Let _mappedValue_ be ? Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
b. Let _mappedValue_ be ? Await(_mappedValue_).
...
6. Perform ? CreateDataPropertyOrThrow(_A_, _Pk_, _mappedValue_).
flags: [async]
includes: [asyncHelpers.js, compareArray.js]
features: [Array.fromAsync]
---*/
const arrayLike = {
length: 4,
0: 0,
1: 2,
2: Promise.resolve(4),
3: 6,
};
async function asyncMap(val, ix) {
return Promise.resolve(val * ix);
}
asyncTest(async () => {
const result = await Array.fromAsync(arrayLike, asyncMap);
assert.compareArray(result, [0, 2, 8, 18], "async mapfn should be applied to arraylike");
});

View File

@ -0,0 +1,35 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
An asynchronous mapping function is applied to each item yielded by an
asynchronous iterable.
info: |
3.j.ii.6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
...
c. Set _mappedValue_ to Await(_mappedValue_).
...
...
8. Let _defineStatus_ be CreateDataPropertyOrThrow(_A_, _Pk_, _mappedValue_).
flags: [async]
includes: [asyncHelpers.js, compareArray.js]
features: [Array.fromAsync]
---*/
async function* asyncGen() {
for (let i = 0; i < 4; i++) {
yield Promise.resolve(i * 2);
}
}
async function asyncMap(val, ix) {
return Promise.resolve(val * ix);
}
asyncTest(async () => {
const result = await Array.fromAsync({ [Symbol.asyncIterator]: asyncGen }, asyncMap);
assert.compareArray(result, [0, 2, 8, 18], "async mapfn should be applied to async iterable");
});

View File

@ -0,0 +1,35 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
An asynchronous mapping function is applied to each item yielded by a
synchronous iterable.
info: |
3.j.ii.6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
...
c. Set _mappedValue_ to Await(_mappedValue_).
...
...
8. Let _defineStatus_ be CreateDataPropertyOrThrow(_A_, _Pk_, _mappedValue_).
flags: [async]
includes: [asyncHelpers.js, compareArray.js]
features: [Array.fromAsync]
---*/
function* syncGen() {
for (let i = 0; i < 4; i++) {
yield i * 2;
}
}
async function asyncMap(val, ix) {
return Promise.resolve(val * ix);
}
asyncTest(async () => {
const result = await Array.fromAsync({ [Symbol.iterator]: syncGen }, asyncMap);
assert.compareArray(result, [0, 2, 8, 18], "async mapfn should be applied to sync iterable");
});

View File

@ -0,0 +1,40 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
The iterator of an asynchronous iterable is closed when the asynchronous
mapping function throws.
info: |
3.j.ii.6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
...
c. Set _mappedValue_ to Await(_mappedValue_).
d. IfAbruptCloseAsyncIterator(_mappedValue_, _iteratorRecord_).
flags: [async]
includes: [asyncHelpers.js]
features: [Array.fromAsync]
---*/
let closed = false;
const iterator = {
next() {
return Promise.resolve({ value: 1, done: false });
},
return() {
closed = true;
return Promise.resolve({ done: true });
},
[Symbol.asyncIterator]() {
return this;
}
}
asyncTest(async () => {
await assert.throwsAsync(Error, () => Array.fromAsync(iterator, async (val) => {
assert.sameValue(val, 1, "mapfn receives value from iterator");
throw new Error("mapfn throws");
}), "async mapfn rejecting should cause fromAsync to reject");
assert(closed, "async mapfn rejecting should close iterator")
});

View File

@ -0,0 +1,40 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
The iterator of a synchronous iterable is closed when the asynchronous mapping
function throws.
info: |
3.j.ii.6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
...
c. Set _mappedValue_ to Await(_mappedValue_).
d. IfAbruptCloseAsyncIterator(_mappedValue_, _iteratorRecord_).
flags: [async]
includes: [asyncHelpers.js]
features: [Array.fromAsync]
---*/
let closed = false;
const iterator = {
next() {
return { value: 1, done: false };
},
return() {
closed = true;
return { done: true };
},
[Symbol.iterator]() {
return this;
}
}
asyncTest(async () => {
await assert.throwsAsync(Error, () => Array.fromAsync(iterator, async (val) => {
assert.sameValue(val, 1, "mapfn receives value from iterator");
throw new Error("mapfn throws");
}), "async mapfn rejecting should cause fromAsync to reject");
assert(closed, "async mapfn rejecting should close iterator")
});

View File

@ -0,0 +1,23 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
The output promise rejects if the asynchronous mapping function rejects.
info: |
3.j.ii.6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
...
c. Set _mappedValue_ to Await(_mappedValue_).
d. IfAbruptCloseAsyncIterator(_mappedValue_, _iteratorRecord_).
flags: [async]
includes: [asyncHelpers.js]
features: [Array.fromAsync]
---*/
asyncTest(async () => {
await assert.throwsAsync(Test262Error, () => Array.fromAsync([1, 2, 3], async () => {
throw new Test262Error("mapfn throws");
}), "async mapfn rejecting should cause fromAsync to reject");
});

View File

@ -0,0 +1,25 @@
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
A TypeError is thrown if the mapfn argument to Array.fromAsync is not callable
info: |
3.a. If _mapfn_ is *undefined*, let _mapping_ be *false*.
b. Else,
i. If IsCallable(_mapfn_) is *false*, throw a *TypeError* exception.
flags: [async]
includes: [asyncHelpers.js]
features: [Array.fromAsync, BigInt, Symbol]
---*/
asyncTest(async () => {
await assert.throwsAsync(TypeError, () => Array.fromAsync([], null), "null mapfn");
await assert.throwsAsync(TypeError, () => Array.fromAsync([], {}), "non-callable object mapfn");
await assert.throwsAsync(TypeError, () => Array.fromAsync([], "String"), "string mapfn");
await assert.throwsAsync(TypeError, () => Array.fromAsync([], true), "boolean mapfn");
await assert.throwsAsync(TypeError, () => Array.fromAsync([], 3.1416), "number mapfn");
await assert.throwsAsync(TypeError, () => Array.fromAsync([], 42n), "bigint mapfn");
await assert.throwsAsync(TypeError, () => Array.fromAsync([], Symbol()), "symbol mapfn");
});

View File

@ -0,0 +1,47 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
The returned value from each invocation of the asynchronous mapping function
is awaited exactly once.
info: |
3.j.ii.6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
...
c. Set _mappedValue_ to Await(_mappedValue_).
flags: [async]
includes: [asyncHelpers.js, compareArray.js, temporalHelpers.js]
features: [Array.fromAsync]
---*/
const calls = [];
const expected = [
"call mapping",
"get thenable_0.then",
"call thenable_0.then",
"call mapping",
"get thenable_1.then",
"call thenable_1.then",
"call mapping",
"get thenable_2.then",
"call thenable_2.then",
];
function mapping(val, ix) {
calls.push("call mapping");
const thenableName = `thenable_${ix}`;
return TemporalHelpers.propertyBagObserver(calls, {
then(resolve, reject) {
calls.push(`call ${thenableName}.then`);
resolve(val * 2);
}
}, thenableName)
}
asyncTest(async () => {
const result = await Array.fromAsync([1, 2, 3], mapping);
assert.compareArray(result, [2, 4, 6], "mapping function applied");
assert.compareArray(calls, expected, "observable operations");
});

View File

@ -0,0 +1,35 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
A synchronous mapping function is applied to each (awaited) item of an
arraylike.
info: |
3.k.vii.4. If _mapping_ is *true*, then
a. Let _mappedValue_ be ? Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
...
...
6. Perform ? CreateDataPropertyOrThrow(_A_, _Pk_, _mappedValue_).
flags: [async]
includes: [asyncHelpers.js, compareArray.js]
features: [Array.fromAsync]
---*/
const arrayLike = {
length: 4,
0: 0,
1: 2,
2: Promise.resolve(4),
3: 6,
};
function syncMap(val, ix) {
return val * ix;
}
asyncTest(async () => {
const result = await Array.fromAsync(arrayLike, syncMap);
assert.compareArray(result, [0, 2, 8, 18], "sync mapfn should be applied to arraylike");
});

View File

@ -0,0 +1,33 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
A synchronous mapping function is applied to each item yielded by an
asynchronous iterable.
info: |
3.j.ii.6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
...
...
8. Let _defineStatus_ be CreateDataPropertyOrThrow(_A_, _Pk_, _mappedValue_).
flags: [async]
includes: [asyncHelpers.js, compareArray.js]
features: [Array.fromAsync]
---*/
async function* asyncGen() {
for (let i = 0; i < 4; i++) {
yield Promise.resolve(i * 2);
}
}
function syncMap(val, ix) {
return val * ix;
}
asyncTest(async () => {
const result = await Array.fromAsync({ [Symbol.asyncIterator]: asyncGen }, syncMap);
assert.compareArray(result, [0, 2, 8, 18], "sync mapfn should be applied to async iterable");
});

View File

@ -0,0 +1,33 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
A synchronous mapping function is applied to each item yielded by a
synchronous iterable.
info: |
3.j.ii.6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
...
...
8. Let _defineStatus_ be CreateDataPropertyOrThrow(_A_, _Pk_, _mappedValue_).
flags: [async]
includes: [asyncHelpers.js, compareArray.js]
features: [Array.fromAsync]
---*/
function* syncGen() {
for (let i = 0; i < 4; i++) {
yield i * 2;
}
}
function syncMap(val, ix) {
return val * ix;
}
asyncTest(async () => {
const result = await Array.fromAsync({ [Symbol.iterator]: syncGen }, syncMap);
assert.compareArray(result, [0, 2, 8, 18], "sync mapfn should be applied to sync iterable");
});

View File

@ -0,0 +1,39 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
The iterator of an asynchronous iterable is closed when the synchronous
mapping function throws.
info: |
3.j.ii.6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
b. IfAbruptCloseAsyncIterator(_mappedValue_, _iteratorRecord_).
...
flags: [async]
includes: [asyncHelpers.js]
features: [Array.fromAsync]
---*/
let closed = false;
const iterator = {
next() {
return Promise.resolve({ value: 1, done: false });
},
return() {
closed = true;
return Promise.resolve({ done: true });
},
[Symbol.asyncIterator]() {
return this;
}
}
asyncTest(async () => {
await assert.throwsAsync(Error, () => Array.fromAsync(iterator, (val) => {
assert.sameValue(val, 1, "mapfn receives value from iterator");
throw new Error("mapfn throws");
}), "sync mapfn throwing should cause fromAsync to reject");
assert(closed, "sync mapfn throwing should close iterator")
});

View File

@ -0,0 +1,39 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
The iterator of a synchronous iterable is closed when the synchronous mapping
function throws.
info: |
3.j.ii.6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
b. IfAbruptCloseAsyncIterator(_mappedValue_, _iteratorRecord_).
...
flags: [async]
includes: [asyncHelpers.js]
features: [Array.fromAsync]
---*/
let closed = false;
const iterator = {
next() {
return { value: 1, done: false };
},
return() {
closed = true;
return { done: true };
},
[Symbol.iterator]() {
return this;
}
}
asyncTest(async () => {
await assert.throwsAsync(Error, () => Array.fromAsync(iterator, (val) => {
assert.sameValue(val, 1, "mapfn receives value from iterator");
throw new Error("mapfn throws");
}), "sync mapfn throwing should cause fromAsync to reject");
assert(closed, "sync mapfn throwing should close iterator")
});

View File

@ -0,0 +1,22 @@
// Copyright (C) 2023 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
The output promise rejects if the synchronous mapping function throws.
info: |
3.j.ii.6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
b. IfAbruptCloseAsyncIterator(_mappedValue_, _iteratorRecord_).
...
flags: [async]
includes: [asyncHelpers.js]
features: [Array.fromAsync]
---*/
asyncTest(async () => {
await assert.throwsAsync(Test262Error, () => Array.fromAsync([1, 2, 3], () => {
throw new Test262Error("mapfn throws");
}), "sync mapfn throwing should cause fromAsync to reject");
});

View File

@ -0,0 +1,21 @@
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: If thisArg is an object, it's bound to mapfn as the this-value
info: |
6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
flags: [async]
includes: [asyncHelpers.js]
features: [Array.fromAsync]
---*/
asyncTest(async () => {
const myThisValue = {};
await Array.fromAsync([1, 2, 3], async function () {
assert.sameValue(this, myThisValue, "thisArg should be bound as the this-value of mapfn");
}, myThisValue);
});

View File

@ -0,0 +1,33 @@
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
If thisArg is omitted, mapfn is called with the global object as the
this-value in sloppy mode
info: |
6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
OrdinaryCallBindThis, when _F_.[[ThisMode]] is ~global~, where _F_ is the
function object:
6. Else,
a. If _thisArgument_ is *undefined* or *null*, then
i. Let _globalEnv_ be _calleeRealm_.[[GlobalEnv]].
ii. Assert: _globalEnv_ is a Global Environment Record.
iii. Let _thisValue_ be _globalEnv_.[[GlobalThisValue]].
flags: [async, noStrict]
includes: [asyncHelpers.js]
features: [Array.fromAsync]
---*/
asyncTest(async () => {
await Array.fromAsync([1, 2, 3], async function () {
assert.sameValue(
this,
globalThis,
"the global should be bound as the this-value of mapfn when thisArg is omitted"
);
});
});

View File

@ -0,0 +1,28 @@
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
If thisArg is omitted, mapfn is called with undefined as the this-value in
strict mode
info: |
6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
In OrdinaryCallBindThis, _thisArgument_ is always bound as the this-value in
strict mode (_F_.[[ThisMode]] is ~strict~, where _F_ is the function object.)
flags: [async, onlyStrict]
includes: [asyncHelpers.js]
features: [Array.fromAsync]
---*/
asyncTest(async () => {
await Array.fromAsync([1, 2, 3], async function () {
assert.sameValue(
this,
undefined,
"undefined should be bound as the this-value of mapfn when thisArg is omitted"
);
});
});

View File

@ -0,0 +1,75 @@
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
If thisArg is a primitive, mapfn is called with a wrapper this-value or the
global, according to the usual rules of sloppy mode
info: |
6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
OrdinaryCallBindThis, when _F_.[[ThisMode]] is ~global~, where _F_ is the
function object:
6. Else,
a. If _thisArgument_ is *undefined* or *null*, then
i. Let _globalEnv_ be _calleeRealm_.[[GlobalEnv]].
ii. Assert: _globalEnv_ is a Global Environment Record.
iii. Let _thisValue_ be _globalEnv_.[[GlobalThisValue]].
b. Else,
i. Let _thisValue_ be ! ToObject(_thisArgument_).
ii. NOTE: ToObject produces wrapper objects using _calleeRealm_.
flags: [async, noStrict]
includes: [asyncHelpers.js]
features: [Array.fromAsync]
---*/
asyncTest(async () => {
await Array.fromAsync([1, 2, 3], async function () {
assert.sameValue(
this,
globalThis,
"the global should be bound as the this-value of mapfn when thisArg is undefined"
);
}, undefined);
await Array.fromAsync([1, 2, 3], async function () {
assert.sameValue(
this,
globalThis,
"the global should be bound as the this-value of mapfn when thisArg is null"
);
}, null);
await Array.fromAsync([1, 2, 3], async function () {
assert.notSameValue(this, "string", "string thisArg should not be bound as the this-value of mapfn");
assert.sameValue(typeof this, "object", "a String wrapper object should be bound as the this-value of mapfn when thisArg is a string")
assert.sameValue(this.valueOf(), "string", "String wrapper object should have the same primitive value as thisArg");
}, "string");
await Array.fromAsync([1, 2, 3], async function () {
assert.notSameValue(this, 3.1416, "number thisArg should be not bound as the this-value of mapfn");
assert.sameValue(typeof this, "object", "a Number wrapper object should be bound as the this-value of mapfn when thisArg is a number")
assert.sameValue(this.valueOf(), 3.1416, "Number wrapper object should have the same primitive value as thisArg");
}, 3.1416);
await Array.fromAsync([1, 2, 3], async function () {
assert.notSameValue(this, 42n, "bigint thisArg should not be bound as the this-value of mapfn");
assert.sameValue(typeof this, "object", "a BigInt wrapper object should be bound as the this-value of mapfn when thisArg is a bigint")
assert.sameValue(this.valueOf(), 42n, "BigInt wrapper object should have the same primitive value as thisArg");
}, 42n);
await Array.fromAsync([1, 2, 3], async function () {
assert.notSameValue(this, true, "boolean thisArg should not be bound as the this-value of mapfn");
assert.sameValue(typeof this, "object", "a Boolean wrapper object should be bound as the this-value of mapfn when thisArg is a boolean")
assert.sameValue(this.valueOf(), true, "Boolean wrapper object should have the same primitive value as thisArg");
}, true);
const symbolThis = Symbol("symbol");
await Array.fromAsync([1, 2, 3], async function () {
assert.notSameValue(this, symbolThis, "symbol thisArg should not be bound as the this-value of mapfn");
assert.sameValue(typeof this, "object", "a Symbol wrapper object should be bound as the this-value of mapfn when thisArg is a symbol")
assert.sameValue(this.valueOf(), symbolThis, "Symbol wrapper object should have the same primitive value as thisArg");
}, symbolThis);
});

View File

@ -0,0 +1,49 @@
// Copyright (C) 2022 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-array.fromasync
description: >
If thisArg is a primitive, mapfn is called with it as the this-value in strict
mode
info: |
6. If _mapping_ is *true*, then
a. Let _mappedValue_ be Call(_mapfn_, _thisArg_, « _nextValue_, 𝔽(_k_) »).
In OrdinaryCallBindThis, _thisArgument_ is always bound as the this-value in
strict mode (_F_.[[ThisMode]] is ~strict~, where _F_ is the function object.)
flags: [async, onlyStrict]
includes: [asyncHelpers.js]
features: [Array.fromAsync]
---*/
asyncTest(async () => {
await Array.fromAsync([1, 2, 3], async function () {
assert.sameValue(this, undefined, "undefined thisArg should be bound as the this-value of mapfn");
}, undefined);
await Array.fromAsync([1, 2, 3], async function () {
assert.sameValue(this, null, "null thisArg should be bound as the this-value of mapfn");
}, null);
await Array.fromAsync([1, 2, 3], async function () {
assert.sameValue(this, "string", "string thisArg should be bound as the this-value of mapfn");
}, "string");
await Array.fromAsync([1, 2, 3], async function () {
assert.sameValue(this, 3.1416, "number thisArg should be bound as the this-value of mapfn");
}, 3.1416);
await Array.fromAsync([1, 2, 3], async function () {
assert.sameValue(this, 42n, "bigint thisArg should be bound as the this-value of mapfn");
}, 42n);
await Array.fromAsync([1, 2, 3], async function () {
assert.sameValue(this, true, "boolean thisArg should be bound as the this-value of mapfn");
}, true);
const symbolThis = Symbol("symbol");
await Array.fromAsync([1, 2, 3], async function () {
assert.sameValue(this, symbolThis, "symbol thisArg should be bound as the this-value of mapfn");
}, symbolThis);
});