mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	fix: upgrade unleash-client to v5.3.0 (#5800)
This commit is contained in:
		
							parent
							
								
									3957abf0f6
								
							
						
					
					
						commit
						68eb3dec07
					
				@ -23,6 +23,7 @@ test('should render environment table', async () => {
 | 
			
		||||
                            type: 'string',
 | 
			
		||||
                            value: 'variantValue',
 | 
			
		||||
                        },
 | 
			
		||||
                        feature_enabled: true,
 | 
			
		||||
                    },
 | 
			
		||||
                    environment: 'dev',
 | 
			
		||||
                    context: {
 | 
			
		||||
 | 
			
		||||
@ -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. */
 | 
			
		||||
 | 
			
		||||
@ -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 */
 | 
			
		||||
 | 
			
		||||
@ -15,4 +15,5 @@ export const ProxyFeatureSchemaVariantPayloadType = {
 | 
			
		||||
    json: 'json',
 | 
			
		||||
    csv: 'csv',
 | 
			
		||||
    string: 'string',
 | 
			
		||||
    number: 'number',
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
@ -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. */
 | 
			
		||||
 | 
			
		||||
@ -15,4 +15,5 @@ export const VariantFlagSchemaPayloadType = {
 | 
			
		||||
    string: 'string',
 | 
			
		||||
    json: 'json',
 | 
			
		||||
    csv: 'csv',
 | 
			
		||||
    number: 'number',
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
@ -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": {
 | 
			
		||||
 | 
			
		||||
@ -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,8 +299,7 @@ test('advanced playground evaluation happy path', async () => {
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
test('show matching variant from variants selection only for enabled toggles', async () => {
 | 
			
		||||
    const variants = [
 | 
			
		||||
        {
 | 
			
		||||
    const variant = {
 | 
			
		||||
        stickiness: 'random',
 | 
			
		||||
        name: 'a',
 | 
			
		||||
        weight: 1000,
 | 
			
		||||
@ -308,8 +308,8 @@ test('show matching variant from variants selection only for enabled toggles', a
 | 
			
		||||
            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');
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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 {
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,7 @@ export const offlineUnleashClientNode = async ({
 | 
			
		||||
        storageProvider: new InMemStorageProviderNode(),
 | 
			
		||||
        bootstrap: {
 | 
			
		||||
            data: mapFeaturesForClient(features),
 | 
			
		||||
            segments: mapSegmentsForClient(segments),
 | 
			
		||||
            segments: mapSegmentsForClient(segments || []),
 | 
			
		||||
        },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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, ...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) => ({
 | 
			
		||||
            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 || []),
 | 
			
		||||
        },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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 },
 | 
			
		||||
 | 
			
		||||
@ -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 },
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
                        },
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@ -177,13 +177,12 @@ export const seedDatabaseForPlaygroundTest = async (
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
describe('the playground service (e2e)', () => {
 | 
			
		||||
    const isDisabledVariant = ({
 | 
			
		||||
        name,
 | 
			
		||||
        enabled,
 | 
			
		||||
    }: {
 | 
			
		||||
    const isDisabledVariant = (
 | 
			
		||||
        variant?: {
 | 
			
		||||
            name: string;
 | 
			
		||||
            enabled: boolean;
 | 
			
		||||
    }) => name === 'disabled' && !enabled;
 | 
			
		||||
        } | 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,
 | 
			
		||||
                                });
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
@ -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"
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user