import React from 'react'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import VideoManagement from '../src/pages/VideoManagement/VideoManagement'
// Mock Taro
jest.mock('@tarojs/taro', () => ({
showToast: jest.fn(),
showLoading: jest.fn(),
hideLoading: jest.fn(),
showShareMenu: jest.fn(),
showModal: jest.fn(({ success }) => success?.({ confirm: true })),
openDocument: jest.fn()
}))
// Mock API client
jest.mock('../src/api/enterpriseOrderClient', () => ({
enterpriseOrderClient: {
'video-statistics': {
$get: jest.fn()
},
'company-videos': {
$get: jest.fn()
},
'batch-download': {
$post: jest.fn()
}
}
}))
// Mock layouts
jest.mock('@d8d/yongren-shared-ui/components/YongrenTabBarLayout', () => ({
YongrenTabBarLayout: ({ children, activeKey }: any) => (
{children}
)
}))
jest.mock('@d8d/mini-shared-ui-components/components/navbar', () => ({
Navbar: ({ title }: any) => {title}
}))
const { enterpriseOrderClient } = require('../../api/enterpriseOrderClient')
const Taro = require('@tarojs/taro')
const createTestQueryClient = () => new QueryClient({
defaultOptions: {
queries: { retry: false },
mutations: { retry: false }
}
})
const renderWithQueryClient = (component: React.ReactElement) => {
const queryClient = createTestQueryClient()
return render(
{component}
)
}
describe('VideoManagement', () => {
beforeEach(() => {
jest.clearAllMocks()
})
describe('视频列表加载', () => {
it('应该显示加载状态', async () => {
enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
ok: true,
json: async () => ({ total: 10, stats: [] })
})
enterpriseOrderClient['company-videos'].$get.mockImplementation(
() => new Promise(() => {}) // 永不resolve,测试加载状态
)
renderWithQueryClient()
expect(screen.getByText('加载中...')).toBeInTheDocument()
})
it('应该成功加载并显示视频列表', async () => {
const mockStatistics = {
total: 12,
stats: [
{ assetType: 'salary_video', count: 4, percentage: 33 },
{ assetType: 'tax_video', count: 3, percentage: 25 },
{ assetType: 'checkin_video', count: 5, percentage: 42 }
]
}
const mockVideos = {
data: [
{
id: '1',
talentName: '张明',
assetType: 'salary_video',
status: 'verified',
fileSize: 12345678,
duration: 45,
description: '工资发放确认视频',
createdAt: '2023-11-25T10:00:00Z',
fileUrl: 'https://example.com/video1.mp4'
},
{
id: '2',
talentName: '李小红',
assetType: 'tax_video',
status: 'pending',
fileSize: 10800000,
duration: 38,
description: '个税申报确认视频',
createdAt: '2023-11-24T10:00:00Z',
fileUrl: 'https://example.com/video2.mp4'
}
]
}
enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
ok: true,
json: async () => mockStatistics
})
enterpriseOrderClient['company-videos'].$get.mockResolvedValue({
ok: true,
json: async () => mockVideos
})
renderWithQueryClient()
await waitFor(() => {
expect(screen.getByText('视频列表 (2)')).toBeInTheDocument()
expect(screen.getByText('张明 - 工资视频')).toBeInTheDocument()
expect(screen.getByText('李小红 - 个税视频')).toBeInTheDocument()
expect(screen.getByText('已验证')).toBeInTheDocument()
expect(screen.getByText('待审核')).toBeInTheDocument()
})
})
it('应该显示空状态', async () => {
enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
ok: true,
json: async () => ({ total: 0, stats: [] })
})
enterpriseOrderClient['company-videos'].$get.mockResolvedValue({
ok: true,
json: async () => ({ data: [] })
})
renderWithQueryClient()
await waitFor(() => {
expect(screen.getByText('暂无视频数据')).toBeInTheDocument()
})
})
})
describe('视频分类筛选', () => {
it('应该显示所有分类标签及计数', async () => {
const mockStatistics = {
total: 12,
stats: [
{ assetType: 'salary_video', count: 4 },
{ assetType: 'tax_video', count: 3 },
{ assetType: 'checkin_video', count: 5 }
]
}
enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
ok: true,
json: async () => mockStatistics
})
enterpriseOrderClient['company-videos'].$get.mockResolvedValue({
ok: true,
json: async () => ({ data: [] })
})
renderWithQueryClient()
await waitFor(() => {
expect(screen.getByText('全部视频 (12)')).toBeInTheDocument()
expect(screen.getByText('工资视频 (4)')).toBeInTheDocument()
expect(screen.getByText('个税视频 (3)')).toBeInTheDocument()
expect(screen.getByText('打卡视频 (5)')).toBeInTheDocument()
})
})
it('应该能够切换视频分类', async () => {
enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
ok: true,
json: async () => ({ total: 10, stats: [] })
})
enterpriseOrderClient['company-videos'].$get.mockResolvedValue({
ok: true,
json: async () => ({ data: [] })
})
renderWithQueryClient()
await waitFor(() => {
expect(screen.getByText('工资视频')).toBeInTheDocument()
})
fireEvent.click(screen.getByText('工资视频'))
await waitFor(() => {
expect(enterpriseOrderClient['company-videos'].$get).toHaveBeenCalledWith(
expect.objectContaining({
query: { assetType: 'salary_video' }
})
)
})
})
})
describe('视频操作', () => {
beforeEach(async () => {
const mockVideos = {
data: [
{
id: '1',
talentName: '张明',
assetType: 'salary_video',
status: 'verified',
fileSize: 12345678,
duration: 45,
description: '工资发放确认视频',
createdAt: '2023-11-25T10:00:00Z',
fileUrl: 'https://example.com/video1.mp4'
}
]
}
enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
ok: true,
json: async () => ({ total: 1, stats: [] })
})
enterpriseOrderClient['company-videos'].$get.mockResolvedValue({
ok: true,
json: async () => mockVideos
})
})
it('应该能够选择视频进行批量下载', async () => {
renderWithQueryClient()
await waitFor(() => {
expect(screen.getByText('张明 - 工资视频')).toBeInTheDocument()
})
// 点击选择按钮
const selectButtons = screen.getAllByText('选择')
fireEvent.click(selectButtons[0])
await waitFor(() => {
expect(screen.getByText('已选择')).toBeInTheDocument()
expect(screen.getByText('批量下载 (1)')).toBeInTheDocument()
})
})
it('应该能够执行批量下载', async () => {
enterpriseOrderClient['batch-download'].$post.mockResolvedValue({
ok: true,
json: async () => ({ success: true })
})
renderWithQueryClient()
await waitFor(() => {
expect(screen.getByText('张明 - 工资视频')).toBeInTheDocument()
})
// 先选择视频
const selectButtons = screen.getAllByText('选择')
fireEvent.click(selectButtons[0])
// 再点击批量下载
fireEvent.click(screen.getByText(/批量下载/))
await waitFor(() => {
expect(enterpriseOrderClient['batch-download'].$post).toHaveBeenCalled()
expect(Taro.showToast).toHaveBeenCalledWith(
expect.objectContaining({ title: '下载任务已创建' })
)
})
})
it('应该在批量下载前提示选择视频', async () => {
renderWithQueryClient()
await waitFor(() => {
expect(screen.getByText('张明 - 工资视频')).toBeInTheDocument()
})
// 直接点击批量下载,不选择视频
fireEvent.click(screen.getByText(/批量下载/))
expect(Taro.showToast).toHaveBeenCalledWith(
expect.objectContaining({ title: '请先选择要下载的视频' })
)
})
it('应该能够播放视频', async () => {
renderWithQueryClient()
await waitFor(() => {
expect(screen.getByText('张明 - 工资视频')).toBeInTheDocument()
})
const playButton = screen.getByText('播放')
fireEvent.click(playButton)
expect(Taro.showModal).toHaveBeenCalledWith(
expect.objectContaining({
title: '播放视频',
content: '即将播放:张明 - 工资视频'
})
)
})
it('应该能够下载单个视频', async () => {
enterpriseOrderClient['batch-download'].$post.mockResolvedValue({
ok: true,
json: async () => ({ success: true })
})
renderWithQueryClient()
await waitFor(() => {
expect(screen.getByText('张明 - 工资视频')).toBeInTheDocument()
})
const downloadButton = screen.getByText('下载')
fireEvent.click(downloadButton)
await waitFor(() => {
expect(enterpriseOrderClient['batch-download'].$post).toHaveBeenCalled()
expect(Taro.showToast).toHaveBeenCalledWith(
expect.objectContaining({ title: '下载成功' })
)
})
})
it('应该能够分享视频', async () => {
renderWithQueryClient()
await waitFor(() => {
expect(screen.getByText('张明 - 工资视频')).toBeInTheDocument()
})
const shareButton = screen.getByText('分享')
fireEvent.click(shareButton)
expect(Taro.showShareMenu).toHaveBeenCalledWith(
expect.objectContaining({ withShareTicket: true })
)
})
})
describe('组件集成', () => {
it('应该正确集成Navbar组件', async () => {
enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
ok: true,
json: async () => ({ total: 0, stats: [] })
})
enterpriseOrderClient['company-videos'].$get.mockResolvedValue({
ok: true,
json: async () => ({ data: [] })
})
renderWithQueryClient()
await waitFor(() => {
const navbar = screen.getByTestId('navbar')
expect(navbar).toBeInTheDocument()
expect(navbar).toHaveTextContent('视频管理')
})
})
it('应该正确集成TabBarLayout并激活settings标签', async () => {
enterpriseOrderClient['video-statistics'].$get.mockResolvedValue({
ok: true,
json: async () => ({ total: 0, stats: [] })
})
enterpriseOrderClient['company-videos'].$get.mockResolvedValue({
ok: true,
json: async () => ({ data: [] })
})
renderWithQueryClient()
await waitFor(() => {
const layout = screen.getByTestId('tab-bar-layout')
expect(layout).toHaveAttribute('data-active-key', 'settings')
})
})
})
})