diff --git a/packages/expect/src/__tests__/utils.test.ts b/packages/expect/src/__tests__/utils.test.ts index d5b31b84a16b..c210abf9fb34 100644 --- a/packages/expect/src/__tests__/utils.test.ts +++ b/packages/expect/src/__tests__/utils.test.ts @@ -11,7 +11,6 @@ import { emptyObject, getObjectSubset, getPath, - hasOwnProperty, iterableEquality, subsetEquality, } from '../utils'; @@ -107,46 +106,6 @@ describe('getPath()', () => { }); }); -describe('hasOwnProperty', () => { - it('does inherit getter from class', () => { - class MyClass { - get key() { - return 'value'; - } - } - expect(hasOwnProperty(new MyClass(), 'key')).toBe(true); - }); - - it('does not inherit setter from class', () => { - class MyClass { - set key(_value: unknown) {} - } - expect(hasOwnProperty(new MyClass(), 'key')).toBe(false); - }); - - it('does not inherit method from class', () => { - class MyClass { - key() {} - } - expect(hasOwnProperty(new MyClass(), 'key')).toBe(false); - }); - - it('does not inherit property from constructor prototype', () => { - function MyClass() {} - MyClass.prototype.key = 'value'; - // @ts-expect-error - expect(hasOwnProperty(new MyClass(), 'key')).toBe(false); - }); - - it('does not inherit __proto__ getter from Object', () => { - expect(hasOwnProperty({}, '__proto__')).toBe(false); - }); - - it('does not inherit toString method from Object', () => { - expect(hasOwnProperty({}, 'toString')).toBe(false); - }); -}); - describe('getObjectSubset', () => { [ [{a: 'b', c: 'd'}, {a: 'd'}, {a: 'b'}], diff --git a/packages/expect/src/utils.ts b/packages/expect/src/utils.ts index ba24819c6cda..e4b60c31c835 100644 --- a/packages/expect/src/utils.ts +++ b/packages/expect/src/utils.ts @@ -21,7 +21,10 @@ type GetPath = { value?: unknown; }; -const hasPropertyInObject = (object: object, key: string) => { +/** + * Checks if `hasOwnProperty(object, key)` up the prototype chain, stopping at `Object.prototype`. + */ +const hasPropertyInObject = (object: object, key: string): boolean => { const shouldTerminate = !object || typeof object !== 'object' || object === Object.prototype; @@ -35,33 +38,6 @@ const hasPropertyInObject = (object: object, key: string) => { ); }; -// Return whether object instance inherits getter from its class. -const hasGetterFromConstructor = (object: object, key: string) => { - const constructor = object.constructor; - if (constructor === Object) { - // A literal object has Object as constructor. - // Therefore, it cannot inherit application-specific getters. - // Furthermore, Object has __proto__ getter which is not relevant. - // Array, Boolean, Number, String constructors don’t have any getters. - return false; - } - if (typeof constructor !== 'function') { - // Object.create(null) constructs object with no constructor nor prototype. - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Custom_and_Null_objects - return false; - } - - const descriptor = Object.getOwnPropertyDescriptor( - constructor.prototype, - key, - ); - return descriptor !== undefined && typeof descriptor.get === 'function'; -}; - -export const hasOwnProperty = (object: object, key: string): boolean => - Object.prototype.hasOwnProperty.call(object, key) || - hasGetterFromConstructor(object, key); - export const getPath = ( object: Record, propertyPath: string | Array, @@ -143,7 +119,7 @@ export const getObjectSubset = ( seenReferences.set(object, trimmed); Object.keys(object) - .filter(key => hasOwnProperty(subset, key)) + .filter(key => hasPropertyInObject(subset, key)) .forEach(key => { trimmed[key] = seenReferences.has(object[key]) ? seenReferences.get(object[key])