1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-20 00:08:02 +01:00
unleash.unleash/src/lib/features/playground/offline-unleash-client.test.ts

444 lines
14 KiB
TypeScript

import {
ClientInitOptions,
mapFeaturesForClient,
mapSegmentsForClient,
offlineUnleashClient,
} from './offline-unleash-client';
import {
Unleash as UnleashClientNode,
InMemStorageProvider as InMemStorageProviderNode,
} from 'unleash-client';
import { once } from 'events';
import { playgroundStrategyEvaluation } from '../../openapi/spec/playground-strategy-schema';
export const offlineUnleashClientNode = async ({
features,
context,
logError,
segments,
}: ClientInitOptions): Promise<UnleashClientNode> => {
const client = new UnleashClientNode({
...context,
appName: context.appName,
disableMetrics: true,
refreshInterval: 0,
skipInstanceCountWarning: true,
url: 'not-needed',
storageProvider: new InMemStorageProviderNode(),
bootstrap: {
data: mapFeaturesForClient(features),
segments: mapSegmentsForClient(segments),
},
});
client.on('error', logError);
client.start();
await once(client, 'ready');
return client;
};
describe('offline client', () => {
it('considers enabled variants with a default strategy to be on', async () => {
const name = 'toggle-name';
const client = await offlineUnleashClient({
features: [
{
name,
project: 'default',
enabled: true,
strategies: [{ name: 'default' }],
variants: [],
type: '',
stale: false,
},
],
context: { appName: 'other-app', environment: 'default' },
logError: console.log,
});
expect(client.isEnabled(name).result).toBeTruthy();
});
it('constrains on appName', async () => {
const enabledFeature = 'toggle-name';
const disabledFeature = 'other-toggle';
const appName = 'app-name';
const client = await offlineUnleashClient({
features: [
{
name: enabledFeature,
enabled: true,
project: 'default',
strategies: [
{
name: 'default',
constraints: [
{
contextName: 'appName',
operator: 'IN',
values: [appName],
},
],
},
],
variants: [],
type: '',
stale: false,
},
{
name: disabledFeature,
enabled: true,
project: 'default',
strategies: [
{
name: 'default',
constraints: [
{
contextName: 'appName',
operator: 'IN',
values: ['otherApp'],
},
],
},
],
variants: [],
type: '',
stale: false,
},
],
context: { appName, environment: 'default' },
logError: console.log,
});
expect(client.isEnabled(enabledFeature).result).toBeTruthy();
expect(client.isEnabled(disabledFeature).result).toBeFalsy();
});
it('considers disabled features with a default strategy to be enabled', async () => {
const name = 'toggle-name';
const context = { appName: 'client-test' };
const client = await offlineUnleashClient({
features: [
{
strategies: [
{
name: 'default',
},
],
project: 'default',
stale: false,
enabled: false,
name,
type: 'experiment',
variants: [],
},
],
context,
logError: console.log,
});
const result = client.isEnabled(name, context);
expect(result.result).toBe(true);
});
it('considers disabled variants with a default strategy and variants to be on', async () => {
const name = 'toggle-name';
const client = await offlineUnleashClient({
features: [
{
strategies: [
{
name: 'default',
},
],
project: 'default',
stale: false,
enabled: false,
name,
type: 'experiment',
variants: [
{
name: 'a',
weight: 500,
weightType: 'variable',
stickiness: 'default',
overrides: [],
},
{
name: 'b',
weight: 500,
weightType: 'variable',
stickiness: 'default',
overrides: [],
},
],
},
],
context: { appName: 'client-test' },
logError: console.log,
});
expect(client.isEnabled(name).result).toBe(true);
});
it("returns variant {name: 'disabled', enabled: false } if the toggle isn't enabled", async () => {
const name = 'toggle-name';
const client = await offlineUnleashClient({
features: [
{
strategies: [],
stale: false,
enabled: false,
name,
project: 'default',
type: 'experiment',
variants: [
{
name: 'a',
weight: 500,
weightType: 'variable',
stickiness: 'default',
overrides: [],
},
{
name: 'b',
weight: 500,
weightType: 'variable',
stickiness: 'default',
overrides: [],
},
],
},
],
context: { appName: 'client-test' },
logError: console.log,
});
expect(client.isEnabled(name).result).toBeFalsy();
expect(client.getVariant(name).name).toEqual('disabled');
expect(client.getVariant(name).enabled).toBeFalsy();
});
it('returns the disabled variant if there are no variants', async () => {
const name = 'toggle-name';
const client = await offlineUnleashClient({
features: [
{
strategies: [
{
name: 'default',
constraints: [],
},
],
project: 'default',
stale: false,
enabled: true,
name,
type: 'experiment',
variants: [],
},
],
context: { appName: 'client-test' },
logError: console.log,
});
expect(client.getVariant(name, {}).name).toEqual('disabled');
expect(client.getVariant(name, {}).enabled).toBeFalsy();
expect(client.isEnabled(name, {}).result).toBeTruthy();
});
it(`returns '${playgroundStrategyEvaluation.unknownResult}' if it can't evaluate a feature`, async () => {
const name = 'toggle-name';
const context = { appName: 'client-test' };
const client = await offlineUnleashClient({
features: [
{
strategies: [
{
name: 'unimplemented-custom-strategy',
constraints: [],
},
],
project: 'default',
stale: false,
enabled: true,
name,
type: 'experiment',
variants: [],
},
],
context,
logError: console.log,
});
const result = client.isEnabled(name, context);
result.strategies.forEach((strategy) =>
expect(strategy.result.enabled).toEqual(
playgroundStrategyEvaluation.unknownResult,
),
);
expect(result.result).toEqual(
playgroundStrategyEvaluation.unknownResult,
);
});
it(`returns '${playgroundStrategyEvaluation.unknownResult}' for the application hostname strategy`, async () => {
const name = 'toggle-name';
const context = { appName: 'client-test' };
const client = await offlineUnleashClient({
features: [
{
strategies: [
{
name: 'applicationHostname',
constraints: [],
},
],
project: 'default',
stale: false,
enabled: true,
name,
type: 'experiment',
variants: [],
},
],
context,
logError: console.log,
});
const result = client.isEnabled(name, context);
result.strategies.forEach((strategy) =>
expect(strategy.result.enabled).toEqual(
playgroundStrategyEvaluation.unknownResult,
),
);
expect(result.result).toEqual(
playgroundStrategyEvaluation.unknownResult,
);
});
it('returns strategies in the order they are provided', async () => {
const featureName = 'featureName';
const strategies = [
{
name: 'default',
constraints: [],
parameters: {},
},
{
name: 'default',
constraints: [
{
values: ['my-app-name'],
inverted: false,
operator: 'IN' as 'IN',
contextName: 'appName',
caseInsensitive: false,
},
],
parameters: {},
},
{
name: 'applicationHostname',
constraints: [],
parameters: {
hostNames: 'myhostname.com',
},
},
{
name: 'flexibleRollout',
constraints: [],
parameters: {
groupId: 'killer',
rollout: '34',
stickiness: 'userId',
},
},
{
name: 'userWithId',
constraints: [],
parameters: {
userIds: 'uoea,ueoa',
},
},
{
name: 'remoteAddress',
constraints: [],
parameters: {
IPs: '196.6.6.05',
},
},
];
const context = { appName: 'client-test' };
const client = await offlineUnleashClient({
features: [
{
strategies,
// impressionData: false,
enabled: true,
name: featureName,
project: 'default',
// description: '',
// project: 'heartman-for-test',
stale: false,
type: 'kill-switch',
variants: [
{
name: 'a',
weight: 334,
weightType: 'variable',
stickiness: 'default',
overrides: [],
payload: {
type: 'json',
value: '{"hello": "world"}',
},
},
{
name: 'b',
weight: 333,
weightType: 'variable',
stickiness: 'default',
overrides: [],
payload: {
type: 'string',
value: 'ueoau',
},
},
{
name: 'c',
weight: 333,
weightType: 'variable',
stickiness: 'default',
payload: {
type: 'csv',
value: '1,2,3',
},
overrides: [],
},
],
},
],
context,
logError: console.log,
});
const evaluatedStrategies = client
.isEnabled(featureName, context)
.strategies.map((strategy) => strategy.name);
expect(evaluatedStrategies).toEqual(
strategies.map((strategy) => strategy.name),
);
});
});