mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 07:43:35 +00:00
Combined State (#7383)
* Introduce Combined State * Cleanup Test * Update Fakes * Address PR Feedback * Update libs/common/src/platform/state/implementations/default-active-user-state.ts Co-authored-by: Matt Gibson <mgibson@bitwarden.com> * Prettier * Get rid of ReplaySubject reference --------- Co-authored-by: Matt Gibson <mgibson@bitwarden.com>
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import { ReplaySubject, firstValueFrom, timeout } from "rxjs";
|
||||
import { Observable, ReplaySubject, firstValueFrom, map, timeout } from "rxjs";
|
||||
|
||||
import { DerivedState, GlobalState, SingleUserState, ActiveUserState } from "../src/platform/state";
|
||||
// eslint-disable-next-line import/no-restricted-paths -- using unexposed options for clean typing in test class
|
||||
import { StateUpdateOptions } from "../src/platform/state/state-update-options";
|
||||
// eslint-disable-next-line import/no-restricted-paths -- using unexposed options for clean typing in test class
|
||||
import { UserState, activeMarker } from "../src/platform/state/user-state";
|
||||
import { CombinedState, UserState, activeMarker } from "../src/platform/state/user-state";
|
||||
import { UserId } from "../src/types/guid";
|
||||
|
||||
const DEFAULT_TEST_OPTIONS: StateUpdateOptions<any, any> = {
|
||||
@@ -57,9 +57,19 @@ export class FakeGlobalState<T> implements GlobalState<T> {
|
||||
}
|
||||
}
|
||||
|
||||
export class FakeUserState<T> implements UserState<T> {
|
||||
abstract class FakeUserState<T> implements UserState<T> {
|
||||
// eslint-disable-next-line rxjs/no-exposed-subjects -- exposed for testing setup
|
||||
stateSubject = new ReplaySubject<T>(1);
|
||||
stateSubject = new ReplaySubject<CombinedState<T>>(1);
|
||||
|
||||
protected userId: UserId;
|
||||
|
||||
state$: Observable<T>;
|
||||
combinedState$: Observable<CombinedState<T>>;
|
||||
|
||||
constructor() {
|
||||
this.combinedState$ = this.stateSubject.asObservable();
|
||||
this.state$ = this.combinedState$.pipe(map(([_userId, state]) => state));
|
||||
}
|
||||
|
||||
update: <TCombine>(
|
||||
configureState: (state: T, dependency: TCombine) => T,
|
||||
@@ -75,34 +85,24 @@ export class FakeUserState<T> implements UserState<T> {
|
||||
return current;
|
||||
}
|
||||
const newState = configureState(current, combinedDependencies);
|
||||
this.stateSubject.next(newState);
|
||||
this.stateSubject.next([this.userId, newState]);
|
||||
return newState;
|
||||
});
|
||||
|
||||
updateMock = this.update as jest.MockedFunction<typeof this.update>;
|
||||
|
||||
updateFor: <TCombine>(
|
||||
userId: UserId,
|
||||
configureState: (state: T, dependency: TCombine) => T,
|
||||
options?: StateUpdateOptions<T, TCombine>,
|
||||
) => Promise<T> = jest.fn();
|
||||
|
||||
getFromState: () => Promise<T> = jest.fn(async () => {
|
||||
return await firstValueFrom(this.state$.pipe(timeout(10)));
|
||||
});
|
||||
|
||||
get state$() {
|
||||
return this.stateSubject.asObservable();
|
||||
}
|
||||
}
|
||||
|
||||
export class FakeSingleUserState<T> extends FakeUserState<T> implements SingleUserState<T> {
|
||||
constructor(readonly userId: UserId) {
|
||||
super();
|
||||
this.userId = userId;
|
||||
}
|
||||
}
|
||||
export class FakeActiveUserState<T> extends FakeUserState<T> implements ActiveUserState<T> {
|
||||
[activeMarker]: true;
|
||||
changeActiveUser(userId: UserId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
}
|
||||
|
||||
export class FakeDerivedState<T> implements DerivedState<T> {
|
||||
|
||||
Reference in New Issue
Block a user