Skip to content

Commit 31fee7a

Browse files
authored
Fix/clear sub scope with new root value (#67)
* fixed update scoped values logic * add a test where root scope value
1 parent 6d43da2 commit 31fee7a

File tree

3 files changed

+52
-26
lines changed

3 files changed

+52
-26
lines changed

src/featureToggles.js

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,39 +1080,36 @@ class FeatureToggles {
10801080
scopeKey = SCOPE_ROOT_KEY,
10811081
{ clearSubScopes = false } = {}
10821082
) {
1083-
// NOTE: this first check is just an optimization
1084-
if (clearSubScopes && scopeKey === SCOPE_ROOT_KEY) {
1085-
return null;
1083+
// NOTE: if there are no existing scoped values, or we want to delete everything but the root key, than the
1084+
// response is trivial.
1085+
if (!scopedValues || (clearSubScopes && scopeKey === SCOPE_ROOT_KEY)) {
1086+
if (newValue !== null) {
1087+
return { [scopeKey]: newValue };
1088+
} else {
1089+
return null;
1090+
}
10861091
}
10871092

1088-
if (scopedValues) {
1089-
if (clearSubScopes) {
1090-
const scopeKeyInnerPairs = scopeKey.split(SCOPE_KEY_OUTER_SEPARATOR);
1091-
const subScopeKeys = Object.keys(scopedValues).filter((someScopeKey) =>
1092-
scopeKeyInnerPairs.every((scopeKeyInnerPair) => someScopeKey.includes(scopeKeyInnerPair))
1093-
);
1094-
for (const subScopeKey of subScopeKeys) {
1095-
Reflect.deleteProperty(scopedValues, subScopeKey);
1096-
}
1093+
if (clearSubScopes) {
1094+
// NOTE: we use here, that the scopeKey !== SCOPE_ROOT_KEY
1095+
const scopeKeyInnerPairs = scopeKey.split(SCOPE_KEY_OUTER_SEPARATOR);
1096+
const subScopeKeys = Object.keys(scopedValues).filter((someScopeKey) =>
1097+
scopeKeyInnerPairs.every((scopeKeyInnerPair) => someScopeKey.includes(scopeKeyInnerPair))
1098+
);
1099+
for (const subScopeKey of subScopeKeys) {
1100+
Reflect.deleteProperty(scopedValues, subScopeKey);
10971101
}
1102+
}
10981103

1099-
if (newValue !== null) {
1100-
scopedValues[scopeKey] = newValue;
1101-
} else {
1102-
if (Object.keys(scopedValues).length > 1) {
1103-
Reflect.deleteProperty(scopedValues, scopeKey);
1104-
} else {
1105-
return null;
1106-
}
1107-
}
1108-
return scopedValues;
1104+
if (newValue !== null) {
1105+
scopedValues[scopeKey] = newValue;
11091106
} else {
1110-
if (newValue !== null) {
1111-
return { [scopeKey]: newValue };
1112-
} else {
1107+
Reflect.deleteProperty(scopedValues, scopeKey);
1108+
if (Object.keys(scopedValues).length === 0) {
11131109
return null;
11141110
}
11151111
}
1112+
return scopedValues;
11161113
}
11171114

11181115
// NOTE: stateScopedValues needs to be at least an empty object {}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ exports[`local integration test common config init getFeatureValue, changeFeatur
1616

1717
exports[`local integration test common config init getFeatureValue, changeFeatureValue with scopes 8`] = `[]`;
1818

19-
exports[`local integration test common config init getFeatureValue, changeFeatureValue with scopes and clearSubScopes, resetFeatureValue 5`] = `[]`;
19+
exports[`local integration test common config init getFeatureValue, changeFeatureValue with scopes and clearSubScopes, resetFeatureValue 7`] = `[]`;
2020

2121
exports[`local integration test common config init getFeatureValue, changeFeatureValue without scopes 1`] = `
2222
[

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,7 @@ describe("local integration test", () => {
551551
const superScopeNewValue = 2;
552552
const scopeNewValue = 3;
553553
const subScopeNewValue = 4;
554+
const rootClearNewValue = 5;
554555

555556
expect(await toggles.changeFeatureValue(FEATURE.E, scopeNewValue, scopeMap)).toBeUndefined();
556557
expect(await toggles.changeFeatureValue(FEATURE.E, superScopeNewValue, superScopeMap)).toBeUndefined();
@@ -588,6 +589,34 @@ describe("local integration test", () => {
588589
expect(toggles.getFeatureValue(FEATURE.E, superScopeMap)).toEqual(superScopeNewValue);
589590
expect(toggles.getFeatureValue(FEATURE.E)).toEqual(rootNewValue);
590591

592+
expect(
593+
await toggles.changeFeatureValue(FEATURE.E, rootClearNewValue, undefined, { clearSubScopes: true })
594+
).toBeUndefined();
595+
expect(stateFromInfo(toggles.getFeatureInfo(FEATURE.E))).toMatchInlineSnapshot(`
596+
{
597+
"rootValue": 5,
598+
}
599+
`);
600+
expect(toggles.getFeatureValue(FEATURE.E, subScopeMap)).toEqual(rootClearNewValue);
601+
expect(toggles.getFeatureValue(FEATURE.E, scopeMap)).toEqual(rootClearNewValue);
602+
expect(toggles.getFeatureValue(FEATURE.E, superScopeMap)).toEqual(rootClearNewValue);
603+
expect(toggles.getFeatureValue(FEATURE.E)).toEqual(rootClearNewValue);
604+
605+
// re-add scoped values for reset test
606+
expect(await toggles.changeFeatureValue(FEATURE.E, scopeNewValue, scopeMap)).toBeUndefined();
607+
expect(await toggles.changeFeatureValue(FEATURE.E, superScopeNewValue, superScopeMap)).toBeUndefined();
608+
expect(await toggles.changeFeatureValue(FEATURE.E, subScopeNewValue, subScopeMap)).toBeUndefined();
609+
expect(stateFromInfo(toggles.getFeatureInfo(FEATURE.E))).toMatchInlineSnapshot(`
610+
{
611+
"rootValue": 5,
612+
"scopedValues": {
613+
"component::c1##layer::l1##tenant::t1": 4,
614+
"component::c1##tenant::t1": 3,
615+
"tenant::t1": 2,
616+
},
617+
}
618+
`);
619+
591620
expect(await toggles.resetFeatureValue(FEATURE.E)).toBeUndefined();
592621
expect(stateFromInfo(toggles.getFeatureInfo(FEATURE.E))).toMatchInlineSnapshot(`{}`);
593622
expect(toggles.getFeatureValue(FEATURE.E, subScopeMap)).toEqual(rootOldValue);

0 commit comments

Comments
 (0)