2
0

setup.ts 15 KB

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