Skip to content

Commit

Permalink
feat: dependent features warning
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew committed Sep 21, 2023
1 parent e2aef0b commit 1ed0994
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 19 deletions.
35 changes: 28 additions & 7 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ export default class UnleashClient extends EventEmitter {

private strategies: Strategy[];

private warned: BooleanMap;
private warnedStrategies: BooleanMap;

private warnedDependencies: BooleanMap;

constructor(repository: RepositoryInterface, strategies: Strategy[]) {
super();
this.repository = repository;
this.strategies = strategies || [];
this.warned = {};
this.warnedStrategies = {};
this.warnedDependencies = {};

this.strategies.forEach((strategy: Strategy) => {
if (
Expand All @@ -43,9 +46,11 @@ export default class UnleashClient extends EventEmitter {
return this.strategies.find((strategy: Strategy): boolean => strategy.name === name);
}

warnOnce(missingStrategy: string, name: string, strategies: StrategyTransportInterface[]) {
if (!this.warned[missingStrategy + name]) {
this.warned[missingStrategy + name] = true;
warnStrategyOnce(missingStrategy: string,
name: string,
strategies: StrategyTransportInterface[]) {
if (!this.warnedStrategies[missingStrategy + name]) {
this.warnedStrategies[missingStrategy + name] = true;
this.emit(
UnleashEvents.Warn,
`Missing strategy "${missingStrategy}" for toggle "${name}". Ensure that "${strategies
Expand All @@ -55,13 +60,29 @@ export default class UnleashClient extends EventEmitter {
}
}

warnDependencyOnce(missingDependency: string, name: string) {
if (!this.warnedDependencies[missingDependency + name]) {
this.warnedDependencies[missingDependency + name] = true;
this.emit(
UnleashEvents.Warn,
`Missing dependency "${missingDependency}" for toggle "${name}"`,
);
}
}

isParentDependencySatisfied(feature: FeatureInterface | undefined, context: Context) {
if (!feature?.dependencies?.length) {
return true;
}

return feature.dependencies.every(parent => {
if (this.repository.getToggle(parent.feature)?.dependencies?.length) {
const parentToggle = this.repository.getToggle(parent.feature);

if (!parentToggle) {
this.warnDependencyOnce(parent.feature, feature.name);
return false;
}
if (parentToggle.dependencies?.length) {
return false;
}

Expand Down Expand Up @@ -130,7 +151,7 @@ export default class UnleashClient extends EventEmitter {
feature.strategies?.some((strategySelector): boolean => {
const strategy = this.getStrategy(strategySelector.name);
if (!strategy) {
this.warnOnce(strategySelector.name, feature.name, feature.strategies);
this.warnStrategyOnce(strategySelector.name, feature.name, feature.strategies);
return false;
}
const constraints = this.yieldConstraintsFor(strategySelector);
Expand Down
32 changes: 20 additions & 12 deletions src/test/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,26 +302,34 @@ test('should trigger events on isEnabled if impressionData is true', (t) => {

});

test('should trigger events on unsatisfied dependency if impressionData is true', (t) => {
let called = false;
test('should trigger events on unsatisfied dependency', (t) => {
let impressionCount = 0;
let recordedWarnings = [];
const repo = {
getToggle() {
return {
name: 'feature-x',
dependencies: [{feature: 'irrelevant'}],
strategies: [{ name: 'default' }],
variants: [],
impressionData: true,
getToggle(name: string) {
if(name === 'feature-x') {
return {
name: 'feature-x',
dependencies: [{feature: 'not-feature-x'}],
strategies: [{ name: 'default' }],
variants: [],
impressionData: true,
}
} else {
return undefined;
}
},
};
const client = new Client(repo, []);
client.on(UnleashEvents.Impression, () => {
called = true;
impressionCount++;
}).on(UnleashEvents.Warn, (warning) => {
recordedWarnings.push(warning);
});
client.isEnabled('feature-x', {}, () => false);
t.true(called);

client.isEnabled('feature-x', {}, () => false);
t.deepEqual(impressionCount, 2);
t.deepEqual(recordedWarnings, ['Missing dependency "not-feature-x" for toggle "feature-x"']);
});

test('should trigger events on getVariant if impressionData is true', (t) => {
Expand Down

0 comments on commit 1ed0994

Please sign in to comment.