Skip to content

Frontend Testing Strategy (Unit & Integration) #357

Description

@SagiEv

Frontend Testing Strategy (Unit & Integration)

Currently, the SwipeLab frontend relies heavily on end-to-end (E2E) testing via Playwright. While E2E tests are excellent for confidence, they are slow and brittle. To align with industry best practices, we should implement a robust lower-level testing strategy utilizing Jest and React Native Testing Library (RNTL).

Goal

Establish a testing pyramid where the bulk of our logic is tested quickly in isolation (Unit Tests), UI components are tested for rendering and interactions (Component Tests), and major screens are tested with mocked APIs (Integration Tests).

Proposed Architecture

We will introduce a __tests__ directory inside the frontend/ root (to separate them from E2E tests) structured as follows:

frontend/__tests__/
  ├── unit/           # Pure functions, utils, and Zustand stores
  ├── hooks/          # Custom React Query hooks and logic
  ├── components/     # Isolated UI component tests
  └── integration/    # Full screen tests with mocked API

1. Unit Testing (Pure Logic & State)

Tools: Jest
Focus: Fast, synchronous logic that does not depend on React components.

  • Utils & Helpers: Test formatting functions, validation logic, and data transformers (app/utils/).
  • Zustand Stores: Test global state mutations (app/stores/). We will render the store in isolation and assert that actions (e.g., setTokens, logout) correctly update the state.
  • API Clients: Mock the global fetch API to ensure app/api/ services correctly format headers and payloads.

2. Hook Testing (React Query)

Tools: @testing-library/react-native (renderHook)
Focus: Validating data fetching and caching logic.

  • Use renderHook wrapped in a test QueryClientProvider to verify that custom hooks (like useTasks, useGamification) fetch, cache, and expose loading/error states correctly.

3. Component Testing (Isolated UI)

Tools: Jest + RNTL (render, fireEvent, screen)
Focus: Ensuring UI components render correctly based on props, and that user interactions fire callbacks.

  • Dumb Components: Test reusable components in app/components/ui/ (e.g., Button, SwipeCard, NotificationBell).
  • Assertions: Verify styles, accessibility labels, and that callbacks (onPress, onSwipe) are triggered with correct arguments.
  • Mocking: Global state (Zustand) and API queries (React Query) will be mocked so the component can be tested in isolation.

4. Integration Testing (Screens)

Tools: RNTL + MSW (Mock Service Worker) or Jest fetch mocks
Focus: Testing the interaction between components, hooks, and stores on a single screen without a real backend.

  • Screens: Test complex views like AdminDashboardScreen or CollectionScreen.
  • Flow: Mock the API response, render the screen, interact with elements, and assert that the UI updates (e.g., clicking a "Mark as Read" button optimistic-updates the UI).

Decisions Made

Note

  1. API Mocking Strategy: We will use Jest global.fetch mocks (via jest.spyOn or jest-fetch-mock). This is the fastest approach to deliver, as it requires zero external setup compared to MSW in a React Native environment.
  2. Coverage Goals: We will not enforce a strict CI coverage threshold initially. Instead, we will generate coverage reports to track progress and prevent the CI pipeline from arbitrarily blocking PRs while the suite is built up.
  1. Writing sample tests for a Zustand Store.
  2. Writing sample tests for a UI Component (e.g., SwipeCard).
  3. (Optional) Integrating MSW for a Screen integration test.

Metadata

Metadata

Assignees

No one assigned

    Labels

    choresetup, cleanup, configs, folder structure, refactors

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions