@sparkleideas/testing 3.0.0-alpha.10
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 +547 -0
- package/__tests__/framework.test.ts +21 -0
- package/package.json +61 -0
- package/src/fixtures/agent-fixtures.ts +793 -0
- package/src/fixtures/agents.ts +212 -0
- package/src/fixtures/configurations.ts +491 -0
- package/src/fixtures/index.ts +21 -0
- package/src/fixtures/mcp-fixtures.ts +1030 -0
- package/src/fixtures/memory-entries.ts +328 -0
- package/src/fixtures/memory-fixtures.ts +750 -0
- package/src/fixtures/swarm-fixtures.ts +837 -0
- package/src/fixtures/tasks.ts +309 -0
- package/src/helpers/assertion-helpers.ts +616 -0
- package/src/helpers/assertions.ts +286 -0
- package/src/helpers/create-mock.ts +200 -0
- package/src/helpers/index.ts +182 -0
- package/src/helpers/mock-factory.ts +711 -0
- package/src/helpers/setup-teardown.ts +678 -0
- package/src/helpers/swarm-instance.ts +326 -0
- package/src/helpers/test-application.ts +310 -0
- package/src/helpers/test-utils.ts +670 -0
- package/src/index.ts +232 -0
- package/src/mocks/index.ts +29 -0
- package/src/mocks/mock-mcp-client.ts +723 -0
- package/src/mocks/mock-services.ts +793 -0
- package/src/regression/api-contract.ts +473 -0
- package/src/regression/index.ts +46 -0
- package/src/regression/integration-regression.ts +416 -0
- package/src/regression/performance-baseline.ts +356 -0
- package/src/regression/regression-runner.ts +339 -0
- package/src/regression/security-regression.ts +331 -0
- package/src/setup.ts +127 -0
- package/src/v2-compat/api-compat.test.ts +590 -0
- package/src/v2-compat/cli-compat.test.ts +484 -0
- package/src/v2-compat/compatibility-validator.ts +1072 -0
- package/src/v2-compat/hooks-compat.test.ts +602 -0
- package/src/v2-compat/index.ts +58 -0
- package/src/v2-compat/mcp-compat.test.ts +557 -0
- package/src/v2-compat/report-generator.ts +441 -0
- package/tmp.json +0 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +12 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Contract Validator
|
|
3
|
+
*
|
|
4
|
+
* Validates MCP tool interfaces to detect breaking changes.
|
|
5
|
+
*
|
|
6
|
+
* @module v3/testing/regression/api-contract
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { readFile, writeFile, mkdir } from 'fs/promises';
|
|
10
|
+
import { join, dirname } from 'path';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Contract definition for a tool or endpoint
|
|
14
|
+
*/
|
|
15
|
+
export interface ContractDefinition {
|
|
16
|
+
name: string;
|
|
17
|
+
version: string;
|
|
18
|
+
description: string;
|
|
19
|
+
input: ParameterSchema;
|
|
20
|
+
output: ParameterSchema;
|
|
21
|
+
required: string[];
|
|
22
|
+
optional: string[];
|
|
23
|
+
errors: ErrorDefinition[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Parameter schema definition
|
|
28
|
+
*/
|
|
29
|
+
interface ParameterSchema {
|
|
30
|
+
type: string;
|
|
31
|
+
properties?: Record<string, PropertyDefinition>;
|
|
32
|
+
items?: PropertyDefinition;
|
|
33
|
+
required?: string[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Property definition
|
|
38
|
+
*/
|
|
39
|
+
interface PropertyDefinition {
|
|
40
|
+
type: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
enum?: string[];
|
|
43
|
+
default?: unknown;
|
|
44
|
+
properties?: Record<string, PropertyDefinition>;
|
|
45
|
+
items?: PropertyDefinition;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Error definition
|
|
50
|
+
*/
|
|
51
|
+
interface ErrorDefinition {
|
|
52
|
+
code: number;
|
|
53
|
+
message: string;
|
|
54
|
+
description: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Contract validation result
|
|
59
|
+
*/
|
|
60
|
+
export interface ContractValidation {
|
|
61
|
+
endpoint: string;
|
|
62
|
+
valid: boolean;
|
|
63
|
+
breaking: boolean;
|
|
64
|
+
message: string;
|
|
65
|
+
diffs: ContractDiff[];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Contract difference
|
|
70
|
+
*/
|
|
71
|
+
export interface ContractDiff {
|
|
72
|
+
type: 'added' | 'removed' | 'changed' | 'deprecated';
|
|
73
|
+
path: string;
|
|
74
|
+
description: string;
|
|
75
|
+
breaking: boolean;
|
|
76
|
+
oldValue?: unknown;
|
|
77
|
+
newValue?: unknown;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Stored contracts
|
|
82
|
+
*/
|
|
83
|
+
interface StoredContracts {
|
|
84
|
+
version: string;
|
|
85
|
+
capturedAt: number;
|
|
86
|
+
contracts: ContractDefinition[];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* MCP tool definitions to validate
|
|
91
|
+
*/
|
|
92
|
+
const MCP_TOOLS: ContractDefinition[] = [
|
|
93
|
+
{
|
|
94
|
+
name: 'agent/spawn',
|
|
95
|
+
version: '1.0.0',
|
|
96
|
+
description: 'Spawn a new agent',
|
|
97
|
+
input: {
|
|
98
|
+
type: 'object',
|
|
99
|
+
properties: {
|
|
100
|
+
agentType: { type: 'string', description: 'Type of agent to spawn' },
|
|
101
|
+
id: { type: 'string', description: 'Optional agent ID' },
|
|
102
|
+
config: { type: 'object', description: 'Agent configuration' },
|
|
103
|
+
priority: { type: 'string', enum: ['low', 'normal', 'high', 'critical'] },
|
|
104
|
+
metadata: { type: 'object', description: 'Additional metadata' },
|
|
105
|
+
},
|
|
106
|
+
required: ['agentType'],
|
|
107
|
+
},
|
|
108
|
+
output: {
|
|
109
|
+
type: 'object',
|
|
110
|
+
properties: {
|
|
111
|
+
agentId: { type: 'string' },
|
|
112
|
+
status: { type: 'string' },
|
|
113
|
+
createdAt: { type: 'string' },
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
required: ['agentType'],
|
|
117
|
+
optional: ['id', 'config', 'priority', 'metadata'],
|
|
118
|
+
errors: [
|
|
119
|
+
{ code: -32602, message: 'Invalid agent type', description: 'The specified agent type is not valid' },
|
|
120
|
+
{ code: -32000, message: 'Agent spawn failed', description: 'Failed to spawn agent' },
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: 'agent/list',
|
|
125
|
+
version: '1.0.0',
|
|
126
|
+
description: 'List all agents',
|
|
127
|
+
input: {
|
|
128
|
+
type: 'object',
|
|
129
|
+
properties: {
|
|
130
|
+
status: { type: 'string', enum: ['active', 'idle', 'terminated', 'all'] },
|
|
131
|
+
agentType: { type: 'string' },
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
output: {
|
|
135
|
+
type: 'object',
|
|
136
|
+
properties: {
|
|
137
|
+
agents: { type: 'array', items: { type: 'object' } },
|
|
138
|
+
totalCount: { type: 'number' },
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
required: [],
|
|
142
|
+
optional: ['status', 'agentType'],
|
|
143
|
+
errors: [],
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: 'memory/store',
|
|
147
|
+
version: '1.0.0',
|
|
148
|
+
description: 'Store a memory entry',
|
|
149
|
+
input: {
|
|
150
|
+
type: 'object',
|
|
151
|
+
properties: {
|
|
152
|
+
content: { type: 'string', description: 'Memory content' },
|
|
153
|
+
category: { type: 'string', description: 'Memory category' },
|
|
154
|
+
metadata: { type: 'object', description: 'Additional metadata' },
|
|
155
|
+
tags: { type: 'array', items: { type: 'string' } },
|
|
156
|
+
ttl: { type: 'number', description: 'Time-to-live in seconds' },
|
|
157
|
+
},
|
|
158
|
+
required: ['content'],
|
|
159
|
+
},
|
|
160
|
+
output: {
|
|
161
|
+
type: 'object',
|
|
162
|
+
properties: {
|
|
163
|
+
id: { type: 'string' },
|
|
164
|
+
storedAt: { type: 'string' },
|
|
165
|
+
expiresAt: { type: 'string' },
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
required: ['content'],
|
|
169
|
+
optional: ['category', 'metadata', 'tags', 'ttl'],
|
|
170
|
+
errors: [
|
|
171
|
+
{ code: -32000, message: 'Storage failed', description: 'Failed to store memory' },
|
|
172
|
+
],
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: 'memory/search',
|
|
176
|
+
version: '1.0.0',
|
|
177
|
+
description: 'Search memory entries',
|
|
178
|
+
input: {
|
|
179
|
+
type: 'object',
|
|
180
|
+
properties: {
|
|
181
|
+
query: { type: 'string', description: 'Search query' },
|
|
182
|
+
category: { type: 'string' },
|
|
183
|
+
limit: { type: 'number', default: 10 },
|
|
184
|
+
threshold: { type: 'number', default: 0.7 },
|
|
185
|
+
semantic: { type: 'boolean', default: true },
|
|
186
|
+
},
|
|
187
|
+
required: ['query'],
|
|
188
|
+
},
|
|
189
|
+
output: {
|
|
190
|
+
type: 'object',
|
|
191
|
+
properties: {
|
|
192
|
+
results: { type: 'array', items: { type: 'object' } },
|
|
193
|
+
totalMatches: { type: 'number' },
|
|
194
|
+
searchTime: { type: 'number' },
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
required: ['query'],
|
|
198
|
+
optional: ['category', 'limit', 'threshold', 'semantic'],
|
|
199
|
+
errors: [],
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
name: 'swarm/init',
|
|
203
|
+
version: '1.0.0',
|
|
204
|
+
description: 'Initialize a swarm',
|
|
205
|
+
input: {
|
|
206
|
+
type: 'object',
|
|
207
|
+
properties: {
|
|
208
|
+
topology: { type: 'string', enum: ['hierarchical', 'mesh', 'star', 'ring', 'adaptive'] },
|
|
209
|
+
maxAgents: { type: 'number' },
|
|
210
|
+
config: { type: 'object' },
|
|
211
|
+
},
|
|
212
|
+
required: ['topology'],
|
|
213
|
+
},
|
|
214
|
+
output: {
|
|
215
|
+
type: 'object',
|
|
216
|
+
properties: {
|
|
217
|
+
swarmId: { type: 'string' },
|
|
218
|
+
status: { type: 'string' },
|
|
219
|
+
topology: { type: 'string' },
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
required: ['topology'],
|
|
223
|
+
optional: ['maxAgents', 'config'],
|
|
224
|
+
errors: [
|
|
225
|
+
{ code: -32602, message: 'Invalid topology', description: 'The specified topology is not valid' },
|
|
226
|
+
],
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
name: 'task/orchestrate',
|
|
230
|
+
version: '1.0.0',
|
|
231
|
+
description: 'Orchestrate a complex task',
|
|
232
|
+
input: {
|
|
233
|
+
type: 'object',
|
|
234
|
+
properties: {
|
|
235
|
+
description: { type: 'string' },
|
|
236
|
+
strategy: { type: 'string', enum: ['sequential', 'parallel', 'adaptive'] },
|
|
237
|
+
maxAgents: { type: 'number' },
|
|
238
|
+
timeout: { type: 'number' },
|
|
239
|
+
},
|
|
240
|
+
required: ['description'],
|
|
241
|
+
},
|
|
242
|
+
output: {
|
|
243
|
+
type: 'object',
|
|
244
|
+
properties: {
|
|
245
|
+
taskId: { type: 'string' },
|
|
246
|
+
phases: { type: 'array' },
|
|
247
|
+
estimatedDuration: { type: 'number' },
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
required: ['description'],
|
|
251
|
+
optional: ['strategy', 'maxAgents', 'timeout'],
|
|
252
|
+
errors: [],
|
|
253
|
+
},
|
|
254
|
+
];
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* API Contract Validator
|
|
258
|
+
*
|
|
259
|
+
* Validates MCP tool contracts for breaking changes.
|
|
260
|
+
*/
|
|
261
|
+
export class APIContractValidator {
|
|
262
|
+
private readonly contractPath: string;
|
|
263
|
+
private cachedContracts: StoredContracts | null = null;
|
|
264
|
+
|
|
265
|
+
constructor(basePath: string = '.regression-baselines') {
|
|
266
|
+
this.contractPath = join(basePath, 'contracts.json');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Capture current contracts as baseline
|
|
271
|
+
*/
|
|
272
|
+
async captureContracts(): Promise<StoredContracts> {
|
|
273
|
+
const contracts: StoredContracts = {
|
|
274
|
+
version: '1.0.0',
|
|
275
|
+
capturedAt: Date.now(),
|
|
276
|
+
contracts: MCP_TOOLS,
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
await this.saveContracts(contracts);
|
|
280
|
+
this.cachedContracts = contracts;
|
|
281
|
+
|
|
282
|
+
return contracts;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Validate all contracts against baseline
|
|
287
|
+
*/
|
|
288
|
+
async validateAll(): Promise<ContractValidation[]> {
|
|
289
|
+
const baseline = await this.loadContracts();
|
|
290
|
+
if (!baseline) {
|
|
291
|
+
console.warn('No contract baseline found. Capturing initial contracts...');
|
|
292
|
+
await this.captureContracts();
|
|
293
|
+
return [];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const validations: ContractValidation[] = [];
|
|
297
|
+
|
|
298
|
+
for (const current of MCP_TOOLS) {
|
|
299
|
+
const baselineContract = baseline.contracts.find((c) => c.name === current.name);
|
|
300
|
+
|
|
301
|
+
if (!baselineContract) {
|
|
302
|
+
// New endpoint added
|
|
303
|
+
validations.push({
|
|
304
|
+
endpoint: current.name,
|
|
305
|
+
valid: true,
|
|
306
|
+
breaking: false,
|
|
307
|
+
message: 'New endpoint added',
|
|
308
|
+
diffs: [{
|
|
309
|
+
type: 'added',
|
|
310
|
+
path: current.name,
|
|
311
|
+
description: `New endpoint: ${current.description}`,
|
|
312
|
+
breaking: false,
|
|
313
|
+
}],
|
|
314
|
+
});
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const diffs = this.compareContracts(baselineContract, current);
|
|
319
|
+
const hasBreakingChanges = diffs.some((d) => d.breaking);
|
|
320
|
+
|
|
321
|
+
validations.push({
|
|
322
|
+
endpoint: current.name,
|
|
323
|
+
valid: !hasBreakingChanges,
|
|
324
|
+
breaking: hasBreakingChanges,
|
|
325
|
+
message: hasBreakingChanges
|
|
326
|
+
? `Breaking changes detected: ${diffs.filter((d) => d.breaking).map((d) => d.description).join(', ')}`
|
|
327
|
+
: diffs.length > 0
|
|
328
|
+
? `Non-breaking changes: ${diffs.map((d) => d.description).join(', ')}`
|
|
329
|
+
: 'No changes',
|
|
330
|
+
diffs,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Check for removed endpoints
|
|
335
|
+
for (const baselineContract of baseline.contracts) {
|
|
336
|
+
const stillExists = MCP_TOOLS.find((c) => c.name === baselineContract.name);
|
|
337
|
+
if (!stillExists) {
|
|
338
|
+
validations.push({
|
|
339
|
+
endpoint: baselineContract.name,
|
|
340
|
+
valid: false,
|
|
341
|
+
breaking: true,
|
|
342
|
+
message: 'Endpoint removed',
|
|
343
|
+
diffs: [{
|
|
344
|
+
type: 'removed',
|
|
345
|
+
path: baselineContract.name,
|
|
346
|
+
description: `Endpoint removed: ${baselineContract.name}`,
|
|
347
|
+
breaking: true,
|
|
348
|
+
}],
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return validations;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Compare two contracts for differences
|
|
358
|
+
*/
|
|
359
|
+
private compareContracts(baseline: ContractDefinition, current: ContractDefinition): ContractDiff[] {
|
|
360
|
+
const diffs: ContractDiff[] = [];
|
|
361
|
+
|
|
362
|
+
// Check required parameters
|
|
363
|
+
for (const param of baseline.required) {
|
|
364
|
+
if (!current.required.includes(param)) {
|
|
365
|
+
if (current.optional.includes(param)) {
|
|
366
|
+
// Parameter became optional - not breaking
|
|
367
|
+
diffs.push({
|
|
368
|
+
type: 'changed',
|
|
369
|
+
path: `${baseline.name}.input.${param}`,
|
|
370
|
+
description: `Parameter '${param}' changed from required to optional`,
|
|
371
|
+
breaking: false,
|
|
372
|
+
oldValue: 'required',
|
|
373
|
+
newValue: 'optional',
|
|
374
|
+
});
|
|
375
|
+
} else {
|
|
376
|
+
// Parameter removed - breaking
|
|
377
|
+
diffs.push({
|
|
378
|
+
type: 'removed',
|
|
379
|
+
path: `${baseline.name}.input.${param}`,
|
|
380
|
+
description: `Required parameter '${param}' removed`,
|
|
381
|
+
breaking: true,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Check for new required parameters (breaking)
|
|
388
|
+
for (const param of current.required) {
|
|
389
|
+
if (!baseline.required.includes(param) && !baseline.optional.includes(param)) {
|
|
390
|
+
diffs.push({
|
|
391
|
+
type: 'added',
|
|
392
|
+
path: `${baseline.name}.input.${param}`,
|
|
393
|
+
description: `New required parameter '${param}' added`,
|
|
394
|
+
breaking: true,
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Check for new optional parameters (not breaking)
|
|
400
|
+
for (const param of current.optional) {
|
|
401
|
+
if (!baseline.required.includes(param) && !baseline.optional.includes(param)) {
|
|
402
|
+
diffs.push({
|
|
403
|
+
type: 'added',
|
|
404
|
+
path: `${baseline.name}.input.${param}`,
|
|
405
|
+
description: `New optional parameter '${param}' added`,
|
|
406
|
+
breaking: false,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Check input schema changes
|
|
412
|
+
if (baseline.input.properties && current.input.properties) {
|
|
413
|
+
for (const [name, prop] of Object.entries(baseline.input.properties)) {
|
|
414
|
+
const currentProp = current.input.properties[name];
|
|
415
|
+
if (currentProp) {
|
|
416
|
+
// Check type changes
|
|
417
|
+
if (prop.type !== currentProp.type) {
|
|
418
|
+
diffs.push({
|
|
419
|
+
type: 'changed',
|
|
420
|
+
path: `${baseline.name}.input.${name}.type`,
|
|
421
|
+
description: `Type of '${name}' changed from '${prop.type}' to '${currentProp.type}'`,
|
|
422
|
+
breaking: true,
|
|
423
|
+
oldValue: prop.type,
|
|
424
|
+
newValue: currentProp.type,
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Check enum changes
|
|
429
|
+
if (prop.enum && currentProp.enum) {
|
|
430
|
+
const removedValues = prop.enum.filter((v) => !currentProp.enum!.includes(v));
|
|
431
|
+
if (removedValues.length > 0) {
|
|
432
|
+
diffs.push({
|
|
433
|
+
type: 'changed',
|
|
434
|
+
path: `${baseline.name}.input.${name}.enum`,
|
|
435
|
+
description: `Enum values removed from '${name}': ${removedValues.join(', ')}`,
|
|
436
|
+
breaking: true,
|
|
437
|
+
oldValue: prop.enum,
|
|
438
|
+
newValue: currentProp.enum,
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return diffs;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Load contracts from file
|
|
451
|
+
*/
|
|
452
|
+
private async loadContracts(): Promise<StoredContracts | null> {
|
|
453
|
+
if (this.cachedContracts) {
|
|
454
|
+
return this.cachedContracts;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
try {
|
|
458
|
+
const content = await readFile(this.contractPath, 'utf-8');
|
|
459
|
+
this.cachedContracts = JSON.parse(content);
|
|
460
|
+
return this.cachedContracts;
|
|
461
|
+
} catch {
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Save contracts to file
|
|
468
|
+
*/
|
|
469
|
+
private async saveContracts(contracts: StoredContracts): Promise<void> {
|
|
470
|
+
await mkdir(dirname(this.contractPath), { recursive: true });
|
|
471
|
+
await writeFile(this.contractPath, JSON.stringify(contracts, null, 2));
|
|
472
|
+
}
|
|
473
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression Testing System
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive regression detection to prevent capability degradation
|
|
5
|
+
* as new features are added. Includes:
|
|
6
|
+
* - Performance baselines
|
|
7
|
+
* - Security vulnerability checks
|
|
8
|
+
* - API contract validation
|
|
9
|
+
* - Integration verification
|
|
10
|
+
*
|
|
11
|
+
* @module v3/testing/regression
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
RegressionTestRunner,
|
|
16
|
+
type RegressionConfig,
|
|
17
|
+
type RegressionResult,
|
|
18
|
+
type RegressionReport,
|
|
19
|
+
} from './regression-runner.js';
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
PerformanceBaseline,
|
|
23
|
+
type BaselineMetric,
|
|
24
|
+
type BaselineComparison,
|
|
25
|
+
type BaselineConfig,
|
|
26
|
+
} from './performance-baseline.js';
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
SecurityRegressionChecker,
|
|
30
|
+
type SecurityCheck,
|
|
31
|
+
type SecurityVulnerability,
|
|
32
|
+
type SecurityReport,
|
|
33
|
+
} from './security-regression.js';
|
|
34
|
+
|
|
35
|
+
export {
|
|
36
|
+
APIContractValidator,
|
|
37
|
+
type ContractDefinition,
|
|
38
|
+
type ContractValidation,
|
|
39
|
+
type ContractDiff,
|
|
40
|
+
} from './api-contract.js';
|
|
41
|
+
|
|
42
|
+
export {
|
|
43
|
+
IntegrationRegressionSuite,
|
|
44
|
+
type IntegrationTest,
|
|
45
|
+
type IntegrationResult,
|
|
46
|
+
} from './integration-regression.js';
|