Skip to main content

Testing Guide

Overview

This guide covers the testing strategy for the EyeNet project, including unit tests, integration tests, and end-to-end tests.

Test Structure

tests/
├── unit/ # Unit tests
│ ├── controllers/ # Controller tests
│ ├── services/ # Service tests
│ └── utils/ # Utility tests
├── integration/ # Integration tests
│ ├── api/ # API tests
│ └── db/ # Database tests
└── e2e/ # End-to-end tests
└── flows/ # User flow tests

Running Tests

Unit Tests

# Run all unit tests
npm run test:unit

# Run specific test file
npm run test:unit -- controllers/networkController.test.ts

# Run with coverage
npm run test:unit:coverage

Integration Tests

# Run all integration tests
npm run test:integration

# Run specific integration test
npm run test:integration -- api/auth.test.ts

E2E Tests

# Run all E2E tests
npm run test:e2e

# Run specific E2E test
npm run test:e2e -- flows/login.test.ts

Writing Tests

Unit Test Example

import { NetworkController } from '../controllers/networkController';
import { MockDevice } from './mocks/device';

describe('NetworkController', () => {
let controller: NetworkController;
let mockDevice: MockDevice;

beforeEach(() => {
mockDevice = new MockDevice();
controller = new NetworkController(mockDevice);
});

it('should connect to device successfully', async () => {
const result = await controller.connect();
expect(result.status).toBe('connected');
expect(mockDevice.isConnected()).toBe(true);
});

it('should handle connection failure', async () => {
mockDevice.simulateFailure();
await expect(controller.connect()).rejects.toThrow('Connection failed');
});
});

Integration Test Example

import request from 'supertest';
import { app } from '../app';
import { db } from '../db';

describe('Authentication API', () => {
beforeAll(async () => {
await db.connect();
});

afterAll(async () => {
await db.disconnect();
});

it('should authenticate user with valid credentials', async () => {
const response = await request(app)
.post('/api/auth/login')
.send({
username: 'testuser',
password: 'testpass'
});

expect(response.status).toBe(200);
expect(response.body).toHaveProperty('token');
});
});

E2E Test Example

import { test, expect } from '@playwright/test';

test('user can log in and view dashboard', async ({ page }) => {
await page.goto('/login');

// Fill login form
await page.fill('[name=username]', 'testuser');
await page.fill('[name=password]', 'testpass');
await page.click('button[type=submit]');

// Check dashboard loaded
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('h1')).toHaveText('Network Dashboard');
});

Test Coverage

Coverage Goals

  • Unit Tests: 80% coverage
  • Integration Tests: 70% coverage
  • Critical Paths: 100% coverage

Generating Coverage Reports

# Generate full coverage report
npm run test:coverage

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

Mocking

Network Devices

class MockNetworkDevice implements INetworkDevice {
private connected = false;

async connect(): Promise<void> {
this.connected = true;
}

async disconnect(): Promise<void> {
this.connected = false;
}

isConnected(): boolean {
return this.connected;
}
}

API Responses

const mockApiResponse = {
data: {
devices: [
{ id: '1', name: 'Router1', status: 'online' },
{ id: '2', name: 'Switch1', status: 'offline' }
]
}
};

jest.mock('../api', () => ({
fetchDevices: jest.fn().mockResolvedValue(mockApiResponse)
}));

Test Environment

Configuration

// test/config.ts
export const testConfig = {
database: {
url: 'mongodb://localhost:27017/eyenet_test'
},
api: {
baseUrl: 'http://localhost:3000/api'
}
};

Setup and Teardown

// test/setup.ts
import { setupTestDatabase } from './utils/db';
import { setupTestServer } from './utils/server';

beforeAll(async () => {
await setupTestDatabase();
await setupTestServer();
});

afterAll(async () => {
await cleanupTestDatabase();
await cleanupTestServer();
});

Continuous Integration

GitHub Actions

name: Tests

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '18'

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm run test:ci

- name: Upload coverage
uses: codecov/codecov-action@v2

Best Practices

  1. Test Organization

    • Group related tests
    • Use descriptive names
    • Follow AAA pattern (Arrange, Act, Assert)
  2. Test Independence

    • Each test should be independent
    • Clean up after tests
    • Don't share state
  3. Test Data

    • Use factories for test data
    • Avoid hardcoded values
    • Use meaningful test data
  4. Assertions

    • Make specific assertions
    • Test edge cases
    • Verify error conditions
  5. Maintenance

    • Keep tests simple
    • Update tests with code changes
    • Remove obsolete tests