mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	Feat/impression data (#1310)
* feat: add impression data column * fix: add default value to impressionData * fix: allow client api to return impressionData * fix: add tests for impressionData * fix: reset server-dev * fix: add test for adding a toggle with impression data on a different project * fix: update tests
This commit is contained in:
		
							parent
							
								
									fb7014a8ab
								
							
						
					
					
						commit
						6520aa1b0c
					
				@ -206,6 +206,7 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
 | 
				
			|||||||
                'features.project as project',
 | 
					                'features.project as project',
 | 
				
			||||||
                'features.stale as stale',
 | 
					                'features.stale as stale',
 | 
				
			||||||
                'features.variants as variants',
 | 
					                'features.variants as variants',
 | 
				
			||||||
 | 
					                'features.impression_data as impression_data',
 | 
				
			||||||
                'features.created_at as created_at',
 | 
					                'features.created_at as created_at',
 | 
				
			||||||
                'features.last_seen_at as last_seen_at',
 | 
					                'features.last_seen_at as last_seen_at',
 | 
				
			||||||
                'feature_environments.enabled as enabled',
 | 
					                'feature_environments.enabled as enabled',
 | 
				
			||||||
@ -249,6 +250,7 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
 | 
				
			|||||||
                    acc.environments = {};
 | 
					                    acc.environments = {};
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                acc.name = r.name;
 | 
					                acc.name = r.name;
 | 
				
			||||||
 | 
					                acc.impressionData = r.impression_data;
 | 
				
			||||||
                acc.description = r.description;
 | 
					                acc.description = r.description;
 | 
				
			||||||
                acc.project = r.project;
 | 
					                acc.project = r.project;
 | 
				
			||||||
                acc.stale = r.stale;
 | 
					                acc.stale = r.stale;
 | 
				
			||||||
 | 
				
			|||||||
@ -74,6 +74,7 @@ export default class FeatureToggleClientStore
 | 
				
			|||||||
                'features.type as type',
 | 
					                'features.type as type',
 | 
				
			||||||
                'features.project as project',
 | 
					                'features.project as project',
 | 
				
			||||||
                'features.stale as stale',
 | 
					                'features.stale as stale',
 | 
				
			||||||
 | 
					                'features.impression_data as impression_data',
 | 
				
			||||||
                'features.variants as variants',
 | 
					                'features.variants as variants',
 | 
				
			||||||
                'features.created_at as created_at',
 | 
					                'features.created_at as created_at',
 | 
				
			||||||
                'features.last_seen_at as last_seen_at',
 | 
					                'features.last_seen_at as last_seen_at',
 | 
				
			||||||
@ -137,6 +138,7 @@ export default class FeatureToggleClientStore
 | 
				
			|||||||
            if (r.strategy_name) {
 | 
					            if (r.strategy_name) {
 | 
				
			||||||
                feature.strategies.push(this.getAdminStrategy(r, isAdmin));
 | 
					                feature.strategies.push(this.getAdminStrategy(r, isAdmin));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            feature.impressionData = r.impression_data;
 | 
				
			||||||
            feature.enabled = !!r.enabled;
 | 
					            feature.enabled = !!r.enabled;
 | 
				
			||||||
            feature.name = r.name;
 | 
					            feature.name = r.name;
 | 
				
			||||||
            feature.description = r.description;
 | 
					            feature.description = r.description;
 | 
				
			||||||
 | 
				
			|||||||
@ -15,6 +15,7 @@ const FEATURE_COLUMNS = [
 | 
				
			|||||||
    'stale',
 | 
					    'stale',
 | 
				
			||||||
    'variants',
 | 
					    'variants',
 | 
				
			||||||
    'created_at',
 | 
					    'created_at',
 | 
				
			||||||
 | 
					    'impression_data',
 | 
				
			||||||
    'last_seen_at',
 | 
					    'last_seen_at',
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -27,6 +28,7 @@ export interface FeaturesTable {
 | 
				
			|||||||
    project: string;
 | 
					    project: string;
 | 
				
			||||||
    last_seen_at?: Date;
 | 
					    last_seen_at?: Date;
 | 
				
			||||||
    created_at?: Date;
 | 
					    created_at?: Date;
 | 
				
			||||||
 | 
					    impression_data: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const TABLE = 'features';
 | 
					const TABLE = 'features';
 | 
				
			||||||
@ -166,6 +168,7 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
 | 
				
			|||||||
            variants: sortedVariants,
 | 
					            variants: sortedVariants,
 | 
				
			||||||
            createdAt: row.created_at,
 | 
					            createdAt: row.created_at,
 | 
				
			||||||
            lastSeenAt: row.last_seen_at,
 | 
					            lastSeenAt: row.last_seen_at,
 | 
				
			||||||
 | 
					            impressionData: row.impression_data,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -188,6 +191,7 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
 | 
				
			|||||||
            archived: data.archived || false,
 | 
					            archived: data.archived || false,
 | 
				
			||||||
            stale: data.stale,
 | 
					            stale: data.stale,
 | 
				
			||||||
            created_at: data.createdAt,
 | 
					            created_at: data.createdAt,
 | 
				
			||||||
 | 
					            impression_data: data.impressionData,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        if (!row.created_at) {
 | 
					        if (!row.created_at) {
 | 
				
			||||||
            delete row.created_at;
 | 
					            delete row.created_at;
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,7 @@ test('should require URL firendly name', () => {
 | 
				
			|||||||
    const toggle = {
 | 
					    const toggle = {
 | 
				
			||||||
        name: 'io`dasd',
 | 
					        name: 'io`dasd',
 | 
				
			||||||
        enabled: false,
 | 
					        enabled: false,
 | 
				
			||||||
 | 
					        impressionData: false,
 | 
				
			||||||
        strategies: [{ name: 'default' }],
 | 
					        strategies: [{ name: 'default' }],
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -15,6 +16,7 @@ test('should be valid toggle name', () => {
 | 
				
			|||||||
    const toggle = {
 | 
					    const toggle = {
 | 
				
			||||||
        name: 'app.name',
 | 
					        name: 'app.name',
 | 
				
			||||||
        enabled: false,
 | 
					        enabled: false,
 | 
				
			||||||
 | 
					        impressionData: false,
 | 
				
			||||||
        strategies: [{ name: 'default' }],
 | 
					        strategies: [{ name: 'default' }],
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -28,6 +30,7 @@ test('should strip extra variant fields', () => {
 | 
				
			|||||||
        type: 'release',
 | 
					        type: 'release',
 | 
				
			||||||
        enabled: false,
 | 
					        enabled: false,
 | 
				
			||||||
        stale: false,
 | 
					        stale: false,
 | 
				
			||||||
 | 
					        impressionData: false,
 | 
				
			||||||
        strategies: [{ name: 'default' }],
 | 
					        strategies: [{ name: 'default' }],
 | 
				
			||||||
        variants: [
 | 
					        variants: [
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -49,6 +52,7 @@ test('should allow weightType=fix', () => {
 | 
				
			|||||||
        type: 'release',
 | 
					        type: 'release',
 | 
				
			||||||
        project: 'default',
 | 
					        project: 'default',
 | 
				
			||||||
        enabled: false,
 | 
					        enabled: false,
 | 
				
			||||||
 | 
					        impressionData: false,
 | 
				
			||||||
        stale: false,
 | 
					        stale: false,
 | 
				
			||||||
        archived: false,
 | 
					        archived: false,
 | 
				
			||||||
        strategies: [{ name: 'default' }],
 | 
					        strategies: [{ name: 'default' }],
 | 
				
			||||||
@ -71,6 +75,7 @@ test('should disallow weightType=unknown', () => {
 | 
				
			|||||||
        name: 'app.name',
 | 
					        name: 'app.name',
 | 
				
			||||||
        type: 'release',
 | 
					        type: 'release',
 | 
				
			||||||
        enabled: false,
 | 
					        enabled: false,
 | 
				
			||||||
 | 
					        impressionData: false,
 | 
				
			||||||
        stale: false,
 | 
					        stale: false,
 | 
				
			||||||
        archived: false,
 | 
					        archived: false,
 | 
				
			||||||
        strategies: [{ name: 'default' }],
 | 
					        strategies: [{ name: 'default' }],
 | 
				
			||||||
@ -95,6 +100,7 @@ test('should be possible to define variant overrides', () => {
 | 
				
			|||||||
        type: 'release',
 | 
					        type: 'release',
 | 
				
			||||||
        project: 'some',
 | 
					        project: 'some',
 | 
				
			||||||
        enabled: false,
 | 
					        enabled: false,
 | 
				
			||||||
 | 
					        impressionData: false,
 | 
				
			||||||
        stale: false,
 | 
					        stale: false,
 | 
				
			||||||
        archived: false,
 | 
					        archived: false,
 | 
				
			||||||
        strategies: [{ name: 'default' }],
 | 
					        strategies: [{ name: 'default' }],
 | 
				
			||||||
@ -125,6 +131,7 @@ test('variant overrides must have corect shape', async () => {
 | 
				
			|||||||
        name: 'app.name',
 | 
					        name: 'app.name',
 | 
				
			||||||
        type: 'release',
 | 
					        type: 'release',
 | 
				
			||||||
        enabled: false,
 | 
					        enabled: false,
 | 
				
			||||||
 | 
					        impressionData: false,
 | 
				
			||||||
        stale: false,
 | 
					        stale: false,
 | 
				
			||||||
        strategies: [{ name: 'default' }],
 | 
					        strategies: [{ name: 'default' }],
 | 
				
			||||||
        variants: [
 | 
					        variants: [
 | 
				
			||||||
@ -154,6 +161,7 @@ test('should keep constraints', () => {
 | 
				
			|||||||
        type: 'release',
 | 
					        type: 'release',
 | 
				
			||||||
        project: 'default',
 | 
					        project: 'default',
 | 
				
			||||||
        enabled: false,
 | 
					        enabled: false,
 | 
				
			||||||
 | 
					        impressionData: false,
 | 
				
			||||||
        stale: false,
 | 
					        stale: false,
 | 
				
			||||||
        archived: false,
 | 
					        archived: false,
 | 
				
			||||||
        strategies: [
 | 
					        strategies: [
 | 
				
			||||||
@ -180,6 +188,7 @@ test('should not accept empty constraint values', () => {
 | 
				
			|||||||
        name: 'app.constraints.empty.value',
 | 
					        name: 'app.constraints.empty.value',
 | 
				
			||||||
        type: 'release',
 | 
					        type: 'release',
 | 
				
			||||||
        enabled: false,
 | 
					        enabled: false,
 | 
				
			||||||
 | 
					        impressionData: false,
 | 
				
			||||||
        stale: false,
 | 
					        stale: false,
 | 
				
			||||||
        strategies: [
 | 
					        strategies: [
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -206,6 +215,7 @@ test('should not accept empty list of constraint values', () => {
 | 
				
			|||||||
        name: 'app.constraints.empty.value.list',
 | 
					        name: 'app.constraints.empty.value.list',
 | 
				
			||||||
        type: 'release',
 | 
					        type: 'release',
 | 
				
			||||||
        enabled: false,
 | 
					        enabled: false,
 | 
				
			||||||
 | 
					        impressionData: false,
 | 
				
			||||||
        stale: false,
 | 
					        stale: false,
 | 
				
			||||||
        strategies: [
 | 
					        strategies: [
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
				
			|||||||
@ -56,6 +56,12 @@ export const featureMetadataSchema = joi
 | 
				
			|||||||
        archived: joi.boolean().default(false),
 | 
					        archived: joi.boolean().default(false),
 | 
				
			||||||
        type: joi.string().default('release'),
 | 
					        type: joi.string().default('release'),
 | 
				
			||||||
        description: joi.string().allow('').allow(null).optional(),
 | 
					        description: joi.string().allow('').allow(null).optional(),
 | 
				
			||||||
 | 
					        impressionData: joi
 | 
				
			||||||
 | 
					            .boolean()
 | 
				
			||||||
 | 
					            .allow(true)
 | 
				
			||||||
 | 
					            .allow(false)
 | 
				
			||||||
 | 
					            .default(false)
 | 
				
			||||||
 | 
					            .optional(),
 | 
				
			||||||
        createdAt: joi.date().optional().allow(null),
 | 
					        createdAt: joi.date().optional().allow(null),
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    .options({ allowUnknown: false, stripUnknown: true, abortEarly: false });
 | 
					    .options({ allowUnknown: false, stripUnknown: true, abortEarly: false });
 | 
				
			||||||
@ -70,6 +76,12 @@ export const featureSchema = joi
 | 
				
			|||||||
        type: joi.string().default('release'),
 | 
					        type: joi.string().default('release'),
 | 
				
			||||||
        project: joi.string().default('default'),
 | 
					        project: joi.string().default('default'),
 | 
				
			||||||
        description: joi.string().allow('').allow(null).optional(),
 | 
					        description: joi.string().allow('').allow(null).optional(),
 | 
				
			||||||
 | 
					        impressionData: joi
 | 
				
			||||||
 | 
					            .boolean()
 | 
				
			||||||
 | 
					            .allow(true)
 | 
				
			||||||
 | 
					            .allow(false)
 | 
				
			||||||
 | 
					            .default(false)
 | 
				
			||||||
 | 
					            .optional(),
 | 
				
			||||||
        strategies: joi
 | 
					        strategies: joi
 | 
				
			||||||
            .array()
 | 
					            .array()
 | 
				
			||||||
            .min(0)
 | 
					            .min(0)
 | 
				
			||||||
 | 
				
			|||||||
@ -38,6 +38,7 @@ export interface FeatureToggleDTO {
 | 
				
			|||||||
    stale?: boolean;
 | 
					    stale?: boolean;
 | 
				
			||||||
    archived?: boolean;
 | 
					    archived?: boolean;
 | 
				
			||||||
    createdAt?: Date;
 | 
					    createdAt?: Date;
 | 
				
			||||||
 | 
					    impressionData?: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface FeatureToggle extends FeatureToggleDTO {
 | 
					export interface FeatureToggle extends FeatureToggleDTO {
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exports.up = function (db, cb) {
 | 
				
			||||||
 | 
					    db.runSql(
 | 
				
			||||||
 | 
					        `
 | 
				
			||||||
 | 
					        ALTER TABLE features ADD COLUMN "impression_data" BOOLEAN DEFAULT FALSE;
 | 
				
			||||||
 | 
					        `,
 | 
				
			||||||
 | 
					        cb,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exports.down = function (db, cb) {
 | 
				
			||||||
 | 
					    db.runSql(
 | 
				
			||||||
 | 
					        `
 | 
				
			||||||
 | 
					        ALTER TABLE features DROP COLUMN "impression_data";
 | 
				
			||||||
 | 
					        `,
 | 
				
			||||||
 | 
					        cb,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -512,13 +512,19 @@ test('Should patch feature toggle', async () => {
 | 
				
			|||||||
    const name = 'new.toggle.patch';
 | 
					    const name = 'new.toggle.patch';
 | 
				
			||||||
    await app.request
 | 
					    await app.request
 | 
				
			||||||
        .post(url)
 | 
					        .post(url)
 | 
				
			||||||
        .send({ name, description: 'some', type: 'release' })
 | 
					        .send({
 | 
				
			||||||
 | 
					            name,
 | 
				
			||||||
 | 
					            description: 'some',
 | 
				
			||||||
 | 
					            type: 'release',
 | 
				
			||||||
 | 
					            impressionData: true,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
        .expect(201);
 | 
					        .expect(201);
 | 
				
			||||||
    await app.request
 | 
					    await app.request
 | 
				
			||||||
        .patch(`${url}/${name}`)
 | 
					        .patch(`${url}/${name}`)
 | 
				
			||||||
        .send([
 | 
					        .send([
 | 
				
			||||||
            { op: 'replace', path: '/description', value: 'New desc' },
 | 
					            { op: 'replace', path: '/description', value: 'New desc' },
 | 
				
			||||||
            { op: 'replace', path: '/type', value: 'kill-switch' },
 | 
					            { op: 'replace', path: '/type', value: 'kill-switch' },
 | 
				
			||||||
 | 
					            { op: 'replace', path: '/impressionData', value: false },
 | 
				
			||||||
        ])
 | 
					        ])
 | 
				
			||||||
        .expect(200);
 | 
					        .expect(200);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -527,6 +533,7 @@ test('Should patch feature toggle', async () => {
 | 
				
			|||||||
    expect(toggle.name).toBe(name);
 | 
					    expect(toggle.name).toBe(name);
 | 
				
			||||||
    expect(toggle.description).toBe('New desc');
 | 
					    expect(toggle.description).toBe('New desc');
 | 
				
			||||||
    expect(toggle.type).toBe('kill-switch');
 | 
					    expect(toggle.type).toBe('kill-switch');
 | 
				
			||||||
 | 
					    expect(toggle.impressionData).toBe(false);
 | 
				
			||||||
    expect(toggle.archived).toBeFalsy();
 | 
					    expect(toggle.archived).toBeFalsy();
 | 
				
			||||||
    const events = await db.stores.eventStore.getAll({
 | 
					    const events = await db.stores.eventStore.getAll({
 | 
				
			||||||
        type: FEATURE_METADATA_UPDATED,
 | 
					        type: FEATURE_METADATA_UPDATED,
 | 
				
			||||||
@ -1983,3 +1990,79 @@ test('should not update project with PATCH', async () => {
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
        .expect(200);
 | 
					        .expect(200);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('Can create a feature with impression data', async () => {
 | 
				
			||||||
 | 
					    await app.request
 | 
				
			||||||
 | 
					        .post('/api/admin/projects/default/features')
 | 
				
			||||||
 | 
					        .send({
 | 
				
			||||||
 | 
					            name: 'new.toggle.with.impressionData',
 | 
				
			||||||
 | 
					            impressionData: true,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .expect(201)
 | 
				
			||||||
 | 
					        .expect((res) => {
 | 
				
			||||||
 | 
					            expect(res.body.impressionData).toBe(true);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('Can create a feature without impression data', async () => {
 | 
				
			||||||
 | 
					    await app.request
 | 
				
			||||||
 | 
					        .post('/api/admin/projects/default/features')
 | 
				
			||||||
 | 
					        .send({
 | 
				
			||||||
 | 
					            name: 'new.toggle.without.impressionData',
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .expect(201)
 | 
				
			||||||
 | 
					        .expect((res) => {
 | 
				
			||||||
 | 
					            expect(res.body.impressionData).toBe(false);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('Can update impression data with PUT', async () => {
 | 
				
			||||||
 | 
					    const toggle = {
 | 
				
			||||||
 | 
					        name: 'update.toggle.with.impressionData',
 | 
				
			||||||
 | 
					        impressionData: true,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    await app.request
 | 
				
			||||||
 | 
					        .post('/api/admin/projects/default/features')
 | 
				
			||||||
 | 
					        .send(toggle)
 | 
				
			||||||
 | 
					        .expect(201)
 | 
				
			||||||
 | 
					        .expect((res) => {
 | 
				
			||||||
 | 
					            expect(res.body.impressionData).toBe(true);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await app.request
 | 
				
			||||||
 | 
					        .put(`/api/admin/projects/default/features/${toggle.name}`)
 | 
				
			||||||
 | 
					        .send({ ...toggle, impressionData: false })
 | 
				
			||||||
 | 
					        .expect(200)
 | 
				
			||||||
 | 
					        .expect((res) => {
 | 
				
			||||||
 | 
					            expect(res.body.impressionData).toBe(false);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('Can create toggle with impression data on different project', async () => {
 | 
				
			||||||
 | 
					    db.stores.projectStore.create({
 | 
				
			||||||
 | 
					        id: 'impression-data',
 | 
				
			||||||
 | 
					        name: 'ImpressionData',
 | 
				
			||||||
 | 
					        description: '',
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const toggle = {
 | 
				
			||||||
 | 
					        name: 'project.impression.data',
 | 
				
			||||||
 | 
					        impressionData: true,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await app.request
 | 
				
			||||||
 | 
					        .post('/api/admin/projects/impression-data/features')
 | 
				
			||||||
 | 
					        .send(toggle)
 | 
				
			||||||
 | 
					        .expect(201)
 | 
				
			||||||
 | 
					        .expect((res) => {
 | 
				
			||||||
 | 
					            expect(res.body.impressionData).toBe(true);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await app.request
 | 
				
			||||||
 | 
					        .put(`/api/admin/projects/impression-data/features/${toggle.name}`)
 | 
				
			||||||
 | 
					        .send({ ...toggle, impressionData: false })
 | 
				
			||||||
 | 
					        .expect(200)
 | 
				
			||||||
 | 
					        .expect((res) => {
 | 
				
			||||||
 | 
					            expect(res.body.impressionData).toBe(false);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,7 @@ beforeAll(async () => {
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            name: 'featureX',
 | 
					            name: 'featureX',
 | 
				
			||||||
            description: 'the #1 feature',
 | 
					            description: 'the #1 feature',
 | 
				
			||||||
 | 
					            impressionData: true,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        'test',
 | 
					        'test',
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@ -134,6 +135,24 @@ test('gets a feature by name', async () => {
 | 
				
			|||||||
        .expect(200);
 | 
					        .expect(200);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('returns a feature toggles impression data', async () => {
 | 
				
			||||||
 | 
					    return app.request
 | 
				
			||||||
 | 
					        .get('/api/client/features/featureX')
 | 
				
			||||||
 | 
					        .expect('Content-Type', /json/)
 | 
				
			||||||
 | 
					        .expect((res) => {
 | 
				
			||||||
 | 
					            expect(res.body.impressionData).toBe(true);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('returns a false for impression data when not specified', async () => {
 | 
				
			||||||
 | 
					    return app.request
 | 
				
			||||||
 | 
					        .get('/api/client/features/featureZ')
 | 
				
			||||||
 | 
					        .expect('Content-Type', /json/)
 | 
				
			||||||
 | 
					        .expect((res) => {
 | 
				
			||||||
 | 
					            expect(res.body.impressionData).toBe(false);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('cant get feature that does not exist', async () => {
 | 
					test('cant get feature that does not exist', async () => {
 | 
				
			||||||
    return app.request
 | 
					    return app.request
 | 
				
			||||||
        .get('/api/client/features/myfeature')
 | 
					        .get('/api/client/features/myfeature')
 | 
				
			||||||
@ -255,3 +274,39 @@ test('Can use multiple filters', async () => {
 | 
				
			|||||||
            expect(res.body.features[0].name).toBe('test.feature');
 | 
					            expect(res.body.features[0].name).toBe('test.feature');
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('returns a feature toggles impression data for a different project', async () => {
 | 
				
			||||||
 | 
					    const project = {
 | 
				
			||||||
 | 
					        id: 'impression-data-client',
 | 
				
			||||||
 | 
					        name: 'ImpressionData',
 | 
				
			||||||
 | 
					        description: '',
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    db.stores.projectStore.create(project);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const toggle = {
 | 
				
			||||||
 | 
					        name: 'project-client.impression.data',
 | 
				
			||||||
 | 
					        impressionData: true,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await app.request
 | 
				
			||||||
 | 
					        .post('/api/admin/projects/impression-data-client/features')
 | 
				
			||||||
 | 
					        .send(toggle)
 | 
				
			||||||
 | 
					        .expect(201)
 | 
				
			||||||
 | 
					        .expect((res) => {
 | 
				
			||||||
 | 
					            expect(res.body.impressionData).toBe(true);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return app.request
 | 
				
			||||||
 | 
					        .get('/api/client/features')
 | 
				
			||||||
 | 
					        .expect('Content-Type', /json/)
 | 
				
			||||||
 | 
					        .expect((res) => {
 | 
				
			||||||
 | 
					            const projectToggle = res.body.features.find(
 | 
				
			||||||
 | 
					                (resToggle) => resToggle.project === project.id,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            expect(projectToggle.name).toBe(toggle.name);
 | 
				
			||||||
 | 
					            expect(projectToggle.project).toBe(project.id);
 | 
				
			||||||
 | 
					            expect(projectToggle.impressionData).toBe(true);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user