Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.thesozocrm.com/llms.txt

Use this file to discover all available pages before exploring further.

Testing Workflow

This guide covers how to write, run, and maintain tests in the Elevate CRM codebase.

Quick Start

Run Tests

# Run all tests
npm test

# Run specific test file
npm test -- RepManagement.test.jsx

# Run tests in watch mode
npm test -- --watch

# Run tests with coverage
npm test -- --coverage

Test Structure

Unit Tests

Location: src/**/__tests__/*.test.js or *.test.jsx Example:
// src/shared/services/__tests__/regionService.test.js
import regionService from '../regionService';

describe('regionService', () => {
  describe('assignTeamToRegion', () => {
    it('should assign team to region and sync rep regionIds', async () => {
      // Test implementation
    });
  });
});

Component Tests

Location: src/**/__tests__/*.test.jsx Example:
// src/features/reps/components/__tests__/RepCard.test.jsx
import { render, screen } from '@testing-library/react';
import RepCard from '../RepCard';

describe('RepCard', () => {
  it('should display rep name and email', () => {
    const rep = { name: 'John Doe', email: 'john@test.com' };
    render(<RepCard rep={rep} />);
    expect(screen.getByText('John Doe')).toBeInTheDocument();
  });
});

Writing Tests

Test-Driven Development (TDD)

1

Write Failing Test

Write a test that describes the behavior you want
2

Run Test

Verify the test fails (Red)
3

Write Minimal Code

Write just enough code to make the test pass (Green)
4

Refactor

Improve the code while keeping tests passing

Test Structure (AAA Pattern)

describe('FeatureName', () => {
  it('should do something when condition', () => {
    // Arrange - Set up test data
    const input = { value: 10 };
    
    // Act - Execute the function
    const result = myFunction(input);
    
    // Assert - Verify the result
    expect(result).toBe(20);
  });
});

Testing Patterns

Mocking Firebase

// Mock Firestore
jest.mock('firebase/firestore', () => ({
  doc: jest.fn(),
  getDoc: jest.fn(),
  setDoc: jest.fn(),
  updateDoc: jest.fn(),
  collection: jest.fn(),
  query: jest.fn(),
  where: jest.fn(),
  getDocs: jest.fn(),
}));

// In test
import { getDoc, setDoc } from 'firebase/firestore';

beforeEach(() => {
  getDoc.mockResolvedValue({
    exists: () => true,
    data: () => ({ name: 'Test' })
  });
});

Testing React Components

import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

test('should handle user interaction', async () => {
  const user = userEvent.setup();
  render(<MyComponent />);
  
  const button = screen.getByRole('button', { name: /click me/i });
  await user.click(button);
  
  expect(screen.getByText('Clicked!')).toBeInTheDocument();
});

Testing Hooks

import { renderHook, act } from '@testing-library/react';
import { useMyHook } from '../useMyHook';

test('should update state', () => {
  const { result } = renderHook(() => useMyHook());
  
  act(() => {
    result.current.updateValue(10);
  });
  
  expect(result.current.value).toBe(10);
});

Coverage Requirements

Minimum Coverage

  • Lines: ≥ 85%
  • Branches: ≥ 90% (for core modules)
  • Functions: ≥ 85%

Check Coverage

# Run with coverage report
npm test -- --coverage

# View HTML report
open coverage/lcov-report/index.html

Coverage Exclusions

Some files are excluded from coverage:
  • Configuration files
  • Test utilities
  • Legacy code (marked with // @ts-nocheck or similar)

Best Practices

Test Behavior, Not Implementation

Test what the component does, not how it does it

One Assertion Per Test

Each test should verify one thing

Use Descriptive Names

Test names should read like specifications

Keep Tests Fast

Unit tests should run in milliseconds

Isolate Tests

Tests should not depend on each other

Mock External Dependencies

Mock Firebase, APIs, and external services

Common Test Patterns

Testing Async Functions

test('should handle async operation', async () => {
  const result = await myAsyncFunction();
  expect(result).toBeDefined();
});

Testing Error Handling

test('should handle errors gracefully', async () => {
  jest.spyOn(console, 'error').mockImplementation(() => {});
  
  await expect(myFunction()).rejects.toThrow('Expected error');
  
  console.error.mockRestore();
});

Testing Form Submissions

test('should submit form with valid data', async () => {
  const user = userEvent.setup();
  const onSubmit = jest.fn();
  
  render(<MyForm onSubmit={onSubmit} />);
  
  await user.type(screen.getByLabelText(/email/i), 'test@test.com');
  await user.click(screen.getByRole('button', { name: /submit/i }));
  
  expect(onSubmit).toHaveBeenCalledWith({ email: 'test@test.com' });
});

Troubleshooting

Tests Failing After Changes

If you changed function signatures, update your mocks
Ensure all dependencies are properly mocked
npm test -- --clearCache