setup.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. import {InjectedRouter} from 'react-router';
  2. import {configure} from '@testing-library/react';
  3. import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
  4. import Enzyme from 'enzyme'; // eslint-disable-line no-restricted-imports
  5. import {Location} from 'history';
  6. import MockDate from 'mockdate';
  7. import PropTypes from 'prop-types';
  8. import type {Client} from 'sentry/__mocks__/api';
  9. import ConfigStore from 'sentry/stores/configStore';
  10. import TestStubFixtures from '../fixtures/js-stubs/types';
  11. import {loadFixtures} from './sentry-test/loadFixtures';
  12. /**
  13. * XXX(epurkhiser): Gross hack to fix a bug in jsdom which makes testing of
  14. * framer-motion SVG components fail
  15. *
  16. * See https://github.com/jsdom/jsdom/issues/1330
  17. */
  18. // @ts-expect-error
  19. SVGElement.prototype.getTotalLength ??= () => 1;
  20. /**
  21. * React Testing Library configuration to override the default test id attribute
  22. *
  23. * See: https://testing-library.com/docs/queries/bytestid/#overriding-data-testid
  24. */
  25. configure({testIdAttribute: 'data-test-id'});
  26. /**
  27. * Enzyme configuration
  28. *
  29. * TODO(epurkhiser): We're using @wojtekmaj's react-17 enzyme adapter, until
  30. * the offical adapter has been released.
  31. *
  32. * https://github.com/enzymejs/enzyme/issues/2429
  33. */
  34. Enzyme.configure({adapter: new Adapter()});
  35. /**
  36. * Mock (current) date to always be National Pasta Day
  37. * 2017-10-17T02:41:20.000Z
  38. */
  39. const constantDate = new Date(1508208080000);
  40. MockDate.set(constantDate);
  41. /**
  42. * Load all files in `tests/js/fixtures/*` as a module.
  43. * These will then be added to the `TestStubs` global below
  44. */
  45. const fixtures = loadFixtures('js-stubs', {flatten: true});
  46. /**
  47. * Global testing configuration
  48. */
  49. ConfigStore.loadInitialData(fixtures.Config());
  50. /**
  51. * Mocks
  52. */
  53. jest.mock('lodash/debounce', () => jest.fn(fn => fn));
  54. jest.mock('sentry/utils/recreateRoute');
  55. jest.mock('sentry/api');
  56. jest.mock('sentry/utils/domId');
  57. jest.mock('sentry/utils/withOrganization');
  58. jest.mock('scroll-to-element', () => jest.fn());
  59. jest.mock('react-router', () => {
  60. const ReactRouter = jest.requireActual('react-router');
  61. return {
  62. ...ReactRouter,
  63. browserHistory: {
  64. goBack: jest.fn(),
  65. push: jest.fn(),
  66. replace: jest.fn(),
  67. listen: jest.fn(() => {}),
  68. },
  69. };
  70. });
  71. jest.mock('react-lazyload', () => {
  72. const LazyLoadMock = ({children}) => children;
  73. return LazyLoadMock;
  74. });
  75. jest.mock('react-virtualized', () => {
  76. const ActualReactVirtualized = jest.requireActual('react-virtualized');
  77. return {
  78. ...ActualReactVirtualized,
  79. AutoSizer: ({children}) => children({width: 100, height: 100}),
  80. };
  81. });
  82. jest.mock('echarts-for-react/lib/core', () => {
  83. // We need to do this because `jest.mock` gets hoisted by babel and `React` is not
  84. // guaranteed to be in scope
  85. const ReactActual = require('react');
  86. // We need a class component here because `BaseChart` passes `ref` which will
  87. // error if we return a stateless/functional component
  88. return class extends ReactActual.Component {
  89. render() {
  90. return null;
  91. }
  92. };
  93. });
  94. jest.mock('@sentry/react', () => {
  95. const SentryReact = jest.requireActual('@sentry/react');
  96. return {
  97. init: jest.fn(),
  98. configureScope: jest.fn(),
  99. setTag: jest.fn(),
  100. setTags: jest.fn(),
  101. setExtra: jest.fn(),
  102. setExtras: jest.fn(),
  103. captureBreadcrumb: jest.fn(),
  104. addBreadcrumb: jest.fn(),
  105. captureMessage: jest.fn(),
  106. captureException: jest.fn(),
  107. showReportDialog: jest.fn(),
  108. startSpan: jest.fn(),
  109. finishSpan: jest.fn(),
  110. lastEventId: jest.fn(),
  111. getCurrentHub: jest.spyOn(SentryReact, 'getCurrentHub'),
  112. withScope: jest.spyOn(SentryReact, 'withScope'),
  113. Severity: SentryReact.Severity,
  114. withProfiler: SentryReact.withProfiler,
  115. startTransaction: () => ({
  116. finish: jest.fn(),
  117. setTag: jest.fn(),
  118. setData: jest.fn(),
  119. setStatus: jest.fn(),
  120. }),
  121. };
  122. });
  123. jest.mock('popper.js', () => {
  124. const PopperJS = jest.requireActual('popper.js');
  125. return class {
  126. static placements = PopperJS.placements;
  127. constructor() {
  128. return {
  129. destroy: () => {},
  130. scheduleUpdate: () => {},
  131. };
  132. }
  133. };
  134. });
  135. const routerFixtures = {
  136. router: (params = {}): InjectedRouter => ({
  137. push: jest.fn(),
  138. replace: jest.fn(),
  139. go: jest.fn(),
  140. goBack: jest.fn(),
  141. goForward: jest.fn(),
  142. setRouteLeaveHook: jest.fn(),
  143. isActive: jest.fn(),
  144. createHref: jest.fn(),
  145. location: TestStubs.location(),
  146. createPath: jest.fn(),
  147. routes: [],
  148. params: {},
  149. ...params,
  150. }),
  151. location: (params: Partial<Location> = {}): Location => ({
  152. key: '',
  153. search: '',
  154. hash: '',
  155. action: 'PUSH',
  156. state: null,
  157. query: {},
  158. pathname: '/mock-pathname/',
  159. ...params,
  160. }),
  161. routerProps: (params = {}) => ({
  162. location: TestStubs.location(),
  163. params: {},
  164. routes: [],
  165. stepBack: () => {},
  166. ...params,
  167. }),
  168. routerContext: ([context, childContextTypes] = []) => ({
  169. context: {
  170. location: TestStubs.location(),
  171. router: TestStubs.router(),
  172. organization: fixtures.Organization(),
  173. project: fixtures.Project(),
  174. ...context,
  175. },
  176. childContextTypes: {
  177. router: PropTypes.object,
  178. location: PropTypes.object,
  179. organization: PropTypes.object,
  180. project: PropTypes.object,
  181. ...childContextTypes,
  182. },
  183. }),
  184. };
  185. type TestStubTypes = TestStubFixtures & typeof routerFixtures;
  186. /**
  187. * Test Globals
  188. */
  189. declare global {
  190. /**
  191. * Test stubs are automatically loaded from the fixtures/js-stubs
  192. * directory. Use these for setting up test data.
  193. */
  194. // eslint-disable-next-line no-var
  195. var TestStubs: TestStubTypes;
  196. /**
  197. * Generates a promise that resolves on the next macro-task
  198. */
  199. // eslint-disable-next-line no-var
  200. var tick: () => Promise<void>;
  201. /**
  202. * Used to mock API requests
  203. */
  204. // eslint-disable-next-line no-var
  205. var MockApiClient: typeof Client;
  206. }
  207. window.TestStubs = {...fixtures, ...routerFixtures};
  208. // This is so we can use async/await in tests instead of wrapping with `setTimeout`.
  209. window.tick = () => new Promise(resolve => setTimeout(resolve));
  210. window.MockApiClient = jest.requireMock('sentry/api').Client;
  211. window.scrollTo = jest.fn();
  212. // We need to re-define `window.location`, otherwise we can't spyOn certain
  213. // methods as `window.location` is read-only
  214. Object.defineProperty(window, 'location', {
  215. value: {...window.location, assign: jest.fn(), reload: jest.fn()},
  216. configurable: true,
  217. writable: true,
  218. });