/** * TDD Phase 1: RED - Write failing tests first * * 测试搜索结果页面的分页功能 */ import React from 'react' import { render, waitFor, fireEvent } from '@testing-library/react-native' import { useRouter, useLocalSearchParams } from 'expo-router' import SearchWorksResultsScreen from '@/app/searchWorksResults' import { useWorksSearch } from '@/hooks/use-works-search' // Mock dependencies jest.mock('expo-router', () => ({ useRouter: jest.fn(), useLocalSearchParams: jest.fn(), })) jest.mock('@/hooks/use-works-search', () => ({ useWorksSearch: jest.fn(), })) jest.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key: string) => key, i18n: { language: 'zh-CN' }, }), })) jest.mock('@/components/SearchBar', () => 'SearchBar') jest.mock('@/components/WorksGallery', () => 'WorksGallery') describe('SearchWorksResultsScreen - Pagination', () => { const mockRouter = { push: jest.fn(), back: jest.fn(), } beforeEach(() => { jest.clearAllMocks() ;(useRouter as jest.Mock).mockReturnValue(mockRouter) ;(useLocalSearchParams as jest.Mock).mockReturnValue({ q: '测试' }) }) describe('Load More Functionality', () => { it('should load first page on initial render', () => { const mockUseWorksSearch = useWorksSearch as jest.Mock mockUseWorksSearch.mockReturnValue({ data: { data: [ { id: '1', createdAt: new Date('2025-01-15'), template: { id: 't1', name: 'Template 1' }, status: 'completed', duration: 5, }, ], total: 50, page: 1, limit: 20, totalPages: 3, }, works: [ { id: '1', createdAt: new Date('2025-01-15'), template: { id: 't1', name: 'Template 1' }, status: 'completed', duration: 5, }, ], isLoading: false, error: null, }) render() // 验证初始调用使用 page: 1 expect(mockUseWorksSearch).toHaveBeenCalledWith( expect.objectContaining({ page: 1, }) ) }) it('should accumulate results when loading more pages', async () => { const mockUseWorksSearch = useWorksSearch as jest.Mock // 第一页数据 const page1Data = [ { id: '1', createdAt: new Date('2025-01-15'), template: { id: 't1', name: 'Template 1' }, status: 'completed', duration: 5, }, ] // 第二页数据 const page2Data = [ { id: '2', createdAt: new Date('2025-01-14'), template: { id: 't2', name: 'Template 2' }, status: 'completed', duration: 10, }, ] mockUseWorksSearch.mockReturnValue({ data: { data: page1Data, total: 50, page: 1, limit: 20, totalPages: 3, }, works: page1Data, isLoading: false, error: null, loadMore: jest.fn(), }) const { rerender } = render() // 模拟加载第二页 mockUseWorksSearch.mockReturnValue({ data: { data: [...page1Data, ...page2Data], total: 50, page: 2, limit: 20, totalPages: 3, }, works: [...page1Data, ...page2Data], isLoading: false, error: null, loadMore: jest.fn(), }) rerender() // 验证结果累积 expect(mockUseWorksSearch).toHaveBeenCalled() }) it('should not load more when already loading', () => { const mockLoadMore = jest.fn() const mockUseWorksSearch = useWorksSearch as jest.Mock mockUseWorksSearch.mockReturnValue({ data: { data: [], total: 50, page: 1, limit: 20, totalPages: 3, }, works: [], isLoading: true, error: null, loadMore: mockLoadMore, }) render() // 验证加载中时不应触发新的加载 expect(mockLoadMore).not.toHaveBeenCalled() }) it('should not load more when all pages loaded', () => { const mockLoadMore = jest.fn() const mockUseWorksSearch = useWorksSearch as jest.Mock mockUseWorksSearch.mockReturnValue({ data: { data: [ { id: '1', createdAt: new Date('2025-01-15'), template: { id: 't1', name: 'Template 1' }, status: 'completed', duration: 5, }, ], total: 1, page: 1, limit: 20, totalPages: 1, }, works: [ { id: '1', createdAt: new Date('2025-01-15'), template: { id: 't1', name: 'Template 1' }, status: 'completed', duration: 5, }, ], isLoading: false, error: null, loadMore: mockLoadMore, hasMore: false, }) render() // 验证没有更多数据时不应触发加载 expect(mockLoadMore).not.toHaveBeenCalled() }) }) describe('Loading State', () => { it('should show loading indicator when loading more', () => { const mockUseWorksSearch = useWorksSearch as jest.Mock mockUseWorksSearch.mockReturnValue({ data: { data: [], total: 50, page: 2, limit: 20, totalPages: 3, }, works: [], isLoading: true, error: null, isLoadingMore: true, }) const { getByTestId } = render() // 验证显示加载指示器 expect(() => getByTestId('loading-more-indicator')).not.toThrow() }) }) })