testing-patterns

安装量: 443
排名: #2285

安装

npx skills add https://github.com/sickn33/antigravity-awesome-skills --skill testing-patterns

Testing Patterns and Utilities Testing Philosophy

Test-Driven Development (TDD):

Write failing test FIRST Implement minimal code to pass Refactor after green Never write production code without a failing test

Behavior-Driven Testing:

Test behavior, not implementation Focus on public APIs and business requirements Avoid testing implementation details Use descriptive test names that describe behavior

Factory Pattern:

Create getMockX(overrides?: Partial) functions Provide sensible defaults Allow overriding specific properties Keep tests DRY and maintainable Test Utilities Custom Render Function

Create a custom render that wraps components with required providers:

// src/utils/testUtils.tsx import { render } from '@testing-library/react-native'; import { ThemeProvider } from './theme';

export const renderWithTheme = (ui: React.ReactElement) => { return render( {ui} ); };

Usage:

import { renderWithTheme } from 'utils/testUtils'; import { screen } from '@testing-library/react-native';

it('should render component', () => { renderWithTheme(); expect(screen.getByText('Hello')).toBeTruthy(); });

Factory Pattern Component Props Factory import { ComponentProps } from 'react';

const getMockMyComponentProps = ( overrides?: Partial> ) => { return { title: 'Default Title', count: 0, onPress: jest.fn(), isLoading: false, ...overrides, }; };

// Usage in tests it('should render with custom title', () => { const props = getMockMyComponentProps({ title: 'Custom Title' }); renderWithTheme(); expect(screen.getByText('Custom Title')).toBeTruthy(); });

Data Factory interface User { id: string; name: string; email: string; role: 'admin' | 'user'; }

const getMockUser = (overrides?: Partial): User => { return { id: '123', name: 'John Doe', email: 'john@example.com', role: 'user', ...overrides, }; };

// Usage it('should display admin badge for admin users', () => { const user = getMockUser({ role: 'admin' }); renderWithTheme(); expect(screen.getByText('Admin')).toBeTruthy(); });

Mocking Patterns Mocking Modules // Mock entire module jest.mock('utils/analytics');

// Mock with factory function jest.mock('utils/analytics', () => ({ Analytics: { logEvent: jest.fn(), }, }));

// Access mock in test const mockLogEvent = jest.requireMock('utils/analytics').Analytics.logEvent;

Mocking GraphQL Hooks jest.mock('./GetItems.generated', () => ({ useGetItemsQuery: jest.fn(), }));

const mockUseGetItemsQuery = jest.requireMock( './GetItems.generated' ).useGetItemsQuery as jest.Mock;

// In test mockUseGetItemsQuery.mockReturnValue({ data: { items: [] }, loading: false, error: undefined, });

Test Structure describe('ComponentName', () => { beforeEach(() => { jest.clearAllMocks(); });

describe('Rendering', () => { it('should render component with default props', () => {}); it('should render loading state when loading', () => {}); });

describe('User interactions', () => { it('should call onPress when button is clicked', async () => {}); });

describe('Edge cases', () => { it('should handle empty data gracefully', () => {}); }); });

Query Patterns // Element must exist expect(screen.getByText('Hello')).toBeTruthy();

// Element should not exist expect(screen.queryByText('Goodbye')).toBeNull();

// Element appears asynchronously await waitFor(() => { expect(screen.findByText('Loaded')).toBeTruthy(); });

User Interaction Patterns import { fireEvent, screen } from '@testing-library/react-native';

it('should submit form on button click', async () => { const onSubmit = jest.fn(); renderWithTheme();

fireEvent.changeText(screen.getByLabelText('Email'), 'user@example.com'); fireEvent.changeText(screen.getByLabelText('Password'), 'password123'); fireEvent.press(screen.getByTestId('login-button'));

await waitFor(() => { expect(onSubmit).toHaveBeenCalled(); }); });

Anti-Patterns to Avoid Testing Mock Behavior Instead of Real Behavior // Bad - testing the mock expect(mockFetchData).toHaveBeenCalled();

// Good - testing actual behavior expect(screen.getByText('John Doe')).toBeTruthy();

Not Using Factories // Bad - duplicated, inconsistent test data it('test 1', () => { const user = { id: '1', name: 'John', email: 'john@test.com', role: 'user' }; }); it('test 2', () => { const user = { id: '2', name: 'Jane', email: 'jane@test.com' }; // Missing role! });

// Good - reusable factory const user = getMockUser({ name: 'Custom Name' });

Best Practices Always use factory functions for props and data Test behavior, not implementation Use descriptive test names Organize with describe blocks Clear mocks between tests Keep tests focused - one behavior per test Running Tests

Run all tests

npm test

Run with coverage

npm run test:coverage

Run specific file

npm test ComponentName.test.tsx

Integration with Other Skills react-ui-patterns: Test all UI states (loading, error, empty, success) systematic-debugging: Write test that reproduces bug before fixing

返回排行榜