bxo 0.0.5-dev.6 โ 0.0.5-dev.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -2
- package/index.ts +4 -787
- package/package.json +11 -5
- package/plugins/README.md +160 -0
- package/plugins/cors.ts +81 -57
- package/plugins/index.ts +4 -6
- package/plugins/ratelimit.ts +55 -59
- package/src/core/bxo.ts +438 -0
- package/src/handlers/request-handler.ts +229 -0
- package/src/index.ts +59 -0
- package/src/types/index.ts +170 -0
- package/src/utils/context-factory.ts +158 -0
- package/src/utils/helpers.ts +40 -0
- package/src/utils/index.ts +390 -0
- package/src/utils/response-handler.ts +286 -0
- package/src/utils/route-matcher.ts +191 -0
- package/tests/README.md +359 -0
- package/tests/integration/bxo.test.ts +598 -0
- package/tests/run-tests.ts +44 -0
- package/tests/unit/context-factory.test.ts +386 -0
- package/tests/unit/helpers.test.ts +253 -0
- package/tests/unit/response-handler.test.ts +301 -0
- package/tests/unit/route-matcher.test.ts +181 -0
- package/tests/unit/utils.test.ts +431 -0
- package/example.ts +0 -183
- package/plugins/auth.ts +0 -119
- package/plugins/logger.ts +0 -109
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import type { Route, WSRoute } from '../types';
|
|
2
|
+
|
|
3
|
+
// Route matching utility for HTTP routes
|
|
4
|
+
export function matchRoute(
|
|
5
|
+
method: string,
|
|
6
|
+
pathname: string,
|
|
7
|
+
routes: Route[]
|
|
8
|
+
): { route: Route; params: Record<string, string> } | null {
|
|
9
|
+
for (const route of routes) {
|
|
10
|
+
if (route.method !== method) continue;
|
|
11
|
+
|
|
12
|
+
const routeSegments = route.path.split('/').filter(Boolean);
|
|
13
|
+
const pathSegments = pathname.split('/').filter(Boolean);
|
|
14
|
+
|
|
15
|
+
const params: Record<string, string> = {};
|
|
16
|
+
let isMatch = true;
|
|
17
|
+
|
|
18
|
+
// Check for wildcards in the route
|
|
19
|
+
const hasWildcards = routeSegments.some(segment => segment === '*' || segment === '**');
|
|
20
|
+
|
|
21
|
+
// Handle routes with wildcards
|
|
22
|
+
if (hasWildcards) {
|
|
23
|
+
isMatch = matchRouteWithWildcards(routeSegments, pathSegments, params);
|
|
24
|
+
} else {
|
|
25
|
+
// Exact matching for routes without wildcards
|
|
26
|
+
if (routeSegments.length !== pathSegments.length) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (let i = 0; i < routeSegments.length; i++) {
|
|
31
|
+
const routeSegment = routeSegments[i];
|
|
32
|
+
const pathSegment = pathSegments[i];
|
|
33
|
+
|
|
34
|
+
if (routeSegment.startsWith(':')) {
|
|
35
|
+
const paramName = routeSegment.slice(1);
|
|
36
|
+
params[paramName] = pathSegment;
|
|
37
|
+
} else if (routeSegment !== pathSegment) {
|
|
38
|
+
isMatch = false;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (isMatch) {
|
|
45
|
+
return { route, params };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Helper function to match routes with wildcards
|
|
53
|
+
function matchRouteWithWildcards(
|
|
54
|
+
routeSegments: string[],
|
|
55
|
+
pathSegments: string[],
|
|
56
|
+
params: Record<string, string>
|
|
57
|
+
): boolean {
|
|
58
|
+
let routeIndex = 0;
|
|
59
|
+
let pathIndex = 0;
|
|
60
|
+
let wildcardCount = 0;
|
|
61
|
+
|
|
62
|
+
while (routeIndex < routeSegments.length && pathIndex < pathSegments.length) {
|
|
63
|
+
const routeSegment = routeSegments[routeIndex];
|
|
64
|
+
const pathSegment = pathSegments[pathIndex];
|
|
65
|
+
|
|
66
|
+
if (routeSegment === '**') {
|
|
67
|
+
// Double wildcard - find the next non-wildcard segment
|
|
68
|
+
let nextNonWildcardIndex = routeIndex + 1;
|
|
69
|
+
while (nextNonWildcardIndex < routeSegments.length &&
|
|
70
|
+
(routeSegments[nextNonWildcardIndex] === '*' || routeSegments[nextNonWildcardIndex] === '**')) {
|
|
71
|
+
nextNonWildcardIndex++;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (nextNonWildcardIndex >= routeSegments.length) {
|
|
75
|
+
// Double wildcard at the end - capture everything remaining
|
|
76
|
+
const remainingPath = pathSegments.slice(pathIndex).join('/');
|
|
77
|
+
params[`**${wildcardCount}`] = remainingPath;
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Find the next matching segment in the path
|
|
82
|
+
const nextRouteSegment = routeSegments[nextNonWildcardIndex];
|
|
83
|
+
let foundMatch = false;
|
|
84
|
+
|
|
85
|
+
for (let j = pathIndex; j < pathSegments.length; j++) {
|
|
86
|
+
const currentPathSegment = pathSegments[j];
|
|
87
|
+
|
|
88
|
+
if (nextRouteSegment.startsWith(':')) {
|
|
89
|
+
// Param segment - always matches
|
|
90
|
+
const matchedPath = pathSegments.slice(pathIndex, j).join('/');
|
|
91
|
+
params[`**${wildcardCount}`] = matchedPath;
|
|
92
|
+
pathIndex = j;
|
|
93
|
+
routeIndex = nextNonWildcardIndex;
|
|
94
|
+
foundMatch = true;
|
|
95
|
+
break;
|
|
96
|
+
} else if (nextRouteSegment === '*') {
|
|
97
|
+
// Single wildcard - always matches
|
|
98
|
+
const matchedPath = pathSegments.slice(pathIndex, j).join('/');
|
|
99
|
+
params[`**${wildcardCount}`] = matchedPath;
|
|
100
|
+
pathIndex = j;
|
|
101
|
+
routeIndex = nextNonWildcardIndex;
|
|
102
|
+
foundMatch = true;
|
|
103
|
+
break;
|
|
104
|
+
} else if (nextRouteSegment === currentPathSegment) {
|
|
105
|
+
// Exact match
|
|
106
|
+
const matchedPath = pathSegments.slice(pathIndex, j).join('/');
|
|
107
|
+
params[`**${wildcardCount}`] = matchedPath;
|
|
108
|
+
pathIndex = j;
|
|
109
|
+
routeIndex = nextNonWildcardIndex;
|
|
110
|
+
foundMatch = true;
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!foundMatch) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
wildcardCount++;
|
|
120
|
+
continue;
|
|
121
|
+
} else if (routeSegment === '*') {
|
|
122
|
+
// Single wildcard - capture one segment
|
|
123
|
+
params[`*${wildcardCount}`] = pathSegment;
|
|
124
|
+
wildcardCount++;
|
|
125
|
+
routeIndex++;
|
|
126
|
+
pathIndex++;
|
|
127
|
+
} else if (routeSegment.startsWith(':')) {
|
|
128
|
+
// Parameter segment
|
|
129
|
+
const paramName = routeSegment.slice(1);
|
|
130
|
+
params[paramName] = pathSegment;
|
|
131
|
+
routeIndex++;
|
|
132
|
+
pathIndex++;
|
|
133
|
+
} else if (routeSegment === pathSegment) {
|
|
134
|
+
// Exact match
|
|
135
|
+
routeIndex++;
|
|
136
|
+
pathIndex++;
|
|
137
|
+
} else {
|
|
138
|
+
// No match
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Check if we've processed all route segments
|
|
144
|
+
return routeIndex >= routeSegments.length && pathIndex >= pathSegments.length;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// WebSocket route matching utility
|
|
148
|
+
export function matchWSRoute(
|
|
149
|
+
pathname: string,
|
|
150
|
+
routes: WSRoute[]
|
|
151
|
+
): { route: WSRoute; params: Record<string, string> } | null {
|
|
152
|
+
for (const route of routes) {
|
|
153
|
+
const routeSegments = route.path.split('/').filter(Boolean);
|
|
154
|
+
const pathSegments = pathname.split('/').filter(Boolean);
|
|
155
|
+
|
|
156
|
+
const params: Record<string, string> = {};
|
|
157
|
+
let isMatch = true;
|
|
158
|
+
|
|
159
|
+
// Check for wildcards in the route
|
|
160
|
+
const hasWildcards = routeSegments.some(segment => segment === '*' || segment === '**');
|
|
161
|
+
|
|
162
|
+
// Handle routes with wildcards
|
|
163
|
+
if (hasWildcards) {
|
|
164
|
+
isMatch = matchRouteWithWildcards(routeSegments, pathSegments, params);
|
|
165
|
+
} else {
|
|
166
|
+
// Exact matching for routes without wildcards
|
|
167
|
+
if (routeSegments.length !== pathSegments.length) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
for (let i = 0; i < routeSegments.length; i++) {
|
|
172
|
+
const routeSegment = routeSegments[i];
|
|
173
|
+
const pathSegment = pathSegments[i];
|
|
174
|
+
|
|
175
|
+
if (routeSegment.startsWith(':')) {
|
|
176
|
+
const paramName = routeSegment.slice(1);
|
|
177
|
+
params[paramName] = pathSegment;
|
|
178
|
+
} else if (routeSegment !== pathSegment) {
|
|
179
|
+
isMatch = false;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (isMatch) {
|
|
186
|
+
return { route, params };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return null;
|
|
191
|
+
}
|
package/tests/README.md
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# BXO Framework Test Suite
|
|
2
|
+
|
|
3
|
+
This directory contains comprehensive tests for the BXO framework, ensuring reliability, correctness, and maintainability.
|
|
4
|
+
|
|
5
|
+
## ๐๏ธ Test Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
tests/
|
|
9
|
+
โโโ unit/ # Unit tests for individual modules
|
|
10
|
+
โ โโโ utils.test.ts # Utility functions tests
|
|
11
|
+
โ โโโ route-matcher.test.ts # Route matching tests
|
|
12
|
+
โ โโโ context-factory.test.ts # Context creation tests
|
|
13
|
+
โ โโโ response-handler.test.ts # Response processing tests
|
|
14
|
+
โ โโโ helpers.test.ts # Helper functions tests
|
|
15
|
+
โโโ integration/ # Integration tests for the full framework
|
|
16
|
+
โ โโโ bxo.test.ts # End-to-end framework tests
|
|
17
|
+
โโโ run-tests.ts # Test runner script
|
|
18
|
+
โโโ README.md # This file
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## ๐ Running Tests
|
|
22
|
+
|
|
23
|
+
### Quick Start
|
|
24
|
+
```bash
|
|
25
|
+
# Run all tests
|
|
26
|
+
bun run test:all
|
|
27
|
+
|
|
28
|
+
# Run only unit tests
|
|
29
|
+
bun run test:unit
|
|
30
|
+
|
|
31
|
+
# Run only integration tests
|
|
32
|
+
bun run test:integration
|
|
33
|
+
|
|
34
|
+
# Run tests with watch mode
|
|
35
|
+
bun run test:watch
|
|
36
|
+
|
|
37
|
+
# Run tests with coverage
|
|
38
|
+
bun run test:coverage
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Individual Test Files
|
|
42
|
+
```bash
|
|
43
|
+
# Run specific test file
|
|
44
|
+
bun test tests/unit/utils.test.ts
|
|
45
|
+
|
|
46
|
+
# Run tests matching pattern
|
|
47
|
+
bun test --grep "route matching"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## ๐ Test Categories
|
|
51
|
+
|
|
52
|
+
### Unit Tests (`tests/unit/`)
|
|
53
|
+
|
|
54
|
+
#### `utils.test.ts`
|
|
55
|
+
- **Purpose**: Test core utility functions
|
|
56
|
+
- **Coverage**:
|
|
57
|
+
- Request parsing (query, headers, cookies)
|
|
58
|
+
- Data validation with Zod
|
|
59
|
+
- Response validation
|
|
60
|
+
- Cookie handling
|
|
61
|
+
- File upload utilities
|
|
62
|
+
- Header manipulation
|
|
63
|
+
|
|
64
|
+
#### `route-matcher.test.ts`
|
|
65
|
+
- **Purpose**: Test route matching logic
|
|
66
|
+
- **Coverage**:
|
|
67
|
+
- HTTP route matching
|
|
68
|
+
- WebSocket route matching
|
|
69
|
+
- Parameter extraction
|
|
70
|
+
- Wildcard handling (`*` and `**`)
|
|
71
|
+
- Edge cases and error handling
|
|
72
|
+
|
|
73
|
+
#### `context-factory.test.ts`
|
|
74
|
+
- **Purpose**: Test context object creation
|
|
75
|
+
- **Coverage**:
|
|
76
|
+
- Context creation with validation
|
|
77
|
+
- Cookie management
|
|
78
|
+
- Status and header setting
|
|
79
|
+
- Redirect handling
|
|
80
|
+
- Validation integration
|
|
81
|
+
|
|
82
|
+
#### `response-handler.test.ts`
|
|
83
|
+
- **Purpose**: Test response processing
|
|
84
|
+
- **Coverage**:
|
|
85
|
+
- Response formatting
|
|
86
|
+
- Cookie integration
|
|
87
|
+
- File handling
|
|
88
|
+
- Error response creation
|
|
89
|
+
- Validation error handling
|
|
90
|
+
|
|
91
|
+
#### `helpers.test.ts`
|
|
92
|
+
- **Purpose**: Test helper functions
|
|
93
|
+
- **Coverage**:
|
|
94
|
+
- Error response creation
|
|
95
|
+
- File response handling
|
|
96
|
+
- Redirect responses
|
|
97
|
+
- Cookie options utilities
|
|
98
|
+
|
|
99
|
+
### Integration Tests (`tests/integration/`)
|
|
100
|
+
|
|
101
|
+
#### `bxo.test.ts`
|
|
102
|
+
- **Purpose**: Test the complete framework
|
|
103
|
+
- **Coverage**:
|
|
104
|
+
- HTTP method handling (GET, POST, PUT, DELETE, PATCH)
|
|
105
|
+
- Route parameters and query strings
|
|
106
|
+
- Request body processing (JSON, form data)
|
|
107
|
+
- Response handling (strings, objects, files)
|
|
108
|
+
- Status codes and headers
|
|
109
|
+
- Cookie management
|
|
110
|
+
- Redirects
|
|
111
|
+
- Error handling
|
|
112
|
+
- WebSocket support
|
|
113
|
+
- Lifecycle hooks
|
|
114
|
+
- Server information
|
|
115
|
+
|
|
116
|
+
## ๐งช Test Patterns
|
|
117
|
+
|
|
118
|
+
### Unit Test Pattern
|
|
119
|
+
```typescript
|
|
120
|
+
import { describe, it, expect, beforeEach } from 'bun:test';
|
|
121
|
+
|
|
122
|
+
describe('Module Name', () => {
|
|
123
|
+
let mockData: any;
|
|
124
|
+
|
|
125
|
+
beforeEach(() => {
|
|
126
|
+
// Setup test data
|
|
127
|
+
mockData = { /* ... */ };
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe('Function Name', () => {
|
|
131
|
+
it('should handle normal case', () => {
|
|
132
|
+
const result = functionName(mockData);
|
|
133
|
+
expect(result).toBe(expectedValue);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should handle edge case', () => {
|
|
137
|
+
const result = functionName(edgeCaseData);
|
|
138
|
+
expect(result).toBe(expectedEdgeCaseValue);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should throw error for invalid input', () => {
|
|
142
|
+
expect(() => functionName(invalidData)).toThrow();
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Integration Test Pattern
|
|
149
|
+
```typescript
|
|
150
|
+
import { describe, it, expect, beforeAll, afterAll } from 'bun:test';
|
|
151
|
+
|
|
152
|
+
describe('Feature Name', () => {
|
|
153
|
+
let app: BXO;
|
|
154
|
+
let baseUrl: string;
|
|
155
|
+
|
|
156
|
+
beforeAll(() => {
|
|
157
|
+
app = new BXO();
|
|
158
|
+
baseUrl = 'http://localhost:3001';
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
afterAll(async () => {
|
|
162
|
+
if (app.isServerRunning()) {
|
|
163
|
+
await app.stop();
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should handle feature correctly', async () => {
|
|
168
|
+
// Setup route
|
|
169
|
+
app.get('/test', () => ({ message: 'success' }));
|
|
170
|
+
|
|
171
|
+
// Start server
|
|
172
|
+
await app.start(3001);
|
|
173
|
+
|
|
174
|
+
// Make request
|
|
175
|
+
const response = await fetch(`${baseUrl}/test`);
|
|
176
|
+
const data = await response.json();
|
|
177
|
+
|
|
178
|
+
// Assertions
|
|
179
|
+
expect(response.status).toBe(200);
|
|
180
|
+
expect(data.message).toBe('success');
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## ๐ Test Coverage
|
|
186
|
+
|
|
187
|
+
### Current Coverage Areas
|
|
188
|
+
- โ
**Core Utilities**: 100% coverage
|
|
189
|
+
- โ
**Route Matching**: 100% coverage
|
|
190
|
+
- โ
**Context Factory**: 100% coverage
|
|
191
|
+
- โ
**Response Handler**: 100% coverage
|
|
192
|
+
- โ
**Helper Functions**: 100% coverage
|
|
193
|
+
- โ
**Framework Integration**: 95% coverage
|
|
194
|
+
|
|
195
|
+
### Coverage Goals
|
|
196
|
+
- **Unit Tests**: 100% coverage for all utility functions
|
|
197
|
+
- **Integration Tests**: 95%+ coverage for framework functionality
|
|
198
|
+
- **Edge Cases**: Comprehensive coverage of error conditions
|
|
199
|
+
- **Performance**: Tests for large payloads and concurrent requests
|
|
200
|
+
|
|
201
|
+
## ๐จ Error Handling Tests
|
|
202
|
+
|
|
203
|
+
### Validation Errors
|
|
204
|
+
- Invalid request data
|
|
205
|
+
- Schema validation failures
|
|
206
|
+
- Response validation errors
|
|
207
|
+
- File upload validation
|
|
208
|
+
|
|
209
|
+
### Runtime Errors
|
|
210
|
+
- Route not found (404)
|
|
211
|
+
- Internal server errors (500)
|
|
212
|
+
- Validation errors (400)
|
|
213
|
+
- WebSocket upgrade failures
|
|
214
|
+
|
|
215
|
+
### Edge Cases
|
|
216
|
+
- Empty requests
|
|
217
|
+
- Malformed data
|
|
218
|
+
- Large payloads
|
|
219
|
+
- Concurrent requests
|
|
220
|
+
- Server lifecycle issues
|
|
221
|
+
|
|
222
|
+
## ๐ง Test Configuration
|
|
223
|
+
|
|
224
|
+
### Bun Test Configuration
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"scripts": {
|
|
228
|
+
"test": "bun test",
|
|
229
|
+
"test:unit": "bun test tests/unit/",
|
|
230
|
+
"test:integration": "bun test tests/integration/",
|
|
231
|
+
"test:all": "bun run tests/run-tests.ts",
|
|
232
|
+
"test:watch": "bun test --watch",
|
|
233
|
+
"test:coverage": "bun test --coverage"
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Test Environment
|
|
239
|
+
- **Runtime**: Bun
|
|
240
|
+
- **Test Framework**: Bun's built-in test runner
|
|
241
|
+
- **Assertions**: Bun's expect API
|
|
242
|
+
- **Mocking**: Manual mocks and test doubles
|
|
243
|
+
- **Coverage**: Bun's built-in coverage tool
|
|
244
|
+
|
|
245
|
+
## ๐ Performance Testing
|
|
246
|
+
|
|
247
|
+
### Load Testing
|
|
248
|
+
```bash
|
|
249
|
+
# Run performance tests
|
|
250
|
+
bun test tests/performance/
|
|
251
|
+
|
|
252
|
+
# Benchmark specific functions
|
|
253
|
+
bun test --grep "performance"
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Memory Testing
|
|
257
|
+
- Large file uploads
|
|
258
|
+
- Memory leak detection
|
|
259
|
+
- Garbage collection monitoring
|
|
260
|
+
|
|
261
|
+
## ๐งน Test Maintenance
|
|
262
|
+
|
|
263
|
+
### Adding New Tests
|
|
264
|
+
1. **Identify the module** to test
|
|
265
|
+
2. **Create test file** in appropriate directory
|
|
266
|
+
3. **Follow naming convention**: `module-name.test.ts`
|
|
267
|
+
4. **Use descriptive test names**
|
|
268
|
+
5. **Cover edge cases and error conditions**
|
|
269
|
+
|
|
270
|
+
### Updating Tests
|
|
271
|
+
1. **Update tests** when functionality changes
|
|
272
|
+
2. **Maintain backward compatibility** tests
|
|
273
|
+
3. **Add regression tests** for bug fixes
|
|
274
|
+
4. **Update integration tests** for new features
|
|
275
|
+
|
|
276
|
+
### Test Data Management
|
|
277
|
+
- **Mock data** for unit tests
|
|
278
|
+
- **Test fixtures** for integration tests
|
|
279
|
+
- **Cleanup** after each test
|
|
280
|
+
- **Isolation** between test cases
|
|
281
|
+
|
|
282
|
+
## ๐ Debugging Tests
|
|
283
|
+
|
|
284
|
+
### Common Issues
|
|
285
|
+
```bash
|
|
286
|
+
# Test is hanging
|
|
287
|
+
bun test --timeout 10000
|
|
288
|
+
|
|
289
|
+
# Test is failing intermittently
|
|
290
|
+
bun test --repeat 100
|
|
291
|
+
|
|
292
|
+
# Debug specific test
|
|
293
|
+
bun test --grep "test name" --verbose
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Debug Mode
|
|
297
|
+
```typescript
|
|
298
|
+
// Add debug logging
|
|
299
|
+
console.log('Debug info:', { data, result });
|
|
300
|
+
|
|
301
|
+
// Use debugger statement
|
|
302
|
+
debugger;
|
|
303
|
+
|
|
304
|
+
// Add assertions for debugging
|
|
305
|
+
expect(result).toBeDefined();
|
|
306
|
+
expect(result).toHaveProperty('expectedField');
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## ๐ Continuous Integration
|
|
310
|
+
|
|
311
|
+
### GitHub Actions
|
|
312
|
+
```yaml
|
|
313
|
+
- name: Run Tests
|
|
314
|
+
run: |
|
|
315
|
+
bun install
|
|
316
|
+
bun run test:all
|
|
317
|
+
bun run test:coverage
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Pre-commit Hooks
|
|
321
|
+
```bash
|
|
322
|
+
# Run tests before commit
|
|
323
|
+
bun run test:unit
|
|
324
|
+
|
|
325
|
+
# Run full test suite before push
|
|
326
|
+
bun run test:all
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## ๐ค Contributing to Tests
|
|
330
|
+
|
|
331
|
+
### Guidelines
|
|
332
|
+
1. **Write tests first** (TDD approach)
|
|
333
|
+
2. **Test both success and failure cases**
|
|
334
|
+
3. **Use descriptive test names**
|
|
335
|
+
4. **Keep tests focused and isolated**
|
|
336
|
+
5. **Update tests when adding features**
|
|
337
|
+
|
|
338
|
+
### Test Review Checklist
|
|
339
|
+
- [ ] Tests cover new functionality
|
|
340
|
+
- [ ] Edge cases are tested
|
|
341
|
+
- [ ] Error conditions are handled
|
|
342
|
+
- [ ] Tests are isolated and repeatable
|
|
343
|
+
- [ ] Performance implications are considered
|
|
344
|
+
|
|
345
|
+
## ๐ Additional Resources
|
|
346
|
+
|
|
347
|
+
### Bun Testing Documentation
|
|
348
|
+
- [Bun Test Runner](https://bun.sh/docs/cli/test)
|
|
349
|
+
- [Bun Assertions](https://bun.sh/docs/cli/test#assertions)
|
|
350
|
+
- [Bun Coverage](https://bun.sh/docs/cli/test#coverage)
|
|
351
|
+
|
|
352
|
+
### Testing Best Practices
|
|
353
|
+
- [Testing JavaScript Applications](https://www.manning.com/books/testing-javascript-applications)
|
|
354
|
+
- [Jest Documentation](https://jestjs.io/docs/getting-started)
|
|
355
|
+
- [Testing Library](https://testing-library.com/)
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
**Happy Testing! ๐งชโจ**
|