-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathvariant.test.ts
More file actions
121 lines (101 loc) · 5.66 KB
/
variant.test.ts
File metadata and controls
121 lines (101 loc) · 5.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import * as chai from "chai";
import * as chaiAsPromised from "chai-as-promised";
import { FeatureManager, ConfigurationObjectFeatureFlagProvider } from "../";
import { Features, featureFlagsConfigurationObject } from "./sampleVariantFeatureFlags.js";
chai.use(chaiAsPromised);
const expect = chai.expect;
describe("feature variant", () => {
let featureManager: FeatureManager;
before(() => {
const provider = new ConfigurationObjectFeatureFlagProvider(featureFlagsConfigurationObject);
featureManager = new FeatureManager(provider);
});
describe("valid scenarios", () => {
const context = { userId: "Marsha", groups: ["Group1"] };
it("should perform default allocation with disabled feature", async () => {
const variant = await featureManager.getVariant(Features.VariantFeatureDefaultDisabled, context);
expect(variant).not.to.be.undefined;
expect(variant?.name).eq("Small");
expect(variant?.configuration).eq("300px");
});
it("should perform default allocation with enabled feature", async () => {
const variant = await featureManager.getVariant(Features.VariantFeatureDefaultEnabled, context);
expect(variant).not.to.be.undefined;
expect(variant?.name).eq("Medium");
expect(variant?.configuration).deep.eq({ Size: "450px", Color: "Purple" });
});
it("should perform user allocation", async () => {
const variant = await featureManager.getVariant(Features.VariantFeatureUser, context);
expect(variant).not.to.be.undefined;
expect(variant?.name).eq("Small");
expect(variant?.configuration).eq("300px");
});
it("should perform group allocation", async () => {
const variant = await featureManager.getVariant(Features.VariantFeatureGroup, context);
expect(variant).not.to.be.undefined;
expect(variant?.name).eq("Small");
expect(variant?.configuration).eq("300px");
});
it("should perform percentile allocation with seed", async () => {
const variant = await featureManager.getVariant(Features.VariantFeaturePercentileOn, context);
expect(variant).not.to.be.undefined;
expect(variant?.name).eq("Big");
const variant2 = await featureManager.getVariant(Features.VariantFeaturePercentileOff, context);
expect(variant2).to.be.undefined;
});
it("should overwrite enabled status", async () => {
const enabledStatus = await featureManager.isEnabled(Features.VariantFeaturePercentileOn, context);
expect(enabledStatus).to.be.false; // featureFlag.enabled = true, overridden to false by variant `Big`.
});
});
describe("invalid scenarios", () => {
const context = { userId: "Jeff" };
it("should return undefined when no variants are specified", async () => {
const variant = await featureManager.getVariant(Features.VariantFeatureNoVariants, context);
expect(variant).to.be.undefined;
});
it("should return undefined when no allocation is specified", async () => {
const variant = await featureManager.getVariant(Features.VariantFeatureNoAllocation, context);
expect(variant).to.be.undefined;
});
// requires IFeatureFlagProvider to throw an exception on validation
it("should throw exception for invalid StatusOverride value", async () => {
await expect(featureManager.getVariant(Features.VariantFeatureInvalidStatusOverride, context))
.eventually.rejectedWith("Invalid feature flag: VariantFeatureInvalidStatusOverride. Variant 'status_override' must be 'None', 'Enabled', or 'Disabled'.");
});
// requires IFeatureFlagProvider to throw an exception on validation
it("should throw exception for invalid doubles From and To in the Percentile section", async () => {
await expect(featureManager.getVariant(Features.VariantFeatureInvalidFromTo, context))
.eventually.rejectedWith("Invalid feature flag: VariantFeatureInvalidFromTo. Percentile allocation 'from' must be a number between 0 and 100.");
});
});
});
describe("variant assignment with targeting context accessor", () => {
it("should assign variant based on targeting context accessor", async () => {
let userId = "";
let groups: string[] = [];
const testTargetingContextAccessor = {
getTargetingContext: () => {
return { userId: userId, groups: groups };
}
};
const provider = new ConfigurationObjectFeatureFlagProvider(featureFlagsConfigurationObject);
const featureManager = new FeatureManager(provider, {targetingContextAccessor: testTargetingContextAccessor});
userId = "Marsha";
let variant = await featureManager.getVariant(Features.VariantFeatureUser);
expect(variant).not.to.be.undefined;
expect(variant?.name).eq("Small");
userId = "Jeff";
variant = await featureManager.getVariant(Features.VariantFeatureUser);
expect(variant).to.be.undefined;
variant = await featureManager.getVariant(Features.VariantFeatureUser, {userId: "Marsha"}); // targeting id will be overridden
expect(variant).not.to.be.undefined;
expect(variant?.name).eq("Small");
groups = ["Group1"];
variant = await featureManager.getVariant(Features.VariantFeatureGroup);
expect(variant).not.to.be.undefined;
expect(variant?.name).eq("Small");
});
});