+describe("array", () => {
+ it("[[Call]] returns an array of the provided values", () => {
+ assertEquals(array("etaoin", [], true), ["etaoin", [], true]);
+ });
+
+ it("[[Call]] returns an empty array with no arguments", () => {
+ assertEquals(array(), []);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new array());
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(array.length, 0);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(array.name, "array");
+ });
+ });
+});
+
+describe("concatSpreadableCatenate", () => {
+ it("[[Call]] catenates concat spreadable values", () => {
+ assertEquals(
+ concatSpreadableCatenate([1, 2], [2, [3]], {
+ length: 1,
+ [Symbol.isConcatSpreadable]: true,
+ }),
+ [1, 2, 2, [3], ,],
+ );
+ });
+
+ it("[[Call]] does not catenate other values", () => {
+ assertEquals(concatSpreadableCatenate({}, "etaoin"), [
+ {},
+ "etaoin",
+ ]);
+ });
+
+ it("[[Call]] allows a nullish first argument", () => {
+ assertEquals(concatSpreadableCatenate(null), [null]);
+ assertEquals(concatSpreadableCatenate(undefined), [undefined]);
+ });
+
+ it("[[Call]] returns an empty array with no arguments", () => {
+ assertEquals(concatSpreadableCatenate(), []);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new concatSpreadableCatenate());
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(concatSpreadableCatenate.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ concatSpreadableCatenate.name,
+ "concatSpreadableCatenate",
+ );
+ });
+ });
+});
+
+describe("copyWithin", () => {
+ it("[[Call]] copies within", () => {
+ assertEquals(
+ copyWithin(["a", "b", "c", , "e"], 0, 3, 4),
+ [, "b", "c", , "e"],
+ );
+ assertEquals(
+ copyWithin(["a", "b", "c", , "e"], 1, 3),
+ ["a", , "e", , "e"],
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new copyWithin([], 0, 0));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(copyWithin.length, 3);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(copyWithin.name, "copyWithin");
+ });
+ });
+});
+
+describe("denseProxy", () => {
+ const makeUnderlying = () =>
+ Object.create({ 2: "inherited" }, {
+ // 0 is not present
+ 1: { value: "static", configurable: true, writable: true },
+ // 2 is not an own property, but is present on the prototype
+ 3: { configurable: true, get: () => "dynamic" },
+ length: { value: "4", configurable: true, writable: true },
+ });
+
+ it("[[Call]] returns an object which inherits from the provided object", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Object.getPrototypeOf(proxy),
+ underlying,
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new denseProxy([]));
+ });
+
+ it("[[OwnPropertyKeys]] lists integer indices, then the length, then other keys", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ const sym = Symbol();
+ proxy[sym] = "shrdlu";
+ proxy["1.2.3"] = "etaion";
+ assertEquals(
+ Reflect.ownKeys(proxy),
+ ["0", "1", "2", "3", "length", "1.2.3", sym],
+ );
+ });
+
+ it("[[PreventExtensions]] fails if the underlying object is extensible", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.preventExtensions(proxy),
+ false,
+ );
+ });
+
+ it("[[PreventExtensions]] fails if the underlying object has a nonconstant length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.defineProperty(underlying, "length", { get: () => 4 });
+ Object.freeze(underlying);
+ assertStrictEquals(
+ Reflect.preventExtensions(proxy),
+ false,
+ );
+ });
+
+ it("[[PreventExtensions]] succeeds if the underlying object is non·extensible and has a constant length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.defineProperty(underlying, "length", {
+ configurable: false,
+ writable: false,
+ });
+ Object.preventExtensions(underlying);
+ assertStrictEquals(
+ Reflect.preventExtensions(proxy),
+ true,
+ );
+ });
+
+ it("[[SetPrototypeOf]] fails to change the prototype", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.setPrototypeOf(proxy, {}),
+ false,
+ );
+ });
+
+ it("[[SetPrototypeOf]] succeeds keeping the prototype the same", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.setPrototypeOf(proxy, underlying),
+ true,
+ );
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(denseProxy.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(denseProxy.name, "denseProxy");
+ });
+ });
+
+ describe("~[]", () => {
+ it("[[DefineProperty]] allows changes when the property is not an index property or length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ const newValue = Symbol();
+ proxy.etaoin = newValue;
+ assertStrictEquals(
+ proxy.etaoin,
+ newValue,
+ );
+ });
+
+ it("[[DefineProperty]] allows changing nothing when the property is not an own property", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "0",
+ {
+ configurable: true,
+ enumerable: true,
+ writable: false,
+ value: undefined,
+ },
+ ),
+ true,
+ );
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "2",
+ {
+ configurable: true,
+ enumerable: true,
+ writable: false,
+ value: undefined,
+ },
+ ),
+ true,
+ );
+ /* test nonconfigurable versions too */
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "0", { configurable: false });
+ Object.defineProperty(proxy, "2", { configurable: false });
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "0",
+ Object.getOwnPropertyDescriptor(proxy, "0"),
+ ),
+ true,
+ );
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "2",
+ Object.getOwnPropertyDescriptor(proxy, "2"),
+ ),
+ true,
+ );
+ });
+
+ it("[[DefineProperty]] allows changing nothing when the property is a data index property", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "1",
+ {
+ configurable: true,
+ enumerable: true,
+ writable: false,
+ value: underlying[1],
+ },
+ ),
+ true,
+ );
+ /* test nonconfigurable versions too */
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "1", { configurable: false });
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "1",
+ Object.getOwnPropertyDescriptor(proxy, "1"),
+ ),
+ true,
+ );
+ });
+
+ it("[[DefineProperty]] allows changing nothing when the property is an accessor index property", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "3",
+ {
+ configurable: true,
+ enumerable: true,
+ writable: false,
+ value: underlying[3],
+ },
+ ),
+ true,
+ );
+ /* test nonconfigurable versions too */
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "1", { configurable: false });
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "1",
+ Object.getOwnPropertyDescriptor(proxy, "1"),
+ ),
+ true,
+ );
+ });
+
+ it("[[DefineProperty]] does not allow a change in enumerablility on index properties", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, i, { enumerable: false }),
+ false,
+ );
+ }
+ });
+
+ it("[[DefineProperty]] does not allow a change in value on index properties", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, i, { value: "new value" })
+ && (() => {
+ throw i;
+ })(),
+ false,
+ );
+ }
+ });
+
+ it("[[DefineProperty]] does not allow a change in getter on index properties", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, i, {
+ get: () => underlying[i],
+ }) && (() => {
+ throw i;
+ })(),
+ false,
+ );
+ }
+ });
+
+ it("[[DefineProperty]] does not allow a change in setter on index properties", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, i, { set: () => undefined }),
+ false,
+ );
+ }
+ });
+
+ it("[[DefineProperty]] does not allow a change in configurability on index properties if the property in the underlying object may change", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.defineProperty(underlying, "length", {
+ configurable: false,
+ writable: false,
+ });
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, i, { configurable: false }),
+ false,
+ );
+ }
+ });
+
+ it("[[DefineProperty]] does not allow a change in configurability on index properties if the length of the underlying object may change", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.seal(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, i, { configurable: false }),
+ false,
+ );
+ }
+ });
+
+ it("[[DefineProperty]] allows a change in configurability on index properties when it is safe to do so", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.defineProperty(underlying, "length", {
+ configurable: false,
+ writable: false,
+ });
+ Object.defineProperty(underlying, "1", {
+ configurable: false,
+ writable: false,
+ });
+ Object.defineProperty(underlying, "3", { configurable: false });
+ Object.preventExtensions(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, i, { configurable: false }),
+ true,
+ );
+ }
+ });
+
+ it("[[Delete]] is allowed when the property is not an index property or length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ proxy.a = "etaoin";
+ assertStrictEquals(
+ Reflect.deleteProperty(proxy, "a"),
+ true,
+ );
+ assertStrictEquals(
+ Reflect.has(proxy, "a"),
+ false,
+ );
+ });
+
+ it("[[Delete]] is forbidden for index properties less than the length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.deleteProperty(proxy, i),
+ false,
+ );
+ }
+ });
+
+ it("[[Delete]] is allowed for index properties greater than or equal to the length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.deleteProperty(proxy, "4"),
+ true,
+ );
+ assertStrictEquals(
+ Reflect.deleteProperty(proxy, "5"),
+ true,
+ );
+ });
+
+ it("[[GetOwnProperty]] gives the value of an index property as a data property by default", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, 1),
+ {
+ configurable: true,
+ enumerable: true,
+ value: underlying[1],
+ writable: false,
+ },
+ );
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, 3),
+ {
+ configurable: true,
+ enumerable: true,
+ value: underlying[3],
+ writable: false,
+ },
+ );
+ /* test nonconfigurable data properties too */
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "1", { configurable: false });
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, 1),
+ {
+ configurable: false,
+ enumerable: true,
+ value: underlying[1],
+ writable: false,
+ },
+ );
+ });
+
+ it("[[GetOwnProperty]] gives a value of undefined if the underlying object does not have an index property as an own property", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, 0),
+ {
+ configurable: true,
+ enumerable: true,
+ value: undefined,
+ writable: false,
+ },
+ );
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, 2),
+ {
+ configurable: true,
+ enumerable: true,
+ value: undefined,
+ writable: false,
+ },
+ );
+ });
+
+ it("[[GetOwnProperty]] gives a value of undefined for index properties less than the length", () => {
+ const underlying = makeUnderlying();
+ underlying.length = 0;
+ const proxy = denseProxy(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(proxy, i),
+ undefined,
+ );
+ }
+ });
+
+ it("[[GetOwnProperty]] gives a getter when the underlying object has a getter and an index property is not configurable", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "3", { configurable: false });
+ const descriptor = Object.getOwnPropertyDescriptor(proxy, 3);
+ assertEquals(
+ descriptor,
+ {
+ configurable: false,
+ enumerable: true,
+ get: descriptor.get,
+ set: undefined,
+ },
+ );
+ });
+
+ describe("[[GetOwnProperty]].get.length", () => {
+ it("[[Get]] returns the correct length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "3", { configurable: false });
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ proxy,
+ "3",
+ ).get.length,
+ 0,
+ );
+ });
+ });
+
+ describe("[[GetOwnProperty]].get.name", () => {
+ it("[[Get]] returns the correct name", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "3", { configurable: false });
+ assertStrictEquals(
+ Object.getOwnPropertyDescriptor(
+ proxy,
+ "3",
+ ).get.name,
+ "get 3",
+ );
+ });
+ });
+
+ it("[[HasProperty]] works when the property is not an index property or length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ proxy.a = "etaoin";
+ Object.getPrototypeOf(underlying).b = "shrdlu";
+ assertStrictEquals(
+ Reflect.has(proxy, "a"),
+ true,
+ );
+ assertStrictEquals(
+ Reflect.has(proxy, "b"),
+ true,
+ );
+ assertStrictEquals(
+ Reflect.has(proxy, "z"),
+ false,
+ );
+ });
+
+ it("[[HasProperty]] works for index properties less than the length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.has(proxy, i),
+ true,
+ );
+ }
+ delete underlying.length;
+ for (let i = 0; i < 4; ++i) {
+ assertStrictEquals(
+ Reflect.has(proxy, i),
+ Reflect.has(underlying, i),
+ );
+ }
+ });
+
+ it("[[HasProperty]] works for index properties greater than or equal to the length", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.has(proxy, "4"),
+ false,
+ );
+ assertStrictEquals(
+ Reflect.has(proxy, "5"),
+ false,
+ );
+ underlying[4] = "inherited now";
+ assertStrictEquals(
+ Reflect.has(proxy, "4"),
+ true,
+ );
+ });
+ });
+
+ describe("~length", () => {
+ it("[[DefineProperty]] allows changing nothing", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "length",
+ {
+ configurable: true,
+ enumerable: false,
+ writable: false,
+ value: underlying.length >>> 0,
+ },
+ ),
+ true,
+ );
+ /* test nonconfigurable versions too */
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "length", { configurable: false });
+ assertStrictEquals(
+ Reflect.defineProperty(
+ proxy,
+ "length",
+ Object.getOwnPropertyDescriptor(proxy, "length"),
+ ),
+ true,
+ );
+ });
+
+ it("[[DefineProperty]] does not allow a change in enumerablility", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, "length", { enumerable: true }),
+ false,
+ );
+ });
+
+ it("[[DefineProperty]] does not allow a change in value", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, "length", { value: 0 }),
+ false,
+ );
+ });
+
+ it("[[DefineProperty]] does not allow a change in getter", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, "length", {
+ get: () => underlying.length >>> 0,
+ }),
+ false,
+ );
+ });
+
+ it("[[DefineProperty]] does not allow a change in setter", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, "length", { set: () => {} }),
+ false,
+ );
+ });
+
+ it("[[DefineProperty]] does not allow a change in configurability if the length of the underlying object may change", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, "length", {
+ configurable: false,
+ }),
+ false,
+ );
+ Object.defineProperty(underlying, "length", {
+ configurable: false,
+ get: () => 0,
+ });
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, "length", {
+ configurable: false,
+ }),
+ false,
+ );
+ });
+
+ it("[[DefineProperty]] allows a change in configurability when it is safe to do so", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ Object.defineProperty(underlying, "length", {
+ configurable: false,
+ writable: false,
+ });
+ assertStrictEquals(
+ Reflect.defineProperty(proxy, "length", {
+ configurable: false,
+ }),
+ true,
+ );
+ });
+
+ it("[[Delete]] is forbidden", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.deleteProperty(
+ proxy,
+ "length",
+ ),
+ false,
+ );
+ });
+
+ it("[[GetOwnProperty]] gives the value as a data property", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, "length"),
+ {
+ configurable: true,
+ enumerable: false,
+ value: underlying.length >>> 0,
+ writable: false,
+ },
+ );
+ /* test nonconfigurable data properties too */
+ Object.freeze(underlying);
+ Object.defineProperty(proxy, "length", { configurable: false });
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, "length"),
+ {
+ configurable: false,
+ enumerable: false,
+ value: underlying.length >>> 0,
+ writable: false,
+ },
+ );
+ });
+
+ it("[[GetOwnProperty]] gives 0 if the underlying object does not have the property as an own property", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ delete underlying.length;
+ Object.getPrototypeOf(underlying).length = 3;
+ assertEquals(
+ Object.getOwnPropertyDescriptor(proxy, "length"),
+ {
+ configurable: true,
+ enumerable: false,
+ value: 0,
+ writable: false,
+ },
+ );
+ });
+
+ it("[[HasProperty]] is always true", () => {
+ const underlying = makeUnderlying();
+ const proxy = denseProxy(underlying);
+ assertStrictEquals(
+ Reflect.has(proxy, "length"),
+ true,
+ );
+ delete underlying.length;
+ assertStrictEquals(
+ Reflect.has(proxy, "length"),
+ true,
+ );
+ });
+ });
+});
+
+describe("fill", () => {
+ it("[[Call]] fills", () => {
+ assertEquals(
+ fill({ 1: "failure", length: 3 }, "success"),
+ { 0: "success", 1: "success", 2: "success", length: 3 },
+ );
+ });
+
+ it("[[Call]] can fill a range", () => {
+ assertEquals(
+ fill({ 1: "failure", length: 4 }, "success", 1, 3),
+ { 1: "success", 2: "success", length: 4 },
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new fill([], null));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(fill.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(fill.name, "fill");
+ });
+ });
+});
+
+describe("filter", () => {
+ it("[[Call]] filters", () => {
+ assertEquals(
+ filter(["failure", "success", ,], function ($) {
+ return !$ || $ == this;
+ }, "success"),
+ ["success"],
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new filter([], () => {}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(filter.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(filter.name, "filter");
+ });
+ });
+});
+
+describe("findFirstIndex", () => {
+ it("[[Call]] returns undefined if no matching entry exists", () => {
+ assertStrictEquals(findFirstIndex([], () => true), undefined);
+ assertStrictEquals(findFirstIndex([1], () => false), undefined);
+ });
+
+ it("[[Call]] returns an index for the first match", () => {
+ assertStrictEquals(
+ findFirstIndex([, true, false], ($) => $ ?? true),
+ 1,
+ );
+ assertStrictEquals(
+ findFirstIndex(
+ ["failure", "success", "success"],
+ ($) => $ == "success",
+ ),
+ 1,
+ );
+ });
+
+ it("[[Call]] works on arraylike objects", () => {
+ assertStrictEquals(
+ findFirstIndex({ 1: "success", length: 2 }, ($) => $),
+ 1,
+ );
+ assertStrictEquals(
+ findFirstIndex({ 1: "failure", length: 1 }, ($) => $),
+ undefined,
+ );
+ });
+
+ it("[[Call]] only gets the value once", () => {
+ const get1 = spy(() => true);
+ findFirstIndex({
+ get 1() {
+ return get1();
+ },
+ length: 2,
+ }, ($) => $);
+ assertSpyCalls(get1, 1);
+ });
+
+ it("[[Call]] passes the value, index, and this value to the callback", () => {
+ const arr = [, "failure", "success", "success"];
+ const callback = spy(($) => $ === "success");
+ const thisArg = {};
+ findFirstIndex(arr, callback, thisArg);
+ assertSpyCalls(callback, 2);
+ assertSpyCall(callback, 0, {
+ args: ["failure", 1, arr],
+ self: thisArg,
+ });
+ assertSpyCall(callback, 1, {
+ args: ["success", 2, arr],
+ self: thisArg,
+ });
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new findFirstIndex([], () => {}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(findFirstIndex.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(findFirstIndex.name, "findFirstIndex");
+ });
+ });
+});
+
+describe("findFirstIndexedEntry", () => {