Skip to content

Commit 7e39b46

Browse files
authored
Fb/better info api (#10)
* better feature info interface * better feature info interface 2
1 parent 2067f95 commit 7e39b46

File tree

6 files changed

+96
-71
lines changed

6 files changed

+96
-71
lines changed

src/featureToggles.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,9 +657,25 @@ class FeatureToggles {
657657
}
658658

659659
_getFeatureInfo(featureKey) {
660+
let rootValue;
661+
let foundScopedValues = false;
662+
let scopedValues;
663+
if (this.__stateScopedValues[featureKey]) {
664+
scopedValues = Object.entries(this.__stateScopedValues[featureKey]).reduce((acc, [scopeKey, value]) => {
665+
if (scopeKey === SCOPE_ROOT_KEY) {
666+
rootValue = value;
667+
} else {
668+
foundScopedValues = true;
669+
acc[scopeKey] = value;
670+
}
671+
return acc;
672+
}, {});
673+
}
674+
660675
return {
661676
fallbackValue: this.__fallbackValues[featureKey],
662-
scopedValues: this.__stateScopedValues[featureKey],
677+
...(rootValue !== undefined && { rootValue }),
678+
...(foundScopedValues && { scopedValues }),
663679
config: FeatureToggles._getFeatureInfoConfig(this.__config, featureKey),
664680
};
665681
}

test/__common__/fromInfo.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"use strict";
2+
3+
const _transformToFromInfos = (fromInfo) => (featureInfos) =>
4+
Object.fromEntries(Object.entries(featureInfos).map(([key, featureInfo]) => [key, fromInfo(featureInfo)]));
5+
6+
const fallbackValuesFromInfo = ({ fallbackValue }) => fallbackValue;
7+
8+
const stateFromInfo = ({ rootValue, scopedValues }) => ({
9+
...(rootValue !== undefined && { rootValue }),
10+
...(scopedValues && { scopedValues }),
11+
});
12+
13+
module.exports = {
14+
fallbackValuesFromInfo,
15+
fallbackValuesFromInfos: _transformToFromInfos(fallbackValuesFromInfo),
16+
stateFromInfo,
17+
stateFromInfos: _transformToFromInfos(stateFromInfo),
18+
};

test/__snapshots__/featureToggles.test.js.snap

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,29 @@
22

33
exports[`feature toggles test basic apis _changeRemoteFeatureValues 2`] = `
44
{
5-
"test/feature_a": undefined,
6-
"test/feature_b": undefined,
7-
"test/feature_c": undefined,
8-
"test/feature_d": undefined,
9-
"test/feature_e": undefined,
10-
"test/feature_f": undefined,
11-
"test/feature_g": undefined,
12-
"test/feature_h": undefined,
5+
"test/feature_a": {},
6+
"test/feature_b": {},
7+
"test/feature_c": {},
8+
"test/feature_d": {},
9+
"test/feature_e": {},
10+
"test/feature_f": {},
11+
"test/feature_g": {},
12+
"test/feature_h": {},
1313
}
1414
`;
1515

1616
exports[`feature toggles test basic apis _changeRemoteFeatureValues 3`] = `
1717
{
18-
"test/feature_a": undefined,
19-
"test/feature_b": undefined,
18+
"test/feature_a": {},
19+
"test/feature_b": {},
2020
"test/feature_c": {
21-
"//": "new_a",
21+
"rootValue": "new_a",
2222
},
23-
"test/feature_d": undefined,
24-
"test/feature_e": undefined,
25-
"test/feature_f": undefined,
26-
"test/feature_g": undefined,
27-
"test/feature_h": undefined,
23+
"test/feature_d": {},
24+
"test/feature_e": {},
25+
"test/feature_f": {},
26+
"test/feature_g": {},
27+
"test/feature_h": {},
2828
}
2929
`;
3030

@@ -35,53 +35,46 @@ exports[`feature toggles test basic apis getFeaturesInfos 1`] = `
3535
"TYPE": "boolean",
3636
},
3737
"fallbackValue": false,
38-
"scopedValues": undefined,
3938
},
4039
"test/feature_b": {
4140
"config": {
4241
"TYPE": "number",
4342
},
4443
"fallbackValue": 1,
45-
"scopedValues": undefined,
4644
},
4745
"test/feature_c": {
4846
"config": {
4947
"TYPE": "string",
5048
},
5149
"fallbackValue": "best",
52-
"scopedValues": undefined,
5350
},
5451
"test/feature_d": {
5552
"config": {
5653
"TYPE": "boolean",
5754
"VALIDATION": "^(?:true)$",
5855
},
5956
"fallbackValue": true,
60-
"scopedValues": undefined,
6157
},
6258
"test/feature_e": {
6359
"config": {
6460
"TYPE": "number",
6561
"VALIDATION": "^\\d{1}$",
6662
},
6763
"fallbackValue": 5,
68-
"scopedValues": undefined,
6964
},
7065
"test/feature_f": {
7166
"config": {
7267
"TYPE": "string",
7368
"VALIDATION": "^(?:best|worst)$",
7469
},
7570
"fallbackValue": "best",
76-
"scopedValues": undefined,
7771
},
7872
"test/feature_g": {
7973
"config": {
8074
"ACTIVE": false,
8175
"TYPE": "string",
8276
},
8377
"fallbackValue": "activeTest",
84-
"scopedValues": undefined,
8578
},
8679
"test/feature_h": {
8780
"config": {
@@ -90,7 +83,6 @@ exports[`feature toggles test basic apis getFeaturesInfos 1`] = `
9083
"TYPE": "string",
9184
},
9285
"fallbackValue": "appUrlTest",
93-
"scopedValues": undefined,
9486
},
9587
}
9688
`;

test/featureToggles.test.js

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ jest.mock("fs", () => ({
1313
readFile: jest.fn(),
1414
}));
1515

16+
const { fallbackValuesFromInfos, stateFromInfos } = require("./__common__/fromInfo");
17+
1618
const { LimitedLazyCache } = require("../src/shared/cache");
1719
const redisWrapperMock = require("../src/redisWrapper");
1820
jest.mock("../src/redisWrapper", () => require("./__mocks__/redisWrapper"));
@@ -31,12 +33,6 @@ const loggerSpy = {
3133
error: jest.spyOn(featureTogglesModule._._getLogger(), "error"),
3234
};
3335

34-
const fallbackValuesFromInfos = (featureInfos) =>
35-
Object.fromEntries(Object.entries(featureInfos).map(([key, value]) => [key, value.fallbackValue]));
36-
37-
const scopedValuesFromInfos = (featureInfos) =>
38-
Object.fromEntries(Object.entries(featureInfos).map(([key, value]) => [key, value.scopedValues]));
39-
4036
describe("feature toggles test", () => {
4137
beforeEach(async () => {
4238
redisWrapperMock._reset();
@@ -243,10 +239,10 @@ describe("feature toggles test", () => {
243239
await featureToggles.initializeFeatures({ config: mockConfig });
244240
redisWrapperMock.watchedHashGetSetObject.mockClear();
245241

246-
const beforeValues = scopedValuesFromInfos(await featureToggles.getFeaturesInfos());
242+
const beforeValues = stateFromInfos(await featureToggles.getFeaturesInfos());
247243
await featureToggles._changeRemoteFeatureValue(FEATURE.B, null);
248244
await featureToggles._changeRemoteFeatureValue(FEATURE.C, "new_a");
249-
const afterValues = scopedValuesFromInfos(await featureToggles.getFeaturesInfos());
245+
const afterValues = stateFromInfos(await featureToggles.getFeaturesInfos());
250246

251247
expect(redisWrapperMock.watchedHashGetSetObject).toHaveBeenCalledTimes(2);
252248
expect(redisWrapperMock.watchedHashGetSetObject).toHaveBeenNthCalledWith(
@@ -438,7 +434,6 @@ describe("feature toggles test", () => {
438434
"TYPE": "boolean",
439435
},
440436
"fallbackValue": false,
441-
"scopedValues": undefined,
442437
}
443438
`);
444439
expect(featureToggles.getFeatureInfo(FEATURE.B)).toMatchInlineSnapshot(`
@@ -447,7 +442,6 @@ describe("feature toggles test", () => {
447442
"TYPE": "number",
448443
},
449444
"fallbackValue": 1,
450-
"scopedValues": undefined,
451445
}
452446
`);
453447
expect(featureToggles.getFeatureInfo(FEATURE.C)).toMatchInlineSnapshot(`
@@ -456,7 +450,6 @@ describe("feature toggles test", () => {
456450
"TYPE": "string",
457451
},
458452
"fallbackValue": "best",
459-
"scopedValues": undefined,
460453
}
461454
`);
462455
});

test/integration-local/__snapshots__/featureToggles.test.js.snap

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,53 +71,46 @@ exports[`local integration test getFeatureValues, getFeaturesInfos 1`] = `
7171
"TYPE": "boolean",
7272
},
7373
"fallbackValue": false,
74-
"scopedValues": undefined,
7574
},
7675
"test/feature_b": {
7776
"config": {
7877
"TYPE": "number",
7978
},
8079
"fallbackValue": 1,
81-
"scopedValues": undefined,
8280
},
8381
"test/feature_c": {
8482
"config": {
8583
"TYPE": "string",
8684
},
8785
"fallbackValue": "best",
88-
"scopedValues": undefined,
8986
},
9087
"test/feature_d": {
9188
"config": {
9289
"TYPE": "boolean",
9390
"VALIDATION": "^(?:true)$",
9491
},
9592
"fallbackValue": true,
96-
"scopedValues": undefined,
9793
},
9894
"test/feature_e": {
9995
"config": {
10096
"TYPE": "number",
10197
"VALIDATION": "^\\d{1}$",
10298
},
10399
"fallbackValue": 5,
104-
"scopedValues": undefined,
105100
},
106101
"test/feature_f": {
107102
"config": {
108103
"TYPE": "string",
109104
"VALIDATION": "^(?:best|worst)$",
110105
},
111106
"fallbackValue": "best",
112-
"scopedValues": undefined,
113107
},
114108
"test/feature_g": {
115109
"config": {
116110
"ACTIVE": false,
117111
"TYPE": "string",
118112
},
119113
"fallbackValue": "activeTest",
120-
"scopedValues": undefined,
121114
},
122115
"test/feature_h": {
123116
"config": {
@@ -126,7 +119,6 @@ exports[`local integration test getFeatureValues, getFeaturesInfos 1`] = `
126119
"TYPE": "string",
127120
},
128121
"fallbackValue": "appUrlTest",
129-
"scopedValues": undefined,
130122
},
131123
}
132124
`;

0 commit comments

Comments
 (0)