mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: stub for create dependent features (#4769)
This commit is contained in:
		
							parent
							
								
									a71c3fe43a
								
							
						
					
					
						commit
						59f2ae435e
					
				@ -76,6 +76,7 @@ exports[`should create default config 1`] = `
 | 
				
			|||||||
      "caseInsensitiveInOperators": false,
 | 
					      "caseInsensitiveInOperators": false,
 | 
				
			||||||
      "customRootRolesKillSwitch": false,
 | 
					      "customRootRolesKillSwitch": false,
 | 
				
			||||||
      "demo": false,
 | 
					      "demo": false,
 | 
				
			||||||
 | 
					      "dependentFeatures": false,
 | 
				
			||||||
      "disableBulkToggle": false,
 | 
					      "disableBulkToggle": false,
 | 
				
			||||||
      "disableNotifications": false,
 | 
					      "disableNotifications": false,
 | 
				
			||||||
      "doraMetrics": false,
 | 
					      "doraMetrics": false,
 | 
				
			||||||
@ -114,6 +115,7 @@ exports[`should create default config 1`] = `
 | 
				
			|||||||
      "caseInsensitiveInOperators": false,
 | 
					      "caseInsensitiveInOperators": false,
 | 
				
			||||||
      "customRootRolesKillSwitch": false,
 | 
					      "customRootRolesKillSwitch": false,
 | 
				
			||||||
      "demo": false,
 | 
					      "demo": false,
 | 
				
			||||||
 | 
					      "dependentFeatures": false,
 | 
				
			||||||
      "disableBulkToggle": false,
 | 
					      "disableBulkToggle": false,
 | 
				
			||||||
      "disableNotifications": false,
 | 
					      "disableNotifications": false,
 | 
				
			||||||
      "doraMetrics": false,
 | 
					      "doraMetrics": false,
 | 
				
			||||||
 | 
				
			|||||||
@ -158,6 +158,8 @@ import {
 | 
				
			|||||||
    createGroupSchema,
 | 
					    createGroupSchema,
 | 
				
			||||||
    doraFeaturesSchema,
 | 
					    doraFeaturesSchema,
 | 
				
			||||||
    projectDoraMetricsSchema,
 | 
					    projectDoraMetricsSchema,
 | 
				
			||||||
 | 
					    dependentFeatureSchema,
 | 
				
			||||||
 | 
					    createDependentFeatureSchema,
 | 
				
			||||||
} from './spec';
 | 
					} from './spec';
 | 
				
			||||||
import { IServerOption } from '../types';
 | 
					import { IServerOption } from '../types';
 | 
				
			||||||
import { mapValues, omitKeys } from '../util';
 | 
					import { mapValues, omitKeys } from '../util';
 | 
				
			||||||
@ -375,6 +377,8 @@ export const schemas: UnleashSchemas = {
 | 
				
			|||||||
    createFeatureNamingPatternSchema,
 | 
					    createFeatureNamingPatternSchema,
 | 
				
			||||||
    doraFeaturesSchema,
 | 
					    doraFeaturesSchema,
 | 
				
			||||||
    projectDoraMetricsSchema,
 | 
					    projectDoraMetricsSchema,
 | 
				
			||||||
 | 
					    dependentFeatureSchema,
 | 
				
			||||||
 | 
					    createDependentFeatureSchema,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Remove JSONSchema keys that would result in an invalid OpenAPI spec.
 | 
					// Remove JSONSchema keys that would result in an invalid OpenAPI spec.
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										35
									
								
								src/lib/openapi/spec/create-dependent-feature-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/lib/openapi/spec/create-dependent-feature-schema.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					import { FromSchema } from 'json-schema-to-ts';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const createDependentFeatureSchema = {
 | 
				
			||||||
 | 
					    $id: '#/components/schemas/createDependentFeatureSchema',
 | 
				
			||||||
 | 
					    type: 'object',
 | 
				
			||||||
 | 
					    description: 'Feature dependency on a parent feature in write model',
 | 
				
			||||||
 | 
					    required: ['feature'],
 | 
				
			||||||
 | 
					    properties: {
 | 
				
			||||||
 | 
					        feature: {
 | 
				
			||||||
 | 
					            type: 'string',
 | 
				
			||||||
 | 
					            description: 'The name of the feature we depend on.',
 | 
				
			||||||
 | 
					            example: 'parent_feature',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        enabled: {
 | 
				
			||||||
 | 
					            type: 'boolean',
 | 
				
			||||||
 | 
					            description:
 | 
				
			||||||
 | 
					                'Whether the parent feature should be enabled. When `false` variants are ignored. `true` by default.',
 | 
				
			||||||
 | 
					            example: false,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        variants: {
 | 
				
			||||||
 | 
					            type: 'array',
 | 
				
			||||||
 | 
					            description:
 | 
				
			||||||
 | 
					                'The list of variants the parent feature should resolve to. Leave empty when you only want to check the `enabled` status.',
 | 
				
			||||||
 | 
					            items: {
 | 
				
			||||||
 | 
					                type: 'string',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            example: ['variantA', 'variantB'],
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    components: {},
 | 
				
			||||||
 | 
					} as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type CreateDependentFeatureSchema = FromSchema<
 | 
				
			||||||
 | 
					    typeof createDependentFeatureSchema
 | 
				
			||||||
 | 
					>;
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/lib/openapi/spec/dependent-feature-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/lib/openapi/spec/dependent-feature-schema.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					import { FromSchema } from 'json-schema-to-ts';
 | 
				
			||||||
 | 
					import { createDependentFeatureSchema } from './create-dependent-feature-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const dependentFeatureSchema = {
 | 
				
			||||||
 | 
					    $id: '#/components/schemas/dependentFeatureSchema',
 | 
				
			||||||
 | 
					    type: 'object',
 | 
				
			||||||
 | 
					    description: 'Feature dependency on a parent feature in read model',
 | 
				
			||||||
 | 
					    required: ['feature'],
 | 
				
			||||||
 | 
					    additionalProperties: false,
 | 
				
			||||||
 | 
					    properties: createDependentFeatureSchema.properties,
 | 
				
			||||||
 | 
					    components: {},
 | 
				
			||||||
 | 
					} as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type DependentFeatureSchema = FromSchema<typeof dependentFeatureSchema>;
 | 
				
			||||||
@ -157,3 +157,5 @@ export * from './create-group-schema';
 | 
				
			|||||||
export * from './application-usage-schema';
 | 
					export * from './application-usage-schema';
 | 
				
			||||||
export * from './dora-features-schema';
 | 
					export * from './dora-features-schema';
 | 
				
			||||||
export * from './project-dora-metrics-schema';
 | 
					export * from './project-dora-metrics-schema';
 | 
				
			||||||
 | 
					export * from './dependent-feature-schema';
 | 
				
			||||||
 | 
					export * from './create-dependent-feature-schema';
 | 
				
			||||||
 | 
				
			|||||||
@ -2,18 +2,18 @@ import { Request, Response } from 'express';
 | 
				
			|||||||
import { applyPatch, Operation } from 'fast-json-patch';
 | 
					import { applyPatch, Operation } from 'fast-json-patch';
 | 
				
			||||||
import Controller from '../../controller';
 | 
					import Controller from '../../controller';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    IUnleashConfig,
 | 
					 | 
				
			||||||
    IUnleashServices,
 | 
					 | 
				
			||||||
    serializeDates,
 | 
					 | 
				
			||||||
    CREATE_FEATURE,
 | 
					    CREATE_FEATURE,
 | 
				
			||||||
    CREATE_FEATURE_STRATEGY,
 | 
					    CREATE_FEATURE_STRATEGY,
 | 
				
			||||||
    DELETE_FEATURE,
 | 
					    DELETE_FEATURE,
 | 
				
			||||||
    DELETE_FEATURE_STRATEGY,
 | 
					    DELETE_FEATURE_STRATEGY,
 | 
				
			||||||
 | 
					    IFlagResolver,
 | 
				
			||||||
 | 
					    IUnleashConfig,
 | 
				
			||||||
 | 
					    IUnleashServices,
 | 
				
			||||||
    NONE,
 | 
					    NONE,
 | 
				
			||||||
 | 
					    serializeDates,
 | 
				
			||||||
    UPDATE_FEATURE,
 | 
					    UPDATE_FEATURE,
 | 
				
			||||||
    UPDATE_FEATURE_ENVIRONMENT,
 | 
					    UPDATE_FEATURE_ENVIRONMENT,
 | 
				
			||||||
    UPDATE_FEATURE_STRATEGY,
 | 
					    UPDATE_FEATURE_STRATEGY,
 | 
				
			||||||
    IFlagResolver,
 | 
					 | 
				
			||||||
} from '../../../types';
 | 
					} from '../../../types';
 | 
				
			||||||
import { Logger } from '../../../logger';
 | 
					import { Logger } from '../../../logger';
 | 
				
			||||||
import { extractUsername } from '../../../util';
 | 
					import { extractUsername } from '../../../util';
 | 
				
			||||||
@ -42,9 +42,9 @@ import {
 | 
				
			|||||||
    UpdateFeatureStrategySchema,
 | 
					    UpdateFeatureStrategySchema,
 | 
				
			||||||
} from '../../../openapi';
 | 
					} from '../../../openapi';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    OpenApiService,
 | 
					 | 
				
			||||||
    FeatureToggleService,
 | 
					 | 
				
			||||||
    FeatureTagService,
 | 
					    FeatureTagService,
 | 
				
			||||||
 | 
					    FeatureToggleService,
 | 
				
			||||||
 | 
					    OpenApiService,
 | 
				
			||||||
} from '../../../services';
 | 
					} from '../../../services';
 | 
				
			||||||
import { querySchema } from '../../../schema/feature-schema';
 | 
					import { querySchema } from '../../../schema/feature-schema';
 | 
				
			||||||
import { BatchStaleSchema } from '../../../openapi/spec/batch-stale-schema';
 | 
					import { BatchStaleSchema } from '../../../openapi/spec/batch-stale-schema';
 | 
				
			||||||
@ -52,7 +52,8 @@ import {
 | 
				
			|||||||
    TransactionCreator,
 | 
					    TransactionCreator,
 | 
				
			||||||
    UnleashTransaction,
 | 
					    UnleashTransaction,
 | 
				
			||||||
} from '../../../db/transaction';
 | 
					} from '../../../db/transaction';
 | 
				
			||||||
import { BadDataError } from '../../../error';
 | 
					import { BadDataError, InvalidOperationError } from '../../../error';
 | 
				
			||||||
 | 
					import { CreateDependentFeatureSchema } from '../../../openapi/spec/create-dependent-feature-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface FeatureStrategyParams {
 | 
					interface FeatureStrategyParams {
 | 
				
			||||||
    projectId: string;
 | 
					    projectId: string;
 | 
				
			||||||
@ -99,6 +100,7 @@ const PATH_ENV = `${PATH_FEATURE}/environments/:environment`;
 | 
				
			|||||||
const BULK_PATH_ENV = `/:projectId/bulk_features/environments/:environment`;
 | 
					const BULK_PATH_ENV = `/:projectId/bulk_features/environments/:environment`;
 | 
				
			||||||
const PATH_STRATEGIES = `${PATH_ENV}/strategies`;
 | 
					const PATH_STRATEGIES = `${PATH_ENV}/strategies`;
 | 
				
			||||||
const PATH_STRATEGY = `${PATH_STRATEGIES}/:strategyId`;
 | 
					const PATH_STRATEGY = `${PATH_STRATEGIES}/:strategyId`;
 | 
				
			||||||
 | 
					const PATH_DEPENDENCIES = `${PATH_FEATURE}/dependencies`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ProjectFeaturesServices = Pick<
 | 
					type ProjectFeaturesServices = Pick<
 | 
				
			||||||
    IUnleashServices,
 | 
					    IUnleashServices,
 | 
				
			||||||
@ -297,6 +299,29 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
            ],
 | 
					            ],
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.route({
 | 
				
			||||||
 | 
					            method: 'post',
 | 
				
			||||||
 | 
					            path: PATH_DEPENDENCIES,
 | 
				
			||||||
 | 
					            handler: this.addFeatureDependency,
 | 
				
			||||||
 | 
					            permission: CREATE_FEATURE,
 | 
				
			||||||
 | 
					            middleware: [
 | 
				
			||||||
 | 
					                openApiService.validPath({
 | 
				
			||||||
 | 
					                    tags: ['Features'],
 | 
				
			||||||
 | 
					                    summary: 'Add a feature dependency.',
 | 
				
			||||||
 | 
					                    description:
 | 
				
			||||||
 | 
					                        'Add a dependency to a parent feature. Each environment will resolve corresponding dependency independently.',
 | 
				
			||||||
 | 
					                    operationId: 'addFeatureDependency',
 | 
				
			||||||
 | 
					                    requestBody: createRequestSchema(
 | 
				
			||||||
 | 
					                        'createDependentFeatureSchema',
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                    responses: {
 | 
				
			||||||
 | 
					                        200: emptyResponse,
 | 
				
			||||||
 | 
					                        ...getStandardResponses(401, 403, 404),
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.route({
 | 
					        this.route({
 | 
				
			||||||
            method: 'get',
 | 
					            method: 'get',
 | 
				
			||||||
            path: PATH_STRATEGY,
 | 
					            path: PATH_STRATEGY,
 | 
				
			||||||
@ -972,6 +997,27 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
        res.status(200).json(updatedStrategy);
 | 
					        res.status(200).json(updatedStrategy);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async addFeatureDependency(
 | 
				
			||||||
 | 
					        req: IAuthRequest<FeatureParams, any, CreateDependentFeatureSchema>,
 | 
				
			||||||
 | 
					        res: Response,
 | 
				
			||||||
 | 
					    ): Promise<void> {
 | 
				
			||||||
 | 
					        const { featureName } = req.params;
 | 
				
			||||||
 | 
					        const { variants, enabled, feature } = req.body;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.config.flagResolver.isEnabled('dependentFeatures')) {
 | 
				
			||||||
 | 
					            await this.featureService.upsertFeatureDependency(featureName, {
 | 
				
			||||||
 | 
					                variants,
 | 
				
			||||||
 | 
					                enabled,
 | 
				
			||||||
 | 
					                feature,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            res.status(200).end();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            throw new InvalidOperationError(
 | 
				
			||||||
 | 
					                'Dependent features are not enabled',
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async getFeatureStrategies(
 | 
					    async getFeatureStrategies(
 | 
				
			||||||
        req: Request<FeatureStrategyParams, any, any, any>,
 | 
					        req: Request<FeatureStrategyParams, any, any, any>,
 | 
				
			||||||
        res: Response<FeatureStrategySchema[]>,
 | 
					        res: Response<FeatureStrategySchema[]>,
 | 
				
			||||||
 | 
				
			|||||||
@ -96,6 +96,7 @@ import { ISegmentService } from 'lib/segments/segment-service-interface';
 | 
				
			|||||||
import { IChangeRequestAccessReadModel } from '../features/change-request-access-service/change-request-access-read-model';
 | 
					import { IChangeRequestAccessReadModel } from '../features/change-request-access-service/change-request-access-read-model';
 | 
				
			||||||
import { checkFeatureFlagNamesAgainstPattern } from '../features/feature-naming-pattern/feature-naming-validation';
 | 
					import { checkFeatureFlagNamesAgainstPattern } from '../features/feature-naming-pattern/feature-naming-validation';
 | 
				
			||||||
import { IPrivateProjectChecker } from '../features/private-project/privateProjectCheckerType';
 | 
					import { IPrivateProjectChecker } from '../features/private-project/privateProjectCheckerType';
 | 
				
			||||||
 | 
					import { CreateDependentFeatureSchema } from '../openapi';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IFeatureContext {
 | 
					interface IFeatureContext {
 | 
				
			||||||
    featureName: string;
 | 
					    featureName: string;
 | 
				
			||||||
@ -122,6 +123,15 @@ export type FeatureNameCheckResultWithFeaturePattern =
 | 
				
			|||||||
          featureNaming: IFeatureNaming;
 | 
					          featureNaming: IFeatureNaming;
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type FeatureDependency =
 | 
				
			||||||
 | 
					    | {
 | 
				
			||||||
 | 
					          parent: string;
 | 
				
			||||||
 | 
					          child: string;
 | 
				
			||||||
 | 
					          enabled: true;
 | 
				
			||||||
 | 
					          variants?: string[];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    | { parent: string; child: string; enabled: false };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const oneOf = (values: string[], match: string) => {
 | 
					const oneOf = (values: string[], match: string) => {
 | 
				
			||||||
    return values.some((value) => value === match);
 | 
					    return values.some((value) => value === match);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -2201,6 +2211,27 @@ class FeatureToggleService {
 | 
				
			|||||||
            );
 | 
					            );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async upsertFeatureDependency(
 | 
				
			||||||
 | 
					        parentFeature: string,
 | 
				
			||||||
 | 
					        dependentFeature: CreateDependentFeatureSchema,
 | 
				
			||||||
 | 
					    ): Promise<void> {
 | 
				
			||||||
 | 
					        const { enabled, feature, variants } = dependentFeature;
 | 
				
			||||||
 | 
					        const featureDependency: FeatureDependency =
 | 
				
			||||||
 | 
					            enabled === false
 | 
				
			||||||
 | 
					                ? {
 | 
				
			||||||
 | 
					                      parent: parentFeature,
 | 
				
			||||||
 | 
					                      child: feature,
 | 
				
			||||||
 | 
					                      enabled,
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                : {
 | 
				
			||||||
 | 
					                      parent: parentFeature,
 | 
				
			||||||
 | 
					                      child: feature,
 | 
				
			||||||
 | 
					                      enabled: true,
 | 
				
			||||||
 | 
					                      variants,
 | 
				
			||||||
 | 
					                  };
 | 
				
			||||||
 | 
					        console.log(featureDependency);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default FeatureToggleService;
 | 
					export default FeatureToggleService;
 | 
				
			||||||
 | 
				
			|||||||
@ -30,7 +30,8 @@ export type IFlagKey =
 | 
				
			|||||||
    | 'doraMetrics'
 | 
					    | 'doraMetrics'
 | 
				
			||||||
    | 'variantTypeNumber'
 | 
					    | 'variantTypeNumber'
 | 
				
			||||||
    | 'accessOverview'
 | 
					    | 'accessOverview'
 | 
				
			||||||
    | 'privateProjects';
 | 
					    | 'privateProjects'
 | 
				
			||||||
 | 
					    | 'dependentFeatures';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;
 | 
					export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -130,6 +131,10 @@ const flags: IFlags = {
 | 
				
			|||||||
        process.env.UNLEASH_EXPERIMENTAL_DORA_METRICS,
 | 
					        process.env.UNLEASH_EXPERIMENTAL_DORA_METRICS,
 | 
				
			||||||
        false,
 | 
					        false,
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
 | 
					    dependentFeatures: parseEnvVarBoolean(
 | 
				
			||||||
 | 
					        process.env.UNLEASH_EXPERIMENTAL_DEPENDENT_FEATURES,
 | 
				
			||||||
 | 
					        false,
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
    variantTypeNumber: parseEnvVarBoolean(
 | 
					    variantTypeNumber: parseEnvVarBoolean(
 | 
				
			||||||
        process.env.UNLEASH_EXPERIMENTAL_VARIANT_TYPE_NUMBER,
 | 
					        process.env.UNLEASH_EXPERIMENTAL_VARIANT_TYPE_NUMBER,
 | 
				
			||||||
        false,
 | 
					        false,
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					import { v4 as uuidv4 } from 'uuid';
 | 
				
			||||||
 | 
					import { CreateDependentFeatureSchema } from '../../../../../lib/openapi';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					    IUnleashTest,
 | 
				
			||||||
 | 
					    setupAppWithCustomConfig,
 | 
				
			||||||
 | 
					} from '../../../helpers/test-helper';
 | 
				
			||||||
 | 
					import dbInit, { ITestDb } from '../../../helpers/database-init';
 | 
				
			||||||
 | 
					import getLogger from '../../../../fixtures/no-logger';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let app: IUnleashTest;
 | 
				
			||||||
 | 
					let db: ITestDb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					beforeAll(async () => {
 | 
				
			||||||
 | 
					    db = await dbInit('feature_dependencies', getLogger);
 | 
				
			||||||
 | 
					    app = await setupAppWithCustomConfig(
 | 
				
			||||||
 | 
					        db.stores,
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            experimental: {
 | 
				
			||||||
 | 
					                flags: {
 | 
				
			||||||
 | 
					                    strictSchemaValidation: true,
 | 
				
			||||||
 | 
					                    dependentFeatures: true,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        db.rawDatabase,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					afterAll(async () => {
 | 
				
			||||||
 | 
					    await app.destroy();
 | 
				
			||||||
 | 
					    await db.destroy();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const addFeatureDependency = async (
 | 
				
			||||||
 | 
					    parentFeature: string,
 | 
				
			||||||
 | 
					    payload: CreateDependentFeatureSchema,
 | 
				
			||||||
 | 
					    expectedCode = 200,
 | 
				
			||||||
 | 
					) => {
 | 
				
			||||||
 | 
					    return app.request
 | 
				
			||||||
 | 
					        .post(
 | 
				
			||||||
 | 
					            `/api/admin/projects/default/features/${parentFeature}/dependencies`,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .send(payload)
 | 
				
			||||||
 | 
					        .expect(expectedCode);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('should add feature dependency', async () => {
 | 
				
			||||||
 | 
					    const parent = uuidv4();
 | 
				
			||||||
 | 
					    const child = uuidv4();
 | 
				
			||||||
 | 
					    await app.createFeature(parent);
 | 
				
			||||||
 | 
					    await app.createFeature(child);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await addFeatureDependency(parent, {
 | 
				
			||||||
 | 
					        feature: child,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user