Proxy.handler-defineProperty.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. describe("[[DefineProperty]] trap normal behavior", () => {
  2. test("forwarding when not defined in handler", () => {
  3. let p = new Proxy({}, { defineProperty: null });
  4. expect(Object.defineProperty(p, "foo", {})).toBe(p);
  5. p = new Proxy({}, { defineProperty: undefined });
  6. expect(Object.defineProperty(p, "foo", {})).toBe(p);
  7. p = new Proxy({}, {});
  8. expect(Object.defineProperty(p, "foo", {})).toBe(p);
  9. });
  10. test("correct arguments passed to trap", () => {
  11. let o = {};
  12. p = new Proxy(o, {
  13. defineProperty(target, name, descriptor) {
  14. expect(target).toBe(o);
  15. expect(name).toBe("foo");
  16. expect(descriptor.configurable).toBeTrue();
  17. expect(descriptor.enumerable).toBeUndefined();
  18. expect(descriptor.writable).toBeTrue();
  19. expect(descriptor.value).toBe(10);
  20. expect(descriptor.get).toBeUndefined();
  21. expect(descriptor.set).toBeUndefined();
  22. return true;
  23. },
  24. });
  25. Object.defineProperty(p, "foo", { configurable: true, writable: true, value: 10 });
  26. });
  27. test("optionally ignoring the define call", () => {
  28. let o = {};
  29. let p = new Proxy(o, {
  30. defineProperty(target, name, descriptor) {
  31. if (target[name] === undefined) Object.defineProperty(target, name, descriptor);
  32. return true;
  33. },
  34. });
  35. Object.defineProperty(p, "foo", {
  36. value: 10,
  37. enumerable: true,
  38. configurable: false,
  39. writable: true,
  40. });
  41. expect(p).toHaveEnumerableProperty("foo");
  42. expect(p).not.toHaveConfigurableProperty("foo");
  43. expect(p).toHaveWritableProperty("foo");
  44. expect(p).toHaveValueProperty("foo", 10);
  45. expect(p).not.toHaveGetterProperty("foo");
  46. expect(p).not.toHaveSetterProperty("foo");
  47. Object.defineProperty(p, "foo", {
  48. value: 20,
  49. enumerable: true,
  50. configurable: false,
  51. writable: true,
  52. });
  53. expect(p).toHaveEnumerableProperty("foo");
  54. expect(p).not.toHaveConfigurableProperty("foo");
  55. expect(p).toHaveWritableProperty("foo");
  56. expect(p).toHaveValueProperty("foo", 10);
  57. expect(p).not.toHaveGetterProperty("foo");
  58. expect(p).not.toHaveSetterProperty("foo");
  59. });
  60. });
  61. describe("[[DefineProperty]] invariants", () => {
  62. test("trap can't return false", () => {
  63. let p = new Proxy(
  64. {},
  65. {
  66. defineProperty() {
  67. return false;
  68. },
  69. }
  70. );
  71. expect(() => {
  72. Object.defineProperty(p, "foo", {});
  73. }).toThrowWithMessage(TypeError, "Object's [[DefineProperty]] method returned false");
  74. });
  75. test("trap cannot return true for a non-extensible target if the property does not exist", () => {
  76. let o = {};
  77. Object.preventExtensions(o);
  78. let p = new Proxy(o, {
  79. defineProperty() {
  80. return true;
  81. },
  82. });
  83. expect(() => {
  84. Object.defineProperty(p, "foo", {});
  85. }).toThrowWithMessage(
  86. TypeError,
  87. "Proxy handler's defineProperty trap violates invariant: a property cannot be reported as being defined if the property does not exist on the target and the target is non-extensible"
  88. );
  89. });
  90. test("trap cannot return true for a non-configurable property if it doesn't already exist on the target", () => {
  91. let o = {};
  92. Object.defineProperty(o, "foo", { value: 10, configurable: true });
  93. let p = new Proxy(o, {
  94. defineProperty() {
  95. return true;
  96. },
  97. });
  98. expect(() => {
  99. Object.defineProperty(p, "bar", { value: 6, configurable: false });
  100. }).toThrowWithMessage(
  101. TypeError,
  102. "Proxy handler's defineProperty trap violates invariant: a property cannot be defined as non-configurable if it does not already exist on the target object"
  103. );
  104. });
  105. test("trap cannot return true for a non-configurable property if it already exists as a configurable property", () => {
  106. let o = {};
  107. Object.defineProperty(o, "foo", { value: 10, configurable: true });
  108. let p = new Proxy(o, {
  109. defineProperty() {
  110. return true;
  111. },
  112. });
  113. expect(() => {
  114. Object.defineProperty(p, "foo", { value: 6, configurable: false });
  115. }).toThrowWithMessage(
  116. TypeError,
  117. "Proxy handler's defineProperty trap violates invariant: a property cannot be defined as non-configurable if it already exists on the target object as a configurable property"
  118. );
  119. });
  120. });