From d45f81ab02f2fe84c75efe898460a2b844d621c0 Mon Sep 17 00:00:00 2001 From: andreas-unleash Date: Tue, 2 May 2023 21:33:14 +0300 Subject: [PATCH] fix: set feature.enabled to false when all strategies are deactivated (#3655) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit set feature.enabled to false when all strategies are deactivated ## About the changes Closes # ### Important files ## Discussion points --------- Signed-off-by: andreas-unleash Co-authored-by: Prabodh Meshram --- src/lib/db/feature-strategy-store.ts | 18 +++++++++++------- src/lib/db/feature-toggle-client-store.ts | 10 +++++++++- src/lib/services/playground-service.ts | 2 +- src/test/e2e/api/proxy/proxy.e2e.test.ts | 11 +++-------- .../e2e/services/playground-service.test.ts | 5 ++--- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/lib/db/feature-strategy-store.ts b/src/lib/db/feature-strategy-store.ts index ad33284e22..767d2e4a16 100644 --- a/src/lib/db/feature-strategy-store.ts +++ b/src/lib/db/feature-strategy-store.ts @@ -378,8 +378,12 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { e.strategies = e.strategies.sort( (a, b) => a.sortOrder - b.sortOrder, ); + if (e.strategies && e.strategies.length === 0) { + e.enabled = false; + } return e; }); + featureToggle.archived = archived; return featureToggle; } @@ -389,10 +393,10 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { } private addSegmentIdsToStrategy( - feature: PartialDeep, + featureToggle: PartialDeep, row: Record, ) { - const strategy = feature.strategies?.find( + const strategy = featureToggle.strategies?.find( (s) => s?.id === row.strategy_id, ); if (!strategy) { @@ -415,22 +419,22 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { } private addTag( - feature: Record, + featureToggle: Record, row: Record, ): void { - const tags = feature.tags || []; + const tags = featureToggle.tags || []; const newTag = FeatureStrategiesStore.rowToTag(row); - feature.tags = [...tags, newTag]; + featureToggle.tags = [...tags, newTag]; } private isNewTag( - feature: Record, + featureToggle: Record, row: Record, ): boolean { return ( row.tag_type && row.tag_value && - !feature.tags?.some( + !featureToggle.tags?.some( (tag) => tag.type === row.tag_type && tag.value === row.tag_value, ) diff --git a/src/lib/db/feature-toggle-client-store.ts b/src/lib/db/feature-toggle-client-store.ts index d7db7e4eb8..9051d0cbbc 100644 --- a/src/lib/db/feature-toggle-client-store.ts +++ b/src/lib/db/feature-toggle-client-store.ts @@ -251,10 +251,18 @@ export default class FeatureToggleClientStore ): IFeatureToggleClient[] { const filtered: IFeatureToggleClient[] = []; features.forEach((feature) => { + let { enabled } = feature; const filteredStrategies = feature.strategies.filter( (strategy) => !strategy.disabled, ); - filtered.push({ ...feature, strategies: filteredStrategies }); + if (!filteredStrategies.length) { + enabled = false; + } + filtered.push({ + ...feature, + enabled, + strategies: filteredStrategies, + }); }); return filtered; } diff --git a/src/lib/services/playground-service.ts b/src/lib/services/playground-service.ts index 42c4d54f3b..f7798c36b0 100644 --- a/src/lib/services/playground-service.ts +++ b/src/lib/services/playground-service.ts @@ -41,7 +41,7 @@ export class PlaygroundService { environment, }, true, - true, + false, ), this.segmentService.getActive(), ]); diff --git a/src/test/e2e/api/proxy/proxy.e2e.test.ts b/src/test/e2e/api/proxy/proxy.e2e.test.ts index 4244899774..729d181d73 100644 --- a/src/test/e2e/api/proxy/proxy.e2e.test.ts +++ b/src/test/e2e/api/proxy/proxy.e2e.test.ts @@ -1108,6 +1108,7 @@ test('should not return all features', async () => { test('should NOT evaluate disabled strategies when returning toggles', async () => { const frontendToken = await createApiToken(ApiTokenType.FRONTEND); + await createFeatureToggle({ name: 'enabledFeature', enabled: true, @@ -1140,7 +1141,7 @@ test('should NOT evaluate disabled strategies when returning toggles', async () ], }); await createFeatureToggle({ - name: 'disabledFeature3', + name: 'disabledFeature2', enabled: true, strategies: [ { @@ -1166,7 +1167,7 @@ test('should NOT evaluate disabled strategies when returning toggles', async () ], }); await createFeatureToggle({ - name: 'enabledFeature2', + name: 'disabledFeature3', enabled: true, strategies: [ { @@ -1196,12 +1197,6 @@ test('should NOT evaluate disabled strategies when returning toggles', async () impressionData: false, variant: { enabled: false, name: 'disabled' }, }, - { - name: 'enabledFeature2', - enabled: true, - impressionData: false, - variant: { enabled: false, name: 'disabled' }, - }, ], }); }); diff --git a/src/test/e2e/services/playground-service.test.ts b/src/test/e2e/services/playground-service.test.ts index efb962dede..c456d64a75 100644 --- a/src/test/e2e/services/playground-service.test.ts +++ b/src/test/e2e/services/playground-service.test.ts @@ -260,7 +260,7 @@ describe('the playground service (e2e)', () => { ); // the playground differs from a normal SDK in that - // it _must_ evaluate all srategies and features + // it _must_ evaluate all strategies and features // regardless of whether they're supposed to be // enabled in the current environment or not. const expectedSDKState = feature.isEnabled; @@ -269,8 +269,6 @@ describe('the playground service (e2e)', () => { expectedSDKState === client.isEnabled(feature.name, clientContext); - expect(enabledStateMatches).toBe(true); - ctx.log( `feature.isEnabled, feature.isEnabledInCurrentEnvironment, presumedSDKState: ${feature.isEnabled}, ${feature.isEnabledInCurrentEnvironment}, ${expectedSDKState}`, ); @@ -280,6 +278,7 @@ describe('the playground service (e2e)', () => { clientContext, )}`, ); + expect(enabledStateMatches).toBe(true); // if x is disabled, then the variant will be the // disabled variant.