@replanejs/test-suite 0.8.19 → 0.9.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/index.cjs +109 -174
- package/dist/index.d.cts +4 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +110 -175
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { afterAll, afterEach, beforeAll, describe, expect, it } from "vitest";
|
|
2
2
|
import { ReplaneAdmin } from "@replanejs/admin";
|
|
3
|
-
import { ReplaneError, ReplaneErrorCode
|
|
3
|
+
import { Replane, ReplaneError, ReplaneErrorCode } from "@replanejs/sdk";
|
|
4
4
|
|
|
5
5
|
//#region src/utils.ts
|
|
6
6
|
/**
|
|
@@ -209,15 +209,17 @@ function createTestContext(admin, workspaceId, projectId, environmentId, sdkKey,
|
|
|
209
209
|
sync,
|
|
210
210
|
async createClient(clientOptions) {
|
|
211
211
|
await sync();
|
|
212
|
-
|
|
212
|
+
const client = new Replane({
|
|
213
|
+
logger: options.debug ? console : silentLogger,
|
|
214
|
+
context: clientOptions?.context,
|
|
215
|
+
defaults: clientOptions?.defaults
|
|
216
|
+
});
|
|
217
|
+
await client.connect({
|
|
213
218
|
sdkKey,
|
|
214
219
|
baseUrl: options.edgeApiBaseUrl,
|
|
215
|
-
|
|
216
|
-
initializationTimeoutMs: defaultTimeout,
|
|
217
|
-
context: clientOptions?.context,
|
|
218
|
-
defaults: clientOptions?.defaults,
|
|
219
|
-
required: clientOptions?.required
|
|
220
|
+
connectTimeoutMs: defaultTimeout
|
|
220
221
|
});
|
|
222
|
+
return client;
|
|
221
223
|
},
|
|
222
224
|
async createConfig(name, value, configOptions) {
|
|
223
225
|
await admin.configs.create({
|
|
@@ -225,7 +227,6 @@ function createTestContext(admin, workspaceId, projectId, environmentId, sdkKey,
|
|
|
225
227
|
name,
|
|
226
228
|
description: configOptions?.description ?? "",
|
|
227
229
|
editors: [],
|
|
228
|
-
maintainers: [],
|
|
229
230
|
base: {
|
|
230
231
|
value,
|
|
231
232
|
schema: null,
|
|
@@ -317,7 +318,7 @@ function testSuite(options) {
|
|
|
317
318
|
});
|
|
318
319
|
afterAll(async () => {
|
|
319
320
|
for (const client of activeClients) try {
|
|
320
|
-
client.
|
|
321
|
+
client.disconnect();
|
|
321
322
|
} catch {}
|
|
322
323
|
activeClients.length = 0;
|
|
323
324
|
if (workspaceId) await admin.workspaces.delete({ workspaceId });
|
|
@@ -340,10 +341,10 @@ function testSuite(options) {
|
|
|
340
341
|
describe("SDK Connection", () => {
|
|
341
342
|
it("should connect and receive initial configs", async () => {
|
|
342
343
|
await ctx.createConfig("test-config", "initial-value");
|
|
343
|
-
const client = trackClient(await ctx.createClient({
|
|
344
|
+
const client = trackClient(await ctx.createClient({}));
|
|
344
345
|
const value = client.get("test-config");
|
|
345
346
|
expect(value).toBe("initial-value");
|
|
346
|
-
client.
|
|
347
|
+
client.disconnect();
|
|
347
348
|
});
|
|
348
349
|
it("should handle empty project (no configs)", async () => {
|
|
349
350
|
const emptyProjectRes = await admin.projects.create({
|
|
@@ -362,51 +363,49 @@ function testSuite(options) {
|
|
|
362
363
|
edgeApiBaseUrl,
|
|
363
364
|
sdkKey
|
|
364
365
|
});
|
|
365
|
-
const
|
|
366
|
+
const emptyClient = new Replane({ logger: silentLogger });
|
|
367
|
+
await emptyClient.connect({
|
|
366
368
|
sdkKey: emptySdkKeyRes.key,
|
|
367
369
|
baseUrl: edgeApiBaseUrl,
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
370
|
+
connectTimeoutMs: defaultTimeout
|
|
371
|
+
});
|
|
372
|
+
const client = trackClient(emptyClient);
|
|
371
373
|
expect(() => client.get("nonexistent")).toThrow();
|
|
372
|
-
client.
|
|
374
|
+
client.disconnect();
|
|
373
375
|
await admin.projects.delete({ projectId: emptyProjectRes.id });
|
|
374
376
|
});
|
|
375
377
|
it("should use default values when config not found", async () => {
|
|
376
378
|
const client = trackClient(await ctx.createClient({ defaults: { "missing-config": "default-value" } }));
|
|
377
379
|
const value = client.get("missing-config");
|
|
378
380
|
expect(value).toBe("default-value");
|
|
379
|
-
client.
|
|
380
|
-
});
|
|
381
|
-
it("should throw when required config is missing", { timeout: 15e3 }, async () => {
|
|
382
|
-
await expect(ctx.createClient({ required: ["definitely-missing-config"] })).rejects.toThrow();
|
|
381
|
+
client.disconnect();
|
|
383
382
|
});
|
|
384
383
|
});
|
|
385
384
|
describe("Get Config", () => {
|
|
386
385
|
it("should get string config", async () => {
|
|
387
386
|
await ctx.createConfig("string-config", "hello");
|
|
388
|
-
const client = trackClient(await ctx.createClient({
|
|
387
|
+
const client = trackClient(await ctx.createClient({}));
|
|
389
388
|
expect(client.get("string-config")).toBe("hello");
|
|
390
|
-
client.
|
|
389
|
+
client.disconnect();
|
|
391
390
|
});
|
|
392
391
|
it("should get number config", async () => {
|
|
393
392
|
await ctx.createConfig("number-config", 42);
|
|
394
|
-
const client = trackClient(await ctx.createClient({
|
|
393
|
+
const client = trackClient(await ctx.createClient({}));
|
|
395
394
|
expect(client.get("number-config")).toBe(42);
|
|
396
|
-
client.
|
|
395
|
+
client.disconnect();
|
|
397
396
|
});
|
|
398
397
|
it("should get boolean config", async () => {
|
|
399
398
|
await ctx.createConfig("boolean-config", true);
|
|
400
|
-
const client = trackClient(await ctx.createClient({
|
|
399
|
+
const client = trackClient(await ctx.createClient({}));
|
|
401
400
|
expect(client.get("boolean-config")).toBe(true);
|
|
402
|
-
client.
|
|
401
|
+
client.disconnect();
|
|
403
402
|
});
|
|
404
403
|
it("should get object config", async () => {
|
|
405
404
|
const objValue = { nested: { value: "deep" } };
|
|
406
405
|
await ctx.createConfig("object-config", objValue);
|
|
407
|
-
const client = trackClient(await ctx.createClient({
|
|
406
|
+
const client = trackClient(await ctx.createClient({}));
|
|
408
407
|
expect(client.get("object-config")).toEqual(objValue);
|
|
409
|
-
client.
|
|
408
|
+
client.disconnect();
|
|
410
409
|
});
|
|
411
410
|
it("should get array config", async () => {
|
|
412
411
|
const arrValue = [
|
|
@@ -415,21 +414,21 @@ function testSuite(options) {
|
|
|
415
414
|
3
|
|
416
415
|
];
|
|
417
416
|
await ctx.createConfig("array-config", arrValue);
|
|
418
|
-
const client = trackClient(await ctx.createClient({
|
|
417
|
+
const client = trackClient(await ctx.createClient({}));
|
|
419
418
|
expect(client.get("array-config")).toEqual(arrValue);
|
|
420
|
-
client.
|
|
419
|
+
client.disconnect();
|
|
421
420
|
});
|
|
422
421
|
it("should get null config", async () => {
|
|
423
422
|
await ctx.createConfig("null-config", null);
|
|
424
|
-
const client = trackClient(await ctx.createClient({
|
|
423
|
+
const client = trackClient(await ctx.createClient({}));
|
|
425
424
|
expect(client.get("null-config")).toBe(null);
|
|
426
|
-
client.
|
|
425
|
+
client.disconnect();
|
|
427
426
|
});
|
|
428
427
|
it("should return default value when config not found", async () => {
|
|
429
428
|
const client = trackClient(await ctx.createClient());
|
|
430
429
|
const value = client.get("nonexistent", { default: "fallback" });
|
|
431
430
|
expect(value).toBe("fallback");
|
|
432
|
-
client.
|
|
431
|
+
client.disconnect();
|
|
433
432
|
});
|
|
434
433
|
it("should throw ReplaneError when config not found and no default", async () => {
|
|
435
434
|
const client = trackClient(await ctx.createClient());
|
|
@@ -440,13 +439,13 @@ function testSuite(options) {
|
|
|
440
439
|
expect(error).toBeInstanceOf(ReplaneError);
|
|
441
440
|
expect(error.code).toBe(ReplaneErrorCode.NotFound);
|
|
442
441
|
}
|
|
443
|
-
client.
|
|
442
|
+
client.disconnect();
|
|
444
443
|
});
|
|
445
444
|
});
|
|
446
445
|
describe("Real-time Updates", () => {
|
|
447
446
|
it("should receive config updates via subscription", async () => {
|
|
448
447
|
await ctx.createConfig("live-config", "initial");
|
|
449
|
-
const client = trackClient(await ctx.createClient({
|
|
448
|
+
const client = trackClient(await ctx.createClient({}));
|
|
450
449
|
expect(client.get("live-config")).toBe("initial");
|
|
451
450
|
const updateSignal = createSignal();
|
|
452
451
|
client.subscribe("live-config", (config) => {
|
|
@@ -456,11 +455,11 @@ function testSuite(options) {
|
|
|
456
455
|
const newValue = await updateSignal.wait({ timeout: defaultTimeout });
|
|
457
456
|
expect(newValue).toBe("updated");
|
|
458
457
|
expect(client.get("live-config")).toBe("updated");
|
|
459
|
-
client.
|
|
458
|
+
client.disconnect();
|
|
460
459
|
});
|
|
461
460
|
it("should receive multiple updates in order", async () => {
|
|
462
461
|
await ctx.createConfig("multi-update-config", 0);
|
|
463
|
-
const client = trackClient(await ctx.createClient({
|
|
462
|
+
const client = trackClient(await ctx.createClient({}));
|
|
464
463
|
expect(client.get("multi-update-config")).toBe(0);
|
|
465
464
|
const collector = createCollector();
|
|
466
465
|
client.subscribe("multi-update-config", (config) => {
|
|
@@ -478,11 +477,11 @@ function testSuite(options) {
|
|
|
478
477
|
2,
|
|
479
478
|
3
|
|
480
479
|
]);
|
|
481
|
-
client.
|
|
480
|
+
client.disconnect();
|
|
482
481
|
});
|
|
483
482
|
it("should handle rapid updates", async () => {
|
|
484
483
|
await ctx.createConfig("rapid-config", 0);
|
|
485
|
-
const client = trackClient(await ctx.createClient({
|
|
484
|
+
const client = trackClient(await ctx.createClient({}));
|
|
486
485
|
expect(client.get("rapid-config")).toBe(0);
|
|
487
486
|
const collector = createCollector();
|
|
488
487
|
client.subscribe("rapid-config", (config) => {
|
|
@@ -492,12 +491,12 @@ function testSuite(options) {
|
|
|
492
491
|
for (let i = 1; i <= updateCount; i++) await ctx.updateConfig("rapid-config", i);
|
|
493
492
|
await collector.waitFor((v) => v === updateCount, { timeout: defaultTimeout });
|
|
494
493
|
expect(client.get("rapid-config")).toBe(updateCount);
|
|
495
|
-
client.
|
|
494
|
+
client.disconnect();
|
|
496
495
|
});
|
|
497
496
|
it("should call global subscription for any config change", async () => {
|
|
498
497
|
await ctx.createConfig("config-a", "a");
|
|
499
498
|
await ctx.createConfig("config-b", "b");
|
|
500
|
-
const client = trackClient(await ctx.createClient({
|
|
499
|
+
const client = trackClient(await ctx.createClient({}));
|
|
501
500
|
expect(client.get("config-a")).toBe("a");
|
|
502
501
|
expect(client.get("config-b")).toBe("b");
|
|
503
502
|
const collector = createCollector();
|
|
@@ -515,11 +514,11 @@ function testSuite(options) {
|
|
|
515
514
|
const bUpdate = values.find((v) => v.name === "config-b");
|
|
516
515
|
expect(aUpdate?.value).toBe("a-updated");
|
|
517
516
|
expect(bUpdate?.value).toBe("b-updated");
|
|
518
|
-
client.
|
|
517
|
+
client.disconnect();
|
|
519
518
|
});
|
|
520
519
|
it("should allow unsubscribing", async () => {
|
|
521
520
|
await ctx.createConfig("unsub-config", "initial");
|
|
522
|
-
const client = trackClient(await ctx.createClient({
|
|
521
|
+
const client = trackClient(await ctx.createClient({}));
|
|
523
522
|
expect(client.get("unsub-config")).toBe("initial");
|
|
524
523
|
const collector = createCollector();
|
|
525
524
|
const unsubscribe = client.subscribe("unsub-config", (config) => {
|
|
@@ -531,7 +530,7 @@ function testSuite(options) {
|
|
|
531
530
|
await ctx.updateConfig("unsub-config", "update-2");
|
|
532
531
|
await delay(2e3);
|
|
533
532
|
expect(collector.count()).toBe(1);
|
|
534
|
-
client.
|
|
533
|
+
client.disconnect();
|
|
535
534
|
});
|
|
536
535
|
});
|
|
537
536
|
describe("Override Evaluation", () => {
|
|
@@ -545,21 +544,15 @@ function testSuite(options) {
|
|
|
545
544
|
}],
|
|
546
545
|
value: "production-value"
|
|
547
546
|
}] });
|
|
548
|
-
const client1 = trackClient(await ctx.createClient({
|
|
547
|
+
const client1 = trackClient(await ctx.createClient({}));
|
|
549
548
|
expect(client1.get("env-config")).toBe("default");
|
|
550
|
-
client1.
|
|
551
|
-
const client2 = trackClient(await ctx.createClient({
|
|
552
|
-
context: { env: "production" },
|
|
553
|
-
required: ["env-config"]
|
|
554
|
-
}));
|
|
549
|
+
client1.disconnect();
|
|
550
|
+
const client2 = trackClient(await ctx.createClient({ context: { env: "production" } }));
|
|
555
551
|
expect(client2.get("env-config")).toBe("production-value");
|
|
556
|
-
client2.
|
|
557
|
-
const client3 = trackClient(await ctx.createClient({
|
|
558
|
-
context: { env: "staging" },
|
|
559
|
-
required: ["env-config"]
|
|
560
|
-
}));
|
|
552
|
+
client2.disconnect();
|
|
553
|
+
const client3 = trackClient(await ctx.createClient({ context: { env: "staging" } }));
|
|
561
554
|
expect(client3.get("env-config")).toBe("default");
|
|
562
|
-
client3.
|
|
555
|
+
client3.disconnect();
|
|
563
556
|
});
|
|
564
557
|
it("should evaluate in condition", async () => {
|
|
565
558
|
await ctx.createConfig("region-config", "default", { overrides: [{
|
|
@@ -571,24 +564,15 @@ function testSuite(options) {
|
|
|
571
564
|
}],
|
|
572
565
|
value: "western"
|
|
573
566
|
}] });
|
|
574
|
-
const client1 = trackClient(await ctx.createClient({
|
|
575
|
-
context: { region: "us" },
|
|
576
|
-
required: ["region-config"]
|
|
577
|
-
}));
|
|
567
|
+
const client1 = trackClient(await ctx.createClient({ context: { region: "us" } }));
|
|
578
568
|
expect(client1.get("region-config")).toBe("western");
|
|
579
|
-
client1.
|
|
580
|
-
const client2 = trackClient(await ctx.createClient({
|
|
581
|
-
context: { region: "eu" },
|
|
582
|
-
required: ["region-config"]
|
|
583
|
-
}));
|
|
569
|
+
client1.disconnect();
|
|
570
|
+
const client2 = trackClient(await ctx.createClient({ context: { region: "eu" } }));
|
|
584
571
|
expect(client2.get("region-config")).toBe("western");
|
|
585
|
-
client2.
|
|
586
|
-
const client3 = trackClient(await ctx.createClient({
|
|
587
|
-
context: { region: "asia" },
|
|
588
|
-
required: ["region-config"]
|
|
589
|
-
}));
|
|
572
|
+
client2.disconnect();
|
|
573
|
+
const client3 = trackClient(await ctx.createClient({ context: { region: "asia" } }));
|
|
590
574
|
expect(client3.get("region-config")).toBe("default");
|
|
591
|
-
client3.
|
|
575
|
+
client3.disconnect();
|
|
592
576
|
});
|
|
593
577
|
it("should evaluate not_in condition", async () => {
|
|
594
578
|
await ctx.createConfig("allow-config", "allowed", { overrides: [{
|
|
@@ -600,18 +584,12 @@ function testSuite(options) {
|
|
|
600
584
|
}],
|
|
601
585
|
value: "not-blocked"
|
|
602
586
|
}] });
|
|
603
|
-
const client1 = trackClient(await ctx.createClient({
|
|
604
|
-
context: { country: "blocked1" },
|
|
605
|
-
required: ["allow-config"]
|
|
606
|
-
}));
|
|
587
|
+
const client1 = trackClient(await ctx.createClient({ context: { country: "blocked1" } }));
|
|
607
588
|
expect(client1.get("allow-config")).toBe("allowed");
|
|
608
|
-
client1.
|
|
609
|
-
const client2 = trackClient(await ctx.createClient({
|
|
610
|
-
context: { country: "normal" },
|
|
611
|
-
required: ["allow-config"]
|
|
612
|
-
}));
|
|
589
|
+
client1.disconnect();
|
|
590
|
+
const client2 = trackClient(await ctx.createClient({ context: { country: "normal" } }));
|
|
613
591
|
expect(client2.get("allow-config")).toBe("not-blocked");
|
|
614
|
-
client2.
|
|
592
|
+
client2.disconnect();
|
|
615
593
|
});
|
|
616
594
|
it("should evaluate numeric comparison conditions", async () => {
|
|
617
595
|
await ctx.createConfig("tier-config", "free", { overrides: [{
|
|
@@ -623,24 +601,15 @@ function testSuite(options) {
|
|
|
623
601
|
}],
|
|
624
602
|
value: "premium"
|
|
625
603
|
}] });
|
|
626
|
-
const client1 = trackClient(await ctx.createClient({
|
|
627
|
-
context: { level: 5 },
|
|
628
|
-
required: ["tier-config"]
|
|
629
|
-
}));
|
|
604
|
+
const client1 = trackClient(await ctx.createClient({ context: { level: 5 } }));
|
|
630
605
|
expect(client1.get("tier-config")).toBe("free");
|
|
631
|
-
client1.
|
|
632
|
-
const client2 = trackClient(await ctx.createClient({
|
|
633
|
-
context: { level: 10 },
|
|
634
|
-
required: ["tier-config"]
|
|
635
|
-
}));
|
|
606
|
+
client1.disconnect();
|
|
607
|
+
const client2 = trackClient(await ctx.createClient({ context: { level: 10 } }));
|
|
636
608
|
expect(client2.get("tier-config")).toBe("premium");
|
|
637
|
-
client2.
|
|
638
|
-
const client3 = trackClient(await ctx.createClient({
|
|
639
|
-
context: { level: 15 },
|
|
640
|
-
required: ["tier-config"]
|
|
641
|
-
}));
|
|
609
|
+
client2.disconnect();
|
|
610
|
+
const client3 = trackClient(await ctx.createClient({ context: { level: 15 } }));
|
|
642
611
|
expect(client3.get("tier-config")).toBe("premium");
|
|
643
|
-
client3.
|
|
612
|
+
client3.disconnect();
|
|
644
613
|
});
|
|
645
614
|
it("should evaluate and condition", async () => {
|
|
646
615
|
await ctx.createConfig("combo-config", "default", { overrides: [{
|
|
@@ -659,24 +628,18 @@ function testSuite(options) {
|
|
|
659
628
|
}],
|
|
660
629
|
value: "enterprise-verified"
|
|
661
630
|
}] });
|
|
662
|
-
const client1 = trackClient(await ctx.createClient({
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
},
|
|
667
|
-
required: ["combo-config"]
|
|
668
|
-
}));
|
|
631
|
+
const client1 = trackClient(await ctx.createClient({ context: {
|
|
632
|
+
plan: "enterprise",
|
|
633
|
+
verified: true
|
|
634
|
+
} }));
|
|
669
635
|
expect(client1.get("combo-config")).toBe("enterprise-verified");
|
|
670
|
-
client1.
|
|
671
|
-
const client2 = trackClient(await ctx.createClient({
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
},
|
|
676
|
-
required: ["combo-config"]
|
|
677
|
-
}));
|
|
636
|
+
client1.disconnect();
|
|
637
|
+
const client2 = trackClient(await ctx.createClient({ context: {
|
|
638
|
+
plan: "enterprise",
|
|
639
|
+
verified: false
|
|
640
|
+
} }));
|
|
678
641
|
expect(client2.get("combo-config")).toBe("default");
|
|
679
|
-
client2.
|
|
642
|
+
client2.disconnect();
|
|
680
643
|
});
|
|
681
644
|
it("should evaluate or condition", async () => {
|
|
682
645
|
await ctx.createConfig("either-config", "default", { overrides: [{
|
|
@@ -695,24 +658,15 @@ function testSuite(options) {
|
|
|
695
658
|
}],
|
|
696
659
|
value: "privileged"
|
|
697
660
|
}] });
|
|
698
|
-
const client1 = trackClient(await ctx.createClient({
|
|
699
|
-
context: { role: "admin" },
|
|
700
|
-
required: ["either-config"]
|
|
701
|
-
}));
|
|
661
|
+
const client1 = trackClient(await ctx.createClient({ context: { role: "admin" } }));
|
|
702
662
|
expect(client1.get("either-config")).toBe("privileged");
|
|
703
|
-
client1.
|
|
704
|
-
const client2 = trackClient(await ctx.createClient({
|
|
705
|
-
context: { role: "superadmin" },
|
|
706
|
-
required: ["either-config"]
|
|
707
|
-
}));
|
|
663
|
+
client1.disconnect();
|
|
664
|
+
const client2 = trackClient(await ctx.createClient({ context: { role: "superadmin" } }));
|
|
708
665
|
expect(client2.get("either-config")).toBe("privileged");
|
|
709
|
-
client2.
|
|
710
|
-
const client3 = trackClient(await ctx.createClient({
|
|
711
|
-
context: { role: "user" },
|
|
712
|
-
required: ["either-config"]
|
|
713
|
-
}));
|
|
666
|
+
client2.disconnect();
|
|
667
|
+
const client3 = trackClient(await ctx.createClient({ context: { role: "user" } }));
|
|
714
668
|
expect(client3.get("either-config")).toBe("default");
|
|
715
|
-
client3.
|
|
669
|
+
client3.disconnect();
|
|
716
670
|
});
|
|
717
671
|
it("should allow per-request context override", async () => {
|
|
718
672
|
await ctx.createConfig("dynamic-config", "default", { overrides: [{
|
|
@@ -724,11 +678,11 @@ function testSuite(options) {
|
|
|
724
678
|
}],
|
|
725
679
|
value: "feature-on"
|
|
726
680
|
}] });
|
|
727
|
-
const client = trackClient(await ctx.createClient({
|
|
681
|
+
const client = trackClient(await ctx.createClient({}));
|
|
728
682
|
expect(client.get("dynamic-config")).toBe("default");
|
|
729
683
|
expect(client.get("dynamic-config", { context: { feature: "enabled" } })).toBe("feature-on");
|
|
730
684
|
expect(client.get("dynamic-config")).toBe("default");
|
|
731
|
-
client.
|
|
685
|
+
client.disconnect();
|
|
732
686
|
});
|
|
733
687
|
it("should apply first matching override", async () => {
|
|
734
688
|
await ctx.createConfig("priority-config", "default", { overrides: [
|
|
@@ -760,22 +714,19 @@ function testSuite(options) {
|
|
|
760
714
|
value: "has-score"
|
|
761
715
|
}
|
|
762
716
|
] });
|
|
763
|
-
const client = trackClient(await ctx.createClient({
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
},
|
|
768
|
-
required: ["priority-config"]
|
|
769
|
-
}));
|
|
717
|
+
const client = trackClient(await ctx.createClient({ context: {
|
|
718
|
+
tier: "gold",
|
|
719
|
+
score: 100
|
|
720
|
+
} }));
|
|
770
721
|
expect(client.get("priority-config")).toBe("gold-value");
|
|
771
|
-
client.
|
|
722
|
+
client.disconnect();
|
|
772
723
|
});
|
|
773
724
|
});
|
|
774
725
|
describe("Snapshot", () => {
|
|
775
726
|
it("should create snapshot with current configs", async () => {
|
|
776
727
|
await ctx.createConfig("snap-config-1", "value-1");
|
|
777
728
|
await ctx.createConfig("snap-config-2", "value-2");
|
|
778
|
-
const client = trackClient(await ctx.createClient({
|
|
729
|
+
const client = trackClient(await ctx.createClient({}));
|
|
779
730
|
const snapshot = client.getSnapshot();
|
|
780
731
|
expect(snapshot.configs).toMatchInlineSnapshot(`
|
|
781
732
|
[
|
|
@@ -792,42 +743,32 @@ function testSuite(options) {
|
|
|
792
743
|
]
|
|
793
744
|
`);
|
|
794
745
|
expect(snapshot.configs.map((c) => c.name).sort()).toEqual(["snap-config-1", "snap-config-2"]);
|
|
795
|
-
client.
|
|
796
|
-
});
|
|
797
|
-
it("should include context in snapshot", async () => {
|
|
798
|
-
await ctx.createConfig("ctx-config", "value");
|
|
799
|
-
const client = trackClient(await ctx.createClient({
|
|
800
|
-
context: { userId: "123" },
|
|
801
|
-
required: ["ctx-config"]
|
|
802
|
-
}));
|
|
803
|
-
const snapshot = client.getSnapshot();
|
|
804
|
-
expect(snapshot.context).toEqual({ userId: "123" });
|
|
805
|
-
client.close();
|
|
746
|
+
client.disconnect();
|
|
806
747
|
});
|
|
807
748
|
});
|
|
808
749
|
describe("Error Handling", () => {
|
|
809
750
|
it("should throw on invalid SDK key", async () => {
|
|
810
|
-
|
|
751
|
+
const invalidClient = new Replane({ logger: silentLogger });
|
|
752
|
+
await expect(invalidClient.connect({
|
|
811
753
|
sdkKey: "invalid-key",
|
|
812
754
|
baseUrl: edgeApiBaseUrl,
|
|
813
|
-
|
|
814
|
-
initializationTimeoutMs: 2e3
|
|
755
|
+
connectTimeoutMs: 2e3
|
|
815
756
|
})).rejects.toThrow();
|
|
816
757
|
});
|
|
817
|
-
it("should handle
|
|
758
|
+
it("should handle disconnected client gracefully", async () => {
|
|
818
759
|
await ctx.createConfig("close-test", "value");
|
|
819
|
-
const client = trackClient(await ctx.createClient({
|
|
760
|
+
const client = trackClient(await ctx.createClient({ defaults: { "close-test": "default" } }));
|
|
820
761
|
expect(client.get("close-test")).toBe("value");
|
|
821
|
-
client.
|
|
762
|
+
client.disconnect();
|
|
822
763
|
const cachedValue = client.get("close-test");
|
|
823
764
|
expect(cachedValue).toBe("value");
|
|
824
765
|
});
|
|
825
766
|
it("should timeout on unreachable server", async () => {
|
|
826
|
-
|
|
767
|
+
const unreachableClient = new Replane({ logger: silentLogger });
|
|
768
|
+
await expect(unreachableClient.connect({
|
|
827
769
|
sdkKey: "rp_test",
|
|
828
770
|
baseUrl: "http://localhost:59999",
|
|
829
|
-
|
|
830
|
-
initializationTimeoutMs: 1e3
|
|
771
|
+
connectTimeoutMs: 1e3
|
|
831
772
|
})).rejects.toThrow();
|
|
832
773
|
});
|
|
833
774
|
});
|
|
@@ -842,23 +783,23 @@ function testSuite(options) {
|
|
|
842
783
|
const value = await configSignal.wait({ timeout: defaultTimeout });
|
|
843
784
|
expect(value).toBe("late-value");
|
|
844
785
|
expect(client.get("late-config")).toBe("late-value");
|
|
845
|
-
client.
|
|
786
|
+
client.disconnect();
|
|
846
787
|
});
|
|
847
788
|
it("should ignore config deletion on client", async () => {
|
|
848
789
|
await ctx.createConfig("delete-me", "exists");
|
|
849
|
-
const client = trackClient(await ctx.createClient({
|
|
790
|
+
const client = trackClient(await ctx.createClient({}));
|
|
850
791
|
expect(client.get("delete-me")).toBe("exists");
|
|
851
792
|
await ctx.deleteConfig("delete-me");
|
|
852
793
|
await delay(1e3);
|
|
853
794
|
expect(client.get("delete-me")).toBe("exists");
|
|
854
|
-
client.
|
|
795
|
+
client.disconnect();
|
|
855
796
|
});
|
|
856
797
|
});
|
|
857
798
|
describe("Concurrent Clients", () => {
|
|
858
799
|
it("should handle multiple clients with same SDK key", async () => {
|
|
859
800
|
await ctx.createConfig("shared-config", "initial");
|
|
860
|
-
const client1 = trackClient(await ctx.createClient({
|
|
861
|
-
const client2 = trackClient(await ctx.createClient({
|
|
801
|
+
const client1 = trackClient(await ctx.createClient({}));
|
|
802
|
+
const client2 = trackClient(await ctx.createClient({}));
|
|
862
803
|
expect(client1.get("shared-config")).toBe("initial");
|
|
863
804
|
expect(client2.get("shared-config")).toBe("initial");
|
|
864
805
|
const signal1 = createSignal();
|
|
@@ -873,8 +814,8 @@ function testSuite(options) {
|
|
|
873
814
|
const [v1, v2] = await Promise.all([signal1.wait({ timeout: defaultTimeout }), signal2.wait({ timeout: defaultTimeout })]);
|
|
874
815
|
expect(v1).toBe("updated");
|
|
875
816
|
expect(v2).toBe("updated");
|
|
876
|
-
client1.
|
|
877
|
-
client2.
|
|
817
|
+
client1.disconnect();
|
|
818
|
+
client2.disconnect();
|
|
878
819
|
});
|
|
879
820
|
it("should isolate context between clients", async () => {
|
|
880
821
|
await ctx.createConfig("context-config", "default", { overrides: [{
|
|
@@ -886,18 +827,12 @@ function testSuite(options) {
|
|
|
886
827
|
}],
|
|
887
828
|
value: "prod-value"
|
|
888
829
|
}] });
|
|
889
|
-
const client1 = trackClient(await ctx.createClient({
|
|
890
|
-
|
|
891
|
-
required: ["context-config"]
|
|
892
|
-
}));
|
|
893
|
-
const client2 = trackClient(await ctx.createClient({
|
|
894
|
-
context: { env: "dev" },
|
|
895
|
-
required: ["context-config"]
|
|
896
|
-
}));
|
|
830
|
+
const client1 = trackClient(await ctx.createClient({ context: { env: "prod" } }));
|
|
831
|
+
const client2 = trackClient(await ctx.createClient({ context: { env: "dev" } }));
|
|
897
832
|
expect(client1.get("context-config")).toBe("prod-value");
|
|
898
833
|
expect(client2.get("context-config")).toBe("default");
|
|
899
|
-
client1.
|
|
900
|
-
client2.
|
|
834
|
+
client1.disconnect();
|
|
835
|
+
client2.disconnect();
|
|
901
836
|
});
|
|
902
837
|
});
|
|
903
838
|
});
|