From 406f906d7f54b6f0b242c1f51131f8ac79faa912 Mon Sep 17 00:00:00 2001 From: Mateusz Kwasniewski Date: Fri, 14 Jun 2024 10:39:29 +0200 Subject: [PATCH] fix: backport lifecycle and playground fixes (#7396) --- .../FeatureStrategy/featureStrategy.utils.ts | 2 +- .../FeatureLifecycleTooltip.test.tsx | 27 ++++++++++------ .../FeatureLifecycleTooltip.tsx | 9 ++++++ package.json | 24 +++----------- .../playground/advanced-playground.test.ts | 31 ++++++++++++++++++- .../playground/feature-evaluator/client.ts | 12 ++----- src/test/e2e/helpers/test-helper.ts | 10 ++++-- 7 files changed, 73 insertions(+), 42 deletions(-) diff --git a/frontend/src/component/feature/FeatureStrategy/featureStrategy.utils.ts b/frontend/src/component/feature/FeatureStrategy/featureStrategy.utils.ts index 344f0d37fbfd..0f83613b563f 100644 --- a/frontend/src/component/feature/FeatureStrategy/featureStrategy.utils.ts +++ b/frontend/src/component/feature/FeatureStrategy/featureStrategy.utils.ts @@ -6,5 +6,5 @@ export const comparisonModerator = ( ): DeepOmit => { const tempData = { ...data }; - return deepOmit(tempData, 'lastSeenAt', 'yes', 'no'); + return deepOmit(tempData, 'lastSeenAt', 'yes', 'no', 'lifecycle'); }; diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.test.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.test.tsx index 946273332894..f0596b7ec50d 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.test.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.test.tsx @@ -8,6 +8,7 @@ import { DELETE_FEATURE, UPDATE_FEATURE, } from 'component/providers/AccessProvider/permissions'; +import { Route, Routes } from 'react-router-dom'; const currentTime = '2024-04-25T08:05:00.000Z'; const twoMinutesAgo = '2024-04-25T08:03:00.000Z'; @@ -22,16 +23,24 @@ const renderOpenTooltip = ( loading = false, ) => { render( - - child - , + + + child + + } + /> + , { + route: '/projects/default', permissions: [ { permission: DELETE_FEATURE }, { permission: UPDATE_FEATURE }, diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx index a1815bfdc929..b13929ee14dd 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx @@ -25,6 +25,7 @@ import { isSafeToArchive } from './isSafeToArchive'; import { useLocationSettings } from 'hooks/useLocationSettings'; import { formatDateYMDHMS } from 'utils/formatDate'; import { formatDistanceToNow, parseISO } from 'date-fns'; +import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; const TimeLabel = styled('span')(({ theme }) => ({ color: theme.palette.text.secondary, @@ -264,6 +265,8 @@ const LiveStageDescription: FC<{ onComplete: () => void; loading: boolean; }> = ({ children, onComplete, loading }) => { + const projectId = useRequiredPathParam('projectId'); + return ( <> Is this feature complete? @@ -282,6 +285,7 @@ const LiveStageDescription: FC<{ size='small' onClick={onComplete} disabled={loading} + projectId={projectId} > Mark completed @@ -300,6 +304,8 @@ const SafeToArchive: FC<{ onUncomplete: () => void; loading: boolean; }> = ({ onArchive, onUncomplete, loading }) => { + const projectId = useRequiredPathParam('projectId'); + return ( <> Safe to archive @@ -316,6 +322,7 @@ const SafeToArchive: FC<{ sx={{ display: 'flex', flexDirection: 'row', + flexWrap: 'wrap', gap: 2, }} > @@ -326,6 +333,7 @@ const SafeToArchive: FC<{ size='small' onClick={onUncomplete} disabled={loading} + projectId={projectId} > Revert to live @@ -336,6 +344,7 @@ const SafeToArchive: FC<{ size='small' sx={{ mb: 2 }} onClick={onArchive} + projectId={projectId} > Archive feature diff --git a/package.json b/package.json index 60d3d7a33acd..d51288adaff7 100644 --- a/package.json +++ b/package.json @@ -82,9 +82,7 @@ "testTimeout": 10000, "globalSetup": "./scripts/jest-setup.js", "transform": { - "^.+\\.tsx?$": [ - "@swc/jest" - ] + "^.+\\.tsx?$": ["@swc/jest"] }, "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", "testPathIgnorePatterns": [ @@ -93,13 +91,7 @@ "/frontend/", "/website/" ], - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json" - ], + "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json"], "coveragePathIgnorePatterns": [ "/node_modules/", "/dist/", @@ -240,14 +232,8 @@ "tough-cookie": "4.1.4" }, "lint-staged": { - "*.{js,ts}": [ - "biome check --write --no-errors-on-unmatched" - ], - "*.{jsx,tsx}": [ - "biome check --write --no-errors-on-unmatched" - ], - "*.json": [ - "biome format --write --no-errors-on-unmatched" - ] + "*.{js,ts}": ["biome check --write --no-errors-on-unmatched"], + "*.{jsx,tsx}": ["biome check --write --no-errors-on-unmatched"], + "*.json": ["biome format --write --no-errors-on-unmatched"] } } diff --git a/src/lib/features/playground/advanced-playground.test.ts b/src/lib/features/playground/advanced-playground.test.ts index 4005829ac14d..ba01856918cf 100644 --- a/src/lib/features/playground/advanced-playground.test.ts +++ b/src/lib/features/playground/advanced-playground.test.ts @@ -95,7 +95,7 @@ test('advanced playground evaluation with no toggles', async () => { }); }); -test('advanced playground evaluation with parent dependency', async () => { +test('advanced playground evaluation with unsatisfied parent dependency', async () => { await createFeatureToggle('test-parent'); await createFeatureToggle('test-child'); await enableToggle('test-child'); @@ -126,6 +126,35 @@ test('advanced playground evaluation with parent dependency', async () => { expect(parent.isEnabled).toBe(false); }); +test('advanced playground evaluation with satisfied disabled parent dependency', async () => { + await createFeatureToggle('test-parent'); + await createFeatureToggle('test-child'); + await enableToggle('test-child'); + await app.addDependency('test-child', { + feature: 'test-parent', + enabled: false, + variants: [], + }); + + const { body: result } = await app.request + .post('/api/admin/playground/advanced') + .send({ + environments: ['default'], + projects: ['default'], + context: { appName: 'test' }, + }) + .set('Content-Type', 'application/json') + .expect(200); + + const child = result.features[0].environments.default[0]; + const parent = result.features[1].environments.default[0]; + + expect(child.hasUnsatisfiedDependency).toBe(false); + expect(child.isEnabled).toBe(true); + expect(parent.hasUnsatisfiedDependency).toBe(false); + expect(parent.isEnabled).toBe(false); +}); + test('advanced playground evaluation happy path', async () => { await createFeatureToggleWithStrategy('test-playground-feature'); await enableToggle('test-playground-feature'); diff --git a/src/lib/features/playground/feature-evaluator/client.ts b/src/lib/features/playground/feature-evaluator/client.ts index 2d09cc6dd8f9..177dc81667a5 100644 --- a/src/lib/features/playground/feature-evaluator/client.ts +++ b/src/lib/features/playground/feature-evaluator/client.ts @@ -77,9 +77,6 @@ export default class UnleashClient { } if (parent.enabled !== false) { - if (!parentToggle.enabled) { - return false; - } if (parent.variants?.length) { return parent.variants.includes( this.getVariant(parent.feature, context).name, @@ -91,12 +88,9 @@ export default class UnleashClient { ); } - return ( - !parentToggle.enabled && - !( - this.isEnabled(parent.feature, context, () => false) - .result === true - ) + return !( + this.isEnabled(parent.feature, context, () => false).result === + true ); }); } diff --git a/src/test/e2e/helpers/test-helper.ts b/src/test/e2e/helpers/test-helper.ts index a06f4a5b5c90..bc4f81491b63 100644 --- a/src/test/e2e/helpers/test-helper.ts +++ b/src/test/e2e/helpers/test-helper.ts @@ -15,6 +15,7 @@ import type { Db } from '../../../lib/db/db'; import type { IContextFieldDto } from '../../../lib/types/stores/context-field-store'; import { DEFAULT_ENV } from '../../../lib/util'; import type { + CreateDependentFeatureSchema, CreateFeatureSchema, CreateFeatureStrategySchema, ImportTogglesSchema, @@ -102,7 +103,10 @@ export interface IUnleashHttpAPI { expectedResponseCode?: number, ): supertest.Test; - addDependency(child: string, parent: string): supertest.Test; + addDependency( + child: string, + parent: string | CreateDependentFeatureSchema, + ): supertest.Test; addTag( feature: string, @@ -224,7 +228,7 @@ function httpApis( addDependency( child: string, - parent: string, + parent: string | CreateDependentFeatureSchema, project = DEFAULT_PROJECT, expectedResponseCode: number = 200, ): supertest.Test { @@ -232,7 +236,7 @@ function httpApis( .post( `/api/admin/projects/${project}/features/${child}/dependencies`, ) - .send({ feature: parent }) + .send(typeof parent === 'string' ? { feature: parent } : parent) .set('Content-Type', 'application/json') .expect(expectedResponseCode); },