Skip to content

Commit ca52bf1

Browse files
committed
added evaluation tests
Signed-off-by: jarebudev <[email protected]>
1 parent 1ad0bea commit ca52bf1

File tree

5 files changed

+243
-15
lines changed

5 files changed

+243
-15
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* TestLogger is a logger build for testing purposes.
3+
* This is not ready to be production ready, so please avoid using it.
4+
*/
5+
export default class TestLogger {
6+
public inMemoryLogger: Record<string, string[]> = {
7+
error: [],
8+
warn: [],
9+
info: [],
10+
debug: [],
11+
};
12+
13+
error(...args: unknown[]): void {
14+
this.inMemoryLogger['error'].push(args.join(' '));
15+
}
16+
17+
warn(...args: unknown[]): void {
18+
this.inMemoryLogger['warn'].push(args.join(' '));
19+
}
20+
21+
info(...args: unknown[]): void {
22+
console.log(args)
23+
this.inMemoryLogger['info'].push(args.join(' '));
24+
}
25+
26+
debug(...args: unknown[]): void {
27+
console.log(args)
28+
this.inMemoryLogger['debug'].push(args.join(' '));
29+
}
30+
31+
reset() {
32+
this.inMemoryLogger = {
33+
error: [],
34+
warn: [],
35+
info: [],
36+
debug: [],
37+
};
38+
}
39+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
{
2+
"toggles": [
3+
{
4+
"name": "simpleToggle",
5+
"enabled": true,
6+
"impressionData": true
7+
},
8+
{
9+
"name": "disabledToggle",
10+
"enabled": false,
11+
"impressionData": true
12+
},
13+
{
14+
"name": "variantToggleString",
15+
"enabled": true,
16+
"impressionData": true,
17+
"variant": {
18+
"name": "string",
19+
"payload": {
20+
"type": "string",
21+
"value": "some-text"
22+
},
23+
"enabled": true,
24+
"feature_enabled": true
25+
}
26+
},
27+
{
28+
"name": "variantToggleJson",
29+
"enabled": true,
30+
"impressionData": true,
31+
"variant": {
32+
"name": "json",
33+
"payload": {
34+
"type": "json",
35+
"value": "{hello: world}"
36+
},
37+
"enabled": true,
38+
"feature_enabled": true
39+
}
40+
},
41+
{
42+
"name": "variantToggleCsv",
43+
"enabled": true,
44+
"variant": {
45+
"name": "csv",
46+
"enabled": true,
47+
"payload": {
48+
"type": "csv",
49+
"value": "1,2,3,4"
50+
},
51+
"feature_enabled": true,
52+
"featureEnabled": true
53+
},
54+
"impressionData": false
55+
},
56+
{
57+
"name": "variantToggleInteger",
58+
"enabled": true,
59+
"variant": {
60+
"name": "number",
61+
"enabled": true,
62+
"payload": {
63+
"type": "number",
64+
"value": "3"
65+
},
66+
"feature_enabled": true,
67+
"featureEnabled": true
68+
},
69+
"impressionData": false
70+
},
71+
{
72+
"name": "variantToggleDouble",
73+
"enabled": true,
74+
"variant": {
75+
"name": "number",
76+
"enabled": true,
77+
"payload": {
78+
"type": "number",
79+
"value": "1.2"
80+
},
81+
"feature_enabled": true,
82+
"featureEnabled": true
83+
},
84+
"impressionData": false
85+
}
86+
]
87+
}
Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,111 @@
11
import { UnleashWebProvider } from './unleash-web-provider';
2+
import fetchMock, { enableFetchMocks } from 'jest-fetch-mock';
3+
4+
import testdata from './testdata.json';
5+
import TestLogger from './test-logger';
26

37
describe('UnleashWebProvider', () => {
4-
it('should be and instance of UnleashWebProvider', () => {
5-
expect(new UnleashWebProvider()).toBeInstanceOf(UnleashWebProvider);
8+
const endpoint = 'http://localhost:4242';
9+
const logger = new TestLogger();
10+
const valueProperty = 'value';
11+
12+
let provider: UnleashWebProvider;
13+
14+
beforeEach(() => {
15+
fetchMock.mockClear();
16+
fetchMock.mockReset();
17+
});
18+
19+
beforeAll(async () => {
20+
enableFetchMocks();
21+
//fetchMock.mockResponseOnce(JSON.stringify({"toggles":[]}));
22+
fetchMock.mockResponseOnce(JSON.stringify(testdata));
23+
provider = new UnleashWebProvider({ url: endpoint, clientKey: 'clientsecret', appName: 'test',}, logger);
24+
await provider.initialize();
25+
});
26+
27+
it('should be an instance of UnleashWebProvider', async () => {
28+
expect(provider).toBeInstanceOf(UnleashWebProvider);
29+
});
30+
31+
describe('method resolveBooleanEvaluation', () => {
32+
it('should return false for missing toggle', async () => {
33+
const evaluation = await provider.resolveBooleanEvaluation('nonExistent');
34+
expect(evaluation).toHaveProperty(valueProperty, false);
35+
});
36+
37+
it('should return true if enabled toggle exists', async () => {
38+
const evaluation = await provider.resolveBooleanEvaluation('simpleToggle');
39+
expect(evaluation).toHaveProperty(valueProperty, true);
40+
});
41+
42+
it('should return false if a disabled toggle exists', async () => {
43+
const evaluation = await provider.resolveBooleanEvaluation('disabledToggle');
44+
expect(evaluation).toHaveProperty(valueProperty, false);
45+
});
46+
});
47+
48+
describe('method resolveStringEvaluation', () => {
49+
it('should return default value for missing value', async () => {
50+
const evaluation = await provider.resolveStringEvaluation('nonExistent', 'defaultValue');
51+
expect(evaluation).toHaveProperty(valueProperty, 'defaultValue');
52+
});
53+
54+
it('should return right value if variant toggle exists and is enabled', async () => {
55+
const evaluation = await provider.resolveStringEvaluation('variantToggleString', 'variant1');
56+
expect(evaluation).toHaveProperty(valueProperty, 'some-text');
57+
});
58+
59+
it('should return default value if a toggle is disabled', async () => {
60+
const evaluation = await provider.resolveStringEvaluation('disabledVariant', 'defaultValue');
61+
expect(evaluation).toHaveProperty(valueProperty, 'defaultValue');
62+
});
63+
});
64+
65+
describe('method resolveNumberEvaluation', () => {
66+
it('should return default value for missing value', async () => {
67+
const evaluation = await provider.resolveNumberEvaluation('nonExistent', 5);
68+
expect(evaluation).toHaveProperty(valueProperty, 5);
69+
});
70+
71+
it('should return integer value if variant toggle exists and is enabled', async () => {
72+
const evaluation = await provider.resolveNumberEvaluation('variantToggleInteger', 0);
73+
expect(evaluation).toHaveProperty(valueProperty, 3);
74+
});
75+
76+
it('should return double value if variant toggle exists and is enabled', async () => {
77+
const evaluation = await provider.resolveNumberEvaluation('variantToggleDouble', 0);
78+
expect(evaluation).toHaveProperty(valueProperty, 1.2);
79+
});
80+
81+
it('should return default value if a toggle is disabled', async () => {
82+
const evaluation = await provider.resolveNumberEvaluation('disabledVariant', 0);
83+
expect(evaluation).toHaveProperty(valueProperty, 0);
84+
});
85+
});
86+
87+
describe('method resolveObjectEvaluation', () => {
88+
it('should return default value for missing value', async () => {
89+
const defaultValue = '{"notFound" : true}';
90+
const evaluation = await provider.resolveObjectEvaluation('nonExistent', JSON.parse(defaultValue));
91+
expect(evaluation).toHaveProperty(valueProperty, JSON.parse(defaultValue));
92+
});
93+
94+
it('should return json value if variant toggle exists and is enabled', async () => {
95+
const expectedVariant = '{hello: world}';
96+
const evaluation = await provider.resolveObjectEvaluation('variantToggleJson', JSON.parse('{"default": false}'));
97+
expect(evaluation).toHaveProperty(valueProperty, expectedVariant);
98+
});
99+
100+
it('should return csv value if variant toggle exists and is enabled', async () => {
101+
const evaluation = await provider.resolveObjectEvaluation('variantToggleCsv', 'a,b,c,d');
102+
expect(evaluation).toHaveProperty(valueProperty, '1,2,3,4');
103+
});
104+
105+
it('should return default value if a toggle is disabled', async () => {
106+
const defaultValue = '{foo: bar}';
107+
const evaluation = await provider.resolveObjectEvaluation('disabledVariant', defaultValue);
108+
expect(evaluation).toHaveProperty(valueProperty, defaultValue);
109+
});
6110
});
7111
});

libs/providers/unleash-web/src/lib/unleash-web-provider.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ export class UnleashWebProvider implements Provider {
2020

2121
readonly runsOn = 'client';
2222

23-
hooks = [];
24-
2523
constructor(options: UnleashOptions, logger?: Logger) {
2624
this._options = options;
2725
this._logger = logger;
@@ -64,7 +62,6 @@ export class UnleashWebProvider implements Provider {
6462
}
6563

6664
async onContextChange(_oldContext: EvaluationContext, newContext: EvaluationContext): Promise<void> {
67-
this._logger?.info("onContextChange = " + JSON.stringify(newContext));
6865
let unleashContext = new Map();
6966
let properties = new Map();
7067
Object.keys(newContext).forEach((key) => {
@@ -93,14 +90,11 @@ export class UnleashWebProvider implements Provider {
9390
this._client?.stop();
9491
}
9592

96-
resolveBooleanEvaluation(flagKey: string, defaultValue: boolean): ResolutionDetails<boolean> {
93+
resolveBooleanEvaluation(flagKey: string): ResolutionDetails<boolean> {
9794
const resp = this._client?.isEnabled(flagKey);
98-
this._logger?.debug("resp = " + resp);
9995
if (typeof resp === 'undefined') {
10096
throw new FlagNotFoundError();
10197
}
102-
var message = resp ? ' is enabled' : ' is disabled';
103-
this._logger?.debug(flagKey + message);
10498
return {
10599
value: resp
106100
}
@@ -111,7 +105,9 @@ export class UnleashWebProvider implements Provider {
111105
}
112106

113107
resolveNumberEvaluation(flagKey: string, defaultValue: number): ResolutionDetails<number> {
114-
return this.evaluate(flagKey, defaultValue);
108+
let resolutionDetails = this.evaluate(flagKey, defaultValue);
109+
resolutionDetails.value = Number(resolutionDetails.value);
110+
return resolutionDetails;
115111
}
116112

117113
resolveObjectEvaluation<U extends JsonValue>(flagKey: string, defaultValue: U): ResolutionDetails<U> {
@@ -120,22 +116,23 @@ export class UnleashWebProvider implements Provider {
120116

121117
private evaluate<T>(flagKey: string, defaultValue: T): ResolutionDetails<T> {
122118
const evaluatedVariant = this._client?.getVariant(flagKey);
123-
let retValue;
119+
let value;
124120
let retVariant
125121
this._logger?.debug("evaluatedVariant = " + JSON.stringify(evaluatedVariant));
126122
if (typeof evaluatedVariant === 'undefined') {
127123
throw new FlagNotFoundError();
128124
}
125+
129126
if (evaluatedVariant.name === 'disabled') {
130-
retValue = defaultValue as T;
127+
value = defaultValue as T;
131128
}
132129
else {
133130
retVariant = evaluatedVariant.name;
134-
retValue = evaluatedVariant.payload?.value;
131+
value = evaluatedVariant.payload?.value;
135132
}
136133
return {
137134
variant: retVariant,
138-
value: retValue as T,
135+
value: value as T,
139136
};
140137
}
141138
}

libs/providers/unleash-web/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"noImplicitOverride": true,
88
"noPropertyAccessFromIndexSignature": true,
99
"noImplicitReturns": true,
10-
"noFallthroughCasesInSwitch": true
10+
"noFallthroughCasesInSwitch": true,
11+
"resolveJsonModule": true
1112
},
1213
"files": [],
1314
"include": [],

0 commit comments

Comments
 (0)