Repository: facebook/jest
File: packages/expect-utils/src/utils.ts (TypeScript)

Code before:
  aStack.pop();
  bStack.pop();
  return true;
};

const entries = (obj: any) => {
  if (!isObject(obj)) return [];

  const symbolProperties = Object.getOwnPropertySymbols(obj)
    .filter(key => key !== Symbol.iterator)
    .map(key => [key, obj[key]]);

  return [...symbolProperties, ...Object.entries(obj)];
};

const isObject = (a: any) => a !== null && typeof a === 'object';

const isObjectWithKeys = (a: any) =>
  isObject(a) &&
  !(a instanceof Error) &&
  !Array.isArray(a) &&
  !(a instanceof Date) &&
  !(a instanceof Set);

export const subsetEquality = (
  object: unknown,
  subset: unknown,
  customTesters: Array<Tester> = [],
): boolean | undefined => {
  const filteredCustomTesters = customTesters.filter(t => t !== subsetEquality);

  // subsetEquality needs to keep track of the references
  // it has already visited to avoid infinite loops in case
  // there are circular references in the subset passed to it.
  const subsetEqualityWithContext =
    (seenReferences: WeakMap<object, boolean> = new WeakMap()) =>
    (object: any, subset: any): boolean | undefined => {
      if (!isObjectWithKeys(subset)) {
        return undefined;
      }

      return getObjectKeys(subset).every(key => {
        if (isObjectWithKeys(subset[key])) {
          if (seenReferences.has(subset[key])) {
            return equals(object[key], subset[key], filteredCustomTesters);
          }
          seenReferences.set(subset[key], true);
        }
        const result =
          object != null &&
          hasPropertyInObject(object, key) &&

Review comment (suggestion):
In case of `subset` as a `Set` the `getObjectKeys(subset)` at line 358 returns empty array (`[]`), so the `.every(...)` in the same line is vacuous truth, resulting the comparison not to raise an exception

Code after:
  aStack.pop();
  bStack.pop();
  return true;
};

const entries = (obj: any) => {
  if (!isObject(obj)) return [];

  const symbolProperties = Object.getOwnPropertySymbols(obj)
    .filter(key => key !== Symbol.iterator)
    .map(key => [key, obj[key]]);

  return [...symbolProperties, ...Object.entries(obj)];
};

const isObject = (a: any) => a !== null && typeof a === 'object';

const isObjectWithKeys = (a: any) =>
  isObject(a) &&
  !(a instanceof Error) &&
  !Array.isArray(a) &&
  !(a instanceof Date) &&
  !(a instanceof Set) &&
  !(a instanceof Map);

export const subsetEquality = (
  object: unknown,
  subset: unknown,
  customTesters: Array<Tester> = [],
): boolean | undefined => {
  const filteredCustomTesters = customTesters.filter(t => t !== subsetEquality);

  // subsetEquality needs to keep track of the references
  // it has already visited to avoid infinite loops in case
  // there are circular references in the subset passed to it.
  const subsetEqualityWithContext =
    (seenReferences: WeakMap<object, boolean> = new WeakMap()) =>
    (object: any, subset: any): boolean | undefined => {
      if (!isObjectWithKeys(subset)) {
        return undefined;
      }

      if (seenReferences.has(subset)) return undefined;
      seenReferences.set(subset, true);

      const matchResult = getObjectKeys(subset).every(key => {
        if (isObjectWithKeys(subset[key])) {
          if (seenReferences.has(subset[key])) {
            return equals(object[key], subset[key], filteredCustomTesters);
          }
        }