diff --git a/frontend/src/component/playground/Playground/PlaygroundEnvironmentTable/PlaygroundEnvironmentTable.test.tsx b/frontend/src/component/playground/Playground/PlaygroundEnvironmentTable/PlaygroundEnvironmentTable.test.tsx index d9520fb8db..c05014c603 100644 --- a/frontend/src/component/playground/Playground/PlaygroundEnvironmentTable/PlaygroundEnvironmentTable.test.tsx +++ b/frontend/src/component/playground/Playground/PlaygroundEnvironmentTable/PlaygroundEnvironmentTable.test.tsx @@ -23,6 +23,7 @@ test('should render environment table', async () => { type: 'string', value: 'variantValue', }, + feature_enabled: true, }, environment: 'dev', context: { diff --git a/frontend/src/openapi/models/advancedPlaygroundEnvironmentFeatureSchemaVariant.ts b/frontend/src/openapi/models/advancedPlaygroundEnvironmentFeatureSchemaVariant.ts index 44b4b0eede..ccf260800a 100644 --- a/frontend/src/openapi/models/advancedPlaygroundEnvironmentFeatureSchemaVariant.ts +++ b/frontend/src/openapi/models/advancedPlaygroundEnvironmentFeatureSchemaVariant.ts @@ -14,6 +14,8 @@ import type { AdvancedPlaygroundEnvironmentFeatureSchemaVariantPayload } from '. export type AdvancedPlaygroundEnvironmentFeatureSchemaVariant = { /** Whether the variant is enabled or not. If the feature is disabled or if it doesn't have variants, this property will be `false` */ enabled: boolean; + /** Whether the feature is enabled or not. If the feature is disabled, this property will be `false` */ + feature_enabled?: boolean; /** The variant's name. If there is no variant or if the toggle is disabled, this will be `disabled` */ name: string; /** An optional payload attached to the variant. */ diff --git a/frontend/src/openapi/models/proxyFeatureSchemaVariant.ts b/frontend/src/openapi/models/proxyFeatureSchemaVariant.ts index a6743163e6..143aaa8e0b 100644 --- a/frontend/src/openapi/models/proxyFeatureSchemaVariant.ts +++ b/frontend/src/openapi/models/proxyFeatureSchemaVariant.ts @@ -11,6 +11,8 @@ import type { ProxyFeatureSchemaVariantPayload } from './proxyFeatureSchemaVaria export type ProxyFeatureSchemaVariant = { /** Whether the variant is enabled or not. */ enabled: boolean; + /** Whether the feature is enabled or not. */ + feature_enabled?: boolean; /** The variants name. Is unique for this feature toggle */ name: string; /** Extra data configured for this variant */ diff --git a/frontend/src/openapi/models/proxyFeatureSchemaVariantPayloadType.ts b/frontend/src/openapi/models/proxyFeatureSchemaVariantPayloadType.ts index 6680e4f6fe..149a26c041 100644 --- a/frontend/src/openapi/models/proxyFeatureSchemaVariantPayloadType.ts +++ b/frontend/src/openapi/models/proxyFeatureSchemaVariantPayloadType.ts @@ -15,4 +15,5 @@ export const ProxyFeatureSchemaVariantPayloadType = { json: 'json', csv: 'csv', string: 'string', + number: 'number', } as const; diff --git a/frontend/src/openapi/models/variantFlagSchema.ts b/frontend/src/openapi/models/variantFlagSchema.ts index cc9d00b5d4..e2472e2ee1 100644 --- a/frontend/src/openapi/models/variantFlagSchema.ts +++ b/frontend/src/openapi/models/variantFlagSchema.ts @@ -11,6 +11,8 @@ import type { VariantFlagSchemaPayload } from './variantFlagSchemaPayload'; export interface VariantFlagSchema { /** Whether the variant is enabled or not. */ enabled?: boolean; + /** Whether the feature is enabled or not. */ + feature_enabled?: boolean; /** The name of the variant. Will always be disabled if `enabled` is false. */ name?: string; /** Additional data associated with this variant. */ diff --git a/frontend/src/openapi/models/variantFlagSchemaPayloadType.ts b/frontend/src/openapi/models/variantFlagSchemaPayloadType.ts index 85f7038ba1..2b6429ead8 100644 --- a/frontend/src/openapi/models/variantFlagSchemaPayloadType.ts +++ b/frontend/src/openapi/models/variantFlagSchemaPayloadType.ts @@ -15,4 +15,5 @@ export const VariantFlagSchemaPayloadType = { string: 'string', json: 'json', csv: 'csv', + number: 'number', } as const; diff --git a/package.json b/package.json index f67d2ae4d2..c88f4fa2ef 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "stoppable": "^1.1.0", "ts-toolbelt": "^9.6.0", "type-is": "^1.6.18", - "unleash-client": "5.0.0", + "unleash-client": "5.3.1", "uuid": "^9.0.0" }, "devDependencies": { diff --git a/src/lib/features/playground/advanced-playground.test.ts b/src/lib/features/playground/advanced-playground.test.ts index 0e0be020c3..6086b8b4f9 100644 --- a/src/lib/features/playground/advanced-playground.test.ts +++ b/src/lib/features/playground/advanced-playground.test.ts @@ -120,6 +120,7 @@ test('advanced playground evaluation with parent dependency', async () => { expect(child.variant).toEqual({ name: 'disabled', enabled: false, + feature_enabled: false, }); expect(parent.hasUnsatisfiedDependency).toBe(false); expect(parent.isEnabled).toBe(false); @@ -298,18 +299,17 @@ test('advanced playground evaluation happy path', async () => { }); }); test('show matching variant from variants selection only for enabled toggles', async () => { - const variants = [ - { - stickiness: 'random', - name: 'a', - weight: 1000, - payload: { - type: 'string', - value: 'aval', - }, - weightType: 'variable', + const variant = { + stickiness: 'random', + name: 'a', + weight: 1000, + payload: { + type: 'string', + value: 'aval', }, - ]; + weightType: 'variable', + }; + await createFeatureToggleWithStrategy( 'test-playground-feature-with-variants', { @@ -320,7 +320,7 @@ test('show matching variant from variants selection only for enabled toggles', a stickiness: 'random', groupId: 'test-playground-feature-with-variants', }, - variants, + variants: [variant], }, ); @@ -347,7 +347,7 @@ test('show matching variant from variants selection only for enabled toggles', a enabledFeatures.forEach((feature) => { expect(feature.variant?.name).toBe('a'); - expect(feature.variants).toMatchObject(variants); + expect(feature.variants).toMatchObject([variant]); }); disabledFeatures.forEach((feature) => { expect(feature.variant?.name).toBe('disabled'); diff --git a/src/lib/features/playground/feature-evaluator/client.ts b/src/lib/features/playground/feature-evaluator/client.ts index 0c0678f746..e5b737c553 100644 --- a/src/lib/features/playground/feature-evaluator/client.ts +++ b/src/lib/features/playground/feature-evaluator/client.ts @@ -11,17 +11,18 @@ import { Context } from './context'; import { SegmentForEvaluation } from './strategy/strategy'; import { PlaygroundStrategySchema } from '../../../openapi/spec/playground-strategy-schema'; import { playgroundStrategyEvaluation } from '../../../openapi/spec/playground-strategy-schema'; - -export type StrategyEvaluationResult = Pick< - PlaygroundStrategySchema, - 'result' | 'segments' | 'constraints' ->; +import { randomId } from '../../../util'; export type EvaluatedPlaygroundStrategy = Omit< PlaygroundStrategySchema, 'links' >; +export type StrategyEvaluationResult = Pick< + EvaluatedPlaygroundStrategy, + 'result' | 'segments' | 'constraints' +>; + export type FeatureStrategiesEvaluationResult = { result: boolean | typeof playgroundStrategyEvaluation.unknownResult; variant?: Variant; @@ -144,26 +145,32 @@ export default class UnleashClient { const strategies = feature.strategies.map( (strategySelector): EvaluatedPlaygroundStrategy => { - const getStrategy = () => { + const getStrategy = (): Strategy => { + // assume that 'unknown' strategy is always present + const unknownStrategy = this.getStrategy( + 'unknown', + ) as Strategy; + // the application hostname strategy relies on external // variables to calculate its result. As such, we can't // evaluate it in a way that makes sense. So we'll // use the 'unknown' strategy instead. if (strategySelector.name === 'applicationHostname') { - return this.getStrategy('unknown'); + return unknownStrategy; } + return ( this.getStrategy(strategySelector.name) ?? - this.getStrategy('unknown') + unknownStrategy ); }; const strategy = getStrategy(); const segments = - strategySelector.segments + (strategySelector.segments ?.map(this.getSegment(this.repository)) - .filter(Boolean) ?? []; + .filter(Boolean) as SegmentForEvaluation[]) ?? []; const evaluationResult = strategy.isEnabledWithConstraints( strategySelector.parameters, @@ -176,7 +183,7 @@ export default class UnleashClient { return { name: strategySelector.name, - id: strategySelector.id, + id: strategySelector.id || randomId(), title: strategySelector.title, disabled: strategySelector.disabled || false, parameters: strategySelector.parameters, @@ -189,7 +196,7 @@ export default class UnleashClient { const overallStrategyResult = (): [ boolean | typeof playgroundStrategyEvaluation.unknownResult, VariantDefinition[] | undefined, - Variant | undefined | null, + Variant | undefined, ] => { // if at least one strategy is enabled, then the feature is enabled const enabledStrategy = strategies.find( @@ -202,7 +209,7 @@ export default class UnleashClient { return [ true, enabledStrategy.result.variants, - enabledStrategy.result.variant, + enabledStrategy.result.variant || undefined, ]; } @@ -284,7 +291,11 @@ export default class UnleashClient { 'result' | 'variant' >, ): Variant { - const fallback = fallbackVariant || getDefaultVariant(); + const fallback = { + feature_enabled: false, + featureEnabled: false, + ...(fallbackVariant || getDefaultVariant()), + }; const feature = this.repository.getToggle(name); if ( @@ -294,13 +305,14 @@ export default class UnleashClient { return fallback; } - let enabled = true; const result = forcedResult ?? this.isFeatureEnabled(feature, context, () => fallbackVariant ? fallbackVariant.enabled : false, ); - enabled = result.result === true; + const enabled = result.result === true; + fallback.feature_enabled = fallbackVariant?.feature_enabled ?? enabled; + fallback.featureEnabled = fallback.feature_enabled; const strategyVariant = result.variant; if (enabled && strategyVariant) { return strategyVariant; @@ -330,6 +342,8 @@ export default class UnleashClient { name: variant.name, payload: variant.payload, enabled, + feature_enabled: true, + featureEnabled: true, }; } } diff --git a/src/lib/features/playground/feature-evaluator/feature-evaluator.ts b/src/lib/features/playground/feature-evaluator/feature-evaluator.ts index c56340906c..e60ba8dda9 100644 --- a/src/lib/features/playground/feature-evaluator/feature-evaluator.ts +++ b/src/lib/features/playground/feature-evaluator/feature-evaluator.ts @@ -11,6 +11,7 @@ import { resolveBootstrapProvider, } from './repository/bootstrap-provider'; import { StorageProvider } from './repository/storage-provider'; +import InMemStorageProvider from './repository/storage-provider-in-mem'; export { Strategy }; @@ -41,7 +42,7 @@ export class FeatureEvaluator { strategies = [], repository, bootstrap = { data: [] }, - storageProvider, + storageProvider = new InMemStorageProvider(), }: FeatureEvaluatorConfig) { this.staticContext = { appName, environment }; @@ -52,7 +53,7 @@ export class FeatureEvaluator { new Repository({ appName, bootstrapProvider, - storageProvider: storageProvider, + storageProvider, }); // setup client diff --git a/src/lib/features/playground/feature-evaluator/variant.ts b/src/lib/features/playground/feature-evaluator/variant.ts index 0209d57307..3537d9bedf 100644 --- a/src/lib/features/playground/feature-evaluator/variant.ts +++ b/src/lib/features/playground/feature-evaluator/variant.ts @@ -26,6 +26,11 @@ export interface Variant { name: string; enabled: boolean; payload?: Payload; + featureEnabled?: boolean; + /** + * @deprecated use featureEnabled + */ + feature_enabled?: boolean; } export function getDefaultVariant(): Variant { diff --git a/src/lib/features/playground/offline-unleash-client.test.ts b/src/lib/features/playground/offline-unleash-client.test.ts index bad4d00b0b..7306ecc491 100644 --- a/src/lib/features/playground/offline-unleash-client.test.ts +++ b/src/lib/features/playground/offline-unleash-client.test.ts @@ -27,7 +27,7 @@ export const offlineUnleashClientNode = async ({ storageProvider: new InMemStorageProviderNode(), bootstrap: { data: mapFeaturesForClient(features), - segments: mapSegmentsForClient(segments), + segments: mapSegmentsForClient(segments || []), }, }); diff --git a/src/lib/features/playground/offline-unleash-client.ts b/src/lib/features/playground/offline-unleash-client.ts index 1b966fbc85..c1b580929f 100644 --- a/src/lib/features/playground/offline-unleash-client.ts +++ b/src/lib/features/playground/offline-unleash-client.ts @@ -5,8 +5,9 @@ import { Segment } from './feature-evaluator/strategy/strategy'; import { ISegment } from '../../types/model'; import { serializeDates } from '../../types/serialize-dates'; import { Operator } from './feature-evaluator/constraint'; -import { FeatureInterface } from 'unleash-client/lib/feature'; import { PayloadType } from 'unleash-client'; +import { FeatureInterface } from 'unleash-client/lib/feature'; +import { FeatureInterface as PlaygroundFeatureInterface } from './feature-evaluator/feature'; type NonEmptyList = [T, ...T[]]; @@ -28,6 +29,8 @@ export const mapFeaturesForClient = ( strategies: feature.strategies.map((strategy) => ({ parameters: {}, ...strategy, + title: strategy.title ?? undefined, + disabled: strategy.disabled ?? false, variants: (strategy.variants || []).map((variant) => ({ ...variant, payload: variant.payload && { @@ -35,12 +38,13 @@ export const mapFeaturesForClient = ( type: variant.payload.type as PayloadType, }, })), - constraints: strategy.constraints?.map((constraint) => ({ - inverted: false, - values: [], - ...constraint, - operator: constraint.operator as unknown as Operator, - })), + constraints: + strategy.constraints?.map((constraint) => ({ + inverted: false, + values: [], + ...constraint, + operator: constraint.operator as unknown as Operator, + })) || [], })), dependencies: feature.dependencies, })); @@ -65,8 +69,11 @@ export const offlineUnleashClient = async ({ appName: context.appName, storageProvider: new InMemStorageProvider(), bootstrap: { - data: mapFeaturesForClient(features), - segments: mapSegmentsForClient(segments), + // FIXME: mismatch between playground and proxy types + data: mapFeaturesForClient( + features, + ) as PlaygroundFeatureInterface[], + segments: mapSegmentsForClient(segments || []), }, }); diff --git a/src/lib/features/playground/playground-service.ts b/src/lib/features/playground/playground-service.ts index 6d5e3543c6..caefb5f0b8 100644 --- a/src/lib/features/playground/playground-service.ts +++ b/src/lib/features/playground/playground-service.ts @@ -203,6 +203,17 @@ export class PlaygroundService { feature.enabled && !hasUnsatisfiedDependency; + const variant = { + ...(isEnabled + ? client.forceGetVariant( + feature.name, + strategyEvaluationResult, + clientContext, + ) + : getDefaultVariant()), + feature_enabled: isEnabled, + }; + return { isEnabled, isEnabledInCurrentEnvironment: feature.enabled, @@ -212,13 +223,7 @@ export class PlaygroundService { data: strategyEvaluationResult.strategies, }, projectId: featureProject[feature.name], - variant: isEnabled - ? client.forceGetVariant( - feature.name, - strategyEvaluationResult, - clientContext, - ) - : getDefaultVariant(), + variant, name: feature.name, environment, context, diff --git a/src/lib/openapi/spec/advanced-playground-environment-feature-schema.ts b/src/lib/openapi/spec/advanced-playground-environment-feature-schema.ts index 5401d82a71..011e74660d 100644 --- a/src/lib/openapi/spec/advanced-playground-environment-feature-schema.ts +++ b/src/lib/openapi/spec/advanced-playground-environment-feature-schema.ts @@ -127,6 +127,11 @@ export const advancedPlaygroundEnvironmentFeatureSchema = { }, }, }, + feature_enabled: { + type: 'boolean', + description: + 'Whether the feature is enabled or not. If the feature is disabled, this property will be `false`', + }, }, nullable: true, example: { name: 'green', enabled: true }, diff --git a/src/lib/openapi/spec/playground-feature-schema.ts b/src/lib/openapi/spec/playground-feature-schema.ts index d4bf1eed93..aa58ff8c47 100644 --- a/src/lib/openapi/spec/playground-feature-schema.ts +++ b/src/lib/openapi/spec/playground-feature-schema.ts @@ -121,6 +121,17 @@ export const playgroundFeatureSchema = { }, }, }, + feature_enabled: { + type: 'boolean', + description: 'Use `featureEnabled` instead.', + example: true, + }, + featureEnabled: { + deprecated: true, + type: 'boolean', + description: 'Whether the feature is enabled or not.', + example: true, + }, }, nullable: true, example: { name: 'green', enabled: true }, diff --git a/src/lib/openapi/spec/proxy-feature-schema.ts b/src/lib/openapi/spec/proxy-feature-schema.ts index d7bd1a3782..f9202a8b40 100644 --- a/src/lib/openapi/spec/proxy-feature-schema.ts +++ b/src/lib/openapi/spec/proxy-feature-schema.ts @@ -50,7 +50,7 @@ export const proxyFeatureSchema = { type: { type: 'string', description: 'The format of the payload.', - enum: ['json', 'csv', 'string'], + enum: ['json', 'csv', 'string', 'number'], }, value: { type: 'string', @@ -58,6 +58,17 @@ export const proxyFeatureSchema = { }, }, }, + feature_enabled: { + type: 'boolean', + description: 'Whether the feature is enabled or not.', + example: true, + }, + featureEnabled: { + deprecated: true, + type: 'boolean', + description: 'Use `feature_enabled` instead.', + example: true, + }, }, }, }, diff --git a/src/lib/openapi/spec/variant-flag-schema.ts b/src/lib/openapi/spec/variant-flag-schema.ts index 939a0b5100..0947d16f69 100644 --- a/src/lib/openapi/spec/variant-flag-schema.ts +++ b/src/lib/openapi/spec/variant-flag-schema.ts @@ -25,7 +25,7 @@ export const variantFlagSchema = { type: { description: 'The type of data contained.', type: 'string', - enum: ['string', 'json', 'csv'], + enum: ['string', 'json', 'csv', 'number'], example: 'json', }, value: { @@ -35,6 +35,17 @@ export const variantFlagSchema = { }, }, }, + feature_enabled: { + type: 'boolean', + description: 'Whether the feature is enabled or not.', + example: true, + }, + featureEnabled: { + deprecated: true, + type: 'boolean', + description: 'Use `feature_enabled` instead.', + example: true, + }, }, components: {}, } as const; diff --git a/src/test/e2e/api/proxy/proxy.e2e.test.ts b/src/test/e2e/api/proxy/proxy.e2e.test.ts index 5c4f44bc8a..0e8400a3a3 100644 --- a/src/test/e2e/api/proxy/proxy.e2e.test.ts +++ b/src/test/e2e/api/proxy/proxy.e2e.test.ts @@ -449,13 +449,23 @@ test('should filter features by enabled/disabled', async () => { name: 'enabledFeature1', enabled: true, impressionData: false, - variant: { enabled: false, name: 'disabled' }, + variant: { + enabled: false, + name: 'disabled', + feature_enabled: true, + featureEnabled: true, + }, }, { name: 'enabledFeature2', enabled: true, impressionData: false, - variant: { enabled: false, name: 'disabled' }, + variant: { + enabled: false, + name: 'disabled', + feature_enabled: true, + featureEnabled: true, + }, }, ], }); @@ -486,7 +496,12 @@ test('should filter features by strategies', async () => { name: 'featureWithMultipleStrategies', enabled: true, impressionData: false, - variant: { enabled: false, name: 'disabled' }, + variant: { + enabled: false, + name: 'disabled', + feature_enabled: true, + featureEnabled: true, + }, }, ], }); @@ -629,7 +644,12 @@ test('should filter features by project', async () => { name: 'featureInProjectDefault', enabled: true, impressionData: false, - variant: { enabled: false, name: 'disabled' }, + variant: { + enabled: false, + name: 'disabled', + feature_enabled: true, + featureEnabled: true, + }, }, ], }); @@ -646,7 +666,12 @@ test('should filter features by project', async () => { name: 'featureInProjectA', enabled: true, impressionData: false, - variant: { enabled: false, name: 'disabled' }, + variant: { + enabled: false, + name: 'disabled', + feature_enabled: true, + featureEnabled: true, + }, }, ], }); @@ -663,13 +688,23 @@ test('should filter features by project', async () => { name: 'featureInProjectA', enabled: true, impressionData: false, - variant: { enabled: false, name: 'disabled' }, + variant: { + enabled: false, + name: 'disabled', + feature_enabled: true, + featureEnabled: true, + }, }, { name: 'featureInProjectB', enabled: true, impressionData: false, - variant: { enabled: false, name: 'disabled' }, + variant: { + enabled: false, + name: 'disabled', + feature_enabled: true, + featureEnabled: true, + }, }, ], }); @@ -743,7 +778,12 @@ test('should filter features by environment', async () => { name: 'featureInEnvironmentDefault', enabled: true, impressionData: false, - variant: { enabled: false, name: 'disabled' }, + variant: { + enabled: false, + name: 'disabled', + feature_enabled: true, + featureEnabled: true, + }, }, ], }); @@ -760,7 +800,12 @@ test('should filter features by environment', async () => { name: 'featureInEnvironmentA', enabled: true, impressionData: false, - variant: { enabled: false, name: 'disabled' }, + variant: { + enabled: false, + name: 'disabled', + feature_enabled: true, + featureEnabled: true, + }, }, ], }); @@ -777,7 +822,12 @@ test('should filter features by environment', async () => { name: 'featureInEnvironmentB', enabled: true, impressionData: false, - variant: { enabled: false, name: 'disabled' }, + variant: { + enabled: false, + name: 'disabled', + feature_enabled: true, + featureEnabled: true, + }, }, ], }); @@ -1040,7 +1090,12 @@ test('should evaluate strategies when returning toggles', async () => { name: 'enabledFeature', enabled: true, impressionData: false, - variant: { enabled: false, name: 'disabled' }, + variant: { + enabled: false, + name: 'disabled', + feature_enabled: true, + featureEnabled: true, + }, }, ], }); @@ -1095,13 +1150,23 @@ test('should not return all features', async () => { name: 'enabledFeature1', enabled: true, impressionData: false, - variant: { enabled: false, name: 'disabled' }, + variant: { + enabled: false, + name: 'disabled', + feature_enabled: true, + featureEnabled: true, + }, }, { name: 'enabledFeature2', enabled: true, impressionData: false, - variant: { enabled: false, name: 'disabled' }, + variant: { + enabled: false, + name: 'disabled', + feature_enabled: true, + featureEnabled: true, + }, }, ], }); @@ -1197,7 +1262,12 @@ test('should NOT evaluate disabled strategies when returning toggles', async () name: 'enabledFeature', enabled: true, impressionData: false, - variant: { enabled: false, name: 'disabled' }, + variant: { + enabled: false, + name: 'disabled', + feature_enabled: true, + featureEnabled: true, + }, }, ], }); diff --git a/src/test/e2e/services/playground-service.test.ts b/src/test/e2e/services/playground-service.test.ts index 17778c3bba..0decadfb62 100644 --- a/src/test/e2e/services/playground-service.test.ts +++ b/src/test/e2e/services/playground-service.test.ts @@ -177,13 +177,12 @@ export const seedDatabaseForPlaygroundTest = async ( }; describe('the playground service (e2e)', () => { - const isDisabledVariant = ({ - name, - enabled, - }: { - name: string; - enabled: boolean; - }) => name === 'disabled' && !enabled; + const isDisabledVariant = ( + variant?: { + name: string; + enabled: boolean; + } | null, + ) => variant?.name === 'disabled' && !variant?.enabled; const insertAndEvaluateFeatures = async ({ features, @@ -290,12 +289,12 @@ describe('the playground service (e2e)', () => { ctx.log(JSON.stringify(enabledStateMatches)); ctx.log( JSON.stringify( - feature.variant.name === 'disabled', + feature.variant?.name === 'disabled', ), ); ctx.log( JSON.stringify( - feature.variant.enabled === false, + feature.variant?.enabled === false, ), ); return ( @@ -704,7 +703,7 @@ describe('the playground service (e2e)', () => { }, ); - feature.strategies.forEach( + feature.strategies?.forEach( ({ segments, ...strategy }) => { expect(cleanedReceivedStrategies).toEqual( expect.arrayContaining([ @@ -845,7 +844,7 @@ describe('the playground service (e2e)', () => { features: features.map((feature) => ({ ...feature, // remove any constraints and use a name that doesn't exist - strategies: feature.strategies.map( + strategies: feature.strategies?.map( (strategy) => ({ ...strategy, name: 'bogus-strategy', @@ -907,7 +906,7 @@ describe('the playground service (e2e)', () => { features: features.map((feature) => ({ ...feature, // use a constraint that will never be true - strategies: feature.strategies.map( + strategies: feature.strategies?.map( (strategy) => ({ ...strategy, name: 'bogusStrategy', @@ -1223,6 +1222,7 @@ describe('the playground service (e2e)', () => { expect(feature.variant).toEqual({ name: 'disabled', enabled: false, + feature_enabled: false, }); } }); diff --git a/yarn.lock b/yarn.lock index 9381a054ad..094059316b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7134,10 +7134,10 @@ universalify@^0.2.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== -unleash-client@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/unleash-client/-/unleash-client-5.0.0.tgz#b6725723b38f5572b4b1c5261c1bb2254148ec58" - integrity sha512-9x3SOpHTnMDY0CosKwy/0Hi9gIjw65+i2fsC76bvYaUIVTlqDoPdCfosBokNIZ/IjCF0TjEgSZefSWNGY5SC9A== +unleash-client@5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/unleash-client/-/unleash-client-5.3.1.tgz#8647ea5f8905f21e5fdcb87a79ce91c27a92b605" + integrity sha512-S5WtDNJa9j/JC+tXB/LoBNDMwhtuQ5CxFWge8igoVSspyyypcrKtyd98TSODBeyfzKW0daCyLmE7Pr+jDfROLQ== dependencies: ip "^1.1.8" make-fetch-happen "^10.2.1"