From b49654c3f05c51601e28846c109c0247bb8a8127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20G=C3=B3is?= Date: Tue, 28 Jun 2022 07:54:09 +0100 Subject: [PATCH] fix: copy feature variants (#1750) * fix: copy feature variants * add e2e test for cloning with variants --- src/lib/db/feature-toggle-store.ts | 1 + src/lib/schema/feature-schema.ts | 6 ++ src/lib/types/model.ts | 2 +- .../api/admin/project/features.e2e.test.ts | 57 ++++++++++++++++++- 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/lib/db/feature-toggle-store.ts b/src/lib/db/feature-toggle-store.ts index a24d9ef14d..1b43b7bce6 100644 --- a/src/lib/db/feature-toggle-store.ts +++ b/src/lib/db/feature-toggle-store.ts @@ -192,6 +192,7 @@ export default class FeatureToggleStore implements IFeatureToggleStore { stale: data.stale, created_at: data.createdAt, impression_data: data.impressionData, + variants: JSON.stringify(data.variants), }; if (!row.created_at) { delete row.created_at; diff --git a/src/lib/schema/feature-schema.ts b/src/lib/schema/feature-schema.ts index cc9cee637b..c4659e22fd 100644 --- a/src/lib/schema/feature-schema.ts +++ b/src/lib/schema/feature-schema.ts @@ -92,6 +92,12 @@ export const featureMetadataSchema = joi .default(false) .optional(), createdAt: joi.date().optional().allow(null), + variants: joi + .array() + .allow(null) + .unique((a, b) => a.name === b.name) + .optional() + .items(variantsSchema), }) .options({ allowUnknown: false, stripUnknown: true, abortEarly: false }); diff --git a/src/lib/types/model.ts b/src/lib/types/model.ts index 596109d3d1..c8c802ac3d 100644 --- a/src/lib/types/model.ts +++ b/src/lib/types/model.ts @@ -47,13 +47,13 @@ export interface FeatureToggleDTO { archived?: boolean; createdAt?: Date; impressionData?: boolean; + variants?: IVariant[]; } export interface FeatureToggle extends FeatureToggleDTO { project: string; lastSeenAt?: Date; createdAt?: Date; - variants?: IVariant[]; } export interface IFeatureToggleClient { diff --git a/src/test/e2e/api/admin/project/features.e2e.test.ts b/src/test/e2e/api/admin/project/features.e2e.test.ts index c03888a517..3a35f33916 100644 --- a/src/test/e2e/api/admin/project/features.e2e.test.ts +++ b/src/test/e2e/api/admin/project/features.e2e.test.ts @@ -1701,10 +1701,63 @@ test('should clone feature toggle WITH strategies', async () => { }); }); -test('should clone feature toggle without replacing groupId', async () => { - const envName = 'default'; +test('should clone feature toggle WITH variants', async () => { + const envName = 'some-env-5'; const featureName = 'feature.toggle.base.3'; const cloneName = 'feature.toggle.clone.3'; + const type = 'eExperiment'; + const description = 'Lorem ipsum...'; + const variants = [ + { name: 'variant1', weight: 50 }, + { name: 'variant2', weight: 50 }, + ]; + + // Create environment + await db.stores.environmentStore.create({ + name: envName, + type: 'production', + }); + // Connect environment to project + await app.request + .post('/api/admin/projects/default/environments') + .send({ + environment: envName, + }) + .expect(200); + + await app.request + .post('/api/admin/projects/default/features') + .send({ + name: featureName, + description, + type, + variants, + }) + .expect(201); + await app.request + .post(`/api/admin/projects/default/features/${featureName}/clone`) + .send({ name: cloneName }) + .expect(201); + await app.request + .get(`/api/admin/projects/default/features/${cloneName}`) + .expect(200) + .expect((res) => { + expect(res.body.name).toBe(cloneName); + expect(res.body.type).toBe(type); + expect(res.body.project).toBe('default'); + expect(res.body.description).toBe(description); + + expect(res.body.variants).toHaveLength(2); + res.body.variants.forEach((variant, i) => { + expect(variant.name).toBe(variants[i].name); + }); + }); +}); + +test('should clone feature toggle without replacing groupId', async () => { + const envName = 'default'; + const featureName = 'feature.toggle.base.4'; + const cloneName = 'feature.toggle.clone.4'; await app.request .post('/api/admin/projects/default/features')