1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-07 01:16:28 +02:00
unleash.unleash/src/lib/features/frontend-api/global-frontend-api-cache.test.ts
Christopher Kolstad b681702b77
task: migrate tests to vitest
Vitest Pros:
* Automated failing test comments on github PRs
* A nice local UI with incremental testing when changing files (`yarn
test:ui`)
* Also nicely supported in all major IDEs, click to run test works (so
we won't miss what we had with jest).
* Works well with ESM

Vitest Cons:
* The ESBuild transformer vitest uses takes a little longer to transform
than our current SWC/jest setup, however, it is possible to setup SWC as
the transformer for vitest as well (though it only does one transform,
so we're paying ~7-10 seconds instead of ~ 2-3 seconds in transform
phase).
* Exposes how slow our tests are (tongue in cheek here)
2025-05-16 11:19:10 +02:00

199 lines
5.2 KiB
TypeScript

import {
GlobalFrontendApiCache,
type GlobalFrontendApiCacheState,
} from './global-frontend-api-cache.js';
import noLogger from '../../../test/fixtures/no-logger.js';
import { FakeSegmentReadModel } from '../segment/fake-segment-read-model.js';
import FakeClientFeatureToggleReadModel from './fake-client-feature-toggle-read-model.js';
import EventEmitter from 'events';
import type {
IApiUser,
IFeatureToggleClient,
IFlagResolver,
ISegment,
} from '../../types/index.js';
import { UPDATE_REVISION } from '../feature-toggle/configuration-revision-service.js';
import { vi } from 'vitest';
const state = async (
cache: GlobalFrontendApiCache,
state: GlobalFrontendApiCacheState,
) => {
await new Promise((resolve) => {
cache.on(state, () => {
resolve('done');
});
});
};
const defaultFeature: IFeatureToggleClient = {
name: 'featureA',
enabled: true,
strategies: [],
variants: [],
project: 'projectA',
dependencies: [],
type: 'release',
stale: false,
description: '',
};
const defaultSegment = { name: 'segment', id: 1 } as ISegment;
const alwaysOnFlagResolver = {
isEnabled() {
return true;
},
} as unknown as IFlagResolver;
const createCache = (
segment: ISegment = defaultSegment,
features: Record<string, Record<string, IFeatureToggleClient>> = {},
) => {
const config = {
getLogger: noLogger,
flagResolver: alwaysOnFlagResolver,
eventBus: <any>{ emit: vi.fn() },
};
const segmentReadModel = new FakeSegmentReadModel([segment as ISegment]);
const clientFeatureToggleReadModel = new FakeClientFeatureToggleReadModel(
features,
);
const configurationRevisionService = new EventEmitter();
const cache = new GlobalFrontendApiCache(
config,
segmentReadModel,
clientFeatureToggleReadModel,
configurationRevisionService,
);
return {
cache,
configurationRevisionService,
clientFeatureToggleReadModel,
};
};
test('Can read initial segment', async () => {
const { cache } = createCache({ name: 'segment', id: 1 } as ISegment);
const segmentBeforeRead = cache.getSegment(1);
expect(segmentBeforeRead).toEqual(undefined);
await state(cache, 'ready');
const segment = cache.getSegment(1);
expect(segment).toEqual({ name: 'segment', id: 1 });
});
test('Can read initial features', async () => {
const { cache } = createCache(defaultSegment, {
development: {
featureA: {
...defaultFeature,
name: 'featureA',
enabled: true,
project: 'projectA',
},
featureB: {
...defaultFeature,
name: 'featureB',
enabled: true,
project: 'projectB',
},
},
production: {
featureA: {
...defaultFeature,
name: 'featureA',
enabled: false,
project: 'projectA',
},
},
});
const featuresBeforeRead = cache.getToggles({
environment: 'development',
projects: ['projectA'],
} as IApiUser);
expect(featuresBeforeRead).toEqual([]);
await state(cache, 'ready');
const features = cache.getToggles({
environment: 'development',
projects: ['projectA'],
} as IApiUser);
expect(features).toEqual([
{
...defaultFeature,
name: 'featureA',
enabled: true,
impressionData: false,
},
]);
const allProjectFeatures = cache.getToggles({
environment: 'development',
projects: ['*'],
} as IApiUser);
expect(allProjectFeatures.length).toBe(2);
const defaultProjectFeatures = cache.getToggles({
environment: '*',
projects: ['*'],
} as IApiUser);
expect(defaultProjectFeatures.length).toBe(0);
const singleToggle = cache.getToggle('featureA', {
environment: 'development',
projects: ['*'],
} as IApiUser);
expect(singleToggle).toMatchObject({
...defaultFeature,
name: 'featureA',
enabled: true,
impressionData: false,
});
});
test('Can refresh data on revision update', async () => {
const {
cache,
configurationRevisionService,
clientFeatureToggleReadModel,
} = createCache();
await state(cache, 'ready');
clientFeatureToggleReadModel.setValue({
development: {
featureA: {
...defaultFeature,
name: 'featureA',
enabled: false,
strategies: [{ name: 'default' }],
project: 'projectA',
},
},
});
configurationRevisionService.emit(UPDATE_REVISION);
await state(cache, 'updated');
const features = cache.getToggles({
environment: 'development',
projects: ['projectA'],
} as IApiUser);
expect(features).toMatchObject([
{
...defaultFeature,
name: 'featureA',
enabled: false,
strategies: [{ name: 'default' }],
impressionData: false,
},
]);
});