Browse Source

feat(perf): jest setup.ts (#41172)

Our setup.ts can sometimes really eat into the performance of our tests
(to a point where majority of the time is spent requiring modules).

Some of that can be avoided, for example we now always initialize the
enzyme adapter even when it is not required to do so as some tests have
already been migrated to RTL. This allows us to have some perf benefit
until we fully drop ~RTL~ enzyme (thx @Zylphrex).
![CleanShot 2022-11-09 at 13 02
22@2x](https://user-images.githubusercontent.com/9317857/200906172-3ec88ca5-f71d-46c2-8987-647861aa4d95.png)

I also changed some imports to import type so we can hopefully avoid
eval some modules.

If we average out at 100ms over 800 files, then this should save about
1min of time
Jonas 2 years ago
parent
commit
bb0b69f697
1 changed files with 35 additions and 21 deletions
  1. 35 21
      tests/js/setup.ts

+ 35 - 21
tests/js/setup.ts

@@ -3,14 +3,12 @@
 import path from 'path';
 import {TextDecoder, TextEncoder} from 'util';
 
-import {InjectedRouter} from 'react-router';
+import type {InjectedRouter} from 'react-router';
 import {configure as configureRtl} from '@testing-library/react'; // eslint-disable-line no-restricted-imports
-import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
-import {configure as configureEnzyme} from 'enzyme'; // eslint-disable-line no-restricted-imports
-import {Location} from 'history';
+import type {Location} from 'history';
 import MockDate from 'mockdate';
-import * as PropTypes from 'prop-types';
-import * as qs from 'query-string';
+import {object as propTypesObject} from 'prop-types';
+import {stringify} from 'query-string';
 
 // eslint-disable-next-line jest/no-mocks-import
 import type {Client} from 'sentry/__mocks__/api';
@@ -18,10 +16,6 @@ import ConfigStore from 'sentry/stores/configStore';
 
 import {makeLazyFixtures} from './sentry-test/loadFixtures';
 
-// needed by cbor-web for webauthn
-window.TextEncoder = TextEncoder;
-window.TextDecoder = TextDecoder as typeof window.TextDecoder;
-
 /**
  * XXX(epurkhiser): Gross hack to fix a bug in jsdom which makes testing of
  * framer-motion SVG components fail
@@ -46,7 +40,23 @@ configureRtl({testIdAttribute: 'data-test-id'});
  *
  * https://github.com/enzymejs/enzyme/issues/2429
  */
-configureEnzyme({adapter: new Adapter()});
+// eslint-disable-next-line
+const tsxTestsWithEnzyme = [
+  'eventsV2/savedQuery/index.spec.tsx',
+  'dataScrubbing/modals/edit.spec.tsx',
+  'eventsV2/homepage.spec.tsx',
+  'performance/table.spec.tsx',
+  'projectDebugFiles/index.spec.tsx',
+  'eventsV2/resultsChart.spec.tsx',
+];
+const testPath = expect.getState().testPath;
+
+const isJSXTest = testPath && testPath.endsWith('.jsx');
+if (isJSXTest || (testPath && tsxTestsWithEnzyme.some(e => testPath.endsWith(e)))) {
+  const EnzymeAdapter = require('@wojtekmaj/enzyme-adapter-react-17');
+  const enzyme = require('enzyme'); // eslint-disable-line no-restricted-imports
+  enzyme.configure({adapter: new EnzymeAdapter()});
+}
 
 /**
  * Mock (current) date to always be National Pasta Day
@@ -67,7 +77,7 @@ jest.mock('sentry/utils/recreateRoute');
 jest.mock('sentry/api');
 jest.mock('sentry/utils/withOrganization');
 jest.mock('scroll-to-element', () => jest.fn());
-jest.mock('react-router', () => {
+jest.mock('react-router', function reactRouterMockFactory() {
   const ReactRouter = jest.requireActual('react-router');
   return {
     ...ReactRouter,
@@ -81,12 +91,12 @@ jest.mock('react-router', () => {
     },
   };
 });
-jest.mock('react-lazyload', () => {
+jest.mock('react-lazyload', function reactLazyLoadMockFactory() {
   const LazyLoadMock = ({children}) => children;
   return LazyLoadMock;
 });
 
-jest.mock('react-virtualized', () => {
+jest.mock('react-virtualized', function reactVirtualizedMockFactory() {
   const ActualReactVirtualized = jest.requireActual('react-virtualized');
   return {
     ...ActualReactVirtualized,
@@ -94,7 +104,7 @@ jest.mock('react-virtualized', () => {
   };
 });
 
-jest.mock('echarts-for-react/lib/core', () => {
+jest.mock('echarts-for-react/lib/core', function echartsMockFactory() {
   // We need to do this because `jest.mock` gets hoisted by babel and `React` is not
   // guaranteed to be in scope
   const ReactActual = require('react');
@@ -108,7 +118,7 @@ jest.mock('echarts-for-react/lib/core', () => {
   };
 });
 
-jest.mock('@sentry/react', () => {
+jest.mock('@sentry/react', function sentryReact() {
   const SentryReact = jest.requireActual('@sentry/react');
   return {
     init: jest.fn(),
@@ -163,7 +173,7 @@ const routerFixtures = {
           return to.pathname;
         }
 
-        return `${to.pathname}?${qs.stringify(to.query)}`;
+        return `${to.pathname}?${stringify(to.query)}`;
       }
 
       return '';
@@ -203,10 +213,10 @@ const routerFixtures = {
       ...context,
     },
     childContextTypes: {
-      router: PropTypes.object,
-      location: PropTypes.object,
-      organization: PropTypes.object,
-      project: PropTypes.object,
+      router: propTypesObject,
+      location: propTypesObject,
+      organization: propTypesObject,
+      project: propTypesObject,
       ...childContextTypes,
     },
   }),
@@ -239,6 +249,10 @@ declare global {
   var MockApiClient: typeof Client;
 }
 
+// needed by cbor-web for webauthn
+window.TextEncoder = TextEncoder;
+window.TextDecoder = TextDecoder as typeof window.TextDecoder;
+
 window.TestStubs = fixtures;
 
 // This is so we can use async/await in tests instead of wrapping with `setTimeout`.