2
0

VideoManagement.test.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. import React from 'react'
  2. import { render, screen, fireEvent, waitFor } from '@testing-library/react'
  3. import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
  4. import VideoManagement from '../src/pages/VideoManagement/VideoManagement'
  5. // Mock Taro
  6. jest.mock('@tarojs/taro', () => ({
  7. showToast: jest.fn(),
  8. showLoading: jest.fn(),
  9. hideLoading: jest.fn(),
  10. showShareMenu: jest.fn(),
  11. showModal: jest.fn(({ success }) => success?.({ confirm: true })),
  12. openDocument: jest.fn()
  13. }))
  14. // Mock API client
  15. jest.mock('../src/api/enterpriseOrderClient', () => ({
  16. enterpriseOrderClient: {
  17. 'video-statistics': {
  18. $get: jest.fn()
  19. },
  20. 'company-videos': {
  21. $get: jest.fn()
  22. },
  23. 'batch-download': {
  24. $post: jest.fn()
  25. }
  26. }
  27. }))
  28. // Mock layouts
  29. jest.mock('@d8d/yongren-shared-ui/components/YongrenTabBarLayout', () => ({
  30. YongrenTabBarLayout: ({ children, activeKey }: any) => (
  31. <div data-testid="tab-bar-layout" data-active-key={activeKey}>
  32. {children}
  33. </div>
  34. )
  35. }))
  36. jest.mock('@d8d/mini-shared-ui-components/components/navbar', () => ({
  37. Navbar: ({ title }: any) => <div data-testid="navbar">{title}</div>
  38. }))
  39. const { enterpriseOrderClient } = require('../../api/enterpriseOrderClient')
  40. const Taro = require('@tarojs/taro')
  41. const createTestQueryClient = () => new QueryClient({
  42. defaultOptions: {
  43. queries: { retry: false },
  44. mutations: { retry: false }
  45. }
  46. })
  47. const renderWithQueryClient = (component: React.ReactElement) => {
  48. const queryClient = createTestQueryClient()
  49. return render(
  50. <QueryClientProvider client={queryClient}>
  51. {component}
  52. </QueryClientProvider>
  53. )
  54. }
  55. describe('VideoManagement', () => {
  56. beforeEach(() => {
  57. jest.clearAllMocks()
  58. })
  59. describe('视频列表加载', () => {
  60. it('应该显示加载状态', async () => {
  61. enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
  62. ok: true,
  63. json: async () => ({ total: 10, stats: [] })
  64. })
  65. enterpriseOrderClient['company-videos'].$get.mockImplementation(
  66. () => new Promise(() => {}) // 永不resolve,测试加载状态
  67. )
  68. renderWithQueryClient(<VideoManagement />)
  69. expect(screen.getByText('加载中...')).toBeInTheDocument()
  70. })
  71. it('应该成功加载并显示视频列表', async () => {
  72. const mockStatistics = {
  73. total: 12,
  74. stats: [
  75. { assetType: 'salary_video', count: 4, percentage: 33 },
  76. { assetType: 'tax_video', count: 3, percentage: 25 },
  77. { assetType: 'checkin_video', count: 5, percentage: 42 }
  78. ]
  79. }
  80. const mockVideos = {
  81. data: [
  82. {
  83. id: '1',
  84. talentName: '张明',
  85. assetType: 'salary_video',
  86. status: 'verified',
  87. fileSize: 12345678,
  88. duration: 45,
  89. description: '工资发放确认视频',
  90. createdAt: '2023-11-25T10:00:00Z',
  91. fileUrl: 'https://example.com/video1.mp4'
  92. },
  93. {
  94. id: '2',
  95. talentName: '李小红',
  96. assetType: 'tax_video',
  97. status: 'pending',
  98. fileSize: 10800000,
  99. duration: 38,
  100. description: '个税申报确认视频',
  101. createdAt: '2023-11-24T10:00:00Z',
  102. fileUrl: 'https://example.com/video2.mp4'
  103. }
  104. ]
  105. }
  106. enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
  107. ok: true,
  108. json: async () => mockStatistics
  109. })
  110. enterpriseOrderClient['company-videos'].$get.mockResolvedValue({
  111. ok: true,
  112. json: async () => mockVideos
  113. })
  114. renderWithQueryClient(<VideoManagement />)
  115. await waitFor(() => {
  116. expect(screen.getByText('视频列表 (2)')).toBeInTheDocument()
  117. expect(screen.getByText('张明 - 工资视频')).toBeInTheDocument()
  118. expect(screen.getByText('李小红 - 个税视频')).toBeInTheDocument()
  119. expect(screen.getByText('已验证')).toBeInTheDocument()
  120. expect(screen.getByText('待审核')).toBeInTheDocument()
  121. })
  122. })
  123. it('应该显示空状态', async () => {
  124. enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
  125. ok: true,
  126. json: async () => ({ total: 0, stats: [] })
  127. })
  128. enterpriseOrderClient['company-videos'].$get.mockResolvedValue({
  129. ok: true,
  130. json: async () => ({ data: [] })
  131. })
  132. renderWithQueryClient(<VideoManagement />)
  133. await waitFor(() => {
  134. expect(screen.getByText('暂无视频数据')).toBeInTheDocument()
  135. })
  136. })
  137. })
  138. describe('视频分类筛选', () => {
  139. it('应该显示所有分类标签及计数', async () => {
  140. const mockStatistics = {
  141. total: 12,
  142. stats: [
  143. { assetType: 'salary_video', count: 4 },
  144. { assetType: 'tax_video', count: 3 },
  145. { assetType: 'checkin_video', count: 5 }
  146. ]
  147. }
  148. enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
  149. ok: true,
  150. json: async () => mockStatistics
  151. })
  152. enterpriseOrderClient['company-videos'].$get.mockResolvedValue({
  153. ok: true,
  154. json: async () => ({ data: [] })
  155. })
  156. renderWithQueryClient(<VideoManagement />)
  157. await waitFor(() => {
  158. expect(screen.getByText('全部视频 (12)')).toBeInTheDocument()
  159. expect(screen.getByText('工资视频 (4)')).toBeInTheDocument()
  160. expect(screen.getByText('个税视频 (3)')).toBeInTheDocument()
  161. expect(screen.getByText('打卡视频 (5)')).toBeInTheDocument()
  162. })
  163. })
  164. it('应该能够切换视频分类', async () => {
  165. enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
  166. ok: true,
  167. json: async () => ({ total: 10, stats: [] })
  168. })
  169. enterpriseOrderClient['company-videos'].$get.mockResolvedValue({
  170. ok: true,
  171. json: async () => ({ data: [] })
  172. })
  173. renderWithQueryClient(<VideoManagement />)
  174. await waitFor(() => {
  175. expect(screen.getByText('工资视频')).toBeInTheDocument()
  176. })
  177. fireEvent.click(screen.getByText('工资视频'))
  178. await waitFor(() => {
  179. expect(enterpriseOrderClient['company-videos'].$get).toHaveBeenCalledWith(
  180. expect.objectContaining({
  181. query: { assetType: 'salary_video' }
  182. })
  183. )
  184. })
  185. })
  186. })
  187. describe('视频操作', () => {
  188. beforeEach(async () => {
  189. const mockVideos = {
  190. data: [
  191. {
  192. id: '1',
  193. talentName: '张明',
  194. assetType: 'salary_video',
  195. status: 'verified',
  196. fileSize: 12345678,
  197. duration: 45,
  198. description: '工资发放确认视频',
  199. createdAt: '2023-11-25T10:00:00Z',
  200. fileUrl: 'https://example.com/video1.mp4'
  201. }
  202. ]
  203. }
  204. enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
  205. ok: true,
  206. json: async () => ({ total: 1, stats: [] })
  207. })
  208. enterpriseOrderClient['company-videos'].$get.mockResolvedValue({
  209. ok: true,
  210. json: async () => mockVideos
  211. })
  212. })
  213. it('应该能够选择视频进行批量下载', async () => {
  214. renderWithQueryClient(<VideoManagement />)
  215. await waitFor(() => {
  216. expect(screen.getByText('张明 - 工资视频')).toBeInTheDocument()
  217. })
  218. // 点击选择按钮
  219. const selectButtons = screen.getAllByText('选择')
  220. fireEvent.click(selectButtons[0])
  221. await waitFor(() => {
  222. expect(screen.getByText('已选择')).toBeInTheDocument()
  223. expect(screen.getByText('批量下载 (1)')).toBeInTheDocument()
  224. })
  225. })
  226. it('应该能够执行批量下载', async () => {
  227. enterpriseOrderClient['batch-download'].$post.mockResolvedValue({
  228. ok: true,
  229. json: async () => ({ success: true })
  230. })
  231. renderWithQueryClient(<VideoManagement />)
  232. await waitFor(() => {
  233. expect(screen.getByText('张明 - 工资视频')).toBeInTheDocument()
  234. })
  235. // 先选择视频
  236. const selectButtons = screen.getAllByText('选择')
  237. fireEvent.click(selectButtons[0])
  238. // 再点击批量下载
  239. fireEvent.click(screen.getByText(/批量下载/))
  240. await waitFor(() => {
  241. expect(enterpriseOrderClient['batch-download'].$post).toHaveBeenCalled()
  242. expect(Taro.showToast).toHaveBeenCalledWith(
  243. expect.objectContaining({ title: '下载任务已创建' })
  244. )
  245. })
  246. })
  247. it('应该在批量下载前提示选择视频', async () => {
  248. renderWithQueryClient(<VideoManagement />)
  249. await waitFor(() => {
  250. expect(screen.getByText('张明 - 工资视频')).toBeInTheDocument()
  251. })
  252. // 直接点击批量下载,不选择视频
  253. fireEvent.click(screen.getByText(/批量下载/))
  254. expect(Taro.showToast).toHaveBeenCalledWith(
  255. expect.objectContaining({ title: '请先选择要下载的视频' })
  256. )
  257. })
  258. it('应该能够播放视频', async () => {
  259. renderWithQueryClient(<VideoManagement />)
  260. await waitFor(() => {
  261. expect(screen.getByText('张明 - 工资视频')).toBeInTheDocument()
  262. })
  263. const playButton = screen.getByText('播放')
  264. fireEvent.click(playButton)
  265. expect(Taro.showModal).toHaveBeenCalledWith(
  266. expect.objectContaining({
  267. title: '播放视频',
  268. content: '即将播放:张明 - 工资视频'
  269. })
  270. )
  271. })
  272. it('应该能够下载单个视频', async () => {
  273. enterpriseOrderClient['batch-download'].$post.mockResolvedValue({
  274. ok: true,
  275. json: async () => ({ success: true })
  276. })
  277. renderWithQueryClient(<VideoManagement />)
  278. await waitFor(() => {
  279. expect(screen.getByText('张明 - 工资视频')).toBeInTheDocument()
  280. })
  281. const downloadButton = screen.getByText('下载')
  282. fireEvent.click(downloadButton)
  283. await waitFor(() => {
  284. expect(enterpriseOrderClient['batch-download'].$post).toHaveBeenCalled()
  285. expect(Taro.showToast).toHaveBeenCalledWith(
  286. expect.objectContaining({ title: '下载成功' })
  287. )
  288. })
  289. })
  290. it('应该能够分享视频', async () => {
  291. renderWithQueryClient(<VideoManagement />)
  292. await waitFor(() => {
  293. expect(screen.getByText('张明 - 工资视频')).toBeInTheDocument()
  294. })
  295. const shareButton = screen.getByText('分享')
  296. fireEvent.click(shareButton)
  297. expect(Taro.showShareMenu).toHaveBeenCalledWith(
  298. expect.objectContaining({ withShareTicket: true })
  299. )
  300. })
  301. })
  302. describe('组件集成', () => {
  303. it('应该正确集成Navbar组件', async () => {
  304. enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
  305. ok: true,
  306. json: async () => ({ total: 0, stats: [] })
  307. })
  308. enterpriseOrderClient['company-videos'].$get.mockResolvedValue({
  309. ok: true,
  310. json: async () => ({ data: [] })
  311. })
  312. renderWithQueryClient(<VideoManagement />)
  313. await waitFor(() => {
  314. const navbar = screen.getByTestId('navbar')
  315. expect(navbar).toBeInTheDocument()
  316. expect(navbar).toHaveTextContent('视频管理')
  317. })
  318. })
  319. it('应该正确集成TabBarLayout并激活settings标签', async () => {
  320. enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
  321. ok: true,
  322. json: async () => ({ total: 0, stats: [] })
  323. })
  324. enterpriseOrderClient['company-videos'].$get.mockResolvedValue({
  325. ok: true,
  326. json: async () => ({ data: [] })
  327. })
  328. renderWithQueryClient(<VideoManagement />)
  329. await waitFor(() => {
  330. const layout = screen.getByTestId('tab-bar-layout')
  331. expect(layout).toHaveAttribute('data-active-key', 'settings')
  332. })
  333. })
  334. })
  335. })