@hazeljs/ml 0.2.4 → 0.3.0
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/evaluation/metrics.service.test.js +288 -0
- package/dist/experiments/__tests__/experiment.decorator.test.d.ts +2 -0
- package/dist/experiments/__tests__/experiment.decorator.test.d.ts.map +1 -0
- package/dist/experiments/__tests__/experiment.decorator.test.js +121 -0
- package/dist/experiments/__tests__/experiment.service.test.d.ts +2 -0
- package/dist/experiments/__tests__/experiment.service.test.d.ts.map +1 -0
- package/dist/experiments/__tests__/experiment.service.test.js +460 -0
- package/dist/experiments/experiment.decorator.d.ts +44 -0
- package/dist/experiments/experiment.decorator.d.ts.map +1 -0
- package/dist/experiments/experiment.decorator.js +51 -0
- package/dist/experiments/experiment.service.d.ts +42 -0
- package/dist/experiments/experiment.service.d.ts.map +1 -0
- package/dist/experiments/experiment.service.js +355 -0
- package/dist/experiments/experiment.types.d.ts +60 -0
- package/dist/experiments/experiment.types.d.ts.map +1 -0
- package/dist/experiments/experiment.types.js +5 -0
- package/dist/experiments/index.d.ts +9 -0
- package/dist/experiments/index.d.ts.map +1 -0
- package/dist/experiments/index.js +16 -0
- package/dist/features/__tests__/feature-view.decorator.test.d.ts +2 -0
- package/dist/features/__tests__/feature-view.decorator.test.d.ts.map +1 -0
- package/dist/features/__tests__/feature-view.decorator.test.js +168 -0
- package/dist/features/__tests__/feature.decorator.test.d.ts +2 -0
- package/dist/features/__tests__/feature.decorator.test.d.ts.map +1 -0
- package/dist/features/__tests__/feature.decorator.test.js +167 -0
- package/dist/features/feature-store.service.d.ts +59 -0
- package/dist/features/feature-store.service.d.ts.map +1 -0
- package/dist/features/feature-store.service.js +197 -0
- package/dist/features/feature-view.decorator.d.ts +52 -0
- package/dist/features/feature-view.decorator.d.ts.map +1 -0
- package/dist/features/feature-view.decorator.js +54 -0
- package/dist/features/feature.decorator.d.ts +42 -0
- package/dist/features/feature.decorator.d.ts.map +1 -0
- package/dist/features/feature.decorator.js +49 -0
- package/dist/features/feature.types.d.ts +93 -0
- package/dist/features/feature.types.d.ts.map +1 -0
- package/dist/features/feature.types.js +5 -0
- package/dist/features/index.d.ts +12 -0
- package/dist/features/index.d.ts.map +1 -0
- package/dist/features/index.js +29 -0
- package/dist/features/offline-store.d.ts +40 -0
- package/dist/features/offline-store.d.ts.map +1 -0
- package/dist/features/offline-store.js +215 -0
- package/dist/features/online-store.d.ts +45 -0
- package/dist/features/online-store.d.ts.map +1 -0
- package/dist/features/online-store.js +139 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -1
- package/dist/monitoring/__tests__/drift.service.test.d.ts +2 -0
- package/dist/monitoring/__tests__/drift.service.test.d.ts.map +1 -0
- package/dist/monitoring/__tests__/drift.service.test.js +362 -0
- package/dist/monitoring/__tests__/monitor.service.test.d.ts +2 -0
- package/dist/monitoring/__tests__/monitor.service.test.d.ts.map +1 -0
- package/dist/monitoring/__tests__/monitor.service.test.js +360 -0
- package/dist/monitoring/drift.service.d.ts +68 -0
- package/dist/monitoring/drift.service.d.ts.map +1 -0
- package/dist/monitoring/drift.service.js +360 -0
- package/dist/monitoring/drift.types.d.ts +44 -0
- package/dist/monitoring/drift.types.d.ts.map +1 -0
- package/dist/monitoring/drift.types.js +5 -0
- package/dist/monitoring/index.d.ts +10 -0
- package/dist/monitoring/index.d.ts.map +1 -0
- package/dist/monitoring/index.js +13 -0
- package/dist/monitoring/monitor.service.d.ts +79 -0
- package/dist/monitoring/monitor.service.d.ts.map +1 -0
- package/dist/monitoring/monitor.service.js +192 -0
- package/dist/training/trainer.service.test.js +105 -0
- package/package.json +2 -2
|
@@ -249,5 +249,293 @@ describe('MetricsService', () => {
|
|
|
249
249
|
const result = await svc.evaluate('eval-model', [{ text: 'good', label: 'positive' }]);
|
|
250
250
|
expect(result.version).toBeDefined();
|
|
251
251
|
});
|
|
252
|
+
it('evaluate with precision metric only', async () => {
|
|
253
|
+
const registry = new model_registry_1.ModelRegistry();
|
|
254
|
+
registry.register({
|
|
255
|
+
metadata: { name: 'eval-model', version: '1.0.0', framework: 'custom' },
|
|
256
|
+
instance: new EvalModel(),
|
|
257
|
+
predictMethod: 'predict',
|
|
258
|
+
});
|
|
259
|
+
const predictor = new predictor_service_1.PredictorService(registry);
|
|
260
|
+
const svc = new metrics_service_1.MetricsService(registry, predictor);
|
|
261
|
+
const result = await svc.evaluate('eval-model', [
|
|
262
|
+
{ text: 'good', label: 'positive' },
|
|
263
|
+
{ text: 'bad', label: 'negative' },
|
|
264
|
+
], { metrics: ['precision'] });
|
|
265
|
+
expect(result.metrics.precision).toBeDefined();
|
|
266
|
+
expect(result.metrics.accuracy).toBeUndefined();
|
|
267
|
+
});
|
|
268
|
+
it('evaluate with recall metric only', async () => {
|
|
269
|
+
const registry = new model_registry_1.ModelRegistry();
|
|
270
|
+
registry.register({
|
|
271
|
+
metadata: { name: 'eval-model', version: '1.0.0', framework: 'custom' },
|
|
272
|
+
instance: new EvalModel(),
|
|
273
|
+
predictMethod: 'predict',
|
|
274
|
+
});
|
|
275
|
+
const predictor = new predictor_service_1.PredictorService(registry);
|
|
276
|
+
const svc = new metrics_service_1.MetricsService(registry, predictor);
|
|
277
|
+
const result = await svc.evaluate('eval-model', [
|
|
278
|
+
{ text: 'good', label: 'positive' },
|
|
279
|
+
{ text: 'bad', label: 'negative' },
|
|
280
|
+
], { metrics: ['recall'] });
|
|
281
|
+
expect(result.metrics.recall).toBeDefined();
|
|
282
|
+
expect(result.metrics.accuracy).toBeUndefined();
|
|
283
|
+
});
|
|
284
|
+
it('evaluate with f1 metric only', async () => {
|
|
285
|
+
const registry = new model_registry_1.ModelRegistry();
|
|
286
|
+
registry.register({
|
|
287
|
+
metadata: { name: 'eval-model', version: '1.0.0', framework: 'custom' },
|
|
288
|
+
instance: new EvalModel(),
|
|
289
|
+
predictMethod: 'predict',
|
|
290
|
+
});
|
|
291
|
+
const predictor = new predictor_service_1.PredictorService(registry);
|
|
292
|
+
const svc = new metrics_service_1.MetricsService(registry, predictor);
|
|
293
|
+
const result = await svc.evaluate('eval-model', [
|
|
294
|
+
{ text: 'good', label: 'positive' },
|
|
295
|
+
{ text: 'bad', label: 'negative' },
|
|
296
|
+
], { metrics: ['f1'] });
|
|
297
|
+
expect(result.metrics.f1Score).toBeDefined();
|
|
298
|
+
expect(result.metrics.accuracy).toBeUndefined();
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
describe('getMetrics edge cases', () => {
|
|
302
|
+
it('should return undefined for non-existent model', () => {
|
|
303
|
+
expect(service.getMetrics('non-existent')).toBeUndefined();
|
|
304
|
+
});
|
|
305
|
+
it('should return undefined for non-existent version', () => {
|
|
306
|
+
service.recordEvaluation({
|
|
307
|
+
modelName: 'model',
|
|
308
|
+
version: '1.0.0',
|
|
309
|
+
metrics: { accuracy: 0.9 },
|
|
310
|
+
evaluatedAt: new Date(),
|
|
311
|
+
});
|
|
312
|
+
expect(service.getMetrics('model', '2.0.0')).toBeUndefined();
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
describe('getHistory edge cases', () => {
|
|
316
|
+
it('should return empty array for non-existent model', () => {
|
|
317
|
+
expect(service.getHistory('non-existent')).toEqual([]);
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
describe('compareVersions edge cases', () => {
|
|
321
|
+
it('should return undefined winner when both versions not found', () => {
|
|
322
|
+
const { a, b, winner } = service.compareVersions('model', 'v1', 'v2');
|
|
323
|
+
expect(a).toBeUndefined();
|
|
324
|
+
expect(b).toBeUndefined();
|
|
325
|
+
expect(winner).toBeUndefined();
|
|
326
|
+
});
|
|
327
|
+
it('should return undefined winner when only one version found', () => {
|
|
328
|
+
service.recordEvaluation({
|
|
329
|
+
modelName: 'model',
|
|
330
|
+
version: 'v1',
|
|
331
|
+
metrics: { accuracy: 0.9 },
|
|
332
|
+
evaluatedAt: new Date(),
|
|
333
|
+
});
|
|
334
|
+
const { a, b, winner } = service.compareVersions('model', 'v1', 'v2');
|
|
335
|
+
expect(a).toBeDefined();
|
|
336
|
+
expect(b).toBeUndefined();
|
|
337
|
+
expect(winner).toBeUndefined();
|
|
338
|
+
});
|
|
339
|
+
it('should handle tie in accuracy', () => {
|
|
340
|
+
service.recordEvaluation({
|
|
341
|
+
modelName: 'model',
|
|
342
|
+
version: 'v1',
|
|
343
|
+
metrics: { accuracy: 0.9 },
|
|
344
|
+
evaluatedAt: new Date(),
|
|
345
|
+
});
|
|
346
|
+
service.recordEvaluation({
|
|
347
|
+
modelName: 'model',
|
|
348
|
+
version: 'v2',
|
|
349
|
+
metrics: { accuracy: 0.9 },
|
|
350
|
+
evaluatedAt: new Date(),
|
|
351
|
+
});
|
|
352
|
+
const { winner } = service.compareVersions('model', 'v1', 'v2');
|
|
353
|
+
expect(winner).toBe('v1'); // First one wins in tie
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
describe('evaluate with all metrics', () => {
|
|
357
|
+
let FullModel = class FullModel {
|
|
358
|
+
train() { }
|
|
359
|
+
async predict(input) {
|
|
360
|
+
return { label: input.text.includes('good') ? 'positive' : 'negative' };
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
__decorate([
|
|
364
|
+
(0, decorators_1.Train)(),
|
|
365
|
+
__metadata("design:type", Function),
|
|
366
|
+
__metadata("design:paramtypes", []),
|
|
367
|
+
__metadata("design:returntype", void 0)
|
|
368
|
+
], FullModel.prototype, "train", null);
|
|
369
|
+
__decorate([
|
|
370
|
+
(0, decorators_1.Predict)(),
|
|
371
|
+
__metadata("design:type", Function),
|
|
372
|
+
__metadata("design:paramtypes", [Object]),
|
|
373
|
+
__metadata("design:returntype", Promise)
|
|
374
|
+
], FullModel.prototype, "predict", null);
|
|
375
|
+
FullModel = __decorate([
|
|
376
|
+
(0, decorators_1.Model)({ name: 'full-model', version: '1.0.0', framework: 'custom' })
|
|
377
|
+
], FullModel);
|
|
378
|
+
it('should compute all metrics when requested', async () => {
|
|
379
|
+
const registry = new model_registry_1.ModelRegistry();
|
|
380
|
+
registry.register({
|
|
381
|
+
metadata: { name: 'full-model', version: '1.0.0', framework: 'custom' },
|
|
382
|
+
instance: new FullModel(),
|
|
383
|
+
predictMethod: 'predict',
|
|
384
|
+
});
|
|
385
|
+
const predictor = new predictor_service_1.PredictorService(registry);
|
|
386
|
+
const svc = new metrics_service_1.MetricsService(registry, predictor);
|
|
387
|
+
const result = await svc.evaluate('full-model', [
|
|
388
|
+
{ text: 'good', label: 'positive' },
|
|
389
|
+
{ text: 'bad', label: 'negative' },
|
|
390
|
+
{ text: 'good day', label: 'positive' },
|
|
391
|
+
{ text: 'bad day', label: 'negative' },
|
|
392
|
+
], { metrics: ['accuracy', 'precision', 'recall', 'f1'] });
|
|
393
|
+
expect(result.metrics.accuracy).toBeDefined();
|
|
394
|
+
expect(result.metrics.precision).toBeDefined();
|
|
395
|
+
expect(result.metrics.recall).toBeDefined();
|
|
396
|
+
expect(result.metrics.f1Score).toBeDefined();
|
|
397
|
+
});
|
|
398
|
+
it('should handle mixed correct and incorrect predictions', async () => {
|
|
399
|
+
let MixedModel = class MixedModel {
|
|
400
|
+
train() { }
|
|
401
|
+
async predict(input) {
|
|
402
|
+
return { prediction: input.value > 5 ? 'high' : 'low' };
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
__decorate([
|
|
406
|
+
(0, decorators_1.Train)(),
|
|
407
|
+
__metadata("design:type", Function),
|
|
408
|
+
__metadata("design:paramtypes", []),
|
|
409
|
+
__metadata("design:returntype", void 0)
|
|
410
|
+
], MixedModel.prototype, "train", null);
|
|
411
|
+
__decorate([
|
|
412
|
+
(0, decorators_1.Predict)(),
|
|
413
|
+
__metadata("design:type", Function),
|
|
414
|
+
__metadata("design:paramtypes", [Object]),
|
|
415
|
+
__metadata("design:returntype", Promise)
|
|
416
|
+
], MixedModel.prototype, "predict", null);
|
|
417
|
+
MixedModel = __decorate([
|
|
418
|
+
(0, decorators_1.Model)({ name: 'mixed-model', version: '1.0.0', framework: 'custom' })
|
|
419
|
+
], MixedModel);
|
|
420
|
+
const registry = new model_registry_1.ModelRegistry();
|
|
421
|
+
registry.register({
|
|
422
|
+
metadata: { name: 'mixed-model', version: '1.0.0', framework: 'custom' },
|
|
423
|
+
instance: new MixedModel(),
|
|
424
|
+
predictMethod: 'predict',
|
|
425
|
+
});
|
|
426
|
+
const predictor = new predictor_service_1.PredictorService(registry);
|
|
427
|
+
const svc = new metrics_service_1.MetricsService(registry, predictor);
|
|
428
|
+
const result = await svc.evaluate('mixed-model', [
|
|
429
|
+
{ value: 10, label: 'high' },
|
|
430
|
+
{ value: 2, label: 'low' },
|
|
431
|
+
{ value: 8, label: 'low' }, // Wrong
|
|
432
|
+
{ value: 3, label: 'high' }, // Wrong
|
|
433
|
+
], { labelKey: 'label', predictionKey: 'prediction' });
|
|
434
|
+
expect(result.metrics.accuracy).toBe(0.5);
|
|
435
|
+
});
|
|
436
|
+
it('should calculate precision correctly with false positives', async () => {
|
|
437
|
+
let PrecisionModel = class PrecisionModel {
|
|
438
|
+
train() { }
|
|
439
|
+
async predict() {
|
|
440
|
+
return { result: 'positive' }; // Always predicts positive
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
__decorate([
|
|
444
|
+
(0, decorators_1.Train)(),
|
|
445
|
+
__metadata("design:type", Function),
|
|
446
|
+
__metadata("design:paramtypes", []),
|
|
447
|
+
__metadata("design:returntype", void 0)
|
|
448
|
+
], PrecisionModel.prototype, "train", null);
|
|
449
|
+
__decorate([
|
|
450
|
+
(0, decorators_1.Predict)(),
|
|
451
|
+
__metadata("design:type", Function),
|
|
452
|
+
__metadata("design:paramtypes", []),
|
|
453
|
+
__metadata("design:returntype", Promise)
|
|
454
|
+
], PrecisionModel.prototype, "predict", null);
|
|
455
|
+
PrecisionModel = __decorate([
|
|
456
|
+
(0, decorators_1.Model)({ name: 'precision-model', version: '1.0.0', framework: 'custom' })
|
|
457
|
+
], PrecisionModel);
|
|
458
|
+
const registry = new model_registry_1.ModelRegistry();
|
|
459
|
+
registry.register({
|
|
460
|
+
metadata: { name: 'precision-model', version: '1.0.0', framework: 'custom' },
|
|
461
|
+
instance: new PrecisionModel(),
|
|
462
|
+
predictMethod: 'predict',
|
|
463
|
+
});
|
|
464
|
+
const predictor = new predictor_service_1.PredictorService(registry);
|
|
465
|
+
const svc = new metrics_service_1.MetricsService(registry, predictor);
|
|
466
|
+
const result = await svc.evaluate('precision-model', [
|
|
467
|
+
{ text: 'a', label: 'positive' },
|
|
468
|
+
{ text: 'b', label: 'negative' },
|
|
469
|
+
{ text: 'c', label: 'negative' },
|
|
470
|
+
], { labelKey: 'label', predictionKey: 'result', metrics: ['precision'] });
|
|
471
|
+
expect(result.metrics.precision).toBeLessThan(1);
|
|
472
|
+
});
|
|
473
|
+
it('should calculate recall correctly with false negatives', async () => {
|
|
474
|
+
let RecallModel = class RecallModel {
|
|
475
|
+
train() { }
|
|
476
|
+
async predict() {
|
|
477
|
+
return { result: 'negative' }; // Always predicts negative
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
__decorate([
|
|
481
|
+
(0, decorators_1.Train)(),
|
|
482
|
+
__metadata("design:type", Function),
|
|
483
|
+
__metadata("design:paramtypes", []),
|
|
484
|
+
__metadata("design:returntype", void 0)
|
|
485
|
+
], RecallModel.prototype, "train", null);
|
|
486
|
+
__decorate([
|
|
487
|
+
(0, decorators_1.Predict)(),
|
|
488
|
+
__metadata("design:type", Function),
|
|
489
|
+
__metadata("design:paramtypes", []),
|
|
490
|
+
__metadata("design:returntype", Promise)
|
|
491
|
+
], RecallModel.prototype, "predict", null);
|
|
492
|
+
RecallModel = __decorate([
|
|
493
|
+
(0, decorators_1.Model)({ name: 'recall-model', version: '1.0.0', framework: 'custom' })
|
|
494
|
+
], RecallModel);
|
|
495
|
+
const registry = new model_registry_1.ModelRegistry();
|
|
496
|
+
registry.register({
|
|
497
|
+
metadata: { name: 'recall-model', version: '1.0.0', framework: 'custom' },
|
|
498
|
+
instance: new RecallModel(),
|
|
499
|
+
predictMethod: 'predict',
|
|
500
|
+
});
|
|
501
|
+
const predictor = new predictor_service_1.PredictorService(registry);
|
|
502
|
+
const svc = new metrics_service_1.MetricsService(registry, predictor);
|
|
503
|
+
const result = await svc.evaluate('recall-model', [
|
|
504
|
+
{ text: 'a', label: 'positive' },
|
|
505
|
+
{ text: 'b', label: 'positive' },
|
|
506
|
+
{ text: 'c', label: 'negative' },
|
|
507
|
+
], { labelKey: 'label', predictionKey: 'result', metrics: ['recall'] });
|
|
508
|
+
expect(result.metrics.recall).toBeLessThanOrEqual(1);
|
|
509
|
+
expect(result.metrics.recall).toBeGreaterThanOrEqual(0);
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
describe('recordEvaluation edge cases', () => {
|
|
513
|
+
it('should handle multiple evaluations for same model', () => {
|
|
514
|
+
service.recordEvaluation({
|
|
515
|
+
modelName: 'model',
|
|
516
|
+
version: '1.0.0',
|
|
517
|
+
metrics: { accuracy: 0.9 },
|
|
518
|
+
evaluatedAt: new Date(),
|
|
519
|
+
});
|
|
520
|
+
service.recordEvaluation({
|
|
521
|
+
modelName: 'model',
|
|
522
|
+
version: '1.0.0',
|
|
523
|
+
metrics: { accuracy: 0.95 },
|
|
524
|
+
evaluatedAt: new Date(),
|
|
525
|
+
});
|
|
526
|
+
const history = service.getHistory('model');
|
|
527
|
+
expect(history).toHaveLength(2);
|
|
528
|
+
});
|
|
529
|
+
it('should handle evaluations with custom metrics', () => {
|
|
530
|
+
service.recordEvaluation({
|
|
531
|
+
modelName: 'model',
|
|
532
|
+
version: '1.0.0',
|
|
533
|
+
metrics: { customMetric: 0.85, anotherMetric: 0.92 },
|
|
534
|
+
evaluatedAt: new Date(),
|
|
535
|
+
});
|
|
536
|
+
const metrics = service.getMetrics('model', '1.0.0');
|
|
537
|
+
expect(metrics?.metrics.customMetric).toBe(0.85);
|
|
538
|
+
expect(metrics?.metrics.anotherMetric).toBe(0.92);
|
|
539
|
+
});
|
|
252
540
|
});
|
|
253
541
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"experiment.decorator.test.d.ts","sourceRoot":"","sources":["../../../src/experiments/__tests__/experiment.decorator.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
const experiment_decorator_1 = require("../experiment.decorator");
|
|
10
|
+
describe('Experiment decorator', () => {
|
|
11
|
+
it('should attach metadata to class', () => {
|
|
12
|
+
let TestExperiment = class TestExperiment {
|
|
13
|
+
};
|
|
14
|
+
TestExperiment = __decorate([
|
|
15
|
+
(0, experiment_decorator_1.Experiment)({
|
|
16
|
+
name: 'test-experiment',
|
|
17
|
+
description: 'Test experiment',
|
|
18
|
+
tags: ['test', 'ml'],
|
|
19
|
+
})
|
|
20
|
+
], TestExperiment);
|
|
21
|
+
const metadata = (0, experiment_decorator_1.getExperimentMetadata)(TestExperiment);
|
|
22
|
+
expect(metadata).toBeDefined();
|
|
23
|
+
expect(metadata?.name).toBe('test-experiment');
|
|
24
|
+
expect(metadata?.description).toBe('Test experiment');
|
|
25
|
+
expect(metadata?.tags).toEqual(['test', 'ml']);
|
|
26
|
+
});
|
|
27
|
+
it('should use class name as default experiment name', () => {
|
|
28
|
+
let MyExperiment = class MyExperiment {
|
|
29
|
+
};
|
|
30
|
+
MyExperiment = __decorate([
|
|
31
|
+
(0, experiment_decorator_1.Experiment)()
|
|
32
|
+
], MyExperiment);
|
|
33
|
+
const metadata = (0, experiment_decorator_1.getExperimentMetadata)(MyExperiment);
|
|
34
|
+
expect(metadata?.name).toBe('MyExperiment');
|
|
35
|
+
});
|
|
36
|
+
it('should set default autoLogParams to true', () => {
|
|
37
|
+
let TestExperiment = class TestExperiment {
|
|
38
|
+
};
|
|
39
|
+
TestExperiment = __decorate([
|
|
40
|
+
(0, experiment_decorator_1.Experiment)()
|
|
41
|
+
], TestExperiment);
|
|
42
|
+
const metadata = (0, experiment_decorator_1.getExperimentMetadata)(TestExperiment);
|
|
43
|
+
expect(metadata?.autoLogParams).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
it('should set default autoLogMetrics to true', () => {
|
|
46
|
+
let TestExperiment = class TestExperiment {
|
|
47
|
+
};
|
|
48
|
+
TestExperiment = __decorate([
|
|
49
|
+
(0, experiment_decorator_1.Experiment)()
|
|
50
|
+
], TestExperiment);
|
|
51
|
+
const metadata = (0, experiment_decorator_1.getExperimentMetadata)(TestExperiment);
|
|
52
|
+
expect(metadata?.autoLogMetrics).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
it('should allow disabling autoLogParams', () => {
|
|
55
|
+
let TestExperiment = class TestExperiment {
|
|
56
|
+
};
|
|
57
|
+
TestExperiment = __decorate([
|
|
58
|
+
(0, experiment_decorator_1.Experiment)({ autoLogParams: false })
|
|
59
|
+
], TestExperiment);
|
|
60
|
+
const metadata = (0, experiment_decorator_1.getExperimentMetadata)(TestExperiment);
|
|
61
|
+
expect(metadata?.autoLogParams).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
it('should allow disabling autoLogMetrics', () => {
|
|
64
|
+
let TestExperiment = class TestExperiment {
|
|
65
|
+
};
|
|
66
|
+
TestExperiment = __decorate([
|
|
67
|
+
(0, experiment_decorator_1.Experiment)({ autoLogMetrics: false })
|
|
68
|
+
], TestExperiment);
|
|
69
|
+
const metadata = (0, experiment_decorator_1.getExperimentMetadata)(TestExperiment);
|
|
70
|
+
expect(metadata?.autoLogMetrics).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
it('should handle optional description', () => {
|
|
73
|
+
let TestExperiment = class TestExperiment {
|
|
74
|
+
};
|
|
75
|
+
TestExperiment = __decorate([
|
|
76
|
+
(0, experiment_decorator_1.Experiment)({ name: 'test' })
|
|
77
|
+
], TestExperiment);
|
|
78
|
+
const metadata = (0, experiment_decorator_1.getExperimentMetadata)(TestExperiment);
|
|
79
|
+
expect(metadata?.description).toBeUndefined();
|
|
80
|
+
});
|
|
81
|
+
it('should handle optional tags', () => {
|
|
82
|
+
let TestExperiment = class TestExperiment {
|
|
83
|
+
};
|
|
84
|
+
TestExperiment = __decorate([
|
|
85
|
+
(0, experiment_decorator_1.Experiment)({ name: 'test' })
|
|
86
|
+
], TestExperiment);
|
|
87
|
+
const metadata = (0, experiment_decorator_1.getExperimentMetadata)(TestExperiment);
|
|
88
|
+
expect(metadata?.tags).toBeUndefined();
|
|
89
|
+
});
|
|
90
|
+
it('should handle empty tags array', () => {
|
|
91
|
+
let TestExperiment = class TestExperiment {
|
|
92
|
+
};
|
|
93
|
+
TestExperiment = __decorate([
|
|
94
|
+
(0, experiment_decorator_1.Experiment)({ name: 'test', tags: [] })
|
|
95
|
+
], TestExperiment);
|
|
96
|
+
const metadata = (0, experiment_decorator_1.getExperimentMetadata)(TestExperiment);
|
|
97
|
+
expect(metadata?.tags).toEqual([]);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
describe('hasExperimentMetadata', () => {
|
|
101
|
+
it('should return true for decorated class', () => {
|
|
102
|
+
let TestExperiment = class TestExperiment {
|
|
103
|
+
};
|
|
104
|
+
TestExperiment = __decorate([
|
|
105
|
+
(0, experiment_decorator_1.Experiment)({ name: 'test' })
|
|
106
|
+
], TestExperiment);
|
|
107
|
+
expect((0, experiment_decorator_1.hasExperimentMetadata)(TestExperiment)).toBe(true);
|
|
108
|
+
});
|
|
109
|
+
it('should return false for non-decorated class', () => {
|
|
110
|
+
class TestExperiment {
|
|
111
|
+
}
|
|
112
|
+
expect((0, experiment_decorator_1.hasExperimentMetadata)(TestExperiment)).toBe(false);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
describe('getExperimentMetadata', () => {
|
|
116
|
+
it('should return undefined for non-decorated class', () => {
|
|
117
|
+
class TestExperiment {
|
|
118
|
+
}
|
|
119
|
+
expect((0, experiment_decorator_1.getExperimentMetadata)(TestExperiment)).toBeUndefined();
|
|
120
|
+
});
|
|
121
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"experiment.service.test.d.ts","sourceRoot":"","sources":["../../../src/experiments/__tests__/experiment.service.test.ts"],"names":[],"mappings":""}
|