diff options
Diffstat (limited to 'vid-webpack-master/src/app/featureFlag')
4 files changed, 182 insertions, 0 deletions
diff --git a/vid-webpack-master/src/app/featureFlag/directive/basic/basic.featureFlag.directive.spec.ts b/vid-webpack-master/src/app/featureFlag/directive/basic/basic.featureFlag.directive.spec.ts new file mode 100644 index 000000000..5722aa795 --- /dev/null +++ b/vid-webpack-master/src/app/featureFlag/directive/basic/basic.featureFlag.directive.spec.ts @@ -0,0 +1,93 @@ +import {TestBed, ComponentFixture, tick, inject} from '@angular/core/testing'; +import {Component, DebugElement, Renderer2, Type} from "@angular/core"; +import {By} from "@angular/platform-browser"; +import {BasicFeatureFlagDirective} from "./basic.featureFlag.directive"; +import {FeatureFlagService} from "../../service/featureFlag.service"; +import {ConfigurationService} from "../../../shared/services/configuration.service"; +import {HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing"; +import {NgRedux} from "@angular-redux/store"; +import {of} from "rxjs"; + +@Component({ + template: ` + <div + id="featureFlagOff" + featureFlag + [flagName]='"featureFlagOff"'> + </div> + <div + id="featureFlagOn" + featureFlag + [flagName]='"featureFlagOn"'> + </div>` +}) +class TestFeatureFlagComponent { +} + +class MockRenderer<T> { + setStyle() { + + } +} + +class MockAppStore<T> { + getState() { + return { + global: { + flags : { + + } + } + } + } +} + + +describe('Basic Feature Flag Directive', () => { + let component: TestFeatureFlagComponent; + let fixture: ComponentFixture<TestFeatureFlagComponent>; + let directiveInstance: BasicFeatureFlagDirective; + let elementOff: DebugElement; + let elementOn: DebugElement; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule + ], + declarations: [ + TestFeatureFlagComponent, + BasicFeatureFlagDirective], + providers: [ + FeatureFlagService, + ConfigurationService, + {provide: NgRedux, useClass: MockAppStore}, + {provide: Renderer2, useClass: MockRenderer}] + }).compileComponents(); + + fixture = TestBed.createComponent(TestFeatureFlagComponent); + component = fixture.componentInstance; + elementOff = fixture.debugElement.query(By.css('#featureFlagOff')); + elementOn = fixture.debugElement.query(By.css('#featureFlagOn')); + directiveInstance = elementOff.injector.get(BasicFeatureFlagDirective); + }); + + + test('directive should be defined', () => { + expect(directiveInstance).toBeDefined(); + }); + + test('should hide element if feature flag is off', () => { + directiveInstance.flagName = 'featureFlagOff'; + + directiveInstance.ngAfterContentChecked(); + expect(elementOff.nativeElement.style.display).toEqual('none'); + }); + + test('should show element if feature flag is on', () => { + directiveInstance.flagName = 'featureFlagOn'; + + directiveInstance.ngAfterContentChecked(); + expect(elementOn.nativeElement.style.display).toEqual(''); + }); +}); diff --git a/vid-webpack-master/src/app/featureFlag/directive/basic/basic.featureFlag.directive.ts b/vid-webpack-master/src/app/featureFlag/directive/basic/basic.featureFlag.directive.ts new file mode 100644 index 000000000..e6cbb4f17 --- /dev/null +++ b/vid-webpack-master/src/app/featureFlag/directive/basic/basic.featureFlag.directive.ts @@ -0,0 +1,29 @@ +import {AfterContentChecked, Directive, ElementRef, Input} from '@angular/core'; +import {FeatureFlagService} from "../../service/featureFlag.service"; +import * as _ from 'lodash'; + +/************************************************************************ + Feature Flag Directive + Example: + <div featureFlag [flagName]='"<flag name>"'></div> + ************************************************************************/ +@Directive({ + selector: '[featureFlag]' +}) +export class BasicFeatureFlagDirective implements AfterContentChecked { + @Input() flagName: string; + element: ElementRef; + + constructor(el: ElementRef, private _featureToggleService: FeatureFlagService) { + this.element = el; + } + + ngAfterContentChecked(): void { + if (!_.isNil(this.element)) { + const isFeatureOn: boolean = this._featureToggleService.isFeatureOn(this.flagName); + if(!isFeatureOn){ + this._featureToggleService.hideElement(this.element) + } + } + } +} diff --git a/vid-webpack-master/src/app/featureFlag/featureFlag.module.ts b/vid-webpack-master/src/app/featureFlag/featureFlag.module.ts new file mode 100644 index 000000000..d22076682 --- /dev/null +++ b/vid-webpack-master/src/app/featureFlag/featureFlag.module.ts @@ -0,0 +1,32 @@ +import {ModuleWithProviders, NgModule} from '@angular/core'; +import {CommonModule} from '@angular/common'; +import {BrowserModule} from "@angular/platform-browser"; +import {HttpClientModule} from "@angular/common/http"; +import {FeatureFlagService} from "./service/featureFlag.service"; +import {BasicFeatureFlagDirective} from "./directive/basic/basic.featureFlag.directive"; + + +@NgModule({ + imports: [ + BrowserModule, + HttpClientModule, + CommonModule + ], + declarations: [ + BasicFeatureFlagDirective + ], + exports: [ + BasicFeatureFlagDirective + ], + providers: [ + FeatureFlagService + ] +}) +export class FeatureFlagModule { + static forRoot(): ModuleWithProviders { + return { + ngModule: FeatureFlagModule, + providers: [] + }; + } +} diff --git a/vid-webpack-master/src/app/featureFlag/service/featureFlag.service.ts b/vid-webpack-master/src/app/featureFlag/service/featureFlag.service.ts new file mode 100644 index 000000000..09ce7bbf5 --- /dev/null +++ b/vid-webpack-master/src/app/featureFlag/service/featureFlag.service.ts @@ -0,0 +1,28 @@ +import {ElementRef, Injectable, Renderer2, RendererFactory2} from "@angular/core"; +import {ConfigurationService} from "../../shared/services/configuration.service"; + +@Injectable() +export class FeatureFlagService{ + private features : { [key: string]: boolean } = {}; + private renderer: Renderer2; + constructor(private _configurationService: ConfigurationService, + rendererFactory: RendererFactory2){ + this.renderer = rendererFactory.createRenderer(null, null); + this._configurationService.getFlags().subscribe((res: { [key: string]: boolean }) =>{ + this.features = res; + }) + } + + + isFeatureOn(feature : string) : boolean { + return this.features && this.getFeatureFlag()[feature] === true; + } + + getFeatureFlag() : { [key: string]: boolean } { + return this.features; + } + + hideElement(element: ElementRef) { + this.renderer.setStyle(element.nativeElement, 'display', 'none'); + } +} |