setup.ts 15 KB

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