@plyaz/types 1.5.1 → 1.5.2
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/dist/features/feature-flag/types.d.ts +28 -4
- package/dist/testing/common/factories/types.d.ts +92 -56
- package/dist/testing/common/mocks/types.d.ts +543 -333
- package/dist/testing/common/patterns/types.d.ts +28 -10
- package/dist/testing/common/utils/types.d.ts +559 -400
- package/dist/testing/features/cache/types.d.ts +127 -54
- package/dist/testing/features/feature-flags/types.d.ts +249 -128
- package/package.json +1 -1
|
@@ -99,7 +99,7 @@ export interface SetupFeatureFlagModuleMocks {
|
|
|
99
99
|
/** Mock logger instance */
|
|
100
100
|
mockLogger: MockLogger;
|
|
101
101
|
/** Mock HTTP exception constructor */
|
|
102
|
-
HttpException: Vitest.
|
|
102
|
+
HttpException: Vitest.Mock;
|
|
103
103
|
/** HTTP status code constants */
|
|
104
104
|
HttpStatus: Record<string, number>;
|
|
105
105
|
}
|
|
@@ -250,25 +250,25 @@ export interface FeatureFlagScenarios<FeatureFlagKey extends string> {
|
|
|
250
250
|
*/
|
|
251
251
|
export interface MockFeatureFlagProvider {
|
|
252
252
|
/** Get a specific feature flag */
|
|
253
|
-
getFlag: Vitest.
|
|
253
|
+
getFlag: Vitest.Mock;
|
|
254
254
|
/** Get all feature flags */
|
|
255
|
-
getAllFlags: Vitest.
|
|
255
|
+
getAllFlags: Vitest.Mock;
|
|
256
256
|
/** Evaluate a feature flag */
|
|
257
|
-
evaluateFlag: Vitest.
|
|
257
|
+
evaluateFlag: Vitest.Mock;
|
|
258
258
|
/** Check if a flag is enabled */
|
|
259
|
-
isEnabled: Vitest.
|
|
259
|
+
isEnabled: Vitest.Mock;
|
|
260
260
|
/** Get a flag's value */
|
|
261
|
-
getValue: Vitest.
|
|
261
|
+
getValue: Vitest.Mock;
|
|
262
262
|
/** Update a feature flag */
|
|
263
|
-
updateFlag: Vitest.
|
|
263
|
+
updateFlag: Vitest.Mock;
|
|
264
264
|
/** Delete a feature flag */
|
|
265
|
-
deleteFlag: Vitest.
|
|
265
|
+
deleteFlag: Vitest.Mock;
|
|
266
266
|
/** Refresh flag data */
|
|
267
|
-
refresh: Vitest.
|
|
267
|
+
refresh: Vitest.Mock;
|
|
268
268
|
/** Subscribe to flag changes */
|
|
269
|
-
subscribe: Vitest.
|
|
269
|
+
subscribe: Vitest.Mock;
|
|
270
270
|
/** Unsubscribe from flag changes */
|
|
271
|
-
unsubscribe: Vitest.
|
|
271
|
+
unsubscribe: Vitest.Mock;
|
|
272
272
|
}
|
|
273
273
|
/**
|
|
274
274
|
* Mock feature flag repository interface for database operations testing
|
|
@@ -289,21 +289,21 @@ export interface MockFeatureFlagProvider {
|
|
|
289
289
|
*/
|
|
290
290
|
export interface MockFeatureFlagRepository {
|
|
291
291
|
/** Find a single flag by criteria */
|
|
292
|
-
find: Vitest.
|
|
292
|
+
find: Vitest.Mock;
|
|
293
293
|
/** Find all flags */
|
|
294
|
-
findAll: Vitest.
|
|
294
|
+
findAll: Vitest.Mock;
|
|
295
295
|
/** Create a new flag */
|
|
296
|
-
create: Vitest.
|
|
296
|
+
create: Vitest.Mock;
|
|
297
297
|
/** Update an existing flag */
|
|
298
|
-
update: Vitest.
|
|
298
|
+
update: Vitest.Mock;
|
|
299
299
|
/** Delete a flag */
|
|
300
|
-
delete: Vitest.
|
|
300
|
+
delete: Vitest.Mock;
|
|
301
301
|
/** Save a flag */
|
|
302
|
-
save: Vitest.
|
|
302
|
+
save: Vitest.Mock;
|
|
303
303
|
/** Check if a flag exists */
|
|
304
|
-
exists: Vitest.
|
|
304
|
+
exists: Vitest.Mock;
|
|
305
305
|
/** Count total flags */
|
|
306
|
-
count: Vitest.
|
|
306
|
+
count: Vitest.Mock;
|
|
307
307
|
}
|
|
308
308
|
/**
|
|
309
309
|
* Mock feature flag service interface for business logic testing
|
|
@@ -324,21 +324,21 @@ export interface MockFeatureFlagRepository {
|
|
|
324
324
|
*/
|
|
325
325
|
export interface MockFeatureFlagService {
|
|
326
326
|
/** Evaluate a single flag */
|
|
327
|
-
evaluate: Vitest.
|
|
327
|
+
evaluate: Vitest.Mock;
|
|
328
328
|
/** Evaluate all flags */
|
|
329
|
-
evaluateAll: Vitest.
|
|
329
|
+
evaluateAll: Vitest.Mock;
|
|
330
330
|
/** Check if flag is enabled */
|
|
331
|
-
isEnabled: Vitest.
|
|
331
|
+
isEnabled: Vitest.Mock;
|
|
332
332
|
/** Get flag value */
|
|
333
|
-
getValue: Vitest.
|
|
333
|
+
getValue: Vitest.Mock;
|
|
334
334
|
/** Get flag variation */
|
|
335
|
-
getVariation: Vitest.
|
|
335
|
+
getVariation: Vitest.Mock;
|
|
336
336
|
/** Track flag usage */
|
|
337
|
-
track: Vitest.
|
|
337
|
+
track: Vitest.Mock;
|
|
338
338
|
/** Refresh flag data */
|
|
339
|
-
refresh: Vitest.
|
|
339
|
+
refresh: Vitest.Mock;
|
|
340
340
|
/** Clear cache */
|
|
341
|
-
invalidateCache: Vitest.
|
|
341
|
+
invalidateCache: Vitest.Mock;
|
|
342
342
|
}
|
|
343
343
|
/**
|
|
344
344
|
* Mock feature flag evaluation engine interface for testing flag logic
|
|
@@ -356,15 +356,15 @@ export interface MockFeatureFlagService {
|
|
|
356
356
|
*/
|
|
357
357
|
export interface MockFeatureFlagEngine {
|
|
358
358
|
/** Evaluate flag with context */
|
|
359
|
-
evaluate: Vitest.
|
|
359
|
+
evaluate: Vitest.Mock;
|
|
360
360
|
/** Evaluate conditions */
|
|
361
|
-
evaluateConditions: Vitest.
|
|
361
|
+
evaluateConditions: Vitest.Mock;
|
|
362
362
|
/** Check rollout eligibility */
|
|
363
|
-
checkRollout: Vitest.
|
|
363
|
+
checkRollout: Vitest.Mock;
|
|
364
364
|
/** Calculate variation */
|
|
365
|
-
calculateVariation: Vitest.
|
|
365
|
+
calculateVariation: Vitest.Mock;
|
|
366
366
|
/** Get default value */
|
|
367
|
-
getDefaultValue: Vitest.
|
|
367
|
+
getDefaultValue: Vitest.Mock;
|
|
368
368
|
}
|
|
369
369
|
/**
|
|
370
370
|
* Mock feature flag cache interface for testing caching behavior
|
|
@@ -385,21 +385,21 @@ export interface MockFeatureFlagEngine {
|
|
|
385
385
|
*/
|
|
386
386
|
export interface MockFeatureFlagCache {
|
|
387
387
|
/** Get cached value */
|
|
388
|
-
get: Vitest.
|
|
388
|
+
get: Vitest.Mock;
|
|
389
389
|
/** Set cache value */
|
|
390
|
-
set: Vitest.
|
|
390
|
+
set: Vitest.Mock;
|
|
391
391
|
/** Delete cached value */
|
|
392
|
-
delete: Vitest.
|
|
392
|
+
delete: Vitest.Mock;
|
|
393
393
|
/** Clear all cache */
|
|
394
|
-
clear: Vitest.
|
|
394
|
+
clear: Vitest.Mock;
|
|
395
395
|
/** Check if key exists */
|
|
396
|
-
has: Vitest.
|
|
396
|
+
has: Vitest.Mock;
|
|
397
397
|
/** Get all cache keys */
|
|
398
|
-
keys: Vitest.
|
|
398
|
+
keys: Vitest.Mock;
|
|
399
399
|
/** Get all cache values */
|
|
400
|
-
values: Vitest.
|
|
400
|
+
values: Vitest.Mock;
|
|
401
401
|
/** Get cache size */
|
|
402
|
-
size: Vitest.
|
|
402
|
+
size: Vitest.Mock;
|
|
403
403
|
}
|
|
404
404
|
/**
|
|
405
405
|
* Test context for feature flag testing with React components
|
|
@@ -1076,7 +1076,7 @@ export interface SubscriptionFeatureFlagTracker<FeatureFlagKey extends string> {
|
|
|
1076
1076
|
/** Track a new subscription */
|
|
1077
1077
|
track: (provider: IFeatureFlagProvider<FeatureFlagKey>, id?: string) => {
|
|
1078
1078
|
id: string;
|
|
1079
|
-
callback: Vitest.
|
|
1079
|
+
callback: Vitest.Mock;
|
|
1080
1080
|
unsubscribe: () => void;
|
|
1081
1081
|
};
|
|
1082
1082
|
/** Unsubscribe by ID */
|
|
@@ -1370,132 +1370,253 @@ export interface FileProviderTestScenario<FeatureFlagKey extends string> extends
|
|
|
1370
1370
|
waitForFileChange: (ms?: number) => Promise<void>;
|
|
1371
1371
|
}
|
|
1372
1372
|
/**
|
|
1373
|
-
* Feature flag service interface for NestJS
|
|
1374
|
-
*
|
|
1373
|
+
* Feature flag service interface for NestJS applications.
|
|
1374
|
+
* Provides comprehensive feature flag management including evaluation,
|
|
1375
|
+
* CRUD operations, and provider integration.
|
|
1376
|
+
*
|
|
1377
|
+
* @example
|
|
1378
|
+
* ```typescript
|
|
1379
|
+
* const service: FeatureFlagService = {
|
|
1380
|
+
* logger: new Logger('FeatureFlagService'),
|
|
1381
|
+
* provider: launchDarklyProvider,
|
|
1382
|
+
* featureFlagRepository: repository,
|
|
1383
|
+
*
|
|
1384
|
+
* // Lifecycle hooks
|
|
1385
|
+
* onModuleInit: async () => {
|
|
1386
|
+
* await service.initializeProvider();
|
|
1387
|
+
* },
|
|
1388
|
+
* onModuleDestroy: async () => {
|
|
1389
|
+
* await provider.close();
|
|
1390
|
+
* },
|
|
1391
|
+
*
|
|
1392
|
+
* // Core operations
|
|
1393
|
+
* evaluateFlag: async (key, context) => {
|
|
1394
|
+
* return await provider.evaluate(key, context);
|
|
1395
|
+
* },
|
|
1396
|
+
* isEnabled: async (key, context) => {
|
|
1397
|
+
* const value = await service.evaluateFlag(key, context);
|
|
1398
|
+
* return Boolean(value);
|
|
1399
|
+
* }
|
|
1400
|
+
* };
|
|
1401
|
+
* ```
|
|
1375
1402
|
*/
|
|
1376
1403
|
export interface FeatureFlagService {
|
|
1377
|
-
/** Logger instance */
|
|
1378
1404
|
logger: unknown;
|
|
1379
|
-
/** Feature flag provider */
|
|
1380
1405
|
provider: unknown;
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1406
|
+
featureFlagRepository: unknown;
|
|
1407
|
+
onModuleInit(): Promise<void>;
|
|
1408
|
+
onModuleDestroy(): Promise<void>;
|
|
1409
|
+
evaluateFlag(key: string, context?: unknown): Promise<unknown>;
|
|
1410
|
+
isEnabled(key: string, context?: unknown): Promise<boolean>;
|
|
1411
|
+
getValue(key: string, context?: unknown): Promise<unknown>;
|
|
1412
|
+
getAllFlags(context?: unknown): Promise<unknown>;
|
|
1413
|
+
createFlag(createData: unknown): Promise<unknown>;
|
|
1414
|
+
updateFlag(key: string, updateData: unknown): Promise<unknown>;
|
|
1415
|
+
deleteFlag(key: string): Promise<void>;
|
|
1416
|
+
setOverride(key: string, value: unknown): Promise<void>;
|
|
1417
|
+
removeOverride(key: string): Promise<void>;
|
|
1418
|
+
getAllFeatureFlags(environment?: string): Promise<unknown[]>;
|
|
1419
|
+
getFlagRules(key: string): Promise<unknown[]>;
|
|
1420
|
+
refreshCache(): Promise<void>;
|
|
1421
|
+
getHealthStatus(): Promise<unknown>;
|
|
1422
|
+
initializeProvider(): Promise<void>;
|
|
1423
|
+
getProvider(): unknown;
|
|
1389
1424
|
}
|
|
1390
1425
|
/**
|
|
1391
|
-
* Feature flag repository interface for NestJS
|
|
1392
|
-
*
|
|
1393
|
-
*
|
|
1426
|
+
* Feature flag repository interface for NestJS data persistence.
|
|
1427
|
+
* Handles database operations for feature flags and rules.
|
|
1428
|
+
*
|
|
1429
|
+
* @template FeatureFlagKey - Type of feature flag keys
|
|
1430
|
+
*
|
|
1431
|
+
* @example
|
|
1432
|
+
* ```typescript
|
|
1433
|
+
* const repository: FeatureFlagRepository<AppFlags> = {
|
|
1434
|
+
* logger: new Logger('FeatureFlagRepository'),
|
|
1435
|
+
*
|
|
1436
|
+
* createFlag: async (data) => {
|
|
1437
|
+
* return await db.flags.create(data);
|
|
1438
|
+
* },
|
|
1439
|
+
* getFlag: async (key) => {
|
|
1440
|
+
* return await db.flags.findOne({ key });
|
|
1441
|
+
* },
|
|
1442
|
+
* updateFlag: async (key, data) => {
|
|
1443
|
+
* return await db.flags.update({ key }, data);
|
|
1444
|
+
* },
|
|
1445
|
+
* deleteFlag: async (key) => {
|
|
1446
|
+
* await db.flags.delete({ key });
|
|
1447
|
+
* },
|
|
1448
|
+
* getAllFlags: async (environment) => {
|
|
1449
|
+
* return environment
|
|
1450
|
+
* ? await db.flags.find({ environment })
|
|
1451
|
+
* : await db.flags.find();
|
|
1452
|
+
* }
|
|
1453
|
+
* };
|
|
1454
|
+
* ```
|
|
1394
1455
|
*/
|
|
1395
1456
|
export interface FeatureFlagRepository<FeatureFlagKey extends string> {
|
|
1396
|
-
/** Logger instance */
|
|
1397
1457
|
logger: unknown;
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1458
|
+
createFlag(createData: unknown): Promise<unknown>;
|
|
1459
|
+
updateFlag(key: FeatureFlagKey, updateData: unknown): Promise<unknown>;
|
|
1460
|
+
deleteFlag(key: FeatureFlagKey): Promise<void>;
|
|
1461
|
+
getAllFlags(environment?: string): Promise<unknown[]>;
|
|
1462
|
+
getFlagRules(key: FeatureFlagKey): Promise<unknown[]>;
|
|
1463
|
+
getFlag(key: FeatureFlagKey): Promise<unknown>;
|
|
1464
|
+
createRule(rule: unknown): Promise<unknown>;
|
|
1465
|
+
updateRule(ruleId: string, updateData: unknown): Promise<unknown>;
|
|
1466
|
+
deleteRule(ruleId: string): Promise<void>;
|
|
1467
|
+
getFlagByKey(key: FeatureFlagKey): Promise<unknown>;
|
|
1468
|
+
getAllRules(): Promise<unknown[]>;
|
|
1469
|
+
createSampleFlags(): Promise<void>;
|
|
1470
|
+
filterFlagsByEnvironment(flags: unknown[], environment: string): unknown[];
|
|
1471
|
+
inferFlagType(value: unknown): string;
|
|
1411
1472
|
}
|
|
1412
1473
|
/**
|
|
1413
|
-
*
|
|
1414
|
-
*
|
|
1415
|
-
*
|
|
1474
|
+
* Configuration for gradual feature rollout testing.
|
|
1475
|
+
* Defines parameters for progressive deployment of features.
|
|
1476
|
+
*
|
|
1477
|
+
* @template T - Type of feature flag keys
|
|
1478
|
+
*
|
|
1479
|
+
* @example
|
|
1480
|
+
* ```typescript
|
|
1481
|
+
* const rolloutConfig: RolloutConfig<'newFeature'> = {
|
|
1482
|
+
* flagKey: 'newFeature',
|
|
1483
|
+
* startPercentage: 0,
|
|
1484
|
+
* endPercentage: 100,
|
|
1485
|
+
* duration: 7 * 24 * 60 * 60 * 1000, // 1 week
|
|
1486
|
+
* userBucketingKey: 'userId'
|
|
1487
|
+
* };
|
|
1488
|
+
* ```
|
|
1416
1489
|
*/
|
|
1417
1490
|
export interface RolloutConfig<T extends string> {
|
|
1418
|
-
/** Feature flag key */
|
|
1419
1491
|
flagKey: T;
|
|
1420
|
-
/** Starting rollout percentage */
|
|
1421
1492
|
startPercentage: number;
|
|
1422
|
-
/** Ending rollout percentage */
|
|
1423
1493
|
endPercentage: number;
|
|
1424
|
-
/** Duration of rollout */
|
|
1425
1494
|
duration: number;
|
|
1495
|
+
userBucketingKey?: string;
|
|
1426
1496
|
}
|
|
1427
1497
|
/**
|
|
1428
|
-
* Rollout scenario for
|
|
1429
|
-
*
|
|
1430
|
-
*
|
|
1498
|
+
* Rollout scenario for simulating gradual feature deployment.
|
|
1499
|
+
* Provides methods to test time-based rollout strategies.
|
|
1500
|
+
*
|
|
1501
|
+
* @template T - Type of feature flag keys
|
|
1502
|
+
*
|
|
1503
|
+
* @example
|
|
1504
|
+
* ```typescript
|
|
1505
|
+
* const scenario: RolloutScenario<'betaFeature'> = {
|
|
1506
|
+
* config: rolloutConfig,
|
|
1507
|
+
* getCurrentPercentage: () => {
|
|
1508
|
+
* // Calculate based on elapsed time
|
|
1509
|
+
* return Math.min(100, elapsedTime / duration * 100);
|
|
1510
|
+
* },
|
|
1511
|
+
* advanceTime: (ms) => {
|
|
1512
|
+
* currentTime += ms;
|
|
1513
|
+
* },
|
|
1514
|
+
* isUserEnabled: (userId) => {
|
|
1515
|
+
* const hash = hashUserId(userId);
|
|
1516
|
+
* return hash % 100 < getCurrentPercentage();
|
|
1517
|
+
* },
|
|
1518
|
+
* reset: () => {
|
|
1519
|
+
* currentTime = 0;
|
|
1520
|
+
* }
|
|
1521
|
+
* };
|
|
1522
|
+
* ```
|
|
1431
1523
|
*/
|
|
1432
1524
|
export interface RolloutScenario<T extends string> {
|
|
1433
|
-
/** Rollout configuration */
|
|
1434
1525
|
config: RolloutConfig<T>;
|
|
1435
|
-
/** Get current percentage */
|
|
1436
1526
|
getCurrentPercentage: () => number;
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
isEnabledForUser: (userId: string) => boolean;
|
|
1527
|
+
advanceTime: (ms: number) => void;
|
|
1528
|
+
isUserEnabled: (userId: string) => boolean;
|
|
1529
|
+
reset: () => void;
|
|
1441
1530
|
}
|
|
1442
1531
|
/**
|
|
1443
|
-
* A/B
|
|
1444
|
-
*
|
|
1445
|
-
*
|
|
1532
|
+
* Configuration for A/B testing experiments.
|
|
1533
|
+
* Defines variants, traffic allocation, and segmentation rules.
|
|
1534
|
+
*
|
|
1535
|
+
* @template T - Type of feature flag keys
|
|
1536
|
+
*
|
|
1537
|
+
* @example
|
|
1538
|
+
* ```typescript
|
|
1539
|
+
* const abTestConfig: ABTestConfig<'checkoutFlow'> = {
|
|
1540
|
+
* flagKey: 'checkoutFlow',
|
|
1541
|
+
* variants: {
|
|
1542
|
+
* control: 'oldCheckout',
|
|
1543
|
+
* treatment: 'newCheckout'
|
|
1544
|
+
* },
|
|
1545
|
+
* trafficAllocation: {
|
|
1546
|
+
* control: 50,
|
|
1547
|
+
* treatment: 50
|
|
1548
|
+
* },
|
|
1549
|
+
* userBucketingKey: 'userId',
|
|
1550
|
+
* segmentationRules: [
|
|
1551
|
+
* {
|
|
1552
|
+
* attribute: 'country',
|
|
1553
|
+
* operator: 'equals',
|
|
1554
|
+
* value: 'US',
|
|
1555
|
+
* variant: 'treatment'
|
|
1556
|
+
* }
|
|
1557
|
+
* ]
|
|
1558
|
+
* };
|
|
1559
|
+
* ```
|
|
1446
1560
|
*/
|
|
1447
1561
|
export interface ABTestConfig<T extends string> {
|
|
1448
|
-
/** Feature flag key */
|
|
1449
1562
|
flagKey: T;
|
|
1450
|
-
/** Test variants */
|
|
1451
1563
|
variants: {
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
/** Variant percentage */
|
|
1455
|
-
percentage: number;
|
|
1456
|
-
/** Variant value */
|
|
1457
|
-
value: FeatureFlagValue;
|
|
1458
|
-
};
|
|
1459
|
-
/** Variant B configuration */
|
|
1460
|
-
B: {
|
|
1461
|
-
/** Variant percentage */
|
|
1462
|
-
percentage: number;
|
|
1463
|
-
/** Variant value */
|
|
1464
|
-
value: FeatureFlagValue;
|
|
1465
|
-
};
|
|
1564
|
+
control: FeatureFlagValue;
|
|
1565
|
+
treatment: FeatureFlagValue;
|
|
1466
1566
|
};
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
audience?: {
|
|
1471
|
-
/** Include criteria */
|
|
1472
|
-
include?: string[];
|
|
1473
|
-
/** Exclude criteria */
|
|
1474
|
-
exclude?: string[];
|
|
1567
|
+
trafficAllocation: {
|
|
1568
|
+
control: number;
|
|
1569
|
+
treatment: number;
|
|
1475
1570
|
};
|
|
1571
|
+
userBucketingKey?: string;
|
|
1572
|
+
segmentationRules?: Array<{
|
|
1573
|
+
attribute: string;
|
|
1574
|
+
operator: 'equals' | 'contains' | 'in';
|
|
1575
|
+
value: unknown;
|
|
1576
|
+
variant: 'control' | 'treatment';
|
|
1577
|
+
}>;
|
|
1476
1578
|
}
|
|
1477
1579
|
/**
|
|
1478
|
-
* A/B test scenario for testing
|
|
1479
|
-
*
|
|
1480
|
-
*
|
|
1580
|
+
* A/B test scenario for simulating split testing experiments.
|
|
1581
|
+
* Provides methods to determine user variants and analyze traffic distribution.
|
|
1582
|
+
*
|
|
1583
|
+
* @template T - Type of feature flag keys
|
|
1584
|
+
*
|
|
1585
|
+
* @example
|
|
1586
|
+
* ```typescript
|
|
1587
|
+
* const abTest: CreateABTestScenario<'pricing'> = {
|
|
1588
|
+
* config: abTestConfig,
|
|
1589
|
+
* getVariantForUser: (userId, attributes) => {
|
|
1590
|
+
* // Check segmentation rules first
|
|
1591
|
+
* for (const rule of config.segmentationRules || []) {
|
|
1592
|
+
* if (evaluateRule(rule, attributes)) {
|
|
1593
|
+
* return config.variants[rule.variant];
|
|
1594
|
+
* }
|
|
1595
|
+
* }
|
|
1596
|
+
* // Default to traffic allocation
|
|
1597
|
+
* const hash = hashUserId(userId);
|
|
1598
|
+
* return hash % 100 < config.trafficAllocation.control
|
|
1599
|
+
* ? config.variants.control
|
|
1600
|
+
* : config.variants.treatment;
|
|
1601
|
+
* },
|
|
1602
|
+
* getTrafficDistribution: () => ({
|
|
1603
|
+
* control: config.trafficAllocation.control,
|
|
1604
|
+
* treatment: config.trafficAllocation.treatment
|
|
1605
|
+
* }),
|
|
1606
|
+
* reset: () => {
|
|
1607
|
+
* // Reset any cached results
|
|
1608
|
+
* }
|
|
1609
|
+
* };
|
|
1610
|
+
* ```
|
|
1481
1611
|
*/
|
|
1482
1612
|
export interface CreateABTestScenario<T extends string> {
|
|
1483
1613
|
/** A/B test configuration */
|
|
1484
1614
|
config: ABTestConfig<T>;
|
|
1485
1615
|
/** Get variant for user */
|
|
1486
1616
|
getVariantForUser: (userId: string, attributes?: Record<string, unknown>) => FeatureFlagValue;
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
A: {
|
|
1491
|
-
count: number;
|
|
1492
|
-
percentage: number;
|
|
1493
|
-
};
|
|
1494
|
-
/** Variant B statistics */
|
|
1495
|
-
B: {
|
|
1496
|
-
count: number;
|
|
1497
|
-
percentage: number;
|
|
1498
|
-
};
|
|
1617
|
+
getTrafficDistribution: () => {
|
|
1618
|
+
control: number;
|
|
1619
|
+
treatment: number;
|
|
1499
1620
|
};
|
|
1500
1621
|
/** Reset test state */
|
|
1501
1622
|
reset: () => void;
|
package/package.json
CHANGED