Serenity Operating System
at master 242 lines 6.9 kB view raw
1test("deleting object properties", () => { 2 const o = {}; 3 o.x = 1; 4 o.y = 2; 5 o.z = 3; 6 expect(Object.getOwnPropertyNames(o)).toHaveLength(3); 7 8 expect(delete o.x).toBeTrue(); 9 expect(o.hasOwnProperty("x")).toBeFalse(); 10 expect(o.hasOwnProperty("y")).toBeTrue(); 11 expect(o.hasOwnProperty("z")).toBeTrue(); 12 expect(Object.getOwnPropertyNames(o)).toHaveLength(2); 13 14 expect(delete o.y).toBeTrue(); 15 expect(o.hasOwnProperty("x")).toBeFalse(); 16 expect(o.hasOwnProperty("y")).toBeFalse(); 17 expect(o.hasOwnProperty("z")).toBeTrue(); 18 expect(Object.getOwnPropertyNames(o)).toHaveLength(1); 19 20 expect(delete o.z).toBeTrue(); 21 expect(o.hasOwnProperty("x")).toBeFalse(); 22 expect(o.hasOwnProperty("y")).toBeFalse(); 23 expect(o.hasOwnProperty("z")).toBeFalse(); 24 expect(Object.getOwnPropertyNames(o)).toHaveLength(0); 25}); 26 27test("deleting array indices", () => { 28 const a = [3, 5, 7]; 29 30 expect(Object.getOwnPropertyNames(a)).toHaveLength(4); 31 32 expect(delete a[0]).toBeTrue(); 33 expect(a.hasOwnProperty(0)).toBeFalse(); 34 expect(a.hasOwnProperty(1)).toBeTrue(); 35 expect(a.hasOwnProperty(2)).toBeTrue(); 36 expect(Object.getOwnPropertyNames(a)).toHaveLength(3); 37 38 expect(delete a[1]).toBeTrue(); 39 expect(a.hasOwnProperty(0)).toBeFalse(); 40 expect(a.hasOwnProperty(1)).toBeFalse(); 41 expect(a.hasOwnProperty(2)).toBeTrue(); 42 expect(Object.getOwnPropertyNames(a)).toHaveLength(2); 43 44 expect(delete a[2]).toBeTrue(); 45 expect(a.hasOwnProperty(0)).toBeFalse(); 46 expect(a.hasOwnProperty(1)).toBeFalse(); 47 expect(a.hasOwnProperty(2)).toBeFalse(); 48 expect(Object.getOwnPropertyNames(a)).toHaveLength(1); 49 50 expect(delete a["42"]).toBeTrue(); 51 expect(Object.getOwnPropertyNames(a)).toHaveLength(1); 52}); 53 54test("deleting non-configurable property", () => { 55 const q = {}; 56 Object.defineProperty(q, "foo", { value: 1, writable: false, enumerable: false }); 57 expect(q.foo).toBe(1); 58 59 expect(delete q.foo).toBeFalse(); 60 expect(q.hasOwnProperty("foo")).toBeTrue(); 61}); 62 63test("deleting non-configurable property throws in strict mode", () => { 64 "use strict"; 65 const q = {}; 66 Object.defineProperty(q, "foo", { value: 1, writable: false, enumerable: false }); 67 expect(q.foo).toBe(1); 68 69 expect(() => { 70 delete q.foo; 71 }).toThrowWithMessage(TypeError, "Cannot delete property 'foo' of [object Object]"); 72 expect(q.hasOwnProperty("foo")).toBeTrue(); 73}); 74 75test("deleting super property", () => { 76 class A { 77 foo() {} 78 } 79 80 class B extends A { 81 bar() { 82 delete super.foo; 83 } 84 85 baz() { 86 delete super["foo"]; 87 } 88 } 89 90 const obj = new B(); 91 expect(() => { 92 obj.bar(); 93 }).toThrowWithMessage(ReferenceError, "Can't delete a property on 'super'"); 94 95 expect(() => { 96 obj.baz(); 97 }).toThrowWithMessage(ReferenceError, "Can't delete a property on 'super'"); 98}); 99 100test("deleting an object computed property coerces the object to a property key", () => { 101 let called = false; 102 const obj = { prop1: 1, 2: 2 }; 103 104 function createToPrimitiveFunction(object, valueToReturn) { 105 return function (hint) { 106 called = true; 107 console.log(this, object); 108 expect(this).toBe(object); 109 expect(hint).toBe("string"); 110 return valueToReturn; 111 }; 112 } 113 114 const a = { 115 [Symbol.toPrimitive]: function (hint) { 116 called = true; 117 expect(this).toBe(a); 118 expect(hint).toBe("string"); 119 return "prop1"; 120 }, 121 }; 122 123 const b = { 124 [Symbol.toPrimitive]: function (hint) { 125 called = true; 126 expect(this).toBe(b); 127 expect(hint).toBe("string"); 128 return 2; 129 }, 130 }; 131 132 const c = { 133 [Symbol.toPrimitive]: function (hint) { 134 called = true; 135 expect(this).toBe(c); 136 expect(hint).toBe("string"); 137 return {}; 138 }, 139 }; 140 141 expect(Object.hasOwn(obj, "prop1")).toBeTrue(); 142 expect(Object.hasOwn(obj, 2)).toBeTrue(); 143 144 expect(delete obj[a]).toBeTrue(); 145 expect(called).toBeTrue(); 146 expect(Object.hasOwn(obj, "prop1")).toBeFalse(); 147 expect(Object.hasOwn(obj, 2)).toBeTrue(); 148 expect(obj.prop1).toBeUndefined(); 149 expect(obj[2]).toBe(2); 150 151 called = false; 152 expect(delete obj[b]).toBeTrue(); 153 expect(called).toBeTrue(); 154 expect(Object.hasOwn(obj, "prop1")).toBeFalse(); 155 expect(Object.hasOwn(obj, 2)).toBeFalse(); 156 expect(obj.prop1).toBeUndefined(); 157 expect(obj[2]).toBeUndefined(); 158 159 called = false; 160 expect(() => { 161 delete obj[c]; 162 }).toThrowWithMessage( 163 TypeError, 164 `Can't convert [object Object] to primitive with hint "string", its @@toPrimitive method returned an object` 165 ); 166 expect(called).toBeTrue(); 167}); 168 169test("deleting a symbol returned by @@toPrimitive", () => { 170 let called = false; 171 const obj = { [Symbol.toStringTag]: "hello world" }; 172 173 const a = { 174 [Symbol.toPrimitive]: function (hint) { 175 called = true; 176 expect(this).toBe(a); 177 expect(hint).toBe("string"); 178 return Symbol.toStringTag; 179 }, 180 }; 181 182 expect(Object.hasOwn(obj, Symbol.toStringTag)).toBeTrue(); 183 expect(delete obj[a]).toBeTrue(); 184 expect(called).toBeTrue(); 185 expect(Object.hasOwn(obj, Symbol.toStringTag)).toBeFalse(); 186 expect(obj[Symbol.toStringTag]).toBeUndefined(); 187}); 188 189// FIXME: This currently does not work with the AST interpreter, but works with Bytecode. 190test.skip("delete always evaluates the lhs", () => { 191 const obj = { prop: 1 }; 192 let called = false; 193 function a() { 194 called = true; 195 return obj; 196 } 197 expect(delete a()).toBeTrue(); 198 expect(called).toBeTrue(); 199 expect(obj).toBeDefined(); 200 expect(Object.hasOwn(obj, "prop")).toBeTrue(); 201 expect(obj.prop).toBe(1); 202 203 called = false; 204 expect(delete a().prop).toBeTrue(); 205 expect(called).toBeTrue(); 206 expect(obj).toBeDefined(); 207 expect(Object.hasOwn(obj, "prop")).toBeFalse(); 208 expect(obj.prop).toBeUndefined(); 209 210 let b = 1; 211 expect(delete ++b).toBeTrue(); 212 expect(b).toBe(2); 213 214 expect(delete b++).toBeTrue(); 215 expect(b).toBe(3); 216 217 let c = { d: 1 }; 218 expect(delete (b = c)).toBeTrue(); 219 expect(b).toBeDefined(); 220 expect(c).toBeDefined(); 221 expect(b).toBe(c); 222 223 function d() { 224 throw new Error("called"); 225 } 226 227 expect(() => { 228 delete d(); 229 }).toThrowWithMessage(Error, "called"); 230 231 expect(() => { 232 delete d().stack; 233 }).toThrowWithMessage(Error, "called"); 234 235 expect(() => { 236 delete ~d(); 237 }).toThrowWithMessage(Error, "called"); 238 239 expect(() => { 240 delete new d(); 241 }).toThrowWithMessage(Error, "called"); 242});