From 32889b9e8c9a074dbf8e6c99e551b15092d408af Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Tue, 20 Aug 2024 10:31:34 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F(frontend)=20replace=20env=20?= =?UTF-8?q?NEXT=5FPUBLIC=5FFEATURE=5FTEAM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NEXT_PUBLIC_FEATURE_TEAM is a buid-time env variable, it is not easy to overload it per environment. We will use the config endpoint to get the feature flag at runtime. To do so, we are using the ConfigStore. --- CHANGELOG.md | 4 ++ src/frontend/apps/desk/.env.development | 1 - src/frontend/apps/desk/.env.test | 1 - .../apps/desk/src/__tests__/pages.test.tsx | 34 +++++++--- .../apps/desk/src/core/MainLayout.tsx | 6 +- .../src/core/__tests__/MainLayout.test.tsx | 9 ++- .../mail-domains/components/panel/Panel.tsx | 4 +- .../apps/desk/src/features/menu/Menu.tsx | 2 +- src/frontend/apps/desk/src/pages/index.tsx | 2 +- .../apps/e2e/__tests__/app-desk/404.spec.ts | 2 +- .../e2e/__tests__/app-desk/config.spec.ts | 63 +++++++++++++++++++ .../apps/e2e/__tests__/app-desk/menu.spec.ts | 2 +- 12 files changed, 111 insertions(+), 19 deletions(-) create mode 100644 src/frontend/apps/e2e/__tests__/app-desk/config.spec.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 93a58e4..531ba87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to ## [Unreleased] +### Added + +🔧Runtime config for the frontend #345 + ## [1.0.1] - 2024-08-19 ### Fixed diff --git a/src/frontend/apps/desk/.env.development b/src/frontend/apps/desk/.env.development index 4cb4d49..45ee232 100644 --- a/src/frontend/apps/desk/.env.development +++ b/src/frontend/apps/desk/.env.development @@ -1,2 +1 @@ NEXT_PUBLIC_API_ORIGIN=http://localhost:8071 -NEXT_PUBLIC_FEATURE_TEAM=true diff --git a/src/frontend/apps/desk/.env.test b/src/frontend/apps/desk/.env.test index 026733c..9a4d514 100644 --- a/src/frontend/apps/desk/.env.test +++ b/src/frontend/apps/desk/.env.test @@ -1,2 +1 @@ NEXT_PUBLIC_API_ORIGIN=http://test.jest -NEXT_PUBLIC_FEATURE_TEAM=true diff --git a/src/frontend/apps/desk/src/__tests__/pages.test.tsx b/src/frontend/apps/desk/src/__tests__/pages.test.tsx index 28d66c5..1713238 100644 --- a/src/frontend/apps/desk/src/__tests__/pages.test.tsx +++ b/src/frontend/apps/desk/src/__tests__/pages.test.tsx @@ -1,23 +1,41 @@ import '@testing-library/jest-dom'; -import { render, screen } from '@testing-library/react'; +import { render } from '@testing-library/react'; +import { useConfigStore } from '@/core'; import { AppWrapper } from '@/tests/utils'; import Page from '../pages'; +const mockedPush = jest.fn(); +const mockedUseRouter = jest.fn().mockReturnValue({ + push: mockedPush, +}); + jest.mock('next/navigation', () => ({ ...jest.requireActual('next/navigation'), - useRouter: () => ({}), + useRouter: () => mockedUseRouter(), })); describe('Page', () => { - it('checks Page rendering', () => { + afterEach(() => jest.clearAllMocks()); + + it('checks Page rendering with team feature', () => { + useConfigStore.setState({ + config: { FEATURES: { TEAMS: true }, LANGUAGES: [] }, + }); + render(, { wrapper: AppWrapper }); - expect( - screen.getByRole('button', { - name: /Create a new team/i, - }), - ).toBeInTheDocument(); + expect(mockedPush).toHaveBeenCalledWith('/teams/'); + }); + + it('checks Page rendering without team feature', () => { + useConfigStore.setState({ + config: { FEATURES: { TEAMS: false }, LANGUAGES: [] }, + }); + + render(, { wrapper: AppWrapper }); + + expect(mockedPush).toHaveBeenCalledWith('/mail-domains/'); }); }); diff --git a/src/frontend/apps/desk/src/core/MainLayout.tsx b/src/frontend/apps/desk/src/core/MainLayout.tsx index 88b6ccf..3b90e64 100644 --- a/src/frontend/apps/desk/src/core/MainLayout.tsx +++ b/src/frontend/apps/desk/src/core/MainLayout.tsx @@ -5,13 +5,17 @@ import { Footer } from '@/features/footer/Footer'; import { HEADER_HEIGHT, Header } from '@/features/header'; import { Menu } from '@/features/menu'; +import { useConfigStore } from './config'; + export function MainLayout({ children }: PropsWithChildren) { + const { config } = useConfigStore(); + return (
- {process.env.NEXT_PUBLIC_FEATURE_TEAM === 'true' && } + {config?.FEATURES.TEAMS && } ({ ...jest.requireActual('next/navigation'), @@ -11,7 +12,11 @@ jest.mock('next/navigation', () => ({ })); describe('MainLayout', () => { - it('checks menu rendering', () => { + it('checks menu rendering with team feature', () => { + useConfigStore.setState({ + config: { FEATURES: { TEAMS: true }, LANGUAGES: [] }, + }); + render(, { wrapper: AppWrapper }); expect( @@ -28,8 +33,6 @@ describe('MainLayout', () => { }); it('checks menu rendering without team feature', () => { - process.env.NEXT_PUBLIC_FEATURE_TEAM = 'false'; - render(, { wrapper: AppWrapper }); expect( diff --git a/src/frontend/apps/desk/src/features/mail-domains/components/panel/Panel.tsx b/src/frontend/apps/desk/src/features/mail-domains/components/panel/Panel.tsx index 10b6082..44e67d2 100644 --- a/src/frontend/apps/desk/src/features/mail-domains/components/panel/Panel.tsx +++ b/src/frontend/apps/desk/src/features/mail-domains/components/panel/Panel.tsx @@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next'; import IconOpenClose from '@/assets/icons/icon-open-close.svg'; import { Box, BoxButton, Text } from '@/components'; +import { useConfigStore } from '@/core/'; import { useCunninghamTheme } from '@/cunningham'; import { ItemList } from './ItemList'; @@ -11,6 +12,7 @@ import { PanelActions } from './PanelActions'; export const Panel = () => { const { t } = useTranslation(); const { colorsTokens } = useCunninghamTheme(); + const { config } = useConfigStore(); const [isOpen, setIsOpen] = useState(true); @@ -20,7 +22,7 @@ export const Panel = () => { $minWidth: '0', }; - const styleNoTeam = process.env.NEXT_PUBLIC_FEATURE_TEAM !== 'true' && { + const styleNoTeam = !config?.FEATURES.TEAMS && { $display: 'none', tabIndex: -1, }; diff --git a/src/frontend/apps/desk/src/features/menu/Menu.tsx b/src/frontend/apps/desk/src/features/menu/Menu.tsx index c921646..d8a622e 100644 --- a/src/frontend/apps/desk/src/features/menu/Menu.tsx +++ b/src/frontend/apps/desk/src/features/menu/Menu.tsx @@ -25,7 +25,7 @@ export const Menu = () => { { useEffect(() => { config?.FEATURES.TEAMS ? router.push('/teams/') - : router.push('mail-domains/'); + : router.push('/mail-domains/'); }, [config?.FEATURES.TEAMS, router]); return null; diff --git a/src/frontend/apps/e2e/__tests__/app-desk/404.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/404.spec.ts index 4e4fa70..494676b 100644 --- a/src/frontend/apps/e2e/__tests__/app-desk/404.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-desk/404.spec.ts @@ -24,6 +24,6 @@ test.describe('404', () => { page, }) => { await page.getByText('Back to home page').click(); - await expect(page).toHaveURL('/'); + await expect(page).toHaveURL('/teams/'); }); }); diff --git a/src/frontend/apps/e2e/__tests__/app-desk/config.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/config.spec.ts new file mode 100644 index 0000000..b6d2937 --- /dev/null +++ b/src/frontend/apps/e2e/__tests__/app-desk/config.spec.ts @@ -0,0 +1,63 @@ +import { expect, test } from '@playwright/test'; + +import { keyCloakSignIn } from './common'; + +test.describe('Config', () => { + test.beforeEach(async ({ page, browserName }) => { + await page.goto('/'); + await keyCloakSignIn(page, browserName); + }); + + test('it checks the config api is called', async ({ page }) => { + const responsePromise = page.waitForResponse( + (response) => + response.url().includes('/config/') && response.status() === 200, + ); + + const response = await responsePromise; + expect(response.ok()).toBeTruthy(); + + expect(await response.json()).toStrictEqual({ + LANGUAGES: [ + ['en-us', 'English'], + ['fr-fr', 'French'], + ], + FEATURES: { TEAMS: true }, + }); + }); + + test('it checks that the config can deactivate the feature "teams"', async ({ + page, + }) => { + await page.route('**/api/v1.0/config/', async (route) => { + const request = route.request(); + if (request.method().includes('GET')) { + await route.fulfill({ + json: { + LANGUAGES: [ + ['en-us', 'English'], + ['fr-fr', 'French'], + ], + FEATURES: { TEAMS: false }, + }, + }); + } else { + await route.continue(); + } + }); + + await expect(page.locator('menu')).toBeHidden(); + + await expect( + page.getByRole('button', { + name: 'Create a new team', + }), + ).toBeHidden(); + + await expect( + page.getByRole('button', { + name: 'Add your mail domain', + }), + ).toBeVisible(); + }); +}); diff --git a/src/frontend/apps/e2e/__tests__/app-desk/menu.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/menu.spec.ts index 4cad5c4..5c753fc 100644 --- a/src/frontend/apps/e2e/__tests__/app-desk/menu.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-desk/menu.spec.ts @@ -12,7 +12,7 @@ test.describe('Menu', () => { { name: 'Teams', isDefault: true, - expectedUrl: '', + expectedUrl: '/teams/', expectedText: 'Create a new team', }, {