Skip to content

Sentry 7.30.0 upwards breaks our Jest tests by making fetch not exist #7363

Closed
@gthb

Description

@gthb

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using? If you use the CDN bundles, please specify the exact bundle (e.g. bundle.tracing.min.js) in your SDK setup.

@sentry/nextjs

SDK Version

7.30.0

Framework Version

Next.js 12.3.2

Link to Sentry event

No response

SDK Setup

Sentry.init({
  enabled: isEnabled,
  dsn: SENTRY_DSN,
  environment: SENTRY_ENV,
  release: BUILD_ID,
  ignoreErrors,
  beforeSend: event => {
    const { type, title, contexts } = event;
    if (type === 'error' &&
          /^(?:iPhone|Mac|iPad)$/.test(contexts?.device?.family || '') &&
          (
            /^TypeError: (?:cancelled|geannuleerd|cancelado|annulleret|avbrutt|avbruten|Abgebrochen)$/i.test(title || '')
          )) {
      return null;
    }

    integrateWithFullstory(event);
    return event;
  },
  integrations:  [
    new Integrations.BrowserTracing({
      tracingOrigins: [ getApiHost() ],
      beforeNavigate: context => {
        const dynamicRouteName = mapSlugToRoute(window.location.pathname);
        if (dynamicRouteName) {
          return {
            ...context, name: dynamicRouteName,
          };
        }
        return context;
      },
    }),
  ]
  tracesSampler: samplingRate,
});

Steps to Reproduce

  1. With Sentry SDK at any version 7.29.0 or earlier, run Jest tests; they pass
  2. Upgrade @sentry/nextjs and @sentry/tracing and @sentry/utils to 7.30.0 or later
  3. Run Jest tests; they fail

Expected Result

Our Jest tests pass.

Actual Result

Our Jest tests fail with several tests outputting ReferenceError: fetch is not defined at the line:

  return fetch(resolvePath(url), options)

Actual app works fine, only our Jest tests fail.

Since this failure starts in Sentry SDK 7.30.0, I think it likely has to do with #6500 — in particular the wrapping of fetch and its uses of this check and/or this wrapping utility, interacting poorly with whatever shenanigans Jest gets up to.

Likely relevant: jest.config.js

module.exports = {
  transformIgnorePatterns: [ "/node_modules/(?!@grid-is/)" ],
  clearMocks: true,
  coverageDirectory: './coverage/',
  testEnvironment: 'jsdom',
  testMatch: [
    '**/__tests__/**/*.[jt]s?(x)',
    '**/?(*.)+(spec|test).[tj]s?(x)',
    '**/?(*-)+(test).[tj]s?(x)',
  ],
  moduleNameMapper: {
    '\\.(css|scss)$': 'identity-obj-proxy',
  },
  reporters: [ 'default', 'jest-junit' ],
  testPathIgnorePatterns: [ '.next', '<rootDir>/migrate/' ],
  setupFiles: [ 'jest-canvas-mock' ],
  setupFilesAfterEnv: [ '@testing-library/jest-dom/extend-expect', './jest.setup.js' ],
  globals: {...},
};

and jest.setup.js contains:

let unignorableConsoleErrorMessages;
const originalError = global.console.error;
const spy = jest.spyOn(global.console, 'error');
const infoSpy = jest.spyOn(global.console, 'info');

// sprintf-like string format compatible with console.log
const sprintf = (str, ...argv) => {
  if (!argv.length || !/%[sdif]/.test(str)) {
    return [ str, ...argv ].join(' ');
  }

  return sprintf(str.replace(/%[sdif]/, function (format) {
    switch (format) {
      case '%s': return String(argv.shift());
      case '%d':
      case '%i': return parseInt(argv.shift(), 10);
      case '%f': return parseFloat(argv.shift(), 10);
      default: return format;
    }
  }), ...argv);
};

const ignorableConsoleErrorMessages = [
  /Can't perform a React state update on an unmounted component/,
  /Warning: A component is changing an uncontrolled input to be controlled./,
  /Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?/,
];

beforeEach(() => {
  unignorableConsoleErrorMessages = new Set();
  spy.mockImplementation((...args) => {
    originalError(...args);
    const msg = sprintf(...args);
    for (const regexp of ignorableConsoleErrorMessages) {
      if (regexp.test(msg)) {
        return;
      }
    }
    unignorableConsoleErrorMessages.add(msg);
  });
  infoSpy.mockImplementation(() => {});
});
afterEach(() => {
  if (unignorableConsoleErrorMessages.size) {
    throw new Error(
      'Unignorable console.error output from test execution:\n' +
        Array.from(unignorableConsoleErrorMessages).join('\n')
    );
  }
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    Package: nextjsIssues related to the Sentry Nextjs SDK

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions