// ♓🌟 Piscēs ∷ object.test.js
// ====================================================================
//
-// Copyright © 2022 Lady [@ Lady’s Computer].
+// Copyright © 2022–2023 Lady [@ Lady’s Computer].
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
import {
assert,
assertEquals,
+ assertNotStrictEquals,
assertSpyCall,
assertSpyCalls,
assertStrictEquals,
spy,
} from "./dev-deps.js";
import {
+ defineOwnDataProperty,
+ defineOwnNonenumerableDataProperty,
defineOwnProperties,
+ defineOwnProperty,
deleteOwnProperty,
+ freeze,
frozenCopy,
getMethod,
+ getOwnPropertyDescriptor,
+ getOwnPropertyDescriptors,
+ getOwnPropertyEntries,
getOwnPropertyKeys,
+ getOwnPropertyStrings,
+ getOwnPropertySymbols,
+ getOwnPropertyValue,
+ getOwnPropertyValues,
getPropertyValue,
+ getPrototype,
+ hasOwnProperty,
hasProperty,
+ isArraylikeObject,
+ isConcatSpreadableObject,
+ isExtensibleObject,
+ isPropertyDescriptorRecord,
+ isUnfrozenObject,
+ isUnsealedObject,
LazyLoader,
- PropertyDescriptor,
+ lengthOfArraylike,
+ namedEntries,
+ namedKeys,
+ namedValues,
+ objectCreate,
+ objectFromEntries,
+ preventExtensions,
+ seal,
setPropertyValue,
+ setPropertyValues,
+ setPrototype,
toObject,
- toPropertyKey,
+ toPropertyDescriptorRecord,
} from "./object.js";
describe("LazyLoader", () => {
- const symbol = Symbol();
+ const symbol = Symbol("foo");
const prototype = {};
const etaoinMethod = spy(() => "success");
const shrdluMethod = spy(() => "success");
},
);
+ it("[[Call]] throws an error", () => {
+ assertThrows(() => LazyLoader({}));
+ });
+
it("[[Construct]] creates a new object which inherits from the correct prototype", () => {
assertStrictEquals(
Object.getPrototypeOf(new LazyLoader(methodsObject)),
for (const key of Reflect.ownKeys(ll)) {
yield [
key,
- Object.getOwnPropertyDescriptor(ll, key).get !== void {},
+ Object.getOwnPropertyDescriptor(ll, key).get?.name,
];
}
}(new LazyLoader(methodsObject)),
),
{
- etaoin: true,
- shrdlu: true,
- cmfwyp: true,
- vbgkqj: true,
- xzfiflffffi: true,
- [symbol]: true,
+ etaoin: "get etaoin",
+ shrdlu: "get shrdlu",
+ cmfwyp: "get cmfwyp",
+ vbgkqj: "get vbgkqj",
+ xzfiflffffi: "get xzfiflffffi",
+ [symbol]: `get [${symbol.description}]`,
},
);
});
for (const key of Reflect.ownKeys(ll)) {
yield [
key,
- Object.getOwnPropertyDescriptor(ll, key).set !== void {},
+ Object.getOwnPropertyDescriptor(ll, key).set?.name,
];
}
}(new LazyLoader(methodsObject)),
),
{
- etaoin: false,
- shrdlu: false,
- cmfwyp: false,
- vbgkqj: false,
- xzfiflffffi: false,
- [symbol]: true,
+ etaoin: undefined,
+ shrdlu: undefined,
+ cmfwyp: undefined,
+ vbgkqj: undefined,
+ xzfiflffffi: undefined,
+ [symbol]: `set [${symbol.description}]`,
},
);
});
- describe("[[Construct]] creates a new object with correct getter behaviour", () => {
+ it("[[Construct]] creates a new object with correct getter behaviour", () => {
const ll = new LazyLoader(methodsObject);
ll.etaoin;
assertEquals(
assertThrows(() => ll[symbol]);
});
- describe("[[Construct]] creates a new object with correct setter behaviour", () => {
+ it("[[Construct]] creates a new object with correct setter behaviour", () => {
const ll = new LazyLoader(methodsObject);
ll[symbol] = "success";
assertEquals(
},
);
});
-});
-describe("PropertyDescriptor", () => {
- it("[[Construct]] creates a new PropertyDescriptor", () => {
- assertStrictEquals(
- Object.getPrototypeOf(new PropertyDescriptor({})),
- PropertyDescriptor.prototype,
- );
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(LazyLoader.length, 1);
+ });
});
- it("[[Construct]] throws for primitives", () => {
- assertThrows(() => new PropertyDescriptor("failure"));
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(LazyLoader.name, "LazyLoader");
+ });
});
+});
- describe("::complete", () => {
- it("[[Call]] completes a generic descriptor", () => {
- const desc = {};
- PropertyDescriptor.prototype.complete.call(desc);
- assertEquals(desc, {
- configurable: false,
- enumerable: false,
- value: undefined,
- writable: false,
- });
- });
+describe("defineOwnDataProperty", () => {
+ it("[[Call]] defines the property", () => {
+ const obj = {};
+ defineOwnDataProperty(obj, "etaoin", "success");
+ assert(Object.hasOwn(obj, "etaoin"));
+ assertStrictEquals(obj.etaoin, "success");
+ });
- it("[[Call]] completes a data descriptor", () => {
- const desc = { value: undefined };
- PropertyDescriptor.prototype.complete.call(desc);
- assertEquals(desc, {
- configurable: false,
- enumerable: false,
- value: undefined,
- writable: false,
- });
- });
+ it("[[Call]] defines a configurable, enumerable, writable property", () => {
+ const obj = {};
+ defineOwnDataProperty(obj, "etaoin", "success");
+ assertEquals(
+ Object.getOwnPropertyDescriptor(obj, "etaoin"),
+ {
+ configurable: true,
+ enumerable: true,
+ value: "success",
+ writable: true,
+ },
+ );
+ });
- it("[[Call]] completes an accessor descriptor", () => {
- const desc = { get: undefined };
- PropertyDescriptor.prototype.complete.call(desc);
- assertEquals(desc, {
- configurable: false,
- enumerable: false,
- get: undefined,
- set: undefined,
- });
- });
+ it("[[Call]] returns the provided object", () => {
+ const obj = {};
+ assertStrictEquals(
+ defineOwnDataProperty(obj, "etaoin", null),
+ obj,
+ );
});
- describe("::isAccessorDescriptor", () => {
- it("[[Get]] returns false for a generic descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isAccessorDescriptor",
- {},
- ),
- false,
- );
- });
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new defineOwnDataProperty(obj, "etaoin", null));
+ });
- it("[[Get]] returns false for a data descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isAccessorDescriptor",
- { value: undefined },
- ),
- false,
- );
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(defineOwnDataProperty.length, 3);
});
+ });
- it("[[Get]] returns true for an accessor descriptor", () => {
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isAccessorDescriptor",
- { get: undefined },
- ),
- true,
+ defineOwnDataProperty.name,
+ "defineOwnDataProperty",
);
});
});
+});
- describe("::isDataDescriptor", () => {
- it("[[Get]] returns false for a generic descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isDataDescriptor",
- {},
- ),
- false,
- );
- });
+describe("defineOwnNonenumerableDataProperty", () => {
+ it("[[Call]] defines the property", () => {
+ const obj = {};
+ defineOwnNonenumerableDataProperty(obj, "etaoin", "success");
+ assert(Object.hasOwn(obj, "etaoin"));
+ assertStrictEquals(obj.etaoin, "success");
+ });
- it("[[Get]] returns true for a data descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isDataDescriptor",
- { value: undefined },
- ),
- true,
- );
- });
+ it("[[Call]] defines a configurable, non·enumerable, writable property", () => {
+ const obj = {};
+ defineOwnNonenumerableDataProperty(obj, "etaoin", "success");
+ assertEquals(
+ Object.getOwnPropertyDescriptor(obj, "etaoin"),
+ {
+ configurable: true,
+ enumerable: false,
+ value: "success",
+ writable: true,
+ },
+ );
+ });
- it("[[Get]] returns false for an accessor descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isDataDescriptor",
- { get: undefined },
- ),
- false,
- );
- });
+ it("[[Call]] returns the provided object", () => {
+ const obj = {};
+ assertStrictEquals(
+ defineOwnNonenumerableDataProperty(obj, "etaoin", null),
+ obj,
+ );
});
- describe("::isFullyPopulated", () => {
- it("[[Get]] returns false for a generic descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isFullyPopulated",
- {},
- ),
- false,
- );
- });
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() =>
+ new defineOwnNonenumerableDataProperty(obj, "etaoin", null)
+ );
+ });
- it("[[Get]] returns false for a non‐fully‐populated data descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isFullyPopulated",
- { value: undefined },
- ),
- false,
- );
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(defineOwnNonenumerableDataProperty.length, 3);
});
+ });
- it("[[Get]] returns true for a fully‐populated data descriptor", () => {
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
assertStrictEquals(
- Reflect.get(PropertyDescriptor.prototype, "isFullyPopulated", {
- configurable: true,
- enumerable: true,
- value: undefined,
- writable: true,
- }),
- true,
+ defineOwnNonenumerableDataProperty.name,
+ "defineOwnNonenumerableDataProperty",
);
});
+ });
+});
- it("[[Get]] returns false for a non‐fully‐populated accessor descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isFullyPopulated",
- { get: undefined },
- ),
- false,
- );
- });
+describe("defineOwnProperty", () => {
+ it("[[Call]] defines the property", () => {
+ const obj = {};
+ defineOwnProperty(obj, "etaoin", {});
+ assert(Object.hasOwn(obj, "etaoin"));
+ });
- it("[[Get]] returns true for a fully‐populated accessor descriptor", () => {
- assertStrictEquals(
- Reflect.get(PropertyDescriptor.prototype, "isFullyPopulated", {
- configurable: true,
- enumerable: true,
- get: undefined,
- set: undefined,
- }),
- true,
- );
- });
+ it("[[Call]] returns the provided object", () => {
+ const obj = {};
+ assertStrictEquals(defineOwnProperty(obj, "etaoin", {}), obj);
});
- describe("::isGenericDescriptor", () => {
- it("[[Get]] returns true for a generic descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isGenericDescriptor",
- {},
- ),
- true,
- );
- });
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new defineOwnProperty(obj, "etaoin", {}));
+ });
- it("[[Get]] returns true for a data descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isGenericDescriptor",
- { value: undefined },
- ),
- false,
- );
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(defineOwnProperty.length, 3);
});
+ });
- it("[[Get]] returns false for an accessor descriptor", () => {
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isGenericDescriptor",
- { get: undefined },
- ),
- false,
+ defineOwnProperty.name,
+ "defineOwnProperty",
);
});
});
+});
- describe("~configurable", () => {
- it("[[DefineOwnProperty]] coerces to a boolean", () => {
- const desc = new PropertyDescriptor({});
- Object.defineProperty(desc, "configurable", {});
- assertStrictEquals(desc.configurable, false);
- });
+describe("defineOwnProperties", () => {
+ it("[[Call]] defines properties from the provided objects", () => {
+ const obj = {};
+ defineOwnProperties(obj, {
+ etaoin: {},
+ shrdlu: {},
+ }, { cmfwyp: {} });
+ assert("etaoin" in obj);
+ assert("shrdlu" in obj);
+ assert("cmfwyp" in obj);
+ });
- it("[[DefineOwnProperty]] throws for accessor properties", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(() =>
- Object.defineProperty(desc, "configurable", { get: undefined })
- );
+ it("[[Call]] overrides earlier declarations with later ones", () => {
+ const obj = { etaoin: undefined };
+ defineOwnProperties(obj, {
+ etaoin: { value: "failure" },
+ }, {
+ etaoin: { value: "success" },
});
+ assertStrictEquals(obj.etaoin, "success");
+ });
- it("[[Set]] coerces to a boolean", () => {
- const desc = new PropertyDescriptor({});
- desc.configurable = undefined;
- assertStrictEquals(desc.configurable, false);
- });
+ it("[[Call]] returns the provided object", () => {
+ const obj = {};
+ assertStrictEquals(defineOwnProperties(obj), obj);
+ });
- it("[[Delete]] works", () => {
- const desc = new PropertyDescriptor({ configurable: false });
- delete desc.configurable;
- assert(!("configurable" in desc));
- });
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new defineOwnProperties({}));
});
- describe("~enumerable", () => {
- it("[[DefineOwnProperty]] coerces to a boolean", () => {
- const desc = new PropertyDescriptor({});
- Object.defineProperty(desc, "enumerable", {});
- assertStrictEquals(desc.enumerable, false);
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(defineOwnProperties.length, 1);
});
+ });
- it("[[DefineOwnProperty]] throws for accessor properties", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(() =>
- Object.defineProperty(desc, "enumerable", { get: undefined })
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ defineOwnProperties.name,
+ "defineOwnProperties",
);
});
+ });
+});
- it("[[Set]] coerces to a boolean", () => {
- const desc = new PropertyDescriptor({});
- desc.enumerable = undefined;
- assertStrictEquals(desc.enumerable, false);
- });
-
- it("[[Delete]] works", () => {
- const desc = new PropertyDescriptor({ enumerable: false });
- delete desc.enumerable;
- assert(!("enumerable" in desc));
- });
+describe("deleteOwnProperty", () => {
+ it("[[Call]] deletes the provided property on the provided object", () => {
+ const obj = { failure: undefined };
+ deleteOwnProperty(obj, "failure");
+ assert(!("failure" in obj));
});
- describe("~get", () => {
- it("[[DefineOwnProperty]] works", () => {
- const desc = new PropertyDescriptor({});
- Object.defineProperty(desc, "get", {});
- assertStrictEquals(desc.get, undefined);
- });
+ it("[[Call]] does nothing if the property doesn’t exist", () => {
+ const obj = Object.freeze({});
+ deleteOwnProperty(obj, "failure");
+ assert(!("failure" in obj));
+ });
- it("[[DefineOwnProperty]] throws for accessor properties", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(() =>
- Object.defineProperty(desc, "get", { get: undefined })
- );
- });
+ it("[[Call]] throws if the property can’t be deleted", () => {
+ const obj = Object.seal({ failure: undefined });
+ assertThrows(() => deleteOwnProperty(obj, "failure"));
+ });
- it("[[DefineOwnProperty]] throws if not callable or undefined", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(
- () => Object.defineProperty(desc, "get", { value: null }),
- );
- });
+ it("[[Call]] returns the provided object", () => {
+ const obj = {};
+ assertStrictEquals(deleteOwnProperty(obj, ""), obj);
+ });
- it("[[DefineOwnProperty]] throws if a data property is defined", () => {
- const desc = new PropertyDescriptor({ value: undefined });
- assertThrows(() => Object.defineProperty(desc, "get", {}));
- });
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new deleteOwnProperty({}, ""));
+ });
- it("[[Set]] works", () => {
- const desc = new PropertyDescriptor({});
- const fn = () => {};
- desc.get = fn;
- assertStrictEquals(desc.get, fn);
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(deleteOwnProperty.length, 2);
});
+ });
- it("[[Set]] throws if not callable or undefined", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(() => desc.get = null);
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(deleteOwnProperty.name, "deleteOwnProperty");
});
+ });
+});
- it("[[Set]] throws if a data property is defined", () => {
- const desc = new PropertyDescriptor({ value: undefined });
- assertThrows(() => desc.get = undefined);
- });
+describe("freeze", () => {
+ it("[[Call]] freezes the object", () => {
+ const obj = {};
+ freeze(obj);
+ assert(Object.isFrozen(obj));
+ });
- it("[[Delete]] works", () => {
- const desc = new PropertyDescriptor({ get: undefined });
- delete desc.get;
- assert(!("get" in desc));
- });
+ it("[[Call]] returns the provided object", () => {
+ const obj = {};
+ assertStrictEquals(freeze(obj), obj);
});
- describe("~set", () => {
- it("[[DefineOwnProperty]] works", () => {
- const desc = new PropertyDescriptor({});
- Object.defineProperty(desc, "set", {});
- assertStrictEquals(desc.set, undefined);
- });
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new freeze({}));
+ });
- it("[[DefineOwnProperty]] throws for accessor properties", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(() =>
- Object.defineProperty(desc, "set", { get: undefined })
- );
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(freeze.length, 1);
});
+ });
- it("[[DefineOwnProperty]] throws if not callable or undefined", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(
- () => Object.defineProperty(desc, "set", { value: null }),
- );
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(freeze.name, "freeze");
});
-
- it("[[DefineOwnProperty]] throws if a data property is defined", () => {
- const desc = new PropertyDescriptor({ value: undefined });
- assertThrows(() => Object.defineProperty(desc, "set", {}));
- });
-
- it("[[Set]] works", () => {
- const desc = new PropertyDescriptor({});
- const fn = (_) => {};
- desc.set = fn;
- assertStrictEquals(desc.set, fn);
- });
-
- it("[[Set]] throws if not callable or undefined", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(() => desc.set = null);
- });
-
- it("[[Set]] throws if a data property is defined", () => {
- const desc = new PropertyDescriptor({ value: undefined });
- assertThrows(() => desc.set = undefined);
- });
-
- it("[[Delete]] works", () => {
- const desc = new PropertyDescriptor({ set: undefined });
- delete desc.set;
- assert(!("set" in desc));
- });
- });
-
- describe("~value", () => {
- it("[[DefineOwnProperty]] works", () => {
- const desc = new PropertyDescriptor({});
- Object.defineProperty(desc, "value", {});
- assertStrictEquals(desc.value, undefined);
- });
-
- it("[[DefineOwnProperty]] throws for accessor properties", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(() =>
- Object.defineProperty(desc, "value", { get: undefined })
- );
- });
-
- it("[[DefineOwnProperty]] throws if an accessor property is defined", () => {
- const desc = new PropertyDescriptor({ get: undefined });
- assertThrows(() => Object.defineProperty(desc, "value", {}));
- });
-
- it("[[Set]] works", () => {
- const desc = new PropertyDescriptor({});
- desc.value = "success";
- assertStrictEquals(desc.value, "success");
- });
-
- it("[[Set]] throws if an accessor property is defined", () => {
- const desc = new PropertyDescriptor({ get: undefined });
- assertThrows(() => desc.value = null);
- });
-
- it("[[Delete]] works", () => {
- const desc = new PropertyDescriptor({ value: undefined });
- delete desc.value;
- assert(!("value" in desc));
- });
- });
-
- describe("~writable", () => {
- it("[[DefineOwnProperty]] coerces to a boolean", () => {
- const desc = new PropertyDescriptor({});
- Object.defineProperty(desc, "writable", {});
- assertStrictEquals(desc.writable, false);
- });
-
- it("[[DefineOwnProperty]] throws for accessor properties", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(() =>
- Object.defineProperty(desc, "writable", { get: undefined })
- );
- });
-
- it("[[DefineOwnProperty]] throws if an accessor property is defined", () => {
- const desc = new PropertyDescriptor({ get: undefined });
- assertThrows(() => Object.defineProperty(desc, "writable", {}));
- });
-
- it("[[Set]] coerces to a boolean", () => {
- const desc = new PropertyDescriptor({});
- desc.writable = undefined;
- assertStrictEquals(desc.writable, false);
- });
-
- it("[[Set]] throws if an accessor property is defined", () => {
- const desc = new PropertyDescriptor({ get: undefined });
- assertThrows(() => desc.writable = false);
- });
-
- it("[[Delete]] works", () => {
- const desc = new PropertyDescriptor({ writable: false });
- delete desc.writable;
- assert(!("writable" in desc));
- });
- });
-});
-
-describe("defineOwnProperties", () => {
- it("[[Call]] defines properties from the provided objects", () => {
- const obj = {};
- defineOwnProperties(obj, {
- etaoin: {},
- shrdlu: {},
- }, { cmfwyp: {} });
- assert("etaoin" in obj);
- assert("shrdlu" in obj);
- assert("cmfwyp" in obj);
- });
-
- it("[[Call]] overrides earlier declarations with later ones", () => {
- const obj = { etaoin: undefined };
- defineOwnProperties(obj, {
- etaoin: { value: "failure" },
- }, {
- etaoin: { value: "success" },
- });
- assertStrictEquals(obj.etaoin, "success");
- });
-
- it("[[Call]] returns the provided object", () => {
- const obj = {};
- assertStrictEquals(defineOwnProperties(obj), obj);
- });
-});
-
-describe("deleteOwnProperty", () => {
- it("[[Call]] deletes the provided property on the provided object", () => {
- const obj = { failure: undefined };
- deleteOwnProperty(obj, "failure");
- assert(!("failure" in obj));
- });
-
- it("[[Call]] does nothing if the property doesn’t exist", () => {
- const obj = Object.freeze({});
- deleteOwnProperty(obj, "failure");
- assert(!("failure" in obj));
- });
-
- it("[[Call]] throws if the property can’t be deleted", () => {
- const obj = Object.seal({ failure: undefined });
- assertThrows(() => deleteOwnProperty(obj, "failure"));
- });
-
- it("[[Call]] returns the provided object", () => {
- const obj = {};
- assertStrictEquals(deleteOwnProperty(obj, ""), obj);
- });
-});
+ });
+});
describe("frozenCopy", () => {
it("[[Call]] returns a frozen object", () => {
);
});
+ it("[[Call]] preserves data properties", () => {
+ const properties = {
+ implied: {
+ configurable: false,
+ enumerable: true,
+ },
+ writable: {
+ configurable: false,
+ enumerable: true,
+ value: "etaoin",
+ writable: true,
+ },
+ nonwritable: {
+ configurable: false,
+ enumerable: true,
+ value: "shrdlu",
+ writable: false,
+ },
+ };
+ assertEquals(
+ Object.getOwnPropertyDescriptors(
+ frozenCopy(Object.create(null, properties)),
+ ),
+ {
+ implied: {
+ ...properties.implied,
+ value: undefined,
+ writable: false,
+ },
+ writable: { ...properties.writable, writable: false },
+ nonwritable: properties.nonwritable,
+ },
+ );
+ });
+
it("[[Call]] does not copy properties on the prototype", () => {
assert(
!("failure" in
- frozenCopy(Object.create({ failure: undefined }), {
- data: {
- configurable: true,
- value: undefined,
- writable: true,
- },
- accessor: { configurable: true, get: undefined },
- })),
+ frozenCopy(Object.create({ failure: undefined }))),
);
});
null,
);
});
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new frozenCopy({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(frozenCopy.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(frozenCopy.name, "frozenCopy");
+ });
+ });
});
describe("getMethod", () => {
it("[[Call]] throws if the resulting value isn’t callable", () => {
assertThrows(() => getMethod({ "failure": true }, "failure"));
});
-});
-describe("getOwnPropertyKeys", () => {
- it("[[Call]] gets own (but not inherited) property keys", () => {
- assertEquals(getOwnPropertyKeys({ success: true }), ["success"]);
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getMethod({ method() {} }, "method"));
});
- it("[[Call]] works for values coercible to objects", () => {
- assertEquals(getOwnPropertyKeys("foo"), ["0", "1", "2", "length"]);
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getMethod.length, 2);
+ });
});
- it("[[Call]] throws for null and undefined", () => {
- assertThrows(() => getOwnPropertyKeys(null));
- assertThrows(() => getOwnPropertyKeys(undefined));
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(getMethod.name, "getMethod");
+ });
});
});
-describe("getPropertyValue", () => {
- it("[[Call]] gets property values on the provided object", () => {
- assertStrictEquals(
- getPropertyValue({ success: true }, "success"),
- true,
+describe("getOwnPropertyDescriptor", () => {
+ it("[[Call]] gets the descriptor", () => {
+ assertEquals(
+ getOwnPropertyDescriptor({ success: true }, "success"),
+ {
+ configurable: true,
+ enumerable: true,
+ value: true,
+ writable: true,
+ },
);
});
- it("[[Call]] works for values coercible to objects", () => {
+ it("[[Call]] returns undefined for non‐own properties", () => {
assertStrictEquals(
- getPropertyValue("", "toString"),
- String.prototype.toString,
+ getOwnPropertyDescriptor({}, "valueOf"),
+ undefined,
);
});
- it("[[Call]] throws for null and undefined", () => {
- assertThrows(() => getPropertyValue(null, "valueOf"));
- assertThrows(() => getPropertyValue(undefined, "valueOf"));
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getOwnPropertyDescriptor({}, ""));
});
-});
-describe("hasProperty", () => {
- it("[[Call]] gets whether a property exists on the provided object", () => {
- assertStrictEquals(
- hasProperty({ success: "etaoin" }, "success"),
- true,
- );
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getOwnPropertyDescriptor.length, 2);
+ });
});
- it("[[Call]] works for values coercible to objects", () => {
- assertStrictEquals(hasProperty("", "toString"), true);
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ getOwnPropertyDescriptor.name,
+ "getOwnPropertyDescriptor",
+ );
+ });
});
+});
- it("[[Call]] throws for null and undefined", () => {
- assertThrows(() => hasProperty(null, "valueOf"));
- assertThrows(() => hasProperty(undefined, "valueOf"));
+describe("getOwnPropertyDescriptors", () => {
+ it("[[Call]] gets the descriptors", () => {
+ assertEquals(
+ getOwnPropertyDescriptors({ success: true, etaoin: "shrdlu" }),
+ {
+ success: {
+ configurable: true,
+ enumerable: true,
+ value: true,
+ writable: true,
+ },
+ etaoin: {
+ configurable: true,
+ enumerable: true,
+ value: "shrdlu",
+ writable: true,
+ },
+ },
+ );
});
-});
-describe("setPropertyValue", () => {
- it("[[Call]] sets the provided property on the provided object", () => {
- const obj = {};
- setPropertyValue(obj, "success", true);
- assertStrictEquals(obj.success, true);
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getOwnPropertyDescriptors({}));
});
- it("[[Call]] calls setters", () => {
- const setter = spy((_) => {});
- const obj = Object.create(null, { success: { set: setter } });
- setPropertyValue(obj, "success", true);
- assertSpyCalls(setter, 1);
- assertSpyCall(setter, 0, {
- args: [true],
- self: obj,
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getOwnPropertyDescriptors.length, 1);
});
});
- it("[[Call]] walks the prototype chain", () => {
- const setter = spy((_) => {});
- const obj = Object.create(
- Object.create(null, { success: { set: setter } }),
- );
- setPropertyValue(obj, "success", true);
- assertSpyCalls(setter, 1);
- assertSpyCall(setter, 0, {
- args: [true],
- self: obj,
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ getOwnPropertyDescriptors.name,
+ "getOwnPropertyDescriptors",
+ );
+ });
+ });
+});
+
+describe("getOwnPropertyEntries", () => {
+ it("[[Call]] gets own (but not inherited) property entries", () => {
+ assertEquals(
+ getOwnPropertyEntries({ success: true }),
+ [["success", true]],
+ );
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertEquals(
+ getOwnPropertyEntries("foo"),
+ [["0", "f"], ["1", "o"], ["2", "o"], ["length", 3]],
+ );
+ });
+
+ it("[[Call]] uses the provided receiver", () => {
+ const target = {};
+ assertEquals(
+ getOwnPropertyEntries({
+ get success() {
+ return this;
+ },
+ }, target),
+ [["success", target]],
+ );
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => getOwnPropertyEntries(null));
+ assertThrows(() => getOwnPropertyEntries(undefined));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getOwnPropertyEntries({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getOwnPropertyEntries.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ getOwnPropertyEntries.name,
+ "getOwnPropertyEntries",
+ );
+ });
+ });
+});
+
+describe("getOwnPropertyKeys", () => {
+ it("[[Call]] gets own (but not inherited) property keys", () => {
+ assertEquals(getOwnPropertyKeys({ success: true }), ["success"]);
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertEquals(getOwnPropertyKeys("foo"), ["0", "1", "2", "length"]);
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => getOwnPropertyKeys(null));
+ assertThrows(() => getOwnPropertyKeys(undefined));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getOwnPropertyKeys({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getOwnPropertyKeys.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ getOwnPropertyKeys.name,
+ "getOwnPropertyKeys",
+ );
+ });
+ });
+});
+
+describe("getOwnPropertyStrings", () => {
+ it("[[Call]] gets own string keys", () => {
+ assertEquals(getOwnPropertyStrings({ success: true }), [
+ "success",
+ ]);
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertEquals(getOwnPropertyStrings("foo"), [
+ "0",
+ "1",
+ "2",
+ "length",
+ ]);
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => getOwnPropertyStrings(null));
+ assertThrows(() => getOwnPropertyStrings(undefined));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getOwnPropertyStrings({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getOwnPropertyStrings.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ getOwnPropertyStrings.name,
+ "getOwnPropertyStrings",
+ );
+ });
+ });
+});
+
+describe("getOwnPropertySymbols", () => {
+ it("[[Call]] gets own symbol keys", () => {
+ const sym = Symbol();
+ assertEquals(getOwnPropertySymbols({ [sym]: true }), [sym]);
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertEquals(getOwnPropertySymbols("foo"), []);
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => getOwnPropertySymbols(null));
+ assertThrows(() => getOwnPropertySymbols(undefined));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getOwnPropertySymbols({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getOwnPropertySymbols.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ getOwnPropertySymbols.name,
+ "getOwnPropertySymbols",
+ );
+ });
+ });
+});
+
+describe("getOwnPropertyValue", () => {
+ it("[[Call]] gets the own property value", () => {
+ assertStrictEquals(
+ getOwnPropertyValue({ success: true }, "success"),
+ true,
+ );
+ });
+
+ it("[[Call]] returns undefined for non‐own properties", () => {
+ assertStrictEquals(
+ getOwnPropertyValue(Object.create({ success: true }), "success"),
+ undefined,
+ );
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertStrictEquals(getOwnPropertyValue("foo", "length"), 3);
+ });
+
+ it("[[Call]] uses the provided receiver", () => {
+ const target = {};
+ assertStrictEquals(
+ getOwnPropertyValue(
+ {
+ get success() {
+ return this;
+ },
+ },
+ "success",
+ target,
+ ),
+ target,
+ );
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => getOwnPropertyValue(null));
+ assertThrows(() => getOwnPropertyValue(undefined));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getOwnPropertyValue({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getOwnPropertyValue.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ getOwnPropertyValue.name,
+ "getOwnPropertyValue",
+ );
+ });
+ });
+});
+
+describe("getOwnPropertyValues", () => {
+ it("[[Call]] gets own (but not inherited) property values", () => {
+ assertEquals(getOwnPropertyValues({ success: true }), [true]);
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertEquals(
+ getOwnPropertyValues("foo"),
+ ["f", "o", "o", 3],
+ );
+ });
+
+ it("[[Call]] uses the provided receiver", () => {
+ const target = {};
+ assertEquals(
+ getOwnPropertyValues({
+ get success() {
+ return this;
+ },
+ }, target),
+ [target],
+ );
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => getOwnPropertyValues(null));
+ assertThrows(() => getOwnPropertyValues(undefined));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getOwnPropertyValues({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getOwnPropertyValues.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ getOwnPropertyValues.name,
+ "getOwnPropertyValues",
+ );
+ });
+ });
+});
+
+describe("getPropertyValue", () => {
+ it("[[Call]] gets property values on the provided object", () => {
+ assertStrictEquals(
+ getPropertyValue({ success: true }, "success"),
+ true,
+ );
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertStrictEquals(
+ getPropertyValue("", "toString"),
+ String.prototype.toString,
+ );
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => getPropertyValue(null, "valueOf"));
+ assertThrows(() => getPropertyValue(undefined, "valueOf"));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getPropertyValue({}, "valueOf"));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getPropertyValue.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(getPropertyValue.name, "getPropertyValue");
+ });
+ });
+});
+
+describe("getPrototype", () => {
+ it("[[Call]] gets object prototypes", () => {
+ assertStrictEquals(getPrototype({}), Object.prototype);
+ const proto = {};
+ assertStrictEquals(getPrototype(Object.create(proto)), proto);
+ });
+
+ it("[[Call]] gets null prototypes", () => {
+ assertStrictEquals(getPrototype(Object.create(null)), null);
+ });
+
+ it("[[Call]] gets prototypes for coercible primitives", () => {
+ assertStrictEquals(getPrototype(1), Number.prototype);
+ assertStrictEquals(getPrototype(Symbol()), Symbol.prototype);
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => getPrototype(null));
+ assertThrows(() => getPrototype(undefined));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new getPrototype({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(getPrototype.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(getPrototype.name, "getPrototype");
+ });
+ });
+});
+
+describe("hasProperty", () => {
+ it("[[Call]] gets whether a property exists on the provided object", () => {
+ assertStrictEquals(
+ hasProperty({ success: "etaoin" }, "success"),
+ true,
+ );
+ assertStrictEquals(hasProperty({}, "hasOwnProperty"), true);
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertStrictEquals(hasProperty("", "length"), true);
+ assertStrictEquals(hasProperty("", "toString"), true);
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => hasProperty(null, "valueOf"));
+ assertThrows(() => hasProperty(undefined, "valueOf"));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new hasProperty({}, "valueOf"));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(hasProperty.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(hasProperty.name, "hasProperty");
+ });
+ });
+});
+
+describe("hasOwnProperty", () => {
+ it("[[Call]] gets whether an own property exists on the provided object", () => {
+ assertStrictEquals(
+ hasOwnProperty({ success: "etaoin" }, "success"),
+ true,
+ );
+ assertStrictEquals(hasOwnProperty({}, "hasOwnProperty"), false);
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertStrictEquals(hasOwnProperty("", "length"), true);
+ assertStrictEquals(hasOwnProperty("", "toString"), false);
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => hasOwnProperty(null, "valueOf"));
+ assertThrows(() => hasOwnProperty(undefined, "valueOf"));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new hasOwnProperty({}, "valueOf"));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(hasOwnProperty.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(hasOwnProperty.name, "hasOwnProperty");
+ });
+ });
+});
+
+describe("isArraylikeObject", () => {
+ it("[[Call]] returns false for primitives", () => {
+ assertStrictEquals(isArraylikeObject("failure"), false);
+ });
+
+ it("[[Call]] returns false if length throws", () => {
+ assertStrictEquals(
+ isArraylikeObject({
+ get length() {
+ throw void {};
+ },
+ }),
+ false,
+ );
+ });
+
+ it("[[Call]] returns false if length is not a number and cannot be converted to one", () => {
+ assertStrictEquals(isArraylikeObject({ length: 1n }), false);
+ });
+
+ it("[[Call]] returns true if length is convertable to a number", () => {
+ assertStrictEquals(isArraylikeObject({ length: -0 }), true);
+ assertStrictEquals(isArraylikeObject({ length: 1 }), true);
+ assertStrictEquals(isArraylikeObject({ length: -1.25 }), true);
+ assertStrictEquals(
+ isArraylikeObject({ length: 9007199254740992 }),
+ true,
+ );
+ assertStrictEquals(isArraylikeObject({ length: Infinity }), true);
+ assertStrictEquals(isArraylikeObject({ length: "success" }), true);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new isArraylikeObject({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(isArraylikeObject.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ isArraylikeObject.name,
+ "isArraylikeObject",
+ );
+ });
+ });
+});
+
+describe("isConcatSpreadableObject", () => {
+ it("[[Call]] returns false for primitives", () => {
+ assertStrictEquals(isConcatSpreadableObject("failure"), false);
+ });
+
+ it("[[Call]] returns false if [Symbol.isConcatSpreadable] is null or false", () => {
+ assertStrictEquals(
+ isConcatSpreadableObject(
+ Object.assign([], { [Symbol.isConcatSpreadable]: null }),
+ ),
+ false,
+ );
+ assertStrictEquals(
+ isConcatSpreadableObject(
+ Object.assign([], { [Symbol.isConcatSpreadable]: false }),
+ ),
+ false,
+ );
+ });
+
+ it("[[Call]] returns true if [Symbol.isConcatSpreadable] is undefined and the object is an array", () => {
+ assertStrictEquals(
+ isConcatSpreadableObject(
+ Object.assign([], { [Symbol.isConcatSpreadable]: undefined }),
+ ),
+ true,
+ );
+ });
+
+ it("[[Call]] returns true if [Symbol.isConcatSpreadable] is true", () => {
+ assertStrictEquals(
+ isConcatSpreadableObject({ [Symbol.isConcatSpreadable]: true }),
+ true,
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new isConcatSpreadableObject({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(isConcatSpreadableObject.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ isConcatSpreadableObject.name,
+ "isConcatSpreadableObject",
+ );
+ });
+ });
+});
+
+describe("isExtensibleObject", () => {
+ it("[[Call]] returns true for extensible objects", () => {
+ assertStrictEquals(isExtensibleObject({}), true);
+ });
+
+ it("[[Call]] returns false for coercible primitives", () => {
+ assertStrictEquals(isExtensibleObject(1), false);
+ assertStrictEquals(isExtensibleObject(Symbol()), false);
+ });
+
+ it("[[Call]] returns false for non·extensible objects", () => {
+ assertStrictEquals(
+ isExtensibleObject(Object.preventExtensions({})),
+ false,
+ );
+ });
+
+ it("[[Call]] returns false for null and undefined", () => {
+ assertStrictEquals(isExtensibleObject(null), false);
+ assertStrictEquals(isExtensibleObject(undefined), false);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new isExtensibleObject({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(isExtensibleObject.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ isExtensibleObject.name,
+ "isExtensibleObject",
+ );
+ });
+ });
+});
+
+describe("isPropertyDescriptorRecord", () => {
+ it("[[Call]] returns true for objects created by toPropertyDescriptorRecord", () => {
+ assertStrictEquals(
+ isPropertyDescriptorRecord(toPropertyDescriptorRecord({})),
+ true,
+ );
+ });
+
+ it("[[Get]] returns false for other objects", () => {
+ assertStrictEquals(
+ isPropertyDescriptorRecord(Object.create(null)),
+ false,
+ );
+ });
+
+ it("[[Get]] returns false for undefined", () => {
+ assertStrictEquals(isPropertyDescriptorRecord(undefined), false);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new isPropertyDescriptorRecord({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(isPropertyDescriptorRecord.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ isPropertyDescriptorRecord.name,
+ "isPropertyDescriptorRecord",
+ );
+ });
+ });
+});
+
+describe("isUnfrozenObject", () => {
+ it("[[Call]] returns true for unfrozen objects", () => {
+ assertStrictEquals(isUnfrozenObject({}), true);
+ });
+
+ it("[[Call]] returns false for coercible primitives", () => {
+ assertStrictEquals(isUnfrozenObject(1), false);
+ assertStrictEquals(isUnfrozenObject(Symbol()), false);
+ });
+
+ it("[[Call]] returns false for frozen objects", () => {
+ assertStrictEquals(isUnfrozenObject(Object.freeze({})), false);
+ });
+
+ it("[[Call]] returns false for null and undefined", () => {
+ assertStrictEquals(isUnfrozenObject(null), false);
+ assertStrictEquals(isUnfrozenObject(undefined), false);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new isUnfrozenObject({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(isUnfrozenObject.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(isUnfrozenObject.name, "isUnfrozenObject");
+ });
+ });
+});
+
+describe("isUnsealedObject", () => {
+ it("[[Call]] returns true for unsealed objects", () => {
+ assertStrictEquals(isUnsealedObject({}), true);
+ });
+
+ it("[[Call]] returns false for coercible primitives", () => {
+ assertStrictEquals(isUnsealedObject(1), false);
+ assertStrictEquals(isUnsealedObject(Symbol()), false);
+ });
+
+ it("[[Call]] returns false for sealed objects", () => {
+ assertStrictEquals(isUnsealedObject(Object.seal({})), false);
+ });
+
+ it("[[Call]] returns false for null and undefined", () => {
+ assertStrictEquals(isUnsealedObject(null), false);
+ assertStrictEquals(isUnsealedObject(undefined), false);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new isUnsealedObject({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(isUnsealedObject.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(isUnsealedObject.name, "isUnsealedObject");
+ });
+ });
+});
+
+describe("lengthOfArraylike", () => {
+ it("[[Call]] returns the length", () => {
+ assertStrictEquals(
+ lengthOfArraylike({ length: 9007199254740991 }),
+ 9007199254740991,
+ );
+ });
+
+ it("[[Call]] returns a non·nan result", () => {
+ assertStrictEquals(lengthOfArraylike({ length: NaN }), 0);
+ assertStrictEquals(lengthOfArraylike({ length: "failure" }), 0);
+ });
+
+ it("[[Call]] returns an integral result", () => {
+ assertStrictEquals(lengthOfArraylike({ length: 0.25 }), 0);
+ assertStrictEquals(lengthOfArraylike({ length: 1.1 }), 1);
+ });
+
+ it("[[Call]] returns a result greater than or equal to zero", () => {
+ assertStrictEquals(lengthOfArraylike({ length: -0 }), 0);
+ assertStrictEquals(lengthOfArraylike({ length: -1 }), 0);
+ assertStrictEquals(lengthOfArraylike({ length: -Infinity }), 0);
+ });
+
+ it("[[Call]] returns a result less than 2 ** 53", () => {
+ assertStrictEquals(
+ lengthOfArraylike({ length: 9007199254740992 }),
+ 9007199254740991,
+ );
+ assertStrictEquals(
+ lengthOfArraylike({ length: Infinity }),
+ 9007199254740991,
+ );
+ });
+
+ it("[[Call]] does not require an object argument", () => {
+ assertStrictEquals(lengthOfArraylike("string"), 6);
+ assertStrictEquals(lengthOfArraylike(Symbol()), 0);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new lengthOfArraylike(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(lengthOfArraylike.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(lengthOfArraylike.name, "lengthOfArraylike");
+ });
+ });
+});
+
+describe("namedEntries", () => {
+ it("[[Call]] gets named entries", () => {
+ assertEquals(namedEntries({ success: true }), [["success", true]]);
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertEquals(namedEntries("foo"), [
+ ["0", "f"],
+ ["1", "o"],
+ ["2", "o"],
+ ]);
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => namedEntries(null));
+ assertThrows(() => namedEntries(undefined));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new namedEntries({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(namedEntries.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(namedEntries.name, "namedEntries");
+ });
+ });
+});
+
+describe("namedKeys", () => {
+ it("[[Call]] gets named keys", () => {
+ assertEquals(namedKeys({ success: true }), ["success"]);
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertEquals(namedKeys("foo"), [
+ "0",
+ "1",
+ "2",
+ ]);
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => namedKeys(null));
+ assertThrows(() => namedKeys(undefined));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new namedKeys({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(namedKeys.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(namedKeys.name, "namedKeys");
+ });
+ });
+});
+
+describe("namedValues", () => {
+ it("[[Call]] gets named values", () => {
+ assertEquals(namedValues({ success: true }), [true]);
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertEquals(namedValues("foo"), [
+ "f",
+ "o",
+ "o",
+ ]);
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => namedValues(null));
+ assertThrows(() => namedValues(undefined));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new namedValues({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(namedValues.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(namedValues.name, "namedValues");
+ });
+ });
+});
+
+describe("objectCreate", () => {
+ it("[[Call]] creates an object", () => {
+ const obj = objectCreate(null);
+ assertStrictEquals(Object(obj), obj);
+ });
+
+ it("[[Call]] correctly sets the prototype", () => {
+ const proto = {};
+ assertStrictEquals(
+ Object.getPrototypeOf(objectCreate(proto)),
+ proto,
+ );
+ assertStrictEquals(
+ Object.getPrototypeOf(objectCreate(null)),
+ null,
+ );
+ });
+
+ it("[[Call]] correctly sets own properties", () => {
+ assertEquals(
+ Object.getOwnPropertyDescriptors(
+ objectCreate(null, { success: { value: true } }),
+ ),
+ {
+ success: {
+ configurable: false,
+ enumerable: false,
+ value: true,
+ writable: false,
+ },
+ },
+ );
+ });
+
+ it("[[Call]] throws for coercible primitives", () => {
+ assertThrows(() => objectCreate(1));
+ assertThrows(() => objectCreate(Symbol()));
+ });
+
+ it("[[Call]] throws for undefined", () => {
+ assertThrows(() => objectCreate(undefined));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new objectCreate({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(objectCreate.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(objectCreate.name, "objectCreate");
+ });
+ });
+});
+
+describe("objectFromEntries", () => {
+ it("[[Call]] creates an object", () => {
+ const obj = objectFromEntries([]);
+ assertStrictEquals(Object(obj), obj);
+ });
+
+ it("[[Call]] correctly sets the prototype", () => {
+ assertStrictEquals(
+ Object.getPrototypeOf(objectFromEntries([])),
+ Object.prototype,
+ );
+ });
+
+ it("[[Call]] correctly sets own properties", () => {
+ assertEquals(
+ Object.entries(objectFromEntries([["success", true]])),
+ [["success", true]],
+ );
+ });
+
+ it("[[Call]] throws if the argument is not a nested arraylike", () => {
+ assertThrows(() => objectFromEntries(1));
+ assertThrows(() => objectFromEntries(Symbol()));
+ assertThrows(() => objectFromEntries(null));
+ assertThrows(() => objectFromEntries(undefined));
+ assertThrows(() => objectFromEntries({}));
+ assertThrows(() => objectFromEntries([undefined]));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new objectFromEntries([]));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(objectFromEntries.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(objectFromEntries.name, "objectFromEntries");
+ });
+ });
+});
+
+describe("preventExtensions", () => {
+ it("[[Call]] prevents extensions on the object", () => {
+ const obj = {};
+ preventExtensions(obj);
+ assert(!Object.isExtensible(obj));
+ });
+
+ it("[[Call]] returns the provided object", () => {
+ const obj = {};
+ assertStrictEquals(preventExtensions(obj), obj);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new preventExtensions({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(preventExtensions.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(preventExtensions.name, "preventExtensions");
+ });
+ });
+});
+
+describe("seal", () => {
+ it("[[Call]] seals the object", () => {
+ const obj = {};
+ seal(obj);
+ assert(Object.isSealed(obj));
+ });
+
+ it("[[Call]] returns the provided object", () => {
+ const obj = {};
+ assertStrictEquals(seal(obj), obj);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new seal({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(seal.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(seal.name, "seal");
+ });
+ });
+});
+
+describe("setPropertyValue", () => {
+ it("[[Call]] sets the provided property on the provided object", () => {
+ const obj = {};
+ setPropertyValue(obj, "success", true);
+ assertStrictEquals(obj.success, true);
+ });
+
+ it("[[Call]] calls setters", () => {
+ const setter = spy((_) => {});
+ const obj = Object.create(null, { success: { set: setter } });
+ setPropertyValue(obj, "success", true);
+ assertSpyCalls(setter, 1);
+ assertSpyCall(setter, 0, {
+ args: [true],
+ self: obj,
+ });
+ });
+
+ it("[[Call]] walks the prototype chain", () => {
+ const setter = spy((_) => {});
+ const obj = Object.create(
+ Object.create(null, { success: { set: setter } }),
+ );
+ setPropertyValue(obj, "success", true);
+ assertSpyCalls(setter, 1);
+ assertSpyCall(setter, 0, {
+ args: [true],
+ self: obj,
});
});
});
});
- it("[[Call]] throws if the property can’t be set", () => {
- const obj = Object.freeze({ failure: undefined });
- assertThrows(() => setPropertyValue(obj, "failure", true));
+ it("[[Call]] throws if the property can’t be set", () => {
+ const obj = Object.freeze({ failure: undefined });
+ assertThrows(() => setPropertyValue(obj, "failure", true));
+ });
+
+ it("[[Call]] returns the provided object", () => {
+ const obj = {};
+ assertStrictEquals(setPropertyValue(obj, "", undefined), obj);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new setPropertyValue({}, "", undefined));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(setPropertyValue.length, 3);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(setPropertyValue.name, "setPropertyValue");
+ });
+ });
+});
+
+describe("setPropertyValues", () => {
+ it("[[Call]] sets the provided properties on the provided object", () => {
+ const obj = {};
+ setPropertyValues(obj, { success: true, all: "good" });
+ assertStrictEquals(obj.success, true);
+ assertStrictEquals(obj.all, "good");
+ });
+
+ it("[[Call]] can take multiple objects", () => {
+ const obj = {};
+ setPropertyValues(
+ obj,
+ { success: false, all: "good" },
+ { success: true },
+ );
+ assertStrictEquals(obj.success, true);
+ assertStrictEquals(obj.all, "good");
+ });
+
+ it("[[Call]] ignores nullish arguments", () => {
+ const obj = {};
+ setPropertyValues(obj, null, undefined, { success: true });
+ assertStrictEquals(obj.success, true);
+ });
+
+ it("[[Call]] calls setters", () => {
+ const setter = spy((_) => {});
+ const obj = Object.create(null, { success: { set: setter } });
+ setPropertyValues(obj, { success: true });
+ assertSpyCalls(setter, 1);
+ assertSpyCall(setter, 0, {
+ args: [true],
+ self: obj,
+ });
+ });
+
+ it("[[Call]] calls setters multiple times if property appears more than once", () => {
+ const setter = spy((_) => {});
+ const obj = Object.create(null, { success: { set: setter } });
+ setPropertyValues(obj, { success: false }, { success: true });
+ assertSpyCalls(setter, 2);
+ assertSpyCall(setter, 0, {
+ args: [false],
+ self: obj,
+ });
+ assertSpyCall(setter, 1, {
+ args: [true],
+ self: obj,
+ });
+ });
+
+ it("[[Call]] walks the prototype chain", () => {
+ const setter = spy((_) => {});
+ const obj = Object.create(
+ Object.create(null, { success: { set: setter } }),
+ );
+ setPropertyValues(obj, { success: true });
+ assertSpyCalls(setter, 1);
+ assertSpyCall(setter, 0, {
+ args: [true],
+ self: obj,
+ });
+ });
+
+ it("[[Call]] throws if the property can’t be set", () => {
+ const obj = Object.freeze({ failure: undefined });
+ assertThrows(() => setPropertyValues(obj, { failure: true }));
+ });
+
+ it("[[Call]] returns the provided object", () => {
+ const obj = {};
+ assertStrictEquals(setPropertyValues(obj, { "": undefined }), obj);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new setPropertyValues(obj, { "": undefined }));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(setPropertyValues.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(setPropertyValues.name, "setPropertyValues");
+ });
});
+});
- it("[[Call]] returns the provided object", () => {
+describe("setPrototype", () => {
+ it("[[Call]] sets object prototypes", () => {
const obj = {};
- assertStrictEquals(setPropertyValue(obj, "", undefined), obj);
+ const proto = {};
+ setPrototype(obj, proto);
+ assertStrictEquals(Object.getPrototypeOf(obj), proto);
+ });
+
+ it("[[Call]] sets null prototypes", () => {
+ const obj = {};
+ setPrototype(obj, null);
+ assertStrictEquals(Object.getPrototypeOf(obj), null);
+ });
+
+ it("[[Call]] can set coercible primitives to their same prototype", () => {
+ setPrototype(1, Number.prototype);
+ setPrototype(Symbol(), Symbol.prototype);
+ });
+
+ it("[[Call]] throws when setting coercible primitives to a different prototype", () => {
+ assertThrows(() => setPrototype(1, Object.prototype));
+ assertThrows(() => setPrototype(Symbol(), Object.prototype));
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => setPrototype(null, Object.prototype));
+ assertThrows(() => setPrototype(undefined, Object.prototype));
+ });
+
+ it("[[Call]] returns the provided value", () => {
+ const obj = {};
+ assertStrictEquals(setPrototype(obj, null), obj);
+ assertStrictEquals(setPrototype(1, Number.prototype), 1);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new setPrototype({}, null));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(setPrototype.length, 2);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(setPrototype.name, "setPrototype");
+ });
});
});
assertStrictEquals(typeof toObject(sym), "object");
assertStrictEquals(toObject(sym).valueOf(), sym);
});
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new toObject({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(toObject.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(toObject.name, "toObject");
+ });
+ });
});
-describe("toPropertyKey", () => {
- it("returns a string or symbol", () => {
- const sym = Symbol();
- assertStrictEquals(toPropertyKey(sym), sym);
- assertStrictEquals(
- toPropertyKey(new String("success")),
- "success",
- );
+describe("toPropertyDescriptorRecord", () => {
+ it("[[Call]] creates a new property descriptor record", () => {
+ const obj = {};
+ const desc = toPropertyDescriptorRecord(obj);
+ assertEquals(obj, desc);
+ assertNotStrictEquals(obj, desc);
});
- it("favours the `toString` representation", () => {
- assertStrictEquals(
- toPropertyKey({
- toString() {
- return "success";
- },
- valueOf() {
- return "failure";
- },
+ it("[[Call]] coerces the values", () => {
+ assertEquals(
+ toPropertyDescriptorRecord({
+ configurable: undefined,
+ enumerable: undefined,
+ writable: undefined,
}),
- "success",
+ { configurable: false, enumerable: false, writable: false },
);
});
+
+ it("[[Construct]] throws for primitives", () => {
+ assertThrows(() => toPropertyDescriptorRecord(undefined));
+ assertThrows(() => toPropertyDescriptorRecord("failure"));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new toPropertyDescriptorRecord({}));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(toPropertyDescriptorRecord.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ toPropertyDescriptorRecord.name,
+ "toPropertyDescriptorRecord",
+ );
+ });
+ });
+
+ describe("~configurable", () => {
+ it("[[DefineOwnProperty]] coerces to a boolean", () => {
+ const desc = toPropertyDescriptorRecord({});
+ Object.defineProperty(desc, "configurable", {});
+ assertStrictEquals(desc.configurable, false);
+ });
+
+ it("[[DefineOwnProperty]] throws for accessor properties", () => {
+ const desc = toPropertyDescriptorRecord({});
+ assertThrows(() =>
+ Object.defineProperty(desc, "configurable", { get: undefined })
+ );
+ });
+
+ it("[[Set]] coerces to a boolean", () => {
+ const desc = toPropertyDescriptorRecord({});
+ desc.configurable = undefined;
+ assertStrictEquals(desc.configurable, false);
+ });
+
+ it("[[Delete]] works", () => {
+ const desc = toPropertyDescriptorRecord({ configurable: false });
+ delete desc.configurable;
+ assert(!("configurable" in desc));
+ });
+ });
+
+ describe("~enumerable", () => {
+ it("[[DefineOwnProperty]] coerces to a boolean", () => {
+ const desc = toPropertyDescriptorRecord({});
+ Object.defineProperty(desc, "enumerable", {});
+ assertStrictEquals(desc.enumerable, false);
+ });
+
+ it("[[DefineOwnProperty]] throws for accessor properties", () => {
+ const desc = toPropertyDescriptorRecord({});
+ assertThrows(() =>
+ Object.defineProperty(desc, "enumerable", { get: undefined })
+ );
+ });
+
+ it("[[Set]] coerces to a boolean", () => {
+ const desc = toPropertyDescriptorRecord({});
+ desc.enumerable = undefined;
+ assertStrictEquals(desc.enumerable, false);
+ });
+
+ it("[[Delete]] works", () => {
+ const desc = toPropertyDescriptorRecord({ enumerable: false });
+ delete desc.enumerable;
+ assert(!("enumerable" in desc));
+ });
+ });
+
+ describe("~get", () => {
+ it("[[DefineOwnProperty]] works", () => {
+ const desc = toPropertyDescriptorRecord({});
+ Object.defineProperty(desc, "get", {});
+ assertStrictEquals(desc.get, undefined);
+ });
+
+ it("[[DefineOwnProperty]] throws for accessor properties", () => {
+ const desc = toPropertyDescriptorRecord({});
+ assertThrows(() =>
+ Object.defineProperty(desc, "get", { get: undefined })
+ );
+ });
+
+ it("[[DefineOwnProperty]] throws if not callable or undefined", () => {
+ const desc = toPropertyDescriptorRecord({});
+ assertThrows(
+ () => Object.defineProperty(desc, "get", { value: null }),
+ );
+ });
+
+ it("[[DefineOwnProperty]] throws if a data property is defined", () => {
+ const desc = toPropertyDescriptorRecord({ value: undefined });
+ assertThrows(() => Object.defineProperty(desc, "get", {}));
+ });
+
+ it("[[Set]] works", () => {
+ const desc = toPropertyDescriptorRecord({});
+ const fn = () => {};
+ desc.get = fn;
+ assertStrictEquals(desc.get, fn);
+ });
+
+ it("[[Set]] throws if not callable or undefined", () => {
+ const desc = toPropertyDescriptorRecord({});
+ assertThrows(() => desc.get = null);
+ });
+
+ it("[[Set]] throws if a data property is defined", () => {
+ const desc = toPropertyDescriptorRecord({ value: undefined });
+ assertThrows(() => desc.get = undefined);
+ });
+
+ it("[[Delete]] works", () => {
+ const desc = toPropertyDescriptorRecord({ get: undefined });
+ delete desc.get;
+ assert(!("get" in desc));
+ });
+ });
+
+ describe("~set", () => {
+ it("[[DefineOwnProperty]] works", () => {
+ const desc = toPropertyDescriptorRecord({});
+ Object.defineProperty(desc, "set", {});
+ assertStrictEquals(desc.set, undefined);
+ });
+
+ it("[[DefineOwnProperty]] throws for accessor properties", () => {
+ const desc = toPropertyDescriptorRecord({});
+ assertThrows(() =>
+ Object.defineProperty(desc, "set", { get: undefined })
+ );
+ });
+
+ it("[[DefineOwnProperty]] throws if not callable or undefined", () => {
+ const desc = toPropertyDescriptorRecord({});
+ assertThrows(
+ () => Object.defineProperty(desc, "set", { value: null }),
+ );
+ });
+
+ it("[[DefineOwnProperty]] throws if a data property is defined", () => {
+ const desc = toPropertyDescriptorRecord({ value: undefined });
+ assertThrows(() => Object.defineProperty(desc, "set", {}));
+ });
+
+ it("[[Set]] works", () => {
+ const desc = toPropertyDescriptorRecord({});
+ const fn = (_) => {};
+ desc.set = fn;
+ assertStrictEquals(desc.set, fn);
+ });
+
+ it("[[Set]] throws if not callable or undefined", () => {
+ const desc = toPropertyDescriptorRecord({});
+ assertThrows(() => desc.set = null);
+ });
+
+ it("[[Set]] throws if a data property is defined", () => {
+ const desc = toPropertyDescriptorRecord({ value: undefined });
+ assertThrows(() => desc.set = undefined);
+ });
+
+ it("[[Delete]] works", () => {
+ const desc = toPropertyDescriptorRecord({ set: undefined });
+ delete desc.set;
+ assert(!("set" in desc));
+ });
+ });
+
+ describe("~value", () => {
+ it("[[DefineOwnProperty]] works", () => {
+ const desc = toPropertyDescriptorRecord({});
+ Object.defineProperty(desc, "value", {});
+ assertStrictEquals(desc.value, undefined);
+ });
+
+ it("[[DefineOwnProperty]] throws for accessor properties", () => {
+ const desc = toPropertyDescriptorRecord({});
+ assertThrows(() =>
+ Object.defineProperty(desc, "value", { get: undefined })
+ );
+ });
+
+ it("[[DefineOwnProperty]] throws if an accessor property is defined", () => {
+ const desc = toPropertyDescriptorRecord({ get: undefined });
+ assertThrows(() => Object.defineProperty(desc, "value", {}));
+ });
+
+ it("[[Set]] works", () => {
+ const desc = toPropertyDescriptorRecord({});
+ desc.value = "success";
+ assertStrictEquals(desc.value, "success");
+ });
+
+ it("[[Set]] throws if an accessor property is defined", () => {
+ const desc = toPropertyDescriptorRecord({ get: undefined });
+ assertThrows(() => desc.value = null);
+ });
+
+ it("[[Delete]] works", () => {
+ const desc = toPropertyDescriptorRecord({ value: undefined });
+ delete desc.value;
+ assert(!("value" in desc));
+ });
+ });
+
+ describe("~writable", () => {
+ it("[[DefineOwnProperty]] coerces to a boolean", () => {
+ const desc = toPropertyDescriptorRecord({});
+ Object.defineProperty(desc, "writable", {});
+ assertStrictEquals(desc.writable, false);
+ });
+
+ it("[[DefineOwnProperty]] throws for accessor properties", () => {
+ const desc = toPropertyDescriptorRecord({});
+ assertThrows(() =>
+ Object.defineProperty(desc, "writable", { get: undefined })
+ );
+ });
+
+ it("[[DefineOwnProperty]] throws if an accessor property is defined", () => {
+ const desc = toPropertyDescriptorRecord({ get: undefined });
+ assertThrows(() => Object.defineProperty(desc, "writable", {}));
+ });
+
+ it("[[Set]] coerces to a boolean", () => {
+ const desc = toPropertyDescriptorRecord({});
+ desc.writable = undefined;
+ assertStrictEquals(desc.writable, false);
+ });
+
+ it("[[Set]] throws if an accessor property is defined", () => {
+ const desc = toPropertyDescriptorRecord({ get: undefined });
+ assertThrows(() => desc.writable = false);
+ });
+
+ it("[[Delete]] works", () => {
+ const desc = toPropertyDescriptorRecord({ writable: false });
+ delete desc.writable;
+ assert(!("writable" in desc));
+ });
+ });
});