shim.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. import { AriaAttributes } from 'react';
  20. import 'core-js/stable';
  21. import 'regenerator-runtime/runtime';
  22. import jQuery from 'jquery';
  23. // https://jestjs.io/docs/jest-object#jestmockmodulename-factory-options
  24. // in order to mock modules in test case, so avoid absolute import module
  25. import { configure as configureTranslation } from '../../packages/superset-ui-core/src/translation';
  26. import { Worker } from './Worker';
  27. import { IntersectionObserver } from './IntersectionObserver';
  28. import { ResizeObserver } from './ResizeObserver';
  29. import setupSupersetClient from './setupSupersetClient';
  30. import CacheStorage from './CacheStorage';
  31. const exposedProperties = ['window', 'navigator', 'document'];
  32. const { defaultView } = document;
  33. if (defaultView != null) {
  34. Object.keys(defaultView).forEach(property => {
  35. if (typeof global[property as keyof typeof global] === 'undefined') {
  36. exposedProperties.push(property);
  37. // @ts-ignore due to string-type index signature doesn't apply for `typeof globalThis`.
  38. global[property] = defaultView[property as keyof typeof defaultView];
  39. }
  40. });
  41. }
  42. const g = global as any;
  43. g.window ??= Object.create(window);
  44. g.window.location ??= { href: 'about:blank' };
  45. g.window.performance ??= { now: () => new Date().getTime() };
  46. g.window.Worker ??= Worker;
  47. g.window.IntersectionObserver ??= IntersectionObserver;
  48. g.window.ResizeObserver ??= ResizeObserver;
  49. g.window.featureFlags ??= {};
  50. g.URL.createObjectURL ??= () => '';
  51. g.caches = new CacheStorage();
  52. Object.defineProperty(window, 'matchMedia', {
  53. writable: true,
  54. value: jest.fn().mockImplementation(query => ({
  55. matches: false,
  56. media: query,
  57. onchange: null,
  58. addListener: jest.fn(), // Deprecated
  59. removeListener: jest.fn(), // Deprecated
  60. addEventListener: jest.fn(),
  61. removeEventListener: jest.fn(),
  62. dispatchEvent: jest.fn(),
  63. })),
  64. });
  65. g.$ = jQuery(g.window);
  66. configureTranslation();
  67. setupSupersetClient();
  68. // The useTabId hook depends on BroadcastChannel. Jest has a memory leak problem when
  69. // dealing with native modules. See https://chanind.github.io/javascript/2019/10/12/jest-tests-memory-leak.html
  70. // and https://github.com/facebook/jest/issues/6814 for more information.
  71. jest.mock('src/hooks/useTabId', () => ({
  72. useTabId: () => 1,
  73. }));
  74. // Check https://github.com/remarkjs/react-markdown/issues/635
  75. jest.mock('react-markdown', () => (props: any) => <>{props.children}</>);
  76. jest.mock('rehype-sanitize', () => () => jest.fn());
  77. jest.mock('rehype-raw', () => () => jest.fn());
  78. // Mocks the Icon component due to its async nature
  79. // Tests should override this when needed
  80. jest.mock('@superset-ui/core/components/Icons/AsyncIcon', () => ({
  81. __esModule: true,
  82. default: ({
  83. fileName,
  84. role,
  85. 'aria-label': ariaLabel,
  86. onClick,
  87. ...rest
  88. }: {
  89. fileName: string;
  90. role?: string;
  91. 'aria-label'?: AriaAttributes['aria-label'];
  92. onClick?: () => void;
  93. }) => {
  94. // Simple mock that provides the essential attributes for testing
  95. const label = ariaLabel || fileName?.replace(/_/g, '-').toLowerCase() || '';
  96. return (
  97. // eslint-disable-next-line jsx-a11y/no-static-element-interactions
  98. <span
  99. role={role || (onClick ? 'button' : 'img')}
  100. aria-label={label}
  101. data-test={label}
  102. onClick={onClick}
  103. {...rest}
  104. />
  105. );
  106. },
  107. StyledIcon: ({
  108. component: Component,
  109. role,
  110. 'aria-label': ariaLabel,
  111. ...rest
  112. }: {
  113. component: React.ComponentType<any>;
  114. role: string;
  115. 'aria-label': AriaAttributes['aria-label'];
  116. }) => (
  117. <Component
  118. role={role ?? 'img'}
  119. alt={ariaLabel}
  120. aria-label={ariaLabel}
  121. {...rest}
  122. />
  123. ),
  124. }));
  125. process.env.WEBPACK_MODE = 'test';