Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions src/app/modules/login/login.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import { waitForAsync, ComponentFixture, TestBed, inject } from '@angular/core/t
import { RouterTestingModule } from '@angular/router/testing';
import { AzureAdB2CService } from '../../modules/login/services/azure.ad.b2c.service';
import { of } from 'rxjs';

import { LoginComponent } from './login.component';
import { Router } from '@angular/router';
import { FeatureToggleCookiesService } from '../shared/feature-toggles/feature-toggle-cookies/feature-toggle-cookies.service';

describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
let azureAdB2CService: AzureAdB2CService;
let featureToggleCookiesService: FeatureToggleCookiesService;

const azureAdB2CServiceStub = {
isLogin() {
Expand All @@ -22,12 +23,19 @@ describe('LoginComponent', () => {
}
};

const featureToggleCookiesServiceStub = {
setCookies() {
return null;
}
};

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [ RouterTestingModule ],
declarations: [ LoginComponent ],
providers: [
{ providers: AzureAdB2CService, useValue: azureAdB2CServiceStub}
{ providers: AzureAdB2CService, useValue: azureAdB2CServiceStub},
{ providers: FeatureToggleCookiesService, useValue: featureToggleCookiesServiceStub}
]
})
.compileComponents();
Expand All @@ -38,15 +46,21 @@ describe('LoginComponent', () => {
component = fixture.componentInstance;
fixture.detectChanges();
azureAdB2CService = TestBed.inject(AzureAdB2CService);

featureToggleCookiesService = TestBed.inject(FeatureToggleCookiesService);
});

it('Service injected via inject(...) and TestBed.get(...) should be the same instance',
it('AzureAdB2CService injected via inject(...) and TestBed.get(...) should be the same instance',
inject([AzureAdB2CService], (injectService: AzureAdB2CService) => {
expect(injectService).toEqual(azureAdB2CService);
})
);

it('FeatureToggleCookiesService injected via inject(...) and TestBed.get(...) should be the same instance',
inject([FeatureToggleCookiesService], (injectService: FeatureToggleCookiesService) => {
expect(injectService).toEqual(featureToggleCookiesService);
})
);

it('should create login component', () => {
expect(component).toBeTruthy();
});
Expand All @@ -55,9 +69,13 @@ describe('LoginComponent', () => {
spyOn(azureAdB2CService, 'isLogin').and.returnValue(false);
spyOn(azureAdB2CService, 'setCookies').and.returnValue();
spyOn(azureAdB2CService, 'signIn').and.returnValue(of(() => {}));
spyOn(featureToggleCookiesService, 'setCookies').and.returnValue(featureToggleCookiesService.setCookies());

component.login();

expect(azureAdB2CService.signIn).toHaveBeenCalled();
expect(azureAdB2CService.setCookies).toHaveBeenCalled();
expect(featureToggleCookiesService.setCookies).toHaveBeenCalled();
}));

it('should not sign-up or login with google if is already logged-in into the app', inject([Router], (router: Router) => {
Expand Down
8 changes: 7 additions & 1 deletion src/app/modules/login/login.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Component } from '@angular/core';
import { AzureAdB2CService } from './services/azure.ad.b2c.service';
import { Router } from '@angular/router';
import { FeatureToggleCookiesService } from '../shared/feature-toggles/feature-toggle-cookies/feature-toggle-cookies.service';

@Component({
selector: 'app-login',
Expand All @@ -10,13 +11,18 @@ import { Router } from '@angular/router';

export class LoginComponent {

constructor(private azureAdB2CService: AzureAdB2CService, private router: Router) {}
constructor(
private azureAdB2CService: AzureAdB2CService,
private router: Router,
private featureToggleCookiesService: FeatureToggleCookiesService
) {}

login(): void {
if (this.azureAdB2CService.isLogin()) {
this.router.navigate(['']);
} else {
this.azureAdB2CService.signIn().subscribe(() => {
this.featureToggleCookiesService.setCookies();
this.azureAdB2CService.setCookies();
this.router.navigate(['']);
});
Expand Down
3 changes: 3 additions & 0 deletions src/app/modules/login/services/azure.ad.b2c.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@ describe('AzureAdB2CService', () => {

it('on logout should call msal logout and verify if user localStorage is removed', () => {
spyOn(UserAgentApplication.prototype, 'logout').and.returnValue();
spyOn(cookieService, 'deleteAll');
spyOn(localStorage, 'removeItem').withArgs('user');

service.logout();

expect(cookieService.deleteAll).toHaveBeenCalled();
expect(localStorage.removeItem).toHaveBeenCalledWith('user');
expect(UserAgentApplication.prototype.logout).toHaveBeenCalled();
});
Expand Down
3 changes: 1 addition & 2 deletions src/app/modules/login/services/azure.ad.b2c.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ export class AzureAdB2CService {
}

logout() {
this.cookieService.delete('msal.idtoken');
this.cookieService.delete('msal.client.info');
this.cookieService.deleteAll();
this.msal.logout();
localStorage.removeItem('user');
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { TestBed } from '@angular/core/testing';
import { CookieService } from 'ngx-cookie-service';
import { of } from 'rxjs';
import { FeatureToggleGeneralService } from '../feature-toggle-general/feature-toggle-general.service';
import { FeatureToggleModel } from '../feature-toggle.model';
import { TargetingFeatureFilterModel } from '../filters/targeting/targeting-feature-filter.model';
import { FeatureToggleCookiesService } from './feature-toggle-cookies.service';

describe('FeatureToggleCookiesService', () => {
let cookieService: CookieService;
let featureToggleGeneralService: FeatureToggleGeneralService;
let service: FeatureToggleCookiesService;

beforeEach(() => {
TestBed.configureTestingModule({
providers: [CookieService, FeatureToggleGeneralService]
});
cookieService = TestBed.inject(CookieService);
featureToggleGeneralService = TestBed.inject(FeatureToggleGeneralService);
service = TestBed.inject(FeatureToggleCookiesService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});

it('not call CookieService.set() when call setCookies() and getActivated() return empty', () => {
const fakeAllFeatureaToggleWithFilters = [];
const spyOnSetCookie = spyOn(cookieService, 'set');
spyOn(featureToggleGeneralService, 'getActivated').and.returnValue(of(fakeAllFeatureaToggleWithFilters));

service.setCookies();

expect(spyOnSetCookie).toHaveBeenCalledTimes(0);
});

it('Call 1 time CookieService.set() when call setCookies()', () => {
const anyMatchingFilter = new TargetingFeatureFilterModel(
{ Audience: { Groups: ['group-a'], Users: ['user-a'] } },
{ username: 'user-b', group: 'group-a' }
);
const fakeAllFeatureaToggleWithFilters = [new FeatureToggleModel('any-other-id', true, [anyMatchingFilter])];
const spyOnSetCookie = spyOn(cookieService, 'set');
spyOn(featureToggleGeneralService, 'getActivated').and.returnValue(of(fakeAllFeatureaToggleWithFilters));

service.setCookies();

expect(spyOnSetCookie).toHaveBeenCalledTimes(1);
});

it('Call 2 times CookieService.set() when call setCookies()', () => {
const anyMatchingFilter = new TargetingFeatureFilterModel(
{ Audience: { Groups: ['group-a'], Users: ['user-a'] } },
{ username: 'user-b', group: 'group-a' }
);
const fakeAllFeatureaToggleWithFilters = [
new FeatureToggleModel('first-id', true, [anyMatchingFilter]),
new FeatureToggleModel('second-id', true, [anyMatchingFilter])
];
const spyOnSetCookie = spyOn(cookieService, 'set');
spyOn(featureToggleGeneralService, 'getActivated').and.returnValue(of(fakeAllFeatureaToggleWithFilters));

service.setCookies();

expect(spyOnSetCookie).toHaveBeenCalledTimes(2);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Injectable } from '@angular/core';
import { FeatureToggleGeneralService } from '../feature-toggle-general/feature-toggle-general.service';
import { CookieService } from 'ngx-cookie-service';

@Injectable({
providedIn: 'root'
})
export class FeatureToggleCookiesService {

constructor(
private cookieService: CookieService,
private featureToggleGeneralService: FeatureToggleGeneralService
) { }

setCookies(){
this.featureToggleGeneralService.getActivated().subscribe(
(allFeaturToggle) => {
for (const featureToggle of allFeaturToggle){
this.cookieService.set(featureToggle.name, `${featureToggle.enabled}`, 30);
}
}
);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { FeatureToggle } from './../../../../../environments/enum';
import { TestBed } from '@angular/core/testing';
import { of, Observable } from 'rxjs';
import { of } from 'rxjs';
import { FeatureManagerService } from '../feature-toggle-manager.service';
import { FeatureToggleGeneralService } from './feature-toggle-general.service';
import { FeatureToggleModel } from '../feature-toggle.model';
import { TargetingFeatureFilterModel } from '../filters/targeting/targeting-feature-filter.model';


describe('FeatureToggleGeneralService', () => {
Expand Down Expand Up @@ -33,4 +35,28 @@ describe('FeatureToggleGeneralService', () => {
});
});
});

it('getActivated return a FeatureToggleModel', () => {
const anyNotMatchingFilter = new TargetingFeatureFilterModel(
{ Audience: { Groups: ['a-group'], Users: ['user-a'] } },
{ username: 'user-b', group: 'b-group' }
);
const fakeAllFeatureaToggleWithFilters = [new FeatureToggleModel('any-other-id', true, [anyNotMatchingFilter])];
spyOn(featureManagerService, 'getAllFeatureToggleEnableForUser').and.returnValue(of(fakeAllFeatureaToggleWithFilters));

featureToggleGeneralService.getActivated().subscribe((featureToggleEnableForUser) => {
expect(featureToggleEnableForUser.length).toEqual(1);
expect(featureToggleEnableForUser).toEqual(fakeAllFeatureaToggleWithFilters);
});
});

it('getActivated return empty', () => {
const fakeAllFeatureaToggleWithFilters = [];
spyOn(featureManagerService, 'getAllFeatureToggleEnableForUser').and.returnValue(of(fakeAllFeatureaToggleWithFilters));

featureToggleGeneralService.getActivated().subscribe((featureToggleEnableForUser) => {
expect(featureToggleEnableForUser.length).toEqual(0);
expect(featureToggleEnableForUser).toEqual(fakeAllFeatureaToggleWithFilters);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FeatureToggle } from './../../../../../environments/enum';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { FeatureManagerService } from '../feature-toggle-manager.service';
import { FeatureToggleModel } from '../feature-toggle.model';

@Injectable({
providedIn: 'root',
Expand All @@ -13,4 +14,8 @@ export class FeatureToggleGeneralService {
isActivated(featureToggle: FeatureToggle): Observable<boolean> {
return this.featureManagerService.isToggleEnabledForUser(featureToggle);
}

getActivated(): Observable<FeatureToggleModel[]>{
return this.featureManagerService.getAllFeatureToggleEnableForUser();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,48 @@ describe('FeatureToggleManager', () => {
expect(value).toEqual(false);
});
});

it('Get empty when getAllFeatureToggle() return empty', () => {
const fakeAllFeatureaToggleWithFilters = [];
spyOn(fakeFeatureToggleProvider, 'getAllFeatureToggle').and.returnValue(Promise.resolve(fakeAllFeatureaToggleWithFilters));

const response = service.getAllFeatureToggleEnableForUser();

response.subscribe((result) => {
expect(result.length).toEqual(0);
expect(result).toEqual([]);
});
expect().nothing();
});

it('Get empty when getAllFeatureToggle() return FeatureToggle without fakeuser', () => {
const fakeAllFeatureaToggleWithFilters = [new FeatureToggleModel('any-other-id', true, [anyNotMatchingFilter])];
spyOn(fakeFeatureToggleProvider, 'getAllFeatureToggle').and.returnValue(Promise.resolve(fakeAllFeatureaToggleWithFilters));

const response = service.getAllFeatureToggleEnableForUser();

response.subscribe((result) => {
expect(result.length).toEqual(0);
expect(result).toEqual([]);
});
expect().nothing();
});

it('Get FeatureToggleModel[] when getAllFeatureToggle() return FeatureToggle with fakeuser', () => {
const fakeFeatureToggleModel: FeatureToggleModel = new FeatureToggleModel('good-other-id', false, [anyMatchingFilter]);
const fakeAllFeatureaToggleWithFilters = [
new FeatureToggleModel('any-other-id', true, [anyNotMatchingFilter]),
fakeFeatureToggleModel
];
spyOn(fakeFeatureToggleProvider, 'getAllFeatureToggle').and.returnValue(Promise.resolve(fakeAllFeatureaToggleWithFilters));

const response = service.getAllFeatureToggleEnableForUser();

response.subscribe((result) => {
expect(result.length).toEqual(1);
expect(result[0]).toEqual(fakeFeatureToggleModel);
});
expect().nothing();
});
});
});
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Injectable } from '@angular/core';
import { Observable, zip } from 'rxjs';
import { from, Observable, zip } from 'rxjs';
import { map } from 'rxjs/operators';
import { FeatureToggleProvider } from './feature-toggle-provider.service';

import { FeatureToggleModel } from './feature-toggle.model';

@Injectable({
providedIn: 'root',
Expand All @@ -12,9 +12,9 @@ export class FeatureManagerService {
constructor(private featureToggleProvider: FeatureToggleProvider) { }

public isToggleEnabled(toggleName: string, toggleLabel?: string): Observable<boolean> {
return this.featureToggleProvider.getFeatureToggle(toggleName, toggleLabel).pipe(
map(featureToggle => featureToggle.enabled)
);
return this.featureToggleProvider
.getFeatureToggle(toggleName, toggleLabel)
.pipe(map((featureToggle) => featureToggle.enabled));
}

public isToggleEnabledForUser(toggleName: string, toggleLabel?: string): Observable<boolean> {
Expand All @@ -35,4 +35,14 @@ export class FeatureManagerService {

return result$;
}

public getAllFeatureToggleEnableForUser(): Observable<FeatureToggleModel[]> {
return from(this.featureToggleProvider.getAllFeatureToggle()).pipe(
map((allFeatureToggle) =>
allFeatureToggle.filter((featureToggle) =>
featureToggle.filters.map((filter) => filter.evaluate()).includes(true)
)
)
);
}
}
Loading