setup.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. import '@testing-library/jest-dom'
  2. /* eslint-disable react/display-name */
  3. // 设置环境变量
  4. process.env.TARO_ENV = 'h5'
  5. process.env.TARO_PLATFORM = 'web'
  6. process.env.SUPPORT_TARO_POLYFILL = 'disabled'
  7. // Mock Taro 核心API
  8. const mockNavigateTo = jest.fn()
  9. const mockShowToast = jest.fn()
  10. const mockRequestPayment = jest.fn()
  11. const mockNavigateBack = jest.fn()
  12. jest.mock('@tarojs/taro', () => ({
  13. __esModule: true,
  14. default: {
  15. getEnv: () => 'WEB',
  16. ENV_TYPE: {
  17. WEAPP: 'WEAPP',
  18. WEB: 'WEB'
  19. },
  20. getSystemInfoSync: () => ({
  21. statusBarHeight: 44,
  22. screenWidth: 375,
  23. screenHeight: 667,
  24. windowWidth: 375,
  25. windowHeight: 603,
  26. pixelRatio: 2
  27. }),
  28. getMenuButtonBoundingClientRect: () => ({
  29. width: 87,
  30. height: 32,
  31. top: 48,
  32. right: 314,
  33. bottom: 80,
  34. left: 227
  35. }),
  36. navigateBack: mockNavigateBack,
  37. requestPayment: mockRequestPayment
  38. },
  39. useRouter: () => ({
  40. params: {}
  41. }),
  42. navigateTo: mockNavigateTo,
  43. showToast: mockShowToast
  44. }))
  45. // Mock Taro 组件
  46. // eslint-disable-next-line react/display-name
  47. jest.mock('@tarojs/components', () => {
  48. const React = require('react')
  49. const MockView = React.forwardRef((props: any, ref: any) => {
  50. const { children, ...restProps } = props
  51. return React.createElement('div', { ...restProps, ref }, children)
  52. })
  53. MockView.displayName = 'MockView'
  54. const MockScrollView = React.forwardRef((props: any, ref: any) => {
  55. const {
  56. children,
  57. onScroll,
  58. onTouchStart,
  59. onScrollEnd,
  60. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  61. scrollY,
  62. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  63. showScrollbar,
  64. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  65. scrollTop,
  66. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  67. scrollWithAnimation,
  68. ...restProps
  69. } = props
  70. return React.createElement('div', {
  71. ...restProps,
  72. ref,
  73. onScroll: (e: any) => {
  74. if (onScroll) onScroll(e)
  75. },
  76. onTouchStart: (e: any) => {
  77. if (onTouchStart) onTouchStart(e)
  78. },
  79. onTouchEnd: () => {
  80. if (onScrollEnd) onScrollEnd()
  81. },
  82. style: {
  83. overflow: 'auto',
  84. height: '200px',
  85. ...restProps.style
  86. }
  87. }, children)
  88. })
  89. MockScrollView.displayName = 'MockScrollView'
  90. return {
  91. View: MockView,
  92. ScrollView: MockScrollView,
  93. Text: (() => {
  94. const MockText = React.forwardRef((props: any, ref: any) => {
  95. const { children, ...restProps } = props
  96. return React.createElement('span', { ...restProps, ref }, children)
  97. })
  98. MockText.displayName = 'MockText'
  99. return MockText
  100. })(),
  101. Button: (() => {
  102. const MockButton = React.forwardRef((props: any, ref: any) => {
  103. const { children, ...restProps } = props
  104. return React.createElement('button', { ...restProps, ref }, children)
  105. })
  106. MockButton.displayName = 'MockButton'
  107. return MockButton
  108. })(),
  109. Input: (() => {
  110. const MockInput = React.forwardRef((props: any, ref: any) => {
  111. const { ...restProps } = props
  112. return React.createElement('input', { ...restProps, ref })
  113. })
  114. MockInput.displayName = 'MockInput'
  115. return MockInput
  116. })(),
  117. Textarea: (() => {
  118. const MockTextarea = React.forwardRef((props: any, ref: any) => {
  119. const { children, ...restProps } = props
  120. return React.createElement('textarea', { ...restProps, ref }, children)
  121. })
  122. MockTextarea.displayName = 'MockTextarea'
  123. return MockTextarea
  124. })(),
  125. Image: (() => {
  126. const MockImage = React.forwardRef((props: any, ref: any) => {
  127. const { ...restProps } = props
  128. return React.createElement('img', { ...restProps, ref })
  129. })
  130. MockImage.displayName = 'MockImage'
  131. return MockImage
  132. })(),
  133. Form: (() => {
  134. const MockForm = React.forwardRef((props: any, ref: any) => {
  135. const { children, ...restProps } = props
  136. return React.createElement('form', { ...restProps, ref }, children)
  137. })
  138. MockForm.displayName = 'MockForm'
  139. return MockForm
  140. })(),
  141. Label: (() => {
  142. const MockLabel = React.forwardRef((props: any, ref: any) => {
  143. const { children, ...restProps } = props
  144. return React.createElement('label', { ...restProps, ref }, children)
  145. })
  146. MockLabel.displayName = 'MockLabel'
  147. return MockLabel
  148. })(),
  149. Picker: (() => {
  150. const MockPicker = React.forwardRef((props: any, ref: any) => {
  151. const { children, ...restProps } = props
  152. return React.createElement('div', { ...restProps, ref }, children)
  153. })
  154. MockPicker.displayName = 'MockPicker'
  155. return MockPicker
  156. })(),
  157. Switch: (() => {
  158. const MockSwitch = React.forwardRef((props: any, ref: any) => {
  159. const { ...restProps } = props
  160. return React.createElement('input', { type: 'checkbox', ...restProps, ref })
  161. })
  162. MockSwitch.displayName = 'MockSwitch'
  163. return MockSwitch
  164. })(),
  165. Slider: (() => {
  166. const MockSlider = React.forwardRef((props: any, ref: any) => {
  167. const { ...restProps } = props
  168. return React.createElement('input', { type: 'range', ...restProps, ref })
  169. })
  170. MockSlider.displayName = 'MockSlider'
  171. return MockSlider
  172. })(),
  173. Radio: React.forwardRef((props: any, ref: any) => {
  174. const { children, ...restProps } = props
  175. return React.createElement('input', { type: 'radio', ...restProps, ref }, children)
  176. }),
  177. RadioGroup: React.forwardRef((props: any, ref: any) => {
  178. const { children, ...restProps } = props
  179. return React.createElement('div', { ...restProps, ref }, children)
  180. }),
  181. Checkbox: React.forwardRef((props: any, ref: any) => {
  182. const { children, ...restProps } = props
  183. return React.createElement('input', { type: 'checkbox', ...restProps, ref }, children)
  184. }),
  185. CheckboxGroup: React.forwardRef((props: any, ref: any) => {
  186. const { children, ...restProps } = props
  187. return React.createElement('div', { ...restProps, ref }, children)
  188. }),
  189. Progress: React.forwardRef((props: any, ref: any) => {
  190. const { ...restProps } = props
  191. return React.createElement('progress', { ...restProps, ref })
  192. }),
  193. RichText: React.forwardRef((props: any, ref: any) => {
  194. const { children, ...restProps } = props
  195. return React.createElement('div', { ...restProps, ref }, children)
  196. }),
  197. MovableArea: React.forwardRef((props: any, ref: any) => {
  198. const { children, ...restProps } = props
  199. return React.createElement('div', { ...restProps, ref }, children)
  200. }),
  201. MovableView: React.forwardRef((props: any, ref: any) => {
  202. const { children, ...restProps } = props
  203. return React.createElement('div', { ...restProps, ref }, children)
  204. }),
  205. Swiper: React.forwardRef((props: any, ref: any) => {
  206. const { children, ...restProps } = props
  207. return React.createElement('div', { ...restProps, ref }, children)
  208. }),
  209. SwiperItem: React.forwardRef((props: any, ref: any) => {
  210. const { children, ...restProps } = props
  211. return React.createElement('div', { ...restProps, ref }, children)
  212. }),
  213. Navigator: React.forwardRef((props: any, ref: any) => {
  214. const { children, ...restProps } = props
  215. return React.createElement('a', { ...restProps, ref }, children)
  216. }),
  217. Audio: React.forwardRef((props: any, ref: any) => {
  218. const { ...restProps } = props
  219. return React.createElement('audio', { ...restProps, ref })
  220. }),
  221. Video: React.forwardRef((props: any, ref: any) => {
  222. const { children, ...restProps } = props
  223. return React.createElement('video', { ...restProps, ref }, children)
  224. }),
  225. Camera: React.forwardRef((props: any, ref: any) => {
  226. const { children, ...restProps } = props
  227. return React.createElement('div', { ...restProps, ref }, children)
  228. }),
  229. LivePlayer: React.forwardRef((props: any, ref: any) => {
  230. const { children, ...restProps } = props
  231. return React.createElement('div', { ...restProps, ref }, children)
  232. }),
  233. LivePusher: React.forwardRef((props: any, ref: any) => {
  234. const { children, ...restProps } = props
  235. return React.createElement('div', { ...restProps, ref }, children)
  236. }),
  237. Map: React.forwardRef((props: any, ref: any) => {
  238. const { children, ...restProps } = props
  239. return React.createElement('div', { ...restProps, ref }, children)
  240. }),
  241. Canvas: React.forwardRef((props: any, ref: any) => {
  242. const { children, ...restProps } = props
  243. return React.createElement('canvas', { ...restProps, ref }, children)
  244. }),
  245. OpenData: React.forwardRef((props: any, ref: any) => {
  246. const { children, ...restProps } = props
  247. return React.createElement('div', { ...restProps, ref }, children)
  248. }),
  249. WebView: React.forwardRef((props: any, ref: any) => {
  250. const { children, ...restProps } = props
  251. return React.createElement('iframe', { ...restProps, ref }, children)
  252. }),
  253. Ad: React.forwardRef((props: any, ref: any) => {
  254. const { children, ...restProps } = props
  255. return React.createElement('div', { ...restProps, ref }, children)
  256. }),
  257. OfficialAccount: React.forwardRef((props: any, ref: any) => {
  258. const { children, ...restProps } = props
  259. return React.createElement('div', { ...restProps, ref }, children)
  260. }),
  261. CoverView: React.forwardRef((props: any, ref: any) => {
  262. const { children, ...restProps } = props
  263. return React.createElement('div', { ...restProps, ref }, children)
  264. }),
  265. CoverImage: React.forwardRef((props: any, ref: any) => {
  266. const { ...restProps } = props
  267. return React.createElement('img', { ...restProps, ref })
  268. }),
  269. FunctionalPageNavigator: React.forwardRef((props: any, ref: any) => {
  270. const { children, ...restProps } = props
  271. return React.createElement('div', { ...restProps, ref }, children)
  272. }),
  273. AdContent: React.forwardRef((props: any, ref: any) => {
  274. const { children, ...restProps } = props
  275. return React.createElement('div', { ...restProps, ref }, children)
  276. }),
  277. MatchMedia: React.forwardRef((props: any, ref: any) => {
  278. const { children, ...restProps } = props
  279. return React.createElement('div', { ...restProps, ref }, children)
  280. }),
  281. PageContainer: React.forwardRef((props: any, ref: any) => {
  282. const { children, ...restProps } = props
  283. return React.createElement('div', { ...restProps, ref }, children)
  284. }),
  285. ShareElement: React.forwardRef((props: any, ref: any) => {
  286. const { children, ...restProps } = props
  287. return React.createElement('div', { ...restProps, ref }, children)
  288. }),
  289. KeyboardAccessory: React.forwardRef((props: any, ref: any) => {
  290. const { children, ...restProps } = props
  291. return React.createElement('div', { ...restProps, ref }, children)
  292. }),
  293. RootPortal: React.forwardRef((props: any, ref: any) => {
  294. const { children, ...restProps } = props
  295. return React.createElement('div', { ...restProps, ref }, children)
  296. }),
  297. PageMeta: React.forwardRef((props: any, ref: any) => {
  298. const { children, ...restProps } = props
  299. return React.createElement('div', { ...restProps, ref }, children)
  300. }),
  301. NavigationBar: React.forwardRef((props: any, ref: any) => {
  302. const { children, ...restProps } = props
  303. return React.createElement('div', { ...restProps, ref }, children)
  304. }),
  305. Block: React.forwardRef((props: any, ref: any) => {
  306. const { children, ...restProps } = props
  307. return React.createElement('div', { ...restProps, ref }, children)
  308. }),
  309. Import: React.forwardRef((props: any, ref: any) => {
  310. const { children, ...restProps } = props
  311. return React.createElement('div', { ...restProps, ref }, children)
  312. }),
  313. Include: React.forwardRef((props: any, ref: any) => {
  314. const { children, ...restProps } = props
  315. return React.createElement('div', { ...restProps, ref }, children)
  316. }),
  317. Template: React.forwardRef((props: any, ref: any) => {
  318. const { children, ...restProps } = props
  319. return React.createElement('div', { ...restProps, ref }, children)
  320. }),
  321. Slot: React.forwardRef((props: any, ref: any) => {
  322. const { children, ...restProps } = props
  323. return React.createElement('div', { ...restProps, ref }, children)
  324. }),
  325. NativeSlot: React.forwardRef((props: any, ref: any) => {
  326. const { children, ...restProps } = props
  327. return React.createElement('div', { ...restProps, ref }, children)
  328. }),
  329. CustomWrapper: React.forwardRef((props: any, ref: any) => {
  330. const { children, ...restProps } = props
  331. return React.createElement('div', { ...restProps, ref }, children)
  332. }),
  333. Editor: React.forwardRef((props: any, ref: any) => {
  334. const { children, ...restProps } = props
  335. return React.createElement('div', { ...restProps, ref }, children)
  336. }),
  337. VoipRoom: React.forwardRef((props: any, ref: any) => {
  338. const { children, ...restProps } = props
  339. return React.createElement('div', { ...restProps, ref }, children)
  340. }),
  341. AdCustom: React.forwardRef((props: any, ref: any) => {
  342. const { children, ...restProps } = props
  343. return React.createElement('div', { ...restProps, ref }, children)
  344. })
  345. }
  346. })
  347. // 模拟 MutationObserver
  348. // @ts-ignore
  349. global.MutationObserver = class {
  350. disconnect() {}
  351. observe(_element: any, _initObject: any) {}
  352. takeRecords() { return [] }
  353. }
  354. // 模拟 IntersectionObserver
  355. // @ts-ignore
  356. global.IntersectionObserver = class {
  357. constructor(fn: (args: any[]) => void) {
  358. setTimeout(() => {
  359. fn([{ isIntersecting: true }])
  360. }, 1000)
  361. }
  362. observe() {}
  363. unobserve() {}
  364. disconnect() {}
  365. takeRecords() { return [] }
  366. root: null = null
  367. rootMargin: string = ''
  368. thresholds: number[] = []
  369. }
  370. // 模拟 ResizeObserver
  371. // @ts-ignore
  372. global.ResizeObserver = class {
  373. observe() {}
  374. unobserve() {}
  375. disconnect() {}
  376. }
  377. // 模拟 matchMedia
  378. Object.defineProperty(window, 'matchMedia', {
  379. writable: true,
  380. value: jest.fn().mockImplementation(query => ({
  381. matches: false,
  382. media: query,
  383. onchange: null,
  384. addListener: jest.fn(), // deprecated
  385. removeListener: jest.fn(), // deprecated
  386. addEventListener: jest.fn(),
  387. removeEventListener: jest.fn(),
  388. dispatchEvent: jest.fn(),
  389. })),
  390. })
  391. // 模拟 getComputedStyle
  392. Object.defineProperty(window, 'getComputedStyle', {
  393. value: () => ({
  394. getPropertyValue: (prop: string) => {
  395. return {
  396. 'font-size': '16px',
  397. 'font-family': 'Arial',
  398. color: 'rgb(0, 0, 0)',
  399. 'background-color': 'rgb(255, 255, 255)',
  400. width: '100px',
  401. height: '100px',
  402. top: '0px',
  403. left: '0px',
  404. right: '0px',
  405. bottom: '0px',
  406. x: '0px',
  407. y: '0px'
  408. }[prop] || ''
  409. }
  410. })
  411. })
  412. // 模拟 Element.prototype.getBoundingClientRect
  413. Element.prototype.getBoundingClientRect = jest.fn(() => ({
  414. width: 100,
  415. height: 100,
  416. top: 0,
  417. left: 0,
  418. bottom: 100,
  419. right: 100,
  420. x: 0,
  421. y: 0,
  422. toJSON: () => ({
  423. width: 100,
  424. height: 100,
  425. top: 0,
  426. left: 0,
  427. bottom: 100,
  428. right: 100,
  429. x: 0,
  430. y: 0
  431. })
  432. }))
  433. // 静默 console.error 在测试中
  434. const originalConsoleError = console.error
  435. console.error = (...args: any[]) => {
  436. // 检查是否在测试环境中(通过 Jest 环境变量判断)
  437. const isTestEnv = process.env.JEST_WORKER_ID !== undefined ||
  438. typeof jest !== 'undefined'
  439. // 在测试环境中静默错误输出,除非是重要错误
  440. if (isTestEnv && !args[0]?.includes?.('重要错误')) {
  441. return
  442. }
  443. originalConsoleError(...args)
  444. }