From 54867492a7c1045301a8b1c7a6bfb4d6c8a10181 Mon Sep 17 00:00:00 2001 From: imeepos Date: Wed, 21 Jan 2026 15:28:18 +0800 Subject: [PATCH] test: add unit tests for HomeScreen to ensure proper rendering Following TDD principles (RED-GREEN-REFACTOR): - RED: Created failing tests for HomeScreen rendering - Verify RED: Confirmed tests failed due to missing mocks - GREEN: Added necessary mocks for all dependencies - Verify GREEN: All 4 tests passing (4/4) Tests cover: - Title bar rendering with app name - Category tabs rendering when data is loaded - Template cards rendering when category has templates - Loading state not showing when data is loaded Co-Authored-By: Claude Opus 4.5 --- app/(tabs)/__tests__/index.test.tsx | 134 ++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 app/(tabs)/__tests__/index.test.tsx diff --git a/app/(tabs)/__tests__/index.test.tsx b/app/(tabs)/__tests__/index.test.tsx new file mode 100644 index 0000000..8e752e1 --- /dev/null +++ b/app/(tabs)/__tests__/index.test.tsx @@ -0,0 +1,134 @@ +import React from 'react' +import { render, waitFor } from '@testing-library/react-native' +import { SafeAreaProvider } from 'react-native-safe-area-context' +import HomeScreen from '../index' + +// Mock expo-linear-gradient +jest.mock('expo-linear-gradient', () => ({ + LinearGradient: 'LinearGradient', +})) + +// Mock expo-image +jest.mock('expo-image', () => ({ + Image: 'Image', +})) + +// Mock expo-status-bar +jest.mock('expo-status-bar', () => ({ + StatusBar: 'StatusBar', +})) + +// Mock icons +jest.mock('@/components/icon', () => ({ + DownArrowIcon: () => 'DownArrowIcon', + PointsIcon: () => 'PointsIcon', + SearchIcon: () => 'SearchIcon', +})) + +// Mock components +jest.mock('@/components/ErrorState', () => 'ErrorState') +jest.mock('@/components/LoadingState', () => 'LoadingState') +jest.mock('@/components/RefreshControl', () => 'RefreshControl') + +// Mock dependencies +jest.mock('expo-router', () => ({ + useLocalSearchParams: jest.fn(() => ({})), + useRouter: jest.fn(() => ({ + push: jest.fn(), + })), +})) + +jest.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: (key: string) => key, + }), +})) + +jest.mock('@/hooks/use-activates', () => ({ + useActivates: jest.fn(() => ({ + load: jest.fn(), + data: { + activities: [ + { + id: '1', + title: 'Test Activity', + desc: 'Test Description', + coverUrl: 'https://example.com/image.jpg', + link: '/test', + }, + ], + }, + error: null, + })), +})) + +jest.mock('@/hooks/use-categories', () => ({ + useCategories: jest.fn(() => ({ + load: jest.fn(), + data: { + categories: [ + { + id: 'cat1', + name: 'Test Category', + templates: [ + { + id: 'template1', + title: 'Test Template', + webpPreviewUrl: 'https://example.com/preview.webp', + previewUrl: 'https://example.com/preview.jpg', + coverImageUrl: 'https://example.com/cover.png', + aspectRatio: '1:1', + }, + ], + }, + ], + }, + loading: false, + error: null, + })), +})) + +const renderWithProviders = (component: React.ReactElement) => { + return render( + + {component} + + ) +} + +describe('HomeScreen', () => { + it('should render title bar with app name', async () => { + const { getByText } = renderWithProviders() + + await waitFor(() => { + expect(getByText('Popcore')).toBeTruthy() + }) + }) + + it('should render category tabs when data is loaded', async () => { + const { getByText } = renderWithProviders() + + await waitFor(() => { + expect(getByText('Test Category')).toBeTruthy() + }) + }) + + it('should render template cards when category has templates', async () => { + const { getByText } = renderWithProviders() + + await waitFor(() => { + expect(getByText('Test Template')).toBeTruthy() + }) + }) + + it('should not show loading state when data is loaded', async () => { + const { queryByText } = renderWithProviders() + + await waitFor(() => { + expect(queryByText('加载中')).toBeNull() + }) + }) +})