Proxy.handler-getOwnPropertyDescriptor.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. describe("[Call][GetOwnProperty]] trap normal behavior", () => {
  2. test("forwarding when not defined in handler", () => {
  3. expect(
  4. Object.getOwnPropertyDescriptor(new Proxy({}, { getOwnPropertyDescriptor: null }), "a")
  5. ).toBeUndefined();
  6. expect(
  7. Object.getOwnPropertyDescriptor(
  8. new Proxy({}, { getOwnPropertyDescriptor: undefined }),
  9. "a"
  10. )
  11. ).toBeUndefined();
  12. expect(Object.getOwnPropertyDescriptor(new Proxy({}, {}), "a")).toBeUndefined();
  13. });
  14. test("correct arguments supplied to trap", () => {
  15. let o = {};
  16. let p = new Proxy(o, {
  17. getOwnPropertyDescriptor(target, property) {
  18. expect(target).toBe(o);
  19. expect(property).toBe("foo");
  20. },
  21. });
  22. Object.getOwnPropertyDescriptor(p, "foo");
  23. });
  24. test("correct arguments passed to trap even for number", () => {
  25. let o = {};
  26. let p = new Proxy(o, {
  27. getOwnPropertyDescriptor(target, property) {
  28. expect(target).toBe(o);
  29. expect(property).toBe("1");
  30. },
  31. });
  32. Object.getOwnPropertyDescriptor(p, 1);
  33. });
  34. test("conditional returned descriptor", () => {
  35. let o = { foo: "bar" };
  36. Object.defineProperty(o, "baz", {
  37. value: "qux",
  38. enumerable: false,
  39. configurable: true,
  40. writable: false,
  41. });
  42. let p = new Proxy(o, {
  43. getOwnPropertyDescriptor(target, property) {
  44. if (property === "baz") return Object.getOwnPropertyDescriptor(target, "baz");
  45. return {
  46. value: target[property],
  47. enumerable: false,
  48. configurable: true,
  49. writable: true,
  50. };
  51. },
  52. });
  53. expect(p).toHaveConfigurableProperty("baz");
  54. expect(p).not.toHaveEnumerableProperty("baz");
  55. expect(p).not.toHaveWritableProperty("baz");
  56. expect(p).toHaveValueProperty("baz", "qux");
  57. expect(p).not.toHaveGetterProperty("baz");
  58. expect(p).not.toHaveSetterProperty("baz");
  59. d = Object.getOwnPropertyDescriptor(p, "foo");
  60. expect(p).toHaveConfigurableProperty("foo");
  61. expect(p).not.toHaveEnumerableProperty("foo");
  62. expect(p).toHaveWritableProperty("foo");
  63. expect(p).toHaveValueProperty("foo", "bar");
  64. expect(p).not.toHaveGetterProperty("foo");
  65. expect(p).not.toHaveSetterProperty("foo");
  66. });
  67. });
  68. describe("[[GetOwnProperty]] invariants", () => {
  69. test("must return an object or undefined", () => {
  70. expect(() => {
  71. Object.getOwnPropertyDescriptor(
  72. new Proxy(
  73. {},
  74. {
  75. getOwnPropertyDescriptor() {
  76. return 1;
  77. },
  78. }
  79. )
  80. );
  81. }).toThrowWithMessage(
  82. TypeError,
  83. "Proxy handler's getOwnPropertyDescriptor trap violates invariant: must return an object or undefined"
  84. );
  85. });
  86. test("cannot return undefined for a non-configurable property", () => {
  87. let o = {};
  88. Object.defineProperty(o, "foo", { value: 10, configurable: false });
  89. let p = new Proxy(o, {
  90. getOwnPropertyDescriptor() {
  91. return undefined;
  92. },
  93. });
  94. expect(Object.getOwnPropertyDescriptor(p, "bar")).toBeUndefined();
  95. expect(() => {
  96. Object.getOwnPropertyDescriptor(p, "foo");
  97. }).toThrowWithMessage(
  98. TypeError,
  99. "Proxy handler's getOwnPropertyDescriptor trap violates invariant: cannot return undefined for a property on the target which is a non-configurable property"
  100. );
  101. });
  102. test("cannot return undefined for an existing property if the target is non-extensible", () => {
  103. let o = {};
  104. Object.defineProperty(o, "baz", {
  105. value: 20,
  106. configurable: true,
  107. writable: true,
  108. enumerable: true,
  109. });
  110. Object.preventExtensions(o);
  111. let p = new Proxy(o, {
  112. getOwnPropertyDescriptor() {
  113. return undefined;
  114. },
  115. });
  116. expect(() => {
  117. Object.getOwnPropertyDescriptor(p, "baz");
  118. }).toThrowWithMessage(
  119. TypeError,
  120. "Proxy handler's getOwnPropertyDescriptor trap violates invariant: cannot report a property as being undefined if it exists as an own property of the target and the target is non-extensible"
  121. );
  122. });
  123. test("invalid property descriptors", () => {
  124. let o = {};
  125. Object.defineProperty(o, "v1", { value: 10, configurable: false });
  126. Object.defineProperty(o, "v2", { value: 10, configurable: false, enumerable: true });
  127. Object.defineProperty(o, "v3", {
  128. configurable: false,
  129. get() {
  130. return 1;
  131. },
  132. });
  133. Object.defineProperty(o, "v4", {
  134. value: 10,
  135. configurable: false,
  136. writable: false,
  137. enumerable: true,
  138. });
  139. expect(() => {
  140. Object.getOwnPropertyDescriptor(
  141. new Proxy(o, {
  142. getOwnPropertyDescriptor() {
  143. return { configurable: true };
  144. },
  145. }),
  146. "v1"
  147. );
  148. }).toThrowWithMessage(
  149. TypeError,
  150. "Proxy handler's getOwnPropertyDescriptor trap violates invariant: invalid property descriptor for existing property on the target"
  151. );
  152. expect(() => {
  153. Object.getOwnPropertyDescriptor(
  154. new Proxy(o, {
  155. getOwnPropertyDescriptor() {
  156. return { enumerable: false };
  157. },
  158. }),
  159. "v2"
  160. );
  161. }).toThrowWithMessage(
  162. TypeError,
  163. "Proxy handler's getOwnPropertyDescriptor trap violates invariant: invalid property descriptor for existing property on the target"
  164. );
  165. expect(() => {
  166. Object.getOwnPropertyDescriptor(
  167. new Proxy(o, {
  168. getOwnPropertyDescriptor() {
  169. return { value: 10 };
  170. },
  171. }),
  172. "v3"
  173. );
  174. }).toThrowWithMessage(
  175. TypeError,
  176. "Proxy handler's getOwnPropertyDescriptor trap violates invariant: invalid property descriptor for existing property on the target"
  177. );
  178. expect(() => {
  179. Object.getOwnPropertyDescriptor(
  180. new Proxy(o, {
  181. getOwnPropertyDescriptor() {
  182. return { value: 10, writable: true };
  183. },
  184. }),
  185. "v4"
  186. );
  187. }).toThrowWithMessage(
  188. TypeError,
  189. "Proxy handler's getOwnPropertyDescriptor trap violates invariant: invalid property descriptor for existing property on the target"
  190. );
  191. });
  192. test("cannot report a property as non-configurable if it does not exist or is non-configurable", () => {
  193. let o = {};
  194. Object.defineProperty(o, "v", { configurable: true });
  195. expect(() => {
  196. Object.getOwnPropertyDescriptor(
  197. new Proxy(o, {
  198. getOwnPropertyDescriptor() {
  199. return { configurable: false };
  200. },
  201. }),
  202. "v"
  203. );
  204. }).toThrowWithMessage(
  205. TypeError,
  206. "Proxy handler's getOwnPropertyDescriptor trap violates invariant: cannot report target's property as non-configurable if the property does not exist, or if it is configurable"
  207. );
  208. });
  209. });