From a51b34a04ee7b72a93a04a739e8016c4b800ec23 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Fri, 6 Mar 2026 12:01:39 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B(frontend)=20analytic=20feature=20f?= =?UTF-8?q?lags=20problem?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When multiple analytics are registered, if one analytic has the flag at true, the feature was activated, even if another analytic had it at false. We change the logic to require all analytics to have the flag at true for the feature to be activated. --- CHANGELOG.md | 4 + .../apps/impress/src/libs/Analytics.tsx | 10 +- .../src/libs/__tests__/Analytics.spec.tsx | 95 +++++++++++++++++++ 3 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 src/frontend/apps/impress/src/libs/__tests__/Analytics.spec.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index ed109df2..6dda6548 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ and this project adheres to - 📝(docs) improve README and add documentation hub #1870 - ♿️(frontend) restore focus to triggers after closing menus and modals #1863 +### Fixed + +- 🐛(frontend) analytic feature flags problem #1953 + ## [v4.6.0] - 2026-03-03 ### Added diff --git a/src/frontend/apps/impress/src/libs/Analytics.tsx b/src/frontend/apps/impress/src/libs/Analytics.tsx index 02c996a3..972b24b0 100644 --- a/src/frontend/apps/impress/src/libs/Analytics.tsx +++ b/src/frontend/apps/impress/src/libs/Analytics.tsx @@ -56,16 +56,18 @@ export class Analytics { /** * Check if a feature flag is activated * - * Feature flags are activated if at least one analytic is activated - * because we don't want to hide feature if the user does not - * use analytics (AB testing, etc) + * A feature flag is considered active only if ALL analytics agree it is. + * This ensures that if one analytic explicitly disables a flag, + * it takes precedence over analytics that do not manage flags. + * If no analytics are registered, default to true so features are not hidden + * when analytics are not configured. */ public static isFeatureFlagActivated(flagName: string): boolean { if (!Analytics.analytics.length) { return true; } - return Analytics.analytics.some((analytic) => + return Analytics.analytics.every((analytic) => analytic.isFeatureFlagActivated(flagName), ); } diff --git a/src/frontend/apps/impress/src/libs/__tests__/Analytics.spec.tsx b/src/frontend/apps/impress/src/libs/__tests__/Analytics.spec.tsx new file mode 100644 index 00000000..b0677fb2 --- /dev/null +++ b/src/frontend/apps/impress/src/libs/__tests__/Analytics.spec.tsx @@ -0,0 +1,95 @@ +import { render, screen } from '@testing-library/react'; +import React, { Fragment } from 'react'; + +import { AbstractAnalytic, Analytics, useAnalytics } from '@/libs'; +import { AppWrapper } from '@/tests/utils'; + +class TestAnalytic1 extends AbstractAnalytic { + public constructor() { + super(); + } + + public Provider() { + return ; + } + + public trackEvent() {} + + public isFeatureFlagActivated(flagName: string): boolean { + if (flagName === 'test-flag') { + return false; + } + + if (flagName === 'test-flag2') { + return true; + } + + return true; + } +} + +class TestAnalytic2 extends AbstractAnalytic { + public constructor() { + super(); + } + + public Provider() { + return ; + } + + public trackEvent() {} + + public isFeatureFlagActivated(): boolean { + return true; + } +} + +const TestComponent = ({ flag }: { flag: string }) => { + const { isFeatureFlagActivated } = useAnalytics(); + + return ( +
+ {isFeatureFlagActivated(flag) ? ( + Feature is enabled + ) : ( + Feature is not enabled + )} +
+ ); +}; + +describe('Analytics feature flag', () => { + beforeEach(() => { + Analytics.clearAnalytics(); + }); + + test('renders feature when feature flag is not existing', async () => { + new TestAnalytic1(); + new TestAnalytic2(); + + render(, { + wrapper: AppWrapper, + }); + expect(await screen.findByText('Feature is enabled')).toBeInTheDocument(); + }); + + test('renders feature when feature flag is not enabled', async () => { + new TestAnalytic1(); + new TestAnalytic2(); + + render(, { + wrapper: AppWrapper, + }); + expect(screen.getByText('Feature is not enabled')).toBeInTheDocument(); + }); + + test('renders feature when feature flag is enabled', async () => { + new TestAnalytic1(); + new TestAnalytic2(); + + render(, { + wrapper: AppWrapper, + }); + expect(screen.getByText('Feature is enabled')).toBeInTheDocument(); + }); +});