unleash-server
Version:
Unleash is an enterprise ready feature flag service. It provides different strategies for handling feature flags.
312 lines • 9.27 kB
JavaScript
import { setupAppWithAuth, } from '../../../test/e2e/helpers/test-helper.js';
import dbInit from '../../../test/e2e/helpers/database-init.js';
import getLogger from '../../../test/fixtures/no-logger.js';
import { DEFAULT_PROJECT, RoleName, } from '../../types/index.js';
import { DEFAULT_ENV } from '../../util/index.js';
let app;
let db;
let eventStore;
let environmentStore;
let contextFieldStore;
let projectStore;
let toggleStore;
let accessService;
let adminRole;
let stores;
const regularUserName = 'import-user';
const adminUserName = 'admin-user';
const validateImport = (importPayload, status = 200) => app.request
.post('/api/admin/features-batch/validate')
.send(importPayload)
.set('Content-Type', 'application/json')
.expect(status);
const createContextField = async (contextField) => {
await app.request.post(`/api/admin/context`).send(contextField).expect(201);
};
const createFeature = async (featureName) => {
await app.request
.post(`/api/admin/projects/${DEFAULT_PROJECT}/features`)
.send({
name: featureName,
})
.set('Content-Type', 'application/json')
.expect(201);
};
const createFeatureFlagWithStrategy = async (featureName) => {
await createFeature(featureName);
return app.request
.post(`/api/admin/projects/${DEFAULT_PROJECT}/features/${featureName}/environments/${DEFAULT_ENV}/strategies`)
.send({
name: 'default',
parameters: {
userId: 'string',
},
})
.expect(200);
};
const archiveFeature = async (featureName) => {
await app.request
.delete(`/api/admin/projects/${DEFAULT_PROJECT}/features/${featureName}`)
.set('Content-Type', 'application/json')
.expect(202);
};
const createProject = async () => {
await db.stores.environmentStore.create({
name: DEFAULT_ENV,
type: 'production',
});
await db.stores.projectStore.create({
name: DEFAULT_PROJECT,
description: '',
id: DEFAULT_PROJECT,
mode: 'open',
});
};
const newFeature = 'new_feature';
const archivedFeature = 'archived_feature';
const existingFeature = 'existing_feature';
const variants = [
{
name: 'variantA',
weight: 500,
payload: {
type: 'string',
value: 'payloadA',
},
overrides: [],
stickiness: 'default',
weightType: 'variable',
},
{
name: 'variantB',
weight: 500,
payload: {
type: 'string',
value: 'payloadB',
},
overrides: [],
stickiness: 'default',
weightType: 'variable',
},
];
const feature1 = {
project: 'old_project',
name: archivedFeature,
};
const feature2 = {
project: 'old_project',
name: newFeature,
};
const feature3 = {
project: 'old_project',
name: existingFeature,
};
const constraints = [
{
values: ['conduit'],
inverted: false,
operator: 'IN',
contextName: 'appName',
caseInsensitive: false,
},
];
const exportedStrategy = {
featureName: newFeature,
id: '798cb25a-2abd-47bd-8a95-40ec13472309',
name: 'default',
parameters: {},
constraints,
};
const tags = [
{
featureName: newFeature,
tagType: 'simple',
tagValue: 'tag1',
},
{
featureName: newFeature,
tagType: 'simple',
tagValue: 'tag2',
},
{
featureName: newFeature,
tagType: 'special_tag',
tagValue: 'feature_tagged',
},
];
const tagTypes = [
{
name: 'bestt',
description: 'test',
},
{
name: 'special_tag',
description: 'this is my special tag',
},
{
name: 'special_tag',
description: 'this is my special tag',
}, // deliberate duplicate
];
const importPayload = {
data: {
features: [feature1, feature2, feature3],
featureStrategies: [exportedStrategy],
featureEnvironments: [
{
enabled: true,
environment: 'irrelevant',
featureName: newFeature,
name: newFeature,
variants,
},
],
featureTags: tags,
tagTypes,
contextFields: [],
segments: [],
},
project: DEFAULT_PROJECT,
environment: DEFAULT_ENV,
};
const createUserEditorAccess = async (name, email) => {
const { userStore } = stores;
const user = await userStore.insert({
name,
email,
});
return user;
};
const createUserAdminAccess = async (name, email) => {
const { userStore } = stores;
const user = await userStore.insert({
name,
email,
});
await accessService.addUserToRole(user.id, adminRole.id, 'default');
return user;
};
const loginRegularUser = () => app.request
.post(`/auth/demo/login`)
.send({
email: `${regularUserName}@getunleash.io`,
})
.expect(200);
const loginAdminUser = () => app.request
.post(`/auth/demo/login`)
.send({
email: `${adminUserName}@getunleash.io`,
})
.expect(200);
beforeAll(async () => {
db = await dbInit('export_import_permissions_api_serial', getLogger);
stores = db.stores;
app = await setupAppWithAuth(db.stores, {
experimental: {
flags: {},
},
}, db.rawDatabase);
eventStore = db.stores.eventStore;
environmentStore = db.stores.environmentStore;
projectStore = db.stores.projectStore;
toggleStore = db.stores.featureToggleStore;
accessService = app.services.accessService;
contextFieldStore = db.stores.contextFieldStore;
const roles = await accessService.getRootRoles();
adminRole = roles.find((role) => role.name === RoleName.ADMIN);
await createUserEditorAccess(regularUserName, `${regularUserName}@getunleash.io`);
await createUserAdminAccess(adminUserName, `${adminUserName}@getunleash.io`);
});
beforeEach(async () => {
await eventStore.deleteAll();
await toggleStore.deleteAll();
await projectStore.deleteAll();
await environmentStore.deleteAll();
await contextFieldStore.deleteAll();
await contextFieldStore.deleteAll();
await loginAdminUser();
await createContextField({ name: 'appName' });
});
afterAll(async () => {
await app.destroy();
await db.destroy();
});
test('validate import data', async () => {
await loginAdminUser();
await createProject();
const contextField = {
name: 'validate_context_field',
legalValues: [{ value: 'Value1' }],
};
const createdContextField = {
name: 'created_context_field',
legalValues: [{ value: 'new_value' }],
};
await createFeature(archivedFeature);
await archiveFeature(archivedFeature);
await createFeatureFlagWithStrategy(existingFeature);
await createContextField(contextField);
const importPayloadWithContextFields = {
...importPayload,
data: {
...importPayload.data,
featureStrategies: [{ name: 'customStrategy' }],
segments: [
{
id: 1,
name: 'customSegment',
},
],
contextFields: [
{
...contextField,
legalValues: [{ value: 'Value2' }],
},
createdContextField,
],
},
};
await loginRegularUser();
const { body } = await validateImport(importPayloadWithContextFields, 200);
expect(body).toMatchObject({
errors: [
{
message: 'We detected the following custom strategy that needs to be created first:',
affectedItems: ['customStrategy'],
},
{
message: 'We detected the following context fields that do not have matching legal values with the imported ones:',
affectedItems: [contextField.name],
},
{
affectedItems: ['customSegment'],
message: 'We detected the following segments that need to be created first:',
},
],
warnings: [
{
message: 'The following features will not be imported as they are currently archived. To import them, please unarchive them first:',
affectedItems: [archivedFeature],
},
{
message: 'The following features already exist in this project and will be overwritten:',
affectedItems: ['existing_feature'],
},
],
permissions: [
{
message: 'We detected you are missing the following permissions:',
affectedItems: [
'Create context fields',
'Create activation strategies',
'Delete activation strategies',
'Update variants',
'Create feature flags',
'Update feature flags',
'Create tag types',
],
},
],
});
});
//# sourceMappingURL=export-import-permissions.e2e.test.js.map