OrderDetail.test.tsx 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. import React from 'react'
  2. import { render, screen, fireEvent } from '@testing-library/react'
  3. import '@testing-library/jest-dom'
  4. import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
  5. import OrderDetail from '../src/pages/OrderDetail/OrderDetail'
  6. import { setupTestEnv } from './__helpers__/local-test-utils'
  7. setupTestEnv()
  8. // 创建测试用的QueryClient
  9. const createTestQueryClient = () => new QueryClient({
  10. defaultOptions: {
  11. queries: {
  12. retry: false,
  13. },
  14. },
  15. })
  16. // 测试包装器组件
  17. const TestWrapper = ({ children }: { children: React.ReactNode }) => {
  18. const queryClient = createTestQueryClient()
  19. return (
  20. <QueryClientProvider client={queryClient}>
  21. {children}
  22. </QueryClientProvider>
  23. )
  24. }
  25. // 包装的render函数
  26. const renderWithQueryClient = (component: React.ReactElement) => {
  27. return render(<TestWrapper>{component}</TestWrapper>)
  28. }
  29. // Mock Taro组件
  30. jest.mock('@tarojs/components', () => ({
  31. View: ({ children, className, ...props }: any) => (
  32. <div className={className} {...props}>{children}</div>
  33. ),
  34. Text: ({ children, className, ...props }: any) => (
  35. <span className={className} {...props}>{children}</span>
  36. ),
  37. ScrollView: ({ children, className, scrollY, ...props }: any) => (
  38. <div className={className} data-scroll-y={scrollY} {...props}>{children}</div>
  39. ),
  40. Button: ({ children, className, onClick, ...props }: any) => (
  41. <button className={className} onClick={onClick} {...props}>
  42. {children}
  43. </button>
  44. ),
  45. Input: ({ className, placeholder, value, onInput, ...props }: any) => (
  46. <input
  47. className={className}
  48. placeholder={placeholder}
  49. value={value}
  50. onChange={(e) => onInput?.({ detail: { value: e.target.value } })}
  51. {...props}
  52. />
  53. ),
  54. Textarea: ({ className, placeholder, value, onInput, ...props }: any) => (
  55. <textarea
  56. className={className}
  57. placeholder={placeholder}
  58. value={value}
  59. onChange={(e) => onInput?.({ detail: { value: e.target.value } })}
  60. {...props}
  61. />
  62. ),
  63. }))
  64. // Mock UI组件
  65. jest.mock('@d8d/mini-shared-ui-components/components/navbar', () => ({
  66. Navbar: ({ title, leftIcon, leftText, onClickLeft }: any) => (
  67. <div data-testid="navbar" data-title={title} data-left-icon={leftIcon} data-left-text={leftText}>
  68. <button onClick={onClickLeft}>Navbar Left</button>
  69. </div>
  70. ),
  71. }))
  72. // Mock RPC客户端
  73. jest.mock('@d8d/mini-shared-ui-components/utils/rpc/rpc-client', () => ({
  74. rpcClient: jest.fn(() => ({
  75. detail: {
  76. ':id': {
  77. $get: jest.fn(() => Promise.resolve({
  78. ok: true,
  79. json: () => Promise.resolve({
  80. id: 1,
  81. orderName: '阿里巴巴2023-11',
  82. orderStatus: 'in_progress',
  83. createTime: new Date().toISOString(),
  84. updateTime: new Date().toISOString(),
  85. companyId: 1,
  86. platformId: 1,
  87. expectedPersonCount: 30,
  88. expectedStartDate: new Date().toISOString(),
  89. actualStartDate: new Date().toISOString(),
  90. orderPersons: [
  91. { id: 1, workStatus: 'working', joinDate: new Date().toISOString(), person: { name: '张三', gender: '男', disabilityType: '肢体残疾', phone: '13800138001' } },
  92. { id: 2, workStatus: 'pre_working', joinDate: new Date().toISOString(), person: { name: '李四', gender: '女', disabilityType: '听力残疾', phone: '13800138002' } },
  93. { id: 3, workStatus: 'working', joinDate: new Date().toISOString(), person: { name: '王五', gender: '男', disabilityType: '视力残疾', phone: '13800138003' } }
  94. ]
  95. })
  96. }))
  97. }
  98. },
  99. 'company-videos': {
  100. $get: jest.fn(() => Promise.resolve({
  101. ok: true,
  102. json: () => Promise.resolve({
  103. data: [
  104. { id: 1, assetType: 'checkin_video', file: { name: '打卡视频_2023-12-01.mp4', size: 10485760, uploadTime: new Date().toISOString() } },
  105. { id: 2, assetType: 'salary_video', file: { name: '工资视频_2023-11-30.mp4', size: 15728640, uploadTime: new Date().toISOString() } }
  106. ]
  107. })
  108. }))
  109. },
  110. 'checkin-statistics': {
  111. $get: jest.fn(() => Promise.resolve({
  112. ok: true,
  113. json: () => Promise.resolve({
  114. companyId: 1,
  115. checkinVideoCount: 15,
  116. totalVideos: 30
  117. })
  118. }))
  119. },
  120. 'video-statistics': {
  121. $get: jest.fn(() => Promise.resolve({
  122. ok: true,
  123. json: () => Promise.resolve({
  124. companyId: 1,
  125. stats: [
  126. { assetType: 'checkin_video', count: 15, percentage: 50 },
  127. { assetType: 'salary_video', count: 10, percentage: 33 },
  128. { assetType: 'tax_video', count: 5, percentage: 17 }
  129. ],
  130. total: 30
  131. })
  132. }))
  133. }
  134. }))
  135. }))
  136. // 模拟Taro方法
  137. import Taro from '@tarojs/taro'
  138. describe('OrderDetail 组件测试', () => {
  139. beforeEach(() => {
  140. // 模拟useRouter返回订单ID
  141. (Taro.useRouter as jest.Mock).mockReturnValue({ params: { id: '1' } })
  142. // 模拟企业用户信息
  143. (Taro.getStorageSync as jest.Mock).mockReturnValue(JSON.stringify({
  144. data: JSON.stringify({
  145. id: 1,
  146. companyId: 1,
  147. name: '测试企业'
  148. })
  149. }))
  150. })
  151. afterEach(() => {
  152. jest.clearAllMocks()
  153. })
  154. test('渲染订单详情页面', () => {
  155. renderWithQueryClient(<OrderDetail />)
  156. // 验证Navbar存在
  157. expect(screen.getByTestId('navbar')).toBeInTheDocument()
  158. expect(screen.getByTestId('navbar')).toHaveAttribute('data-title', '订单详情')
  159. expect(screen.getByTestId('navbar')).toHaveAttribute('data-left-text', '返回')
  160. // 验证订单信息
  161. expect(screen.getByText('阿里巴巴2023-11')).toBeInTheDocument()
  162. expect(screen.getByText('订单编号: ORDER-1')).toBeInTheDocument()
  163. expect(screen.getAllByText('进行中').length).toBeGreaterThan(0)
  164. // 验证基本信息卡片
  165. expect(screen.getByText('基本信息')).toBeInTheDocument()
  166. expect(screen.getByText('预计人数')).toBeInTheDocument()
  167. expect(screen.getByText('30人')).toBeInTheDocument()
  168. expect(screen.getByText('实际人数')).toBeInTheDocument()
  169. expect(screen.getByText('3人')).toBeInTheDocument()
  170. // 验证打卡统计卡片
  171. expect(screen.getByText('打卡数据统计')).toBeInTheDocument()
  172. expect(screen.getByText('本月打卡')).toBeInTheDocument()
  173. expect(screen.getByText('工资视频')).toBeInTheDocument()
  174. expect(screen.getByText('个税视频')).toBeInTheDocument()
  175. // 验证关联人才卡片
  176. expect(screen.getByText('关联人才')).toBeInTheDocument()
  177. expect(screen.getByText('张三')).toBeInTheDocument()
  178. expect(screen.getByText('李四')).toBeInTheDocument()
  179. expect(screen.getByText('王五')).toBeInTheDocument()
  180. // 验证视频资料卡片
  181. expect(screen.getByText('视频资料')).toBeInTheDocument()
  182. expect(screen.getByText('打卡视频_2023-12-01.mp4')).toBeInTheDocument()
  183. expect(screen.getByText('工资视频_2023-11-30.mp4')).toBeInTheDocument()
  184. // 验证状态管理卡片
  185. expect(screen.getByText('状态管理')).toBeInTheDocument()
  186. expect(screen.getByText('草稿')).toBeInTheDocument()
  187. expect(screen.getByText('已确认')).toBeInTheDocument()
  188. expect(screen.getAllByText('进行中').length).toBeGreaterThan(0)
  189. expect(screen.getByText('已完成')).toBeInTheDocument()
  190. expect(screen.getByText('已取消')).toBeInTheDocument()
  191. // 验证操作按钮
  192. expect(screen.getByText('编辑订单')).toBeInTheDocument()
  193. expect(screen.getByText('下载订单报告')).toBeInTheDocument()
  194. expect(screen.getByText('分享订单')).toBeInTheDocument()
  195. })
  196. test('状态变更功能', () => {
  197. renderWithQueryClient(<OrderDetail />)
  198. // 初始状态为"进行中"
  199. const inProgressButton = screen.getByRole('button', { name: '进行中' })
  200. expect(inProgressButton).toHaveClass('bg-green-100')
  201. // 点击"已完成"状态
  202. const completedButton = screen.getByText('已完成')
  203. fireEvent.click(completedButton)
  204. // 验证状态变更(通过控制台日志验证)
  205. })
  206. test('添加备注功能', () => {
  207. renderWithQueryClient(<OrderDetail />)
  208. const textarea = screen.getByPlaceholderText('请输入备注内容...')
  209. const saveButton = screen.getByText('保存备注')
  210. // 输入备注内容
  211. fireEvent.change(textarea, { target: { value: '这是一个测试备注' } })
  212. expect(textarea).toHaveValue('这是一个测试备注')
  213. // 点击保存按钮
  214. fireEvent.click(saveButton)
  215. })
  216. test('查看详细打卡记录', () => {
  217. renderWithQueryClient(<OrderDetail />)
  218. const viewDetailButton = screen.getByText('查看详细打卡记录')
  219. fireEvent.click(viewDetailButton)
  220. })
  221. test('视频播放和下载按钮', () => {
  222. renderWithQueryClient(<OrderDetail />)
  223. const playButtons = screen.getAllByText('播放')
  224. const downloadButtons = screen.getAllByText('下载')
  225. expect(playButtons.length).toBeGreaterThan(0)
  226. expect(downloadButtons.length).toBeGreaterThan(0)
  227. // 点击第一个播放按钮
  228. fireEvent.click(playButtons[0])
  229. // 点击第一个下载按钮
  230. fireEvent.click(downloadButtons[0])
  231. })
  232. })