@engjts/nexus 0.1.8 → 0.1.9
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/package.json +1 -1
- package/BENCHMARK_REPORT.md +0 -343
- package/documentation/01-getting-started.md +0 -240
- package/documentation/02-context.md +0 -335
- package/documentation/03-routing.md +0 -397
- package/documentation/04-middleware.md +0 -483
- package/documentation/05-validation.md +0 -514
- package/documentation/06-error-handling.md +0 -465
- package/documentation/07-performance.md +0 -364
- package/documentation/08-adapters.md +0 -470
- package/documentation/09-api-reference.md +0 -548
- package/documentation/10-examples.md +0 -582
- package/documentation/11-deployment.md +0 -477
- package/documentation/12-sentry.md +0 -620
- package/documentation/13-sentry-data-storage.md +0 -996
- package/documentation/14-sentry-data-reference.md +0 -457
- package/documentation/15-sentry-summary.md +0 -409
- package/documentation/16-alerts-system.md +0 -745
- package/documentation/17-alert-adapters.md +0 -696
- package/documentation/18-alerts-implementation-summary.md +0 -385
- package/documentation/19-class-based-routing.md +0 -840
- package/documentation/20-websocket-realtime.md +0 -813
- package/documentation/21-cache-system.md +0 -510
- package/documentation/22-job-queue.md +0 -772
- package/documentation/23-sentry-plugin.md +0 -551
- package/documentation/24-testing-utilities.md +0 -1287
- package/documentation/25-api-versioning.md +0 -533
- package/documentation/26-context-store.md +0 -607
- package/documentation/27-dependency-injection.md +0 -329
- package/documentation/28-lifecycle-hooks.md +0 -521
- package/documentation/29-package-structure.md +0 -196
- package/documentation/30-plugin-system.md +0 -414
- package/documentation/31-jwt-authentication.md +0 -597
- package/documentation/32-cli.md +0 -268
- package/documentation/ALERTS-COMPLETE-SUMMARY.md +0 -429
- package/documentation/ALERTS-INDEX.md +0 -330
- package/documentation/ALERTS-QUICK-REFERENCE.md +0 -286
- package/documentation/README.md +0 -178
- package/documentation/index.html +0 -34
- package/modern_framework_paper.md +0 -1870
- package/public/css/style.css +0 -87
- package/public/index.html +0 -34
- package/public/js/app.js +0 -27
- package/src/advanced/cache/InMemoryCacheStore.ts +0 -68
- package/src/advanced/cache/MultiTierCache.ts +0 -194
- package/src/advanced/cache/RedisCacheStore.ts +0 -341
- package/src/advanced/cache/index.ts +0 -5
- package/src/advanced/cache/types.ts +0 -40
- package/src/advanced/graphql/SimpleDataLoader.ts +0 -42
- package/src/advanced/graphql/index.ts +0 -22
- package/src/advanced/graphql/server.ts +0 -252
- package/src/advanced/graphql/types.ts +0 -42
- package/src/advanced/jobs/InMemoryQueueStore.ts +0 -68
- package/src/advanced/jobs/JobQueue.ts +0 -556
- package/src/advanced/jobs/RedisQueueStore.ts +0 -367
- package/src/advanced/jobs/index.ts +0 -5
- package/src/advanced/jobs/types.ts +0 -70
- package/src/advanced/observability/APMManager.ts +0 -163
- package/src/advanced/observability/AlertManager.ts +0 -109
- package/src/advanced/observability/MetricRegistry.ts +0 -151
- package/src/advanced/observability/ObservabilityCenter.ts +0 -304
- package/src/advanced/observability/StructuredLogger.ts +0 -154
- package/src/advanced/observability/TracingManager.ts +0 -117
- package/src/advanced/observability/adapters.ts +0 -304
- package/src/advanced/observability/createObservabilityMiddleware.ts +0 -63
- package/src/advanced/observability/index.ts +0 -11
- package/src/advanced/observability/types.ts +0 -174
- package/src/advanced/playground/extractPathParams.ts +0 -6
- package/src/advanced/playground/generateFieldExample.ts +0 -31
- package/src/advanced/playground/generatePlaygroundHTML.ts +0 -1956
- package/src/advanced/playground/generateSummary.ts +0 -19
- package/src/advanced/playground/getTagFromPath.ts +0 -9
- package/src/advanced/playground/index.ts +0 -8
- package/src/advanced/playground/playground.ts +0 -250
- package/src/advanced/playground/types.ts +0 -49
- package/src/advanced/playground/zodToExample.ts +0 -16
- package/src/advanced/playground/zodToParams.ts +0 -15
- package/src/advanced/postman/buildAuth.ts +0 -31
- package/src/advanced/postman/buildBody.ts +0 -15
- package/src/advanced/postman/buildQueryParams.ts +0 -27
- package/src/advanced/postman/buildRequestItem.ts +0 -36
- package/src/advanced/postman/buildResponses.ts +0 -11
- package/src/advanced/postman/buildUrl.ts +0 -33
- package/src/advanced/postman/capitalize.ts +0 -4
- package/src/advanced/postman/generateCollection.ts +0 -59
- package/src/advanced/postman/generateEnvironment.ts +0 -34
- package/src/advanced/postman/generateExampleFromZod.ts +0 -21
- package/src/advanced/postman/generateFieldExample.ts +0 -45
- package/src/advanced/postman/generateName.ts +0 -20
- package/src/advanced/postman/generateUUID.ts +0 -11
- package/src/advanced/postman/getTagFromPath.ts +0 -10
- package/src/advanced/postman/index.ts +0 -28
- package/src/advanced/postman/postman.ts +0 -156
- package/src/advanced/postman/slugify.ts +0 -7
- package/src/advanced/postman/types.ts +0 -140
- package/src/advanced/realtime/index.ts +0 -18
- package/src/advanced/realtime/websocket.ts +0 -231
- package/src/advanced/sentry/index.ts +0 -1236
- package/src/advanced/sentry/types.ts +0 -355
- package/src/advanced/static/generateDirectoryListing.ts +0 -47
- package/src/advanced/static/generateETag.ts +0 -7
- package/src/advanced/static/getMimeType.ts +0 -9
- package/src/advanced/static/index.ts +0 -32
- package/src/advanced/static/isSafePath.ts +0 -13
- package/src/advanced/static/publicDir.ts +0 -21
- package/src/advanced/static/serveStatic.ts +0 -225
- package/src/advanced/static/spa.ts +0 -24
- package/src/advanced/static/types.ts +0 -159
- package/src/advanced/swagger/SwaggerGenerator.ts +0 -66
- package/src/advanced/swagger/buildOperation.ts +0 -61
- package/src/advanced/swagger/buildParameters.ts +0 -61
- package/src/advanced/swagger/buildRequestBody.ts +0 -21
- package/src/advanced/swagger/buildResponses.ts +0 -54
- package/src/advanced/swagger/capitalize.ts +0 -5
- package/src/advanced/swagger/convertPath.ts +0 -9
- package/src/advanced/swagger/createSwagger.ts +0 -12
- package/src/advanced/swagger/generateOperationId.ts +0 -21
- package/src/advanced/swagger/generateSpec.ts +0 -105
- package/src/advanced/swagger/generateSummary.ts +0 -24
- package/src/advanced/swagger/generateSwaggerUI.ts +0 -70
- package/src/advanced/swagger/generateThemeCss.ts +0 -53
- package/src/advanced/swagger/index.ts +0 -25
- package/src/advanced/swagger/swagger.ts +0 -237
- package/src/advanced/swagger/types.ts +0 -206
- package/src/advanced/swagger/zodFieldToOpenAPI.ts +0 -94
- package/src/advanced/swagger/zodSchemaToOpenAPI.ts +0 -50
- package/src/advanced/swagger/zodToOpenAPI.ts +0 -22
- package/src/advanced/testing/factory.ts +0 -509
- package/src/advanced/testing/harness.ts +0 -612
- package/src/advanced/testing/index.ts +0 -430
- package/src/advanced/testing/load-test.ts +0 -618
- package/src/advanced/testing/mock-server.ts +0 -498
- package/src/advanced/testing/mock.ts +0 -670
- package/src/cli/bin.ts +0 -9
- package/src/cli/cli.ts +0 -158
- package/src/cli/commands/add.ts +0 -178
- package/src/cli/commands/build.ts +0 -73
- package/src/cli/commands/create.ts +0 -166
- package/src/cli/commands/dev.ts +0 -85
- package/src/cli/commands/generate.ts +0 -99
- package/src/cli/commands/help.ts +0 -95
- package/src/cli/commands/init.ts +0 -91
- package/src/cli/commands/version.ts +0 -38
- package/src/cli/index.ts +0 -6
- package/src/cli/templates/generators.ts +0 -359
- package/src/cli/templates/index.ts +0 -680
- package/src/cli/utils/exec.ts +0 -52
- package/src/cli/utils/file-system.ts +0 -78
- package/src/cli/utils/logger.ts +0 -111
- package/src/core/adapter.ts +0 -88
- package/src/core/application.ts +0 -1453
- package/src/core/context-pool.ts +0 -79
- package/src/core/context.ts +0 -856
- package/src/core/index.ts +0 -94
- package/src/core/middleware.ts +0 -272
- package/src/core/performance/buffer-pool.ts +0 -108
- package/src/core/performance/middleware-optimizer.ts +0 -162
- package/src/core/plugin/PluginManager.ts +0 -435
- package/src/core/plugin/builder.ts +0 -358
- package/src/core/plugin/index.ts +0 -50
- package/src/core/plugin/types.ts +0 -214
- package/src/core/router/file-router.ts +0 -623
- package/src/core/router/index.ts +0 -260
- package/src/core/router/radix-tree.ts +0 -242
- package/src/core/serializer.ts +0 -397
- package/src/core/store/index.ts +0 -30
- package/src/core/store/registry.ts +0 -178
- package/src/core/store/request-store.ts +0 -240
- package/src/core/store/types.ts +0 -233
- package/src/core/types.ts +0 -616
- package/src/database/adapter.ts +0 -35
- package/src/database/adapters/index.ts +0 -1
- package/src/database/adapters/mysql.ts +0 -669
- package/src/database/database.ts +0 -70
- package/src/database/dialect.ts +0 -388
- package/src/database/index.ts +0 -12
- package/src/database/migrations.ts +0 -86
- package/src/database/optimizer.ts +0 -125
- package/src/database/query-builder.ts +0 -404
- package/src/database/realtime.ts +0 -53
- package/src/database/schema.ts +0 -71
- package/src/database/transactions.ts +0 -56
- package/src/database/types.ts +0 -87
- package/src/deployment/cluster.ts +0 -471
- package/src/deployment/config.ts +0 -454
- package/src/deployment/docker.ts +0 -599
- package/src/deployment/graceful-shutdown.ts +0 -373
- package/src/deployment/index.ts +0 -56
- package/src/index.ts +0 -281
- package/src/security/adapter.ts +0 -318
- package/src/security/auth/JWTPlugin.ts +0 -234
- package/src/security/auth/JWTProvider.ts +0 -316
- package/src/security/auth/adapter.ts +0 -12
- package/src/security/auth/jwt.ts +0 -234
- package/src/security/auth/middleware.ts +0 -188
- package/src/security/csrf.ts +0 -220
- package/src/security/headers.ts +0 -108
- package/src/security/index.ts +0 -60
- package/src/security/rate-limit/adapter.ts +0 -7
- package/src/security/rate-limit/memory.ts +0 -108
- package/src/security/rate-limit/middleware.ts +0 -181
- package/src/security/sanitization.ts +0 -75
- package/src/security/types.ts +0 -240
- package/src/security/utils.ts +0 -52
- package/tsconfig.json +0 -39
|
@@ -1,430 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test Framework Integration
|
|
3
|
-
* Provides seamless integration with Jest, Vitest, and Node test runner
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Application } from '../../core/application';
|
|
7
|
-
import { TestClient, createTestSuite, TestSuiteOptions } from './harness';
|
|
8
|
-
import { MockDatabase, MockFetch, MockTimers, mockDb, mockFetch, mockTimers } from './mock';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Detected test framework
|
|
12
|
-
*/
|
|
13
|
-
export type TestFramework = 'jest' | 'vitest' | 'node' | 'unknown';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Detect which test framework is being used
|
|
17
|
-
*/
|
|
18
|
-
export function detectTestFramework(): TestFramework {
|
|
19
|
-
// Check for Jest
|
|
20
|
-
if (typeof (globalThis as any).jest !== 'undefined') {
|
|
21
|
-
return 'jest';
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Check for Vitest
|
|
25
|
-
if (typeof (globalThis as any).__vitest__ !== 'undefined') {
|
|
26
|
-
return 'vitest';
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Check for Node test runner
|
|
30
|
-
if (typeof (globalThis as any).describe === 'function' &&
|
|
31
|
-
typeof (globalThis as any).test === 'function' &&
|
|
32
|
-
typeof (globalThis as any).it === 'function') {
|
|
33
|
-
return 'node';
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return 'unknown';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Test suite configuration for framework integration
|
|
41
|
-
*/
|
|
42
|
-
export interface NexusTestConfig<T = void> {
|
|
43
|
-
/**
|
|
44
|
-
* Nexus application instance
|
|
45
|
-
*/
|
|
46
|
-
app: Application;
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Setup function called before all tests
|
|
50
|
-
*/
|
|
51
|
-
setup?: () => Promise<T>;
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Teardown function called after all tests
|
|
55
|
-
*/
|
|
56
|
-
teardown?: (context: T) => Promise<void>;
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Reset function called before each test
|
|
60
|
-
*/
|
|
61
|
-
reset?: (context: T) => Promise<void>;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Enable mock database
|
|
65
|
-
* @default true
|
|
66
|
-
*/
|
|
67
|
-
mockDatabase?: boolean;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Enable mock fetch
|
|
71
|
-
* @default false
|
|
72
|
-
*/
|
|
73
|
-
mockFetch?: boolean;
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Enable mock timers
|
|
77
|
-
* @default false
|
|
78
|
-
*/
|
|
79
|
-
mockTimers?: boolean;
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Auto-cleanup after each test
|
|
83
|
-
* @default true
|
|
84
|
-
*/
|
|
85
|
-
autoCleanup?: boolean;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Test context available in tests
|
|
90
|
-
*/
|
|
91
|
-
export interface NexusTestContext<T = void> {
|
|
92
|
-
/**
|
|
93
|
-
* HTTP test client
|
|
94
|
-
*/
|
|
95
|
-
client: TestClient;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Base URL of the test server
|
|
99
|
-
*/
|
|
100
|
-
baseUrl: string;
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Mock database instance
|
|
104
|
-
*/
|
|
105
|
-
db: MockDatabase;
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Mock fetch instance
|
|
109
|
-
*/
|
|
110
|
-
fetch: MockFetch;
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Mock timers instance
|
|
114
|
-
*/
|
|
115
|
-
timers: MockTimers;
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Custom context from setup
|
|
119
|
-
*/
|
|
120
|
-
context: T;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Create a Nexus test suite with automatic setup/teardown
|
|
125
|
-
*
|
|
126
|
-
* @example Jest/Vitest
|
|
127
|
-
* ```typescript
|
|
128
|
-
* import { createNexusTest } from 'nexus/testing';
|
|
129
|
-
* import { app } from './app';
|
|
130
|
-
*
|
|
131
|
-
* const { beforeAll, afterAll, beforeEach, getContext } = createNexusTest({
|
|
132
|
-
* app,
|
|
133
|
-
* mockDatabase: true,
|
|
134
|
-
* setup: async () => {
|
|
135
|
-
* // Seed test data
|
|
136
|
-
* return { adminToken: 'test-admin-token' };
|
|
137
|
-
* }
|
|
138
|
-
* });
|
|
139
|
-
*
|
|
140
|
-
* describe('Users API', () => {
|
|
141
|
-
* beforeAll();
|
|
142
|
-
* afterAll();
|
|
143
|
-
* beforeEach();
|
|
144
|
-
*
|
|
145
|
-
* test('should list users', async () => {
|
|
146
|
-
* const { client, context } = getContext();
|
|
147
|
-
*
|
|
148
|
-
* const res = await client.get('/users', {
|
|
149
|
-
* headers: { Authorization: `Bearer ${context.adminToken}` }
|
|
150
|
-
* });
|
|
151
|
-
*
|
|
152
|
-
* expect(res.status).toBe(200);
|
|
153
|
-
* expect(res.json().users).toBeArray();
|
|
154
|
-
* });
|
|
155
|
-
* });
|
|
156
|
-
* ```
|
|
157
|
-
*/
|
|
158
|
-
export function createNexusTest<T = void>(config: NexusTestConfig<T>) {
|
|
159
|
-
const {
|
|
160
|
-
app,
|
|
161
|
-
setup,
|
|
162
|
-
teardown,
|
|
163
|
-
reset,
|
|
164
|
-
mockDatabase = true,
|
|
165
|
-
mockFetch: enableMockFetch = false,
|
|
166
|
-
mockTimers: enableMockTimers = false,
|
|
167
|
-
autoCleanup = true
|
|
168
|
-
} = config;
|
|
169
|
-
|
|
170
|
-
const client = new TestClient(app);
|
|
171
|
-
let setupContext: T = undefined as T;
|
|
172
|
-
let baseUrl = '';
|
|
173
|
-
|
|
174
|
-
// Context getter
|
|
175
|
-
const getContext = (): NexusTestContext<T> => ({
|
|
176
|
-
client,
|
|
177
|
-
baseUrl,
|
|
178
|
-
db: mockDb,
|
|
179
|
-
fetch: mockFetch,
|
|
180
|
-
timers: mockTimers,
|
|
181
|
-
context: setupContext
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
return {
|
|
185
|
-
/**
|
|
186
|
-
* Call this in beforeAll/before hook
|
|
187
|
-
*/
|
|
188
|
-
beforeAll: () => async () => {
|
|
189
|
-
// Start test server
|
|
190
|
-
await client.start();
|
|
191
|
-
baseUrl = (client as any).baseUrl;
|
|
192
|
-
|
|
193
|
-
// Install mocks
|
|
194
|
-
if (enableMockFetch) {
|
|
195
|
-
mockFetch.install();
|
|
196
|
-
}
|
|
197
|
-
if (enableMockTimers) {
|
|
198
|
-
mockTimers.install();
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Run custom setup
|
|
202
|
-
if (setup) {
|
|
203
|
-
setupContext = await setup();
|
|
204
|
-
}
|
|
205
|
-
},
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Call this in afterAll/after hook
|
|
209
|
-
*/
|
|
210
|
-
afterAll: () => async () => {
|
|
211
|
-
// Stop test server
|
|
212
|
-
await client.stop();
|
|
213
|
-
|
|
214
|
-
// Run custom teardown
|
|
215
|
-
if (teardown) {
|
|
216
|
-
await teardown(setupContext);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Restore mocks
|
|
220
|
-
if (enableMockFetch) {
|
|
221
|
-
mockFetch.restore();
|
|
222
|
-
}
|
|
223
|
-
if (enableMockTimers) {
|
|
224
|
-
mockTimers.restore();
|
|
225
|
-
}
|
|
226
|
-
},
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Call this in beforeEach hook
|
|
230
|
-
*/
|
|
231
|
-
beforeEach: () => async () => {
|
|
232
|
-
// Reset mocks
|
|
233
|
-
if (autoCleanup) {
|
|
234
|
-
if (mockDatabase) {
|
|
235
|
-
mockDb.clear();
|
|
236
|
-
}
|
|
237
|
-
if (enableMockFetch) {
|
|
238
|
-
mockFetch.reset();
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Run custom reset
|
|
243
|
-
if (reset) {
|
|
244
|
-
await reset(setupContext);
|
|
245
|
-
}
|
|
246
|
-
},
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Call this in afterEach hook (optional)
|
|
250
|
-
*/
|
|
251
|
-
afterEach: () => async () => {
|
|
252
|
-
// Additional cleanup if needed
|
|
253
|
-
},
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Get current test context
|
|
257
|
-
*/
|
|
258
|
-
getContext,
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Get the test client directly
|
|
262
|
-
*/
|
|
263
|
-
getClient: () => client
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Assertion helpers for Nexus testing
|
|
269
|
-
*/
|
|
270
|
-
export const assertions = {
|
|
271
|
-
/**
|
|
272
|
-
* Assert response status
|
|
273
|
-
*/
|
|
274
|
-
expectStatus(response: { status: number }, expected: number): void {
|
|
275
|
-
if (response.status !== expected) {
|
|
276
|
-
throw new Error(`Expected status ${expected} but got ${response.status}`);
|
|
277
|
-
}
|
|
278
|
-
},
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* Assert response is JSON
|
|
282
|
-
*/
|
|
283
|
-
expectJson(response: { body: string; headers: Record<string, any> }): any {
|
|
284
|
-
const contentType = response.headers['content-type'];
|
|
285
|
-
if (!contentType?.includes('application/json')) {
|
|
286
|
-
throw new Error(`Expected JSON content-type but got ${contentType}`);
|
|
287
|
-
}
|
|
288
|
-
return JSON.parse(response.body);
|
|
289
|
-
},
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Assert response contains key
|
|
293
|
-
*/
|
|
294
|
-
expectBodyHas(response: { body: string }, key: string): void {
|
|
295
|
-
const body = JSON.parse(response.body);
|
|
296
|
-
if (!(key in body)) {
|
|
297
|
-
throw new Error(`Expected body to have key "${key}"`);
|
|
298
|
-
}
|
|
299
|
-
},
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Assert response body equals
|
|
303
|
-
*/
|
|
304
|
-
expectBodyEquals(response: { body: string }, expected: any): void {
|
|
305
|
-
const body = JSON.parse(response.body);
|
|
306
|
-
const actual = JSON.stringify(body);
|
|
307
|
-
const exp = JSON.stringify(expected);
|
|
308
|
-
if (actual !== exp) {
|
|
309
|
-
throw new Error(`Body mismatch:\nExpected: ${exp}\nActual: ${actual}`);
|
|
310
|
-
}
|
|
311
|
-
},
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* Assert header exists
|
|
315
|
-
*/
|
|
316
|
-
expectHeader(response: { headers: Record<string, any> }, name: string, value?: string): void {
|
|
317
|
-
const headerValue = response.headers[name.toLowerCase()];
|
|
318
|
-
if (!headerValue) {
|
|
319
|
-
throw new Error(`Expected header "${name}" to exist`);
|
|
320
|
-
}
|
|
321
|
-
if (value !== undefined && headerValue !== value) {
|
|
322
|
-
throw new Error(`Expected header "${name}" to be "${value}" but got "${headerValue}"`);
|
|
323
|
-
}
|
|
324
|
-
},
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Assert response time
|
|
328
|
-
*/
|
|
329
|
-
expectFast(response: { duration: number }, maxMs: number = 100): void {
|
|
330
|
-
if (response.duration > maxMs) {
|
|
331
|
-
throw new Error(`Expected response within ${maxMs}ms but took ${response.duration}ms`);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
};
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Create authenticated test client
|
|
338
|
-
*
|
|
339
|
-
* @example
|
|
340
|
-
* ```typescript
|
|
341
|
-
* const adminClient = createAuthenticatedClient(app, {
|
|
342
|
-
* token: 'admin-jwt-token',
|
|
343
|
-
* headers: { 'X-Tenant-ID': 'test-tenant' }
|
|
344
|
-
* });
|
|
345
|
-
*
|
|
346
|
-
* const res = await adminClient.get('/admin/users');
|
|
347
|
-
* ```
|
|
348
|
-
*/
|
|
349
|
-
export function createAuthenticatedClient(
|
|
350
|
-
app: Application,
|
|
351
|
-
auth: {
|
|
352
|
-
token?: string;
|
|
353
|
-
headers?: Record<string, string>;
|
|
354
|
-
user?: any;
|
|
355
|
-
}
|
|
356
|
-
): TestClient {
|
|
357
|
-
const client = new TestClient(app);
|
|
358
|
-
|
|
359
|
-
if (auth.token) {
|
|
360
|
-
client.authenticate(auth.token);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (auth.headers) {
|
|
364
|
-
client.setDefaultHeaders(auth.headers);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return client;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* Wait for condition with timeout
|
|
372
|
-
*/
|
|
373
|
-
export async function waitForCondition(
|
|
374
|
-
condition: () => boolean | Promise<boolean>,
|
|
375
|
-
options: { timeout?: number; interval?: number; message?: string } = {}
|
|
376
|
-
): Promise<void> {
|
|
377
|
-
const { timeout = 5000, interval = 50, message = 'Condition not met' } = options;
|
|
378
|
-
const start = Date.now();
|
|
379
|
-
|
|
380
|
-
while (Date.now() - start < timeout) {
|
|
381
|
-
if (await condition()) {
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
await new Promise(resolve => setTimeout(resolve, interval));
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
throw new Error(`${message} (timeout: ${timeout}ms)`);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Retry function with exponential backoff
|
|
392
|
-
*/
|
|
393
|
-
export async function retryAsync<T>(
|
|
394
|
-
fn: () => Promise<T>,
|
|
395
|
-
options: { maxAttempts?: number; delay?: number; backoff?: boolean } = {}
|
|
396
|
-
): Promise<T> {
|
|
397
|
-
const { maxAttempts = 3, delay = 100, backoff = true } = options;
|
|
398
|
-
let lastError: Error | undefined;
|
|
399
|
-
|
|
400
|
-
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
401
|
-
try {
|
|
402
|
-
return await fn();
|
|
403
|
-
} catch (error) {
|
|
404
|
-
lastError = error as Error;
|
|
405
|
-
if (attempt < maxAttempts) {
|
|
406
|
-
const waitTime = backoff ? delay * Math.pow(2, attempt - 1) : delay;
|
|
407
|
-
await new Promise(resolve => setTimeout(resolve, waitTime));
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
throw lastError;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* Measure execution time of async function
|
|
417
|
-
*/
|
|
418
|
-
export async function measureTime<T>(fn: () => Promise<T>): Promise<{ result: T; duration: number }> {
|
|
419
|
-
const start = Date.now();
|
|
420
|
-
const result = await fn();
|
|
421
|
-
const duration = Date.now() - start;
|
|
422
|
-
return { result, duration };
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// Re-export everything
|
|
426
|
-
export * from './harness';
|
|
427
|
-
export * from './mock';
|
|
428
|
-
export * from './factory';
|
|
429
|
-
export * from './load-test';
|
|
430
|
-
export * from './mock-server';
|