본문으로 건너뛰기
cccskills
무료GitHub에 공개

testing-patterns

Write Jest unit tests for component behavior and user interactions. Includes reusable test data builders, mock replacements for dependencies, and test-driven development, where a failing test guides implementation before the code is cleaned up.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

원문원문 설명 보기

Jest testing patterns, factory functions, mocking strategies, and TDD workflow. Use when writing unit tests, creating test factories, or following TDD red-green-refactor cycle.

설치 방법 보기

이럴 때 유용합니다

  • Testing component rendering and form interactions
  • Creating reusable test data with selective overrides
  • Replacing modules and GraphQL hooks in tests
  • Developing features from failing tests

포함된 파일(1)

  • SKILL.md5.7 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

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<X>) 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(
    <ThemeProvider>{ui}</ThemeProvider>
  );
};

Usage:

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

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

Factory Pattern

Component Props Factory

import { ComponentProps } from 'react';

const getMockMyComponentProps = (
  overrides?: Partial<ComponentProps<typeof MyComponent>>
) => {
  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(<MyComponent {...props} />);
  expect(screen.getByText('Custom Title')).toBeTruthy();
});

Data Factory

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

const getMockUser = (overrides?: Partial<User>): 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(<UserCard user={user} />);
  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(<LoginForm onSubmit={onSubmit} />);

  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

  1. Always use factory functions for props and data
  2. Test behavior, not implementation
  3. Use descriptive test names
  4. Organize with describe blocks
  5. Clear mocks between tests
  6. 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

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Build screens, forms, and lists with shared UI components and design tokens, named values for spacing, colors, and typography. Provides patterns for consistent layouts, button variants, validation messages, and reusable component properties.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Building screens with shared UI components
  • Replacing fixed colors and spacing with design tokens
  • Creating consistent forms and list layouts
ChrisWiles/claude-code-showcase6.1천2026년 1월 7일 업데이트

Build forms with Formik and yup, a library for defining input validation rules. Apply field errors, submission feedback, edit detection, and step-specific validation to login screens, editing forms, and forms split across multiple steps.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Building login and registration forms
  • Adding conditional input validation
  • Editing existing records with change detection
ChrisWiles/claude-code-showcase6.1천2026년 1월 7일 업데이트

Build GraphQL data queries and updates with separate operation files and generated types and hooks, reusable functions for React. Follow Apollo Client patterns for error messages, loading feedback, cache updates, and reusable field selections.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Building a GraphQL list view
  • Adding data creation or update forms
  • Generating types and hooks from operation files
ChrisWiles/claude-code-showcase6.1천2026년 1월 7일 업데이트

Build React interfaces that clearly handle loading, errors, empty results, and submissions. Use examples and checklists to keep existing data visible during refetching, offer retry actions, and disable buttons while asynchronous operations are running.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Keeping existing data visible during refetching
  • Adding visible errors and retry actions
  • Showing guidance when lists or search results are empty
ChrisWiles/claude-code-showcase6.1천2026년 1월 7일 업데이트

Investigate bugs and failing tests through four stages: finding the root cause, comparing working patterns, testing a hypothesis, and implementing a fix. Uses reproduction steps, diagnostic evidence, and regression tests to check the result.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Tracing the cause of a failing test
  • Following runtime errors back to invalid data
  • Finding the change that broke working code
ChrisWiles/claude-code-showcase6.1천2026년 1월 7일 업데이트

ChrisWiles의 스킬 모두 보기

이 스킬의 문제 신고