import {
assert,
assertEquals,
+ assertNotStrictEquals,
assertSpyCall,
assertSpyCalls,
assertStrictEquals,
spy,
} from "./dev-deps.js";
import {
+ defineOwnDataProperty,
+ defineOwnNonenumerableDataProperty,
defineOwnProperties,
defineOwnProperty,
deleteOwnProperty,
getMethod,
getOwnPropertyDescriptor,
getOwnPropertyDescriptors,
+ getOwnPropertyEntries,
getOwnPropertyKeys,
getOwnPropertyStrings,
getOwnPropertySymbols,
+ getOwnPropertyValue,
+ getOwnPropertyValues,
getPropertyValue,
getPrototype,
hasOwnProperty,
isArraylikeObject,
isConcatSpreadableObject,
isExtensibleObject,
+ isPropertyDescriptorRecord,
isUnfrozenObject,
isUnsealedObject,
LazyLoader,
objectCreate,
objectFromEntries,
preventExtensions,
- PropertyDescriptor,
seal,
setPropertyValue,
setPropertyValues,
setPrototype,
toObject,
- toPropertyKey,
+ toPropertyDescriptorRecord,
} from "./object.js";
describe("LazyLoader", () => {
});
});
-describe("PropertyDescriptor", () => {
- it("[[Call]] throws an error", () => {
- assertThrows(() => PropertyDescriptor({}));
+describe("defineOwnDataProperty", () => {
+ it("[[Call]] defines the property", () => {
+ const obj = {};
+ defineOwnDataProperty(obj, "etaoin", "success");
+ assert(Object.hasOwn(obj, "etaoin"));
+ assertStrictEquals(obj.etaoin, "success");
+ });
+
+ 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("[[Construct]] creates a new PropertyDescriptor", () => {
+ it("[[Call]] returns the provided object", () => {
+ const obj = {};
assertStrictEquals(
- Object.getPrototypeOf(new PropertyDescriptor({})),
- PropertyDescriptor.prototype,
+ defineOwnDataProperty(obj, "etaoin", null),
+ obj,
);
});
- it("[[Construct]] throws for primitives", () => {
- assertThrows(() => new PropertyDescriptor("failure"));
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new defineOwnDataProperty(obj, "etaoin", null));
});
describe(".length", () => {
it("[[Get]] returns the correct length", () => {
- assertStrictEquals(PropertyDescriptor.length, 1);
+ assertStrictEquals(defineOwnDataProperty.length, 3);
});
});
describe(".name", () => {
it("[[Get]] returns the correct name", () => {
assertStrictEquals(
- PropertyDescriptor.name,
- "PropertyDescriptor",
+ defineOwnDataProperty.name,
+ "defineOwnDataProperty",
);
});
});
+});
- 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,
- });
- });
-
- 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,
- });
- });
+describe("defineOwnNonenumerableDataProperty", () => {
+ it("[[Call]] defines the property", () => {
+ const obj = {};
+ defineOwnNonenumerableDataProperty(obj, "etaoin", "success");
+ assert(Object.hasOwn(obj, "etaoin"));
+ assertStrictEquals(obj.etaoin, "success");
+ });
- it("[[Call]] completes an accessor descriptor", () => {
- const desc = { get: undefined };
- PropertyDescriptor.prototype.complete.call(desc);
- assertEquals(desc, {
- configurable: false,
+ it("[[Call]] defines a configurable, non·enumerable, writable property", () => {
+ const obj = {};
+ defineOwnNonenumerableDataProperty(obj, "etaoin", "success");
+ assertEquals(
+ Object.getOwnPropertyDescriptor(obj, "etaoin"),
+ {
+ configurable: true,
enumerable: false,
- get: undefined,
- set: undefined,
- });
- });
-
- describe(".length", () => {
- it("[[Get]] returns the correct length", () => {
- assertStrictEquals(
- PropertyDescriptor.prototype.complete.length,
- 0,
- );
- });
- });
-
- describe(".name", () => {
- it("[[Get]] returns the correct name", () => {
- assertStrictEquals(
- PropertyDescriptor.prototype.complete.name,
- "complete",
- );
- });
- });
+ value: "success",
+ writable: true,
+ },
+ );
});
- describe("::isAccessorDescriptor", () => {
- it("[[Get]] returns false for a generic descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isAccessorDescriptor",
- {},
- ),
- false,
- );
- });
-
- it("[[Get]] returns false for a data descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isAccessorDescriptor",
- { value: undefined },
- ),
- false,
- );
- });
-
- it("[[Get]] returns true for an accessor descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isAccessorDescriptor",
- { get: undefined },
- ),
- true,
- );
- });
-
- describe("[[GetOwnProperty]].get.length", () => {
- it("[[Get]] returns the correct length", () => {
- assertStrictEquals(
- Object.getOwnPropertyDescriptor(
- PropertyDescriptor.prototype,
- "isAccessorDescriptor",
- ).get.length,
- 0,
- );
- });
- });
-
- describe("[[GetOwnProperty]].get.name", () => {
- it("[[Get]] returns the correct name", () => {
- assertStrictEquals(
- Object.getOwnPropertyDescriptor(
- PropertyDescriptor.prototype,
- "isAccessorDescriptor",
- ).get.name,
- "get isAccessorDescriptor",
- );
- });
- });
+ it("[[Call]] returns the provided object", () => {
+ const obj = {};
+ assertStrictEquals(
+ defineOwnNonenumerableDataProperty(obj, "etaoin", null),
+ obj,
+ );
});
- describe("::isDataDescriptor", () => {
- it("[[Get]] returns false for a generic descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isDataDescriptor",
- {},
- ),
- false,
- );
- });
-
- it("[[Get]] returns true for a data descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isDataDescriptor",
- { value: undefined },
- ),
- true,
- );
- });
-
- it("[[Get]] returns false for an accessor descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isDataDescriptor",
- { get: undefined },
- ),
- false,
- );
- });
-
- describe("[[GetOwnProperty]].get.length", () => {
- it("[[Get]] returns the correct length", () => {
- assertStrictEquals(
- Object.getOwnPropertyDescriptor(
- PropertyDescriptor.prototype,
- "isDataDescriptor",
- ).get.length,
- 0,
- );
- });
- });
-
- describe("[[GetOwnProperty]].get.name", () => {
- it("[[Get]] returns the correct name", () => {
- assertStrictEquals(
- Object.getOwnPropertyDescriptor(
- PropertyDescriptor.prototype,
- "isDataDescriptor",
- ).get.name,
- "get isDataDescriptor",
- );
- });
- });
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() =>
+ new defineOwnNonenumerableDataProperty(obj, "etaoin", null)
+ );
});
- describe("::isFullyPopulated", () => {
- it("[[Get]] returns false for a generic descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isFullyPopulated",
- {},
- ),
- false,
- );
- });
-
- it("[[Get]] returns false for a non‐fully‐populated data descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isFullyPopulated",
- { value: undefined },
- ),
- false,
- );
- });
-
- it("[[Get]] returns true for a fully‐populated data descriptor", () => {
- assertStrictEquals(
- Reflect.get(PropertyDescriptor.prototype, "isFullyPopulated", {
- configurable: true,
- enumerable: true,
- value: undefined,
- writable: true,
- }),
- true,
- );
- });
-
- it("[[Get]] returns false for a non‐fully‐populated accessor descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isFullyPopulated",
- { get: undefined },
- ),
- false,
- );
- });
-
- 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,
- );
- });
-
- describe("[[GetOwnProperty]].get.length", () => {
- it("[[Get]] returns the correct length", () => {
- assertStrictEquals(
- Object.getOwnPropertyDescriptor(
- PropertyDescriptor.prototype,
- "isFullyPopulated",
- ).get.length,
- 0,
- );
- });
- });
-
- describe("[[GetOwnProperty]].get.name", () => {
- it("[[Get]] returns the correct name", () => {
- assertStrictEquals(
- Object.getOwnPropertyDescriptor(
- PropertyDescriptor.prototype,
- "isFullyPopulated",
- ).get.name,
- "get isFullyPopulated",
- );
- });
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(defineOwnNonenumerableDataProperty.length, 3);
});
});
- describe("::isGenericDescriptor", () => {
- it("[[Get]] returns true for a generic descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isGenericDescriptor",
- {},
- ),
- true,
- );
- });
-
- it("[[Get]] returns true for a data descriptor", () => {
- assertStrictEquals(
- Reflect.get(
- PropertyDescriptor.prototype,
- "isGenericDescriptor",
- { value: undefined },
- ),
- false,
- );
- });
-
- 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,
+ defineOwnNonenumerableDataProperty.name,
+ "defineOwnNonenumerableDataProperty",
);
});
-
- describe("[[GetOwnProperty]].get.length", () => {
- it("[[Get]] returns the correct length", () => {
- assertStrictEquals(
- Object.getOwnPropertyDescriptor(
- PropertyDescriptor.prototype,
- "isGenericDescriptor",
- ).get.length,
- 0,
- );
- });
- });
-
- describe("[[GetOwnProperty]].get.name", () => {
- it("[[Get]] returns the correct name", () => {
- assertStrictEquals(
- Object.getOwnPropertyDescriptor(
- PropertyDescriptor.prototype,
- "isGenericDescriptor",
- ).get.name,
- "get isGenericDescriptor",
- );
- });
- });
- });
-
- describe("~configurable", () => {
- it("[[DefineOwnProperty]] coerces to a boolean", () => {
- const desc = new PropertyDescriptor({});
- Object.defineProperty(desc, "configurable", {});
- assertStrictEquals(desc.configurable, false);
- });
-
- it("[[DefineOwnProperty]] throws for accessor properties", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(() =>
- Object.defineProperty(desc, "configurable", { get: undefined })
- );
- });
-
- it("[[Set]] coerces to a boolean", () => {
- const desc = new PropertyDescriptor({});
- desc.configurable = undefined;
- assertStrictEquals(desc.configurable, false);
- });
-
- it("[[Delete]] works", () => {
- const desc = new PropertyDescriptor({ configurable: false });
- delete desc.configurable;
- assert(!("configurable" in desc));
- });
- });
-
- describe("~enumerable", () => {
- it("[[DefineOwnProperty]] coerces to a boolean", () => {
- const desc = new PropertyDescriptor({});
- Object.defineProperty(desc, "enumerable", {});
- assertStrictEquals(desc.enumerable, false);
- });
-
- it("[[DefineOwnProperty]] throws for accessor properties", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(() =>
- Object.defineProperty(desc, "enumerable", { get: undefined })
- );
- });
-
- 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("~get", () => {
- it("[[DefineOwnProperty]] works", () => {
- const desc = new PropertyDescriptor({});
- Object.defineProperty(desc, "get", {});
- assertStrictEquals(desc.get, undefined);
- });
-
- it("[[DefineOwnProperty]] throws for accessor properties", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(() =>
- Object.defineProperty(desc, "get", { get: undefined })
- );
- });
-
- it("[[DefineOwnProperty]] throws if not callable or undefined", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(
- () => Object.defineProperty(desc, "get", { value: null }),
- );
- });
-
- it("[[DefineOwnProperty]] throws if a data property is defined", () => {
- const desc = new PropertyDescriptor({ value: undefined });
- assertThrows(() => Object.defineProperty(desc, "get", {}));
- });
-
- it("[[Set]] works", () => {
- const desc = new PropertyDescriptor({});
- const fn = () => {};
- desc.get = fn;
- assertStrictEquals(desc.get, fn);
- });
-
- it("[[Set]] throws if not callable or undefined", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(() => desc.get = null);
- });
-
- it("[[Set]] throws if a data property is defined", () => {
- const desc = new PropertyDescriptor({ value: undefined });
- assertThrows(() => desc.get = undefined);
- });
-
- it("[[Delete]] works", () => {
- const desc = new PropertyDescriptor({ get: undefined });
- delete desc.get;
- assert(!("get" in desc));
- });
- });
-
- describe("~set", () => {
- it("[[DefineOwnProperty]] works", () => {
- const desc = new PropertyDescriptor({});
- Object.defineProperty(desc, "set", {});
- assertStrictEquals(desc.set, undefined);
- });
-
- it("[[DefineOwnProperty]] throws for accessor properties", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(() =>
- Object.defineProperty(desc, "set", { get: undefined })
- );
- });
-
- it("[[DefineOwnProperty]] throws if not callable or undefined", () => {
- const desc = new PropertyDescriptor({});
- assertThrows(
- () => Object.defineProperty(desc, "set", { value: null }),
- );
- });
-
- 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));
- });
});
});
it("[[Call]] defines the property", () => {
const obj = {};
defineOwnProperty(obj, "etaoin", {});
- assert("etaoin" in obj);
+ assert(Object.hasOwn(obj, "etaoin"));
});
it("[[Call]] returns the provided 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 }))),
);
});
});
});
+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"]);
describe(".name", () => {
it("[[Get]] returns the correct name", () => {
assertStrictEquals(
- getOwnPropertyStrings.name,
- "getOwnPropertyStrings",
+ 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("getOwnPropertySymbols", () => {
- it("[[Call]] gets own symbol keys", () => {
- const sym = Symbol();
- assertEquals(getOwnPropertySymbols({ [sym]: true }), [sym]);
+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(getOwnPropertySymbols("foo"), []);
+ 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(() => getOwnPropertySymbols(null));
- assertThrows(() => getOwnPropertySymbols(undefined));
+ assertThrows(() => getOwnPropertyValues(null));
+ assertThrows(() => getOwnPropertyValues(undefined));
});
it("[[Construct]] throws an error", () => {
- assertThrows(() => new getOwnPropertySymbols({}));
+ assertThrows(() => new getOwnPropertyValues({}));
});
describe(".length", () => {
it("[[Get]] returns the correct length", () => {
- assertStrictEquals(getOwnPropertySymbols.length, 1);
+ assertStrictEquals(getOwnPropertyValues.length, 1);
});
});
describe(".name", () => {
it("[[Get]] returns the correct name", () => {
assertStrictEquals(
- getOwnPropertySymbols.name,
- "getOwnPropertySymbols",
+ getOwnPropertyValues.name,
+ "getOwnPropertyValues",
);
});
});
});
});
+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);
});
});
-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 toPropertyKey(""));
+ assertThrows(() => new toPropertyDescriptorRecord({}));
});
describe(".length", () => {
it("[[Get]] returns the correct length", () => {
- assertStrictEquals(toPropertyKey.length, 1);
+ assertStrictEquals(toPropertyDescriptorRecord.length, 1);
});
});
describe(".name", () => {
it("[[Get]] returns the correct name", () => {
- assertStrictEquals(toPropertyKey.name, "toPropertyKey");
+ 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));
});
});
});