diff --git a/src/lib/features/export-import-toggles/export-import-service.ts b/src/lib/features/export-import-toggles/export-import-service.ts index ae9ac604ac..3788bb2f35 100644 --- a/src/lib/features/export-import-toggles/export-import-service.ts +++ b/src/lib/features/export-import-toggles/export-import-service.ts @@ -280,17 +280,17 @@ export default class ExportImportService { await this.importTogglesStore.deleteTagsForFeatures( dto.data.features.map((feature) => feature.name), ); - return Promise.all( - (dto.data.featureTags || []).map((tag) => { - return tag.tagType - ? this.featureTagService.addTag( - tag.featureName, - { type: tag.tagType, value: tag.tagValue }, - extractUsernameFromUser(user), - ) - : Promise.resolve(); - }), - ); + + const featureTags = dto.data.featureTags || []; + for (const tag of featureTags) { + if (tag.tagType) { + await this.featureTagService.addTag( + tag.featureName, + { type: tag.tagType, value: tag.tagValue }, + extractUsernameFromUser(user), + ); + } + } } private async importContextFields(dto: ImportTogglesSchema, user: User) { diff --git a/src/lib/features/export-import-toggles/export-import.e2e.test.ts b/src/lib/features/export-import-toggles/export-import.e2e.test.ts index 9c74daa3c4..647d5de15c 100644 --- a/src/lib/features/export-import-toggles/export-import.e2e.test.ts +++ b/src/lib/features/export-import-toggles/export-import.e2e.test.ts @@ -14,6 +14,7 @@ import { IProjectStore, ISegment, IStrategyConfig, + ITagStore, IVariant, } from '../../types'; import { DEFAULT_ENV } from '../../util'; @@ -33,6 +34,7 @@ let environmentStore: IEnvironmentStore; let contextFieldStore: IContextFieldStore; let projectStore: IProjectStore; let toggleStore: IFeatureToggleStore; +let tagStore: ITagStore; const defaultStrategy: IStrategyConfig = { name: 'default', @@ -150,6 +152,7 @@ beforeAll(async () => { projectStore = db.stores.projectStore; contextFieldStore = db.stores.contextFieldStore; toggleStore = db.stores.featureToggleStore; + tagStore = db.stores.tagStore; }); beforeEach(async () => { @@ -157,6 +160,7 @@ beforeEach(async () => { await toggleStore.deleteAll(); await projectStore.deleteAll(); await environmentStore.deleteAll(); + await tagStore.deleteAll(); await contextFieldStore.deleteAll(); await app.createContextField({ name: 'appName' }); @@ -544,6 +548,10 @@ const exportedFeature: ImportTogglesSchema['data']['features'][0] = { project: 'old_project', name: 'first_feature', }; +const anotherExportedFeature: ImportTogglesSchema['data']['features'][0] = { + project: 'old_project', + name: 'second_feature', +}; const constraints: ImportTogglesSchema['data']['featureStrategies'][0]['constraints'] = [ { @@ -614,6 +622,31 @@ const defaultImportPayload: ImportTogglesSchema = { environment: DEFAULT_ENV, }; +const importWithMultipleFeatures: ImportTogglesSchema = { + data: { + features: [exportedFeature, anotherExportedFeature], + featureStrategies: [], + featureEnvironments: [], + featureTags: [ + { + featureName: exportedFeature.name, + tagType: 'simple', + tagValue: 'tag1', + }, + { + featureName: anotherExportedFeature.name, + tagType: 'simple', + tagValue: 'tag1', + }, + ], + tagTypes, + contextFields: [], + segments: [], + }, + project: DEFAULT_PROJECT, + environment: DEFAULT_ENV, +}; + const getFeature = async (feature: string) => app.request .get(`/api/admin/projects/${DEFAULT_PROJECT}/features/${feature}`) @@ -672,6 +705,24 @@ test('import features to existing project and environment', async () => { }); }); +test('import multiple features with same tag', async () => { + await createProjects(); + + await app.importToggles(importWithMultipleFeatures); + + const { body: tags1 } = await getTags(exportedFeature.name); + const { body: tags2 } = await getTags(anotherExportedFeature.name); + + expect(tags1).toMatchObject({ + version: 1, + tags: [{ value: 'tag1', type: 'simple' }], + }); + expect(tags2).toMatchObject({ + version: 1, + tags: [{ value: 'tag1', type: 'simple' }], + }); +}); + test('importing same JSON should work multiple times in a row', async () => { await createProjects(); await app.importToggles(defaultImportPayload);