← Back to Blog
Testing Strategies for Enterprise Applications: Jest, Enzyme, and Beyond

Over 27 years of development, I've seen testing practices evolve dramatically. From manual QA to comprehensive automated test suites, here's what I've learned about building reliable test strategies for enterprise applications.

The Testing Pyramid

A solid testing strategy follows the testing pyramid - lots of unit tests, fewer integration tests, and minimal end-to-end tests.

Unit Tests with Jest

Jest has become my go-to testing framework for JavaScript/TypeScript applications. Here's how we structured tests at Nutrien:

// CustomButton.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import { CustomButton } from './CustomButton';
 
describe('CustomButton', () => {
  it('renders with correct text', () => {
    render(<CustomButton title="Click Me" onPress={jest.fn()} />);
    expect(screen.getByText('Click Me')).toBeInTheDocument();
  });
 
  it('calls onPress when clicked', () => {
    const mockOnPress = jest.fn();
    render(<CustomButton title="Click Me" onPress={mockOnPress} />);
 
    fireEvent.click(screen.getByRole('button'));
    expect(mockOnPress).toHaveBeenCalledTimes(1);
  });
 
  it('shows loading state correctly', () => {
    render(
      <CustomButton title="Submit" onPress={jest.fn()} loading={true} />
    );
 
    expect(screen.queryByText('Submit')).not.toBeInTheDocument();
    expect(screen.getByRole('status')).toBeInTheDocument(); // ActivityIndicator
  });
 
  it('is disabled when loading', () => {
    const mockOnPress = jest.fn();
    render(
      <CustomButton title="Submit" onPress={mockOnPress} loading={true} />
    );
 
    fireEvent.click(screen.getByRole('button'));
    expect(mockOnPress).not.toHaveBeenCalled();
  });
 
  it('applies correct variant styles', () => {
    const { container, rerender } = render(
      <CustomButton title="Primary" onPress={jest.fn()} variant="primary" />
    );
 
    expect(container.firstChild).toHaveClass('button-primary');
 
    rerender(
      <CustomButton title="Danger" onPress={jest.fn()} variant="danger" />
    );
 
    expect(container.firstChild).toHaveClass('button-danger');
  });
});

Testing Services with Mocks

Service layer tests require mocking external dependencies:

// referrals.service.test.ts
import { ReferralsService } from './referrals.service';
import { PrismaService } from '../prisma/prisma.service';
import { EmailService } from '../email/email.service';
 
// Mock the dependencies
jest.mock('../prisma/prisma.service');
jest.mock('../email/email.service');
 
describe('ReferralsService', () => {
  let service: ReferralsService;
  let prisma: jest.Mocked<PrismaService>;
  let emailService: jest.Mocked<EmailService>;
 
  beforeEach(() => {
    // Create mock instances
    prisma = new PrismaService() as jest.Mocked<PrismaService>;
    emailService = new EmailService() as jest.Mocked<EmailService>;
 
    service = new ReferralsService(prisma, emailService);
  });
 
  afterEach(() => {
    jest.clearAllMocks();
  });
 
  describe('create', () => {
    it('creates a referral and sends email notification', async () => {
      const mockReferral = {
        id: '123',
        motherName: 'Jane Doe',
        status: 'pending',
        priority: 'HIGH',
        userId: 'user123',
        createdAt: new Date(),
        updatedAt: new Date(),
      };
 
      const createDto = {
        motherName: 'Jane Doe',
        priority: 'HIGH',
        userId: 'user123',
        coordinatorEmail: 'coordinator@example.com',
      };
 
      // Mock Prisma response
      prisma.referral.create.mockResolvedValue(mockReferral);
 
      // Mock email service
      emailService.sendReferralNotification.mockResolvedValue(undefined);
 
      const result = await service.create(createDto);
 
      // Verify Prisma was called correctly
      expect(prisma.referral.create).toHaveBeenCalledWith({
        data: expect.objectContaining({
          motherName: 'Jane Doe',
          priority: 'HIGH',
        }),
        include: expect.any(Object),
      });
 
      // Verify email was sent
      expect(emailService.sendReferralNotification).toHaveBeenCalledWith(
        'coordinator@example.com',
        expect.objectContaining({
          motherName: 'Jane Doe',
          priority: 'HIGH',
        })
      );
 
      expect(result).toEqual(mockReferral);
    });
 
    it('still creates referral if email fails', async () => {
      const mockReferral = {
        id: '123',
        motherName: 'Jane Doe',
        status: 'pending',
        priority: 'HIGH',
        userId: 'user123',
        createdAt: new Date(),
        updatedAt: new Date(),
      };
 
      prisma.referral.create.mockResolvedValue(mockReferral);
      emailService.sendReferralNotification.mockRejectedValue(
        new Error('Email service down')
      );
 
      // Should not throw - email failure shouldn't break referral creation
      const result = await service.create({
        motherName: 'Jane Doe',
        priority: 'HIGH',
        userId: 'user123',
        coordinatorEmail: 'coordinator@example.com',
      });
 
      expect(result).toEqual(mockReferral);
    });
  });
 
  describe('findByPriority', () => {
    it('returns referrals filtered by priority', async () => {
      const mockReferrals = [
        { id: '1', priority: 'HIGH', motherName: 'Jane' },
        { id: '2', priority: 'HIGH', motherName: 'Mary' },
      ];
 
      prisma.referral.findMany.mockResolvedValue(mockReferrals as any);
 
      const result = await service.findByPriority('HIGH');
 
      expect(prisma.referral.findMany).toHaveBeenCalledWith({
        where: { priority: 'HIGH' },
        include: expect.any(Object),
        orderBy: { createdAt: 'desc' },
      });
 
      expect(result).toEqual(mockReferrals);
    });
  });
});

Integration Tests

Integration tests verify that multiple parts work together:

// referrals.integration.test.ts
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from '../app.module';
import { PrismaService } from '../prisma/prisma.service';
 
describe('Referrals (Integration)', () => {
  let app: INestApplication;
  let prisma: PrismaService;
 
  beforeAll(async () => {
    const moduleRef = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();
 
    app = moduleRef.createNestApplication();
    await app.init();
 
    prisma = app.get(PrismaService);
  });
 
  afterAll(async () => {
    await app.close();
  });
 
  beforeEach(async () => {
    // Clean database before each test
    await prisma.referral.deleteMany();
    await prisma.user.deleteMany();
  });
 
  describe('POST /referrals', () => {
    it('creates a new referral', async () => {
      // Create a test user
      const user = await prisma.user.create({
        data: {
          email: 'test@example.com',
          firstName: 'Test',
          lastName: 'User',
          role: 'ADVOCATE',
          passwordHash: 'hashed',
        },
      });
 
      const response = await request(app.getHttpServer())
        .post('/referrals')
        .set('Authorization', `Bearer ${testToken}`)
        .send({
          motherName: 'Jane Doe',
          priority: 'HIGH',
          userId: user.id,
          notes: 'Urgent case',
        })
        .expect(201);
 
      expect(response.body).toMatchObject({
        motherName: 'Jane Doe',
        priority: 'HIGH',
        status: 'pending',
      });
 
      // Verify in database
      const referral = await prisma.referral.findUnique({
        where: { id: response.body.id },
      });
 
      expect(referral).toBeTruthy();
      expect(referral.motherName).toBe('Jane Doe');
    });
 
    it('returns 401 without authentication', async () => {
      await request(app.getHttpServer())
        .post('/referrals')
        .send({
          motherName: 'Jane Doe',
          priority: 'HIGH',
        })
        .expect(401);
    });
  });
});

Enzyme for React Native

At Nutrien, we used Enzyme alongside Jest for React Native components:

// DatePicker.enzyme.test.tsx
import { shallow, mount } from 'enzyme';
import { DatePicker } from './DatePicker';
 
describe('DatePicker (Enzyme)', () => {
  it('renders correctly', () => {
    const wrapper = shallow(
      <DatePicker value={new Date()} onChange={jest.fn()} />
    );
 
    expect(wrapper.find('TouchableOpacity')).toHaveLength(1);
  });
 
  it('opens modal when pressed', () => {
    const wrapper = shallow(
      <DatePicker value={new Date()} onChange={jest.fn()} />
    );
 
    expect(wrapper.find('Modal').prop('visible')).toBe(false);
 
    wrapper.find('TouchableOpacity').simulate('press');
 
    expect(wrapper.find('Modal').prop('visible')).toBe(true);
  });
 
  it('calls onChange with selected date', () => {
    const mockOnChange = jest.fn();
    const wrapper = mount(
      <DatePicker value={new Date('2024-01-01')} onChange={mockOnChange} />
    );
 
    const newDate = new Date('2024-12-31');
 
    wrapper.find('DateTimePicker').prop('onChange')(null, newDate);
 
    expect(mockOnChange).toHaveBeenCalledWith(newDate);
  });
});

Testing Best Practices

1. Test Behavior, Not Implementation

// Bad - tests implementation
it('calls setState with the correct value', () => {
  const wrapper = shallow(<Counter />);
  wrapper.instance().setState = jest.fn();
  wrapper.find('button').simulate('click');
  expect(wrapper.instance().setState).toHaveBeenCalledWith({ count: 1 });
});
 
// Good - tests behavior
it('increments counter when button is clicked', () => {
  render(<Counter />);
  fireEvent.click(screen.getByRole('button'));
  expect(screen.getByText('Count: 1')).toBeInTheDocument();
});

2. Use Data-Driven Tests

describe('formatPhoneNumber', () => {
  it.each([
    ['1234567890', '+1 (123) 456-7890'],
    ['+11234567890', '+1 (123) 456-7890'],
    ['123-456-7890', '+1 (123) 456-7890'],
    ['(123) 456-7890', '+1 (123) 456-7890'],
  ])('formats %s as %s', (input, expected) => {
    expect(formatPhoneNumber(input)).toBe(expected);
  });
});

3. Maintain Test Fixtures

// test/fixtures/users.ts
export const testUsers = {
  admin: {
    id: 'admin-1',
    email: 'admin@example.com',
    role: 'ADMIN',
    firstName: 'Admin',
    lastName: 'User',
  },
  coordinator: {
    id: 'coord-1',
    email: 'coordinator@example.com',
    role: 'COORDINATOR',
    firstName: 'Coordinator',
    lastName: 'User',
  },
};
 
// Use in tests
import { testUsers } from '../fixtures/users';
 
it('allows admin to view all referrals', async () => {
  const response = await request(app.getHttpServer())
    .get('/referrals')
    .set('Authorization', `Bearer ${getTokenFor(testUsers.admin)}`)
    .expect(200);
});

CI/CD Integration

Tests are only valuable if they run automatically:

# .circleci/config.yml
version: 2.1
 
jobs:
  test:
    docker:
      - image: circleci/node:16
      - image: circleci/postgres:13
        environment:
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
          POSTGRES_DB: test_db
 
    steps:
      - checkout
 
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "package.json" }}
 
      - run: npm install
 
      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package.json" }}
 
      - run:
          name: Run unit tests
          command: npm test -- --coverage
 
      - run:
          name: Run integration tests
          command: npm run test:integration
 
      - store_test_results:
          path: test-results
 
      - store_artifacts:
          path: coverage
 
workflows:
  version: 2
  test-and-deploy:
    jobs:
      - test

Conclusion

Good testing isn't about achieving 100% coverage - it's about testing the right things in the right ways. Focus on testing behavior, maintain clear test code, and integrate testing into your development workflow.

After 27 years, I can say with confidence: the upfront investment in testing pays massive dividends in reduced bugs, easier refactoring, and better sleep at night.

Share this article

Help others discover this content


Jason Cochran

Jason Cochran

Sofware Engineer | Cloud Consultant | Founder at Strataga

27 years of experience building enterprise software for oil & gas operators and startups. Specializing in SCADA systems, field data solutions, and AI-powered rapid development. Based in Midland, TX serving the Permian Basin.