Features
Docs
CLI
Benchmarks
Examples

© 2024 MoroJs

Testing Guide

Testing strategies for MoroJS applications using standard testing libraries. Learn unit testing, integration testing, and API testing patterns.

What You'll Learn

Unit Testing

Test individual services and functions in isolation

Integration Testing

Test API endpoints and request/response flows

Test Setup

Configure Jest and testing utilities

Mocking

Create mocks for databases and external services

Progress0 / 4 steps

Testing Setup

Set up Jest and testing utilities for your MoroJS application.

Basic Testing Setup

typescript

1// package.json - Testing dependencies
2{
3  "devDependencies": {
4    "@types/jest": "^29.5.0",
5    "@types/supertest": "^2.0.12",
6    "jest": "^29.5.0",
7    "supertest": "^6.3.0",
8    "ts-jest": "^29.1.0"
9  },
10  "scripts": {
11    "test": "jest",
12    "test:watch": "jest --watch"
13  }
14}
15
16// jest.config.js - Simple configuration
17module.exports = {
18  preset: 'ts-jest',
19  testEnvironment: 'node',
20  roots: ['<rootDir>/src', '<rootDir>/tests'],
21  testMatch: ['**/__tests__/**/*.test.ts', '**/?(*.)+(spec|test).ts'],
22  collectCoverageFrom: [
23    'src/**/*.ts',
24    '!src/**/*.d.ts'
25  ],
26  coverageDirectory: 'coverage',
27  testTimeout: 10000
28};
29
30// tests/setup.ts - Simple setup
31import { createApp } from '@morojs/moro';
32
33// Helper to create test app
34export function createTestApp() {
35  const app = createApp({
36    cors: true,
37    compression: false, // Disable for testing
38    helmet: false       // Disable for testing
39  });
40  
41  return app;
42}

Unit Testing

Test individual services and functions in isolation with mocks.

Service Unit Tests

typescript

1// services/__tests__/UserService.test.ts
2import { UserService } from '../UserService';
3import { createMockDatabase, createMockEventBus } from '../../tests/mocks';
4
5describe('UserService', () => {
6  let userService: UserService;
7  let mockDb: any;
8  let mockEvents: any;
9  
10  beforeEach(() => {
11    mockDb = createMockDatabase();
12    mockEvents = createMockEventBus();
13    userService = new UserService(mockDb, mockEvents);
14  });
15  
16  describe('createUser', () => {
17    it('should create a user successfully', async () => {
18      const userData = { email: 'test@example.com', name: 'Test User' };
19      const expectedUser = { id: '1', ...userData, created_at: new Date() };
20      
21      mockDb.query.mockResolvedValueOnce([expectedUser]);
22      
23      const result = await userService.createUser(userData);
24      
25      expect(result).toEqual(expectedUser);
26      expect(mockDb.query).toHaveBeenCalledWith(
27        expect.stringContaining('INSERT INTO users'),
28        [userData.email, userData.name, expect.any(Date)]
29      );
30      expect(mockEvents.emit).toHaveBeenCalledWith('user.created', { user: expectedUser });
31    });
32    
33    it('should validate email format', async () => {
34      const userData = { email: 'invalid-email', name: 'Test User' };
35      
36      await expect(userService.createUser(userData)).rejects.toThrow('Invalid email');
37    });
38    
39    it('should handle database errors', async () => {
40      const userData = { email: 'test@example.com', name: 'Test User' };
41      
42      mockDb.query.mockRejectedValueOnce(new Error('Database connection failed'));
43      
44      await expect(userService.createUser(userData)).rejects.toThrow('Database connection failed');
45    });
46  });
47  
48  describe('getUserById', () => {
49    it('should return user when found', async () => {
50      const userId = '123';
51      const expectedUser = { id: userId, email: 'test@example.com', name: 'Test User' };
52      
53      mockDb.query.mockResolvedValueOnce([expectedUser]);
54      
55      const result = await userService.getUserById(userId);
56      
57      expect(result).toEqual(expectedUser);
58      expect(mockDb.query).toHaveBeenCalledWith(
59        'SELECT * FROM users WHERE id = $1',
60        [userId]
61      );
62    });
63    
64    it('should return null when user not found', async () => {
65      mockDb.query.mockResolvedValueOnce([]);
66      
67      const result = await userService.getUserById('nonexistent');
68      
69      expect(result).toBeNull();
70    });
71  });
72});

Integration Testing

Test API endpoints and request/response flows with Supertest.

Simple API Testing

typescript

1// tests/api.test.ts - Simple API testing
2import request from 'supertest';
3import { createApp, z } from '@morojs/moro';
4
5describe('MoroJS API Tests', () => {
6  let app: any;
7  let server: any;
8  
9  beforeAll(async () => {
10    // Create test app
11    app = createApp({
12      cors: true,
13      compression: false,
14      helmet: false
15    });
16    
17    // In-memory test data
18    const users = [
19      { id: 1, name: 'John Doe', email: 'john@example.com' },
20      { id: 2, name: 'Jane Smith', email: 'jane@example.com' }
21    ];
22    
23    // Test routes
24    app.get('/users', (req, res) => {
25      return { success: true, data: users };
26    });
27    
28    app.post('/users')
29      .body(z.object({
30        name: z.string().min(2),
31        email: z.string().email()
32      }))
33      .handler((req, res) => {
34        const newUser = {
35          id: users.length + 1,
36          ...req.body
37        };
38        users.push(newUser);
39        res.status(201);
40        return { success: true, data: newUser };
41      });
42    
43    app.get('/users/:id', (req, res) => {
44      const user = users.find(u => u.id === parseInt(req.params.id));
45      if (!user) {
46        res.status(404);
47        return { success: false, error: 'User not found' };
48      }
49      return { success: true, data: user };
50    });
51    
52    // Start test server
53    server = app.listen(0); // Random port
54  });
55  
56  afterAll(async () => {
57    server?.close();
58  });
59  
60  describe('GET /users', () => {
61    it('should return list of users', async () => {
62      const response = await request(server)
63        .get('/users')
64        .expect(200);
65      
66      expect(response.body).toMatchObject({
67        success: true,
68        data: expect.arrayContaining([
69          expect.objectContaining({
70            id: expect.any(Number),
71            name: expect.any(String),
72            email: expect.any(String)
73          })
74        ])
75      });
76    });
77  });
78  
79  describe('POST /users', () => {
80    it('should create a user with valid data', async () => {
81      const userData = {
82        name: 'Test User',
83        email: 'test@example.com'
84      };
85      
86      const response = await request(server)
87        .post('/users')
88        .send(userData)
89        .expect(201);
90      
91      expect(response.body).toMatchObject({
92        success: true,
93        data: {
94          id: expect.any(Number),
95          name: userData.name,
96          email: userData.email
97        }
98      });
99    });
100    
101    it('should return 400 for invalid email', async () => {
102      const userData = {
103        name: 'Test User',
104        email: 'invalid-email'
105      };
106      
107      await request(server)
108        .post('/users')
109        .send(userData)
110        .expect(400);
111    });
112  });
113  
114  describe('GET /users/:id', () => {
115    it('should return user when found', async () => {
116      const response = await request(server)
117        .get('/users/1')
118        .expect(200);
119      
120      expect(response.body).toMatchObject({
121        success: true,
122        data: {
123          id: 1,
124          name: 'John Doe',
125          email: 'john@example.com'
126        }
127      });
128    });
129    
130    it('should return 404 for non-existent user', async () => {
131      const response = await request(server)
132        .get('/users/999')
133        .expect(404);
134        
135      expect(response.body).toMatchObject({
136        success: false,
137        error: 'User not found'
138      });
139    });
140  });
141});

Running Tests

Run your tests and view coverage reports.

Test Commands

typescript

1# Run all tests
2npm test
3
4# Run tests in watch mode
5npm run test:watch
6
7# Run tests with coverage
8npm test -- --coverage
9
10# Run specific test file
11npm test -- UserService.test.ts
12
13# Run tests matching a pattern
14npm test -- --testNamePattern="createUser"

Next Steps