mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
AAE-19688 Persist feature flag overrides in session storage (#10832)
* AAE-19688 Persist feature flag overrides in session storage * unit tests
This commit is contained in:
parent
61a1fb64bf
commit
9ee0e5ee3e
@ -17,37 +17,37 @@
|
||||
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { DebugFeaturesService } from './debug-features.service';
|
||||
import { StorageService } from '../../../../src/lib/common/services/storage.service';
|
||||
import { OverridableFeaturesServiceToken, WritableFeaturesServiceToken } from '../interfaces/features.interface';
|
||||
import { OverridableFeaturesServiceToken, WritableFeaturesServiceConfigToken, WritableFeaturesServiceToken } from '../interfaces/features.interface';
|
||||
import { DummyFeaturesService } from './dummy-features.service';
|
||||
import { StorageFeaturesService } from './storage-features.service';
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
describe('DebugFeaturesService', () => {
|
||||
let service: DebugFeaturesService;
|
||||
const mockStorage = {
|
||||
getItem: () =>
|
||||
JSON.stringify({
|
||||
feature1: {
|
||||
current: true
|
||||
},
|
||||
feature2: {
|
||||
current: false,
|
||||
fictive: true
|
||||
}
|
||||
}),
|
||||
setItem: () => {}
|
||||
};
|
||||
let mockStorageKey: string;
|
||||
let mockStorage;
|
||||
|
||||
beforeEach(() => {
|
||||
mockStorageKey = 'storage-key-test';
|
||||
mockStorage = { [mockStorageKey]: true };
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
DebugFeaturesService,
|
||||
{ provide: StorageService, useValue: mockStorage },
|
||||
{
|
||||
provide: WritableFeaturesServiceConfigToken,
|
||||
useValue: { storageKey: mockStorageKey }
|
||||
},
|
||||
{ provide: WritableFeaturesServiceToken, useClass: StorageFeaturesService },
|
||||
{ provide: OverridableFeaturesServiceToken, useClass: DummyFeaturesService }
|
||||
]
|
||||
});
|
||||
|
||||
spyOn(sessionStorage, 'getItem').and.callFake((key) => JSON.stringify(mockStorage[key]));
|
||||
spyOn(sessionStorage, 'setItem').and.callFake((key, value) => {
|
||||
mockStorage[key] = value;
|
||||
});
|
||||
|
||||
service = TestBed.inject(DebugFeaturesService);
|
||||
});
|
||||
|
||||
|
@ -16,8 +16,8 @@
|
||||
*/
|
||||
|
||||
import { Inject, Injectable, Optional } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { skip, switchMap } from 'rxjs/operators';
|
||||
import { BehaviorSubject, Observable, combineLatest } from 'rxjs';
|
||||
import { filter, switchMap } from 'rxjs/operators';
|
||||
import {
|
||||
IDebugFeaturesService,
|
||||
IFeaturesService,
|
||||
@ -29,12 +29,12 @@ import {
|
||||
FlagSet,
|
||||
IWritableFeaturesService
|
||||
} from '../interfaces/features.interface';
|
||||
import { StorageService } from '@alfresco/adf-core';
|
||||
|
||||
@Injectable()
|
||||
export class DebugFeaturesService implements IDebugFeaturesService {
|
||||
private isInDebugMode: BehaviorSubject<boolean>;
|
||||
private isInDebugMode$: Observable<boolean>;
|
||||
private readonly isInDebugModeSubject = new BehaviorSubject<boolean>(false);
|
||||
private readonly isInDebugMode$ = this.isInDebugModeSubject.asObservable();
|
||||
private readonly initSubject = new BehaviorSubject<boolean>(false);
|
||||
|
||||
get storageKey(): string {
|
||||
return `${this.config?.storageKey || 'feature-flags'}-override`;
|
||||
@ -43,14 +43,15 @@ export class DebugFeaturesService implements IDebugFeaturesService {
|
||||
constructor(
|
||||
@Inject(OverridableFeaturesServiceToken) private overriddenFeaturesService: IFeaturesService,
|
||||
@Inject(WritableFeaturesServiceToken) private writableFeaturesService: IFeaturesService & IWritableFeaturesService,
|
||||
private storageService: StorageService,
|
||||
@Optional() @Inject(WritableFeaturesServiceConfigToken) private config?: WritableFeaturesServiceConfig
|
||||
) {
|
||||
this.isInDebugMode = new BehaviorSubject<boolean>(JSON.parse(this.storageService.getItem(this.storageKey) || 'false'));
|
||||
this.isInDebugMode$ = this.isInDebugMode.asObservable();
|
||||
this.init();
|
||||
|
||||
this.isInDebugMode.pipe(skip(1)).subscribe((debugMode) => {
|
||||
this.storageService.setItem(this.storageKey, JSON.stringify(debugMode));
|
||||
combineLatest({
|
||||
debugMode: this.isInDebugModeSubject,
|
||||
init: this.waitForInitializationToFinish()
|
||||
}).subscribe(({ debugMode }) => {
|
||||
sessionStorage.setItem(this.storageKey, JSON.stringify(debugMode));
|
||||
});
|
||||
}
|
||||
|
||||
@ -87,10 +88,20 @@ export class DebugFeaturesService implements IDebugFeaturesService {
|
||||
}
|
||||
|
||||
enable(on: boolean): void {
|
||||
this.isInDebugMode.next(on);
|
||||
this.isInDebugModeSubject.next(on);
|
||||
}
|
||||
|
||||
isEnabled$(): Observable<boolean> {
|
||||
return this.isInDebugMode$;
|
||||
}
|
||||
|
||||
private init() {
|
||||
const storedOverride = JSON.parse(sessionStorage.getItem(this.storageKey) || 'false');
|
||||
this.isInDebugModeSubject.next(storedOverride);
|
||||
this.initSubject.next(true);
|
||||
}
|
||||
|
||||
private waitForInitializationToFinish(): Observable<boolean> {
|
||||
return this.initSubject.pipe(filter((initialized) => !!initialized));
|
||||
}
|
||||
}
|
||||
|
@ -17,17 +17,20 @@
|
||||
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { StorageFeaturesService } from './storage-features.service';
|
||||
import { StorageService } from '../../../../src/public-api';
|
||||
import { FlagSet, WritableFeaturesServiceConfigToken } from '../interfaces/features.interface';
|
||||
import { skip, take } from 'rxjs/operators';
|
||||
|
||||
describe('StorageFeaturesService', () => {
|
||||
let storageFeaturesService: StorageFeaturesService;
|
||||
|
||||
describe('if flags are present in LocalStorage', () => {
|
||||
const mockStorage = {
|
||||
getItem: () =>
|
||||
JSON.stringify({
|
||||
describe('if flags are present in sessionStorage', () => {
|
||||
let mockStorageKey: string;
|
||||
let mockStorage;
|
||||
|
||||
beforeEach(() => {
|
||||
mockStorageKey = 'storage-key-test';
|
||||
mockStorage = {
|
||||
[mockStorageKey]: {
|
||||
feature1: {
|
||||
current: true
|
||||
},
|
||||
@ -35,23 +38,23 @@ describe('StorageFeaturesService', () => {
|
||||
current: false,
|
||||
fictive: true
|
||||
}
|
||||
}),
|
||||
setItem: () => {}
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{ provide: StorageService, useValue: mockStorage },
|
||||
{
|
||||
provide: WritableFeaturesServiceConfigToken,
|
||||
useValue: {
|
||||
storageKey: 'storage-key-test'
|
||||
}
|
||||
useValue: { storageKey: mockStorageKey }
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
spyOn(sessionStorage, 'getItem').and.callFake((key) => JSON.stringify(mockStorage[key]));
|
||||
spyOn(sessionStorage, 'setItem').and.callFake((key, value) => {
|
||||
mockStorage[key] = value;
|
||||
});
|
||||
|
||||
storageFeaturesService = TestBed.inject(StorageFeaturesService);
|
||||
storageFeaturesService.init();
|
||||
});
|
||||
|
@ -16,8 +16,8 @@
|
||||
*/
|
||||
|
||||
import { Inject, Injectable, Optional } from '@angular/core';
|
||||
import { BehaviorSubject, Observable, of } from 'rxjs';
|
||||
import { map, skip } from 'rxjs/operators';
|
||||
import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs';
|
||||
import { filter, map } from 'rxjs/operators';
|
||||
import {
|
||||
FlagChangeset,
|
||||
IFeaturesService,
|
||||
@ -28,21 +28,21 @@ import {
|
||||
WritableFeaturesServiceConfig
|
||||
} from '../interfaces/features.interface';
|
||||
import { FlagSetParser } from './flagset.parser';
|
||||
import { StorageService } from '@alfresco/adf-core';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class StorageFeaturesService implements IFeaturesService, IWritableFeaturesService {
|
||||
private currentFlagState: WritableFlagChangeset = {};
|
||||
private flags = new BehaviorSubject<WritableFlagChangeset>({});
|
||||
private flags$ = this.flags.asObservable();
|
||||
private readonly flags = new BehaviorSubject<WritableFlagChangeset>({});
|
||||
private readonly flags$ = this.flags.asObservable();
|
||||
private readonly initSubject = new BehaviorSubject<boolean>(false);
|
||||
|
||||
constructor(
|
||||
private storageService: StorageService,
|
||||
@Optional() @Inject(WritableFeaturesServiceConfigToken) private config?: WritableFeaturesServiceConfig
|
||||
) {
|
||||
this.flags.pipe(skip(1)).subscribe((flags) => {
|
||||
constructor(@Optional() @Inject(WritableFeaturesServiceConfigToken) private config?: WritableFeaturesServiceConfig) {
|
||||
combineLatest({
|
||||
flags: this.flags,
|
||||
init: this.waitForInitializationToFinish()
|
||||
}).subscribe(({ flags }) => {
|
||||
this.currentFlagState = flags;
|
||||
this.storageService.setItem(this.storageKey, JSON.stringify(FlagSetParser.serialize(flags)));
|
||||
sessionStorage.setItem(this.storageKey, JSON.stringify(FlagSetParser.serialize(flags)));
|
||||
});
|
||||
}
|
||||
|
||||
@ -51,9 +51,10 @@ export class StorageFeaturesService implements IFeaturesService, IWritableFeatur
|
||||
}
|
||||
|
||||
init(): Observable<WritableFlagChangeset> {
|
||||
const storedFlags = JSON.parse(this.storageService.getItem(this.storageKey) || '{}');
|
||||
const storedFlags = JSON.parse(sessionStorage.getItem(this.storageKey) || '{}');
|
||||
const initialFlagChangeSet = FlagSetParser.deserialize(storedFlags);
|
||||
this.flags.next(initialFlagChangeSet);
|
||||
this.initSubject.next(true);
|
||||
return of(initialFlagChangeSet);
|
||||
}
|
||||
|
||||
@ -133,4 +134,8 @@ export class StorageFeaturesService implements IFeaturesService, IWritableFeatur
|
||||
|
||||
this.flags.next(mergedFlags);
|
||||
}
|
||||
|
||||
private waitForInitializationToFinish(): Observable<boolean> {
|
||||
return this.initSubject.pipe(filter((initialized) => !!initialized));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user