mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[PM-24280] Remove account service from state (#15828)
* Introduce ActiveUserAccessor * Use ActiveUserAccessor over AccountService * Updates tests and testing utils to support ActiveUserAccessor * Update all injection points * Fix types test * Use ternary instead
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { mock } from "jest-mock-extended";
|
||||
import { Observable, map, of, switchMap, take } from "rxjs";
|
||||
import { BehaviorSubject, map, Observable, of, switchMap, take } from "rxjs";
|
||||
|
||||
import {
|
||||
GlobalState,
|
||||
@@ -16,11 +16,11 @@ import {
|
||||
DeriveDefinition,
|
||||
DerivedStateProvider,
|
||||
UserKeyDefinition,
|
||||
ActiveUserAccessor,
|
||||
} from "../src/platform/state";
|
||||
import { UserId } from "../src/types/guid";
|
||||
import { DerivedStateDependencies } from "../src/types/state";
|
||||
|
||||
import { FakeAccountService } from "./fake-account-service";
|
||||
import {
|
||||
FakeActiveUserState,
|
||||
FakeDerivedState,
|
||||
@@ -28,6 +28,35 @@ import {
|
||||
FakeSingleUserState,
|
||||
} from "./fake-state";
|
||||
|
||||
export interface MinimalAccountService {
|
||||
activeUserId: UserId | null;
|
||||
activeAccount$: Observable<{ id: UserId } | null>;
|
||||
}
|
||||
|
||||
export class FakeActiveUserAccessor implements MinimalAccountService, ActiveUserAccessor {
|
||||
private _subject: BehaviorSubject<UserId | null>;
|
||||
|
||||
constructor(startingUser: UserId | null) {
|
||||
this._subject = new BehaviorSubject(startingUser);
|
||||
this.activeAccount$ = this._subject
|
||||
.asObservable()
|
||||
.pipe(map((id) => (id != null ? { id } : null)));
|
||||
this.activeUserId$ = this._subject.asObservable();
|
||||
}
|
||||
|
||||
get activeUserId(): UserId {
|
||||
return this._subject.value;
|
||||
}
|
||||
|
||||
activeUserId$: Observable<UserId>;
|
||||
|
||||
activeAccount$: Observable<{ id: UserId }>;
|
||||
|
||||
switch(user: UserId | null) {
|
||||
this._subject.next(user);
|
||||
}
|
||||
}
|
||||
|
||||
export class FakeGlobalStateProvider implements GlobalStateProvider {
|
||||
mock = mock<GlobalStateProvider>();
|
||||
establishedMocks: Map<string, FakeGlobalState<unknown>> = new Map();
|
||||
@@ -138,18 +167,18 @@ export class FakeSingleUserStateProvider implements SingleUserStateProvider {
|
||||
}
|
||||
|
||||
export class FakeActiveUserStateProvider implements ActiveUserStateProvider {
|
||||
activeUserId$: Observable<UserId>;
|
||||
activeUserId$: Observable<UserId | null>;
|
||||
states: Map<string, FakeActiveUserState<unknown>> = new Map();
|
||||
|
||||
constructor(
|
||||
public accountService: FakeAccountService,
|
||||
public accountServiceAccessor: MinimalAccountService,
|
||||
readonly updateSyncCallback?: (
|
||||
key: UserKeyDefinition<unknown>,
|
||||
userId: UserId,
|
||||
newValue: unknown,
|
||||
) => Promise<void>,
|
||||
) {
|
||||
this.activeUserId$ = accountService.activeAccountSubject.asObservable().pipe(map((a) => a?.id));
|
||||
this.activeUserId$ = accountServiceAccessor.activeAccount$.pipe(map((a) => a?.id));
|
||||
}
|
||||
|
||||
get<T>(userKeyDefinition: UserKeyDefinition<T>): ActiveUserState<T> {
|
||||
@@ -182,9 +211,13 @@ export class FakeActiveUserStateProvider implements ActiveUserStateProvider {
|
||||
}
|
||||
|
||||
private buildFakeState<T>(userKeyDefinition: UserKeyDefinition<T>, initialValue?: T) {
|
||||
const state = new FakeActiveUserState<T>(this.accountService, initialValue, async (...args) => {
|
||||
await this.updateSyncCallback?.(userKeyDefinition, ...args);
|
||||
});
|
||||
const state = new FakeActiveUserState<T>(
|
||||
this.accountServiceAccessor,
|
||||
initialValue,
|
||||
async (...args) => {
|
||||
await this.updateSyncCallback?.(userKeyDefinition, ...args);
|
||||
},
|
||||
);
|
||||
state.keyDefinition = userKeyDefinition;
|
||||
return state;
|
||||
}
|
||||
@@ -256,14 +289,14 @@ export class FakeStateProvider implements StateProvider {
|
||||
return this.derived.get(parentState$, deriveDefinition, dependencies);
|
||||
}
|
||||
|
||||
constructor(public accountService: FakeAccountService) {}
|
||||
constructor(private activeAccountAccessor: MinimalAccountService) {}
|
||||
|
||||
private distributeSingleUserUpdate(
|
||||
key: UserKeyDefinition<unknown>,
|
||||
userId: UserId,
|
||||
newState: unknown,
|
||||
) {
|
||||
if (this.activeUser.accountService.activeUserId === userId) {
|
||||
if (this.activeUser.accountServiceAccessor.activeUserId === userId) {
|
||||
const state = this.activeUser.getFake(key, { allowInit: false });
|
||||
state?.nextState(newState, { syncValue: false });
|
||||
}
|
||||
@@ -284,7 +317,7 @@ export class FakeStateProvider implements StateProvider {
|
||||
this.distributeSingleUserUpdate.bind(this),
|
||||
);
|
||||
activeUser: FakeActiveUserStateProvider = new FakeActiveUserStateProvider(
|
||||
this.accountService,
|
||||
this.activeAccountAccessor,
|
||||
this.distributeActiveUserUpdate.bind(this),
|
||||
);
|
||||
derived: FakeDerivedStateProvider = new FakeDerivedStateProvider();
|
||||
|
||||
@@ -18,7 +18,7 @@ import { CombinedState, activeMarker } from "../src/platform/state/user-state";
|
||||
import { UserId } from "../src/types/guid";
|
||||
import { DerivedStateDependencies } from "../src/types/state";
|
||||
|
||||
import { FakeAccountService } from "./fake-account-service";
|
||||
import { MinimalAccountService } from "./fake-state-provider";
|
||||
|
||||
const DEFAULT_TEST_OPTIONS: StateUpdateOptions<any, any> = {
|
||||
shouldUpdate: () => true,
|
||||
@@ -177,7 +177,7 @@ export class FakeActiveUserState<T> implements ActiveUserState<T> {
|
||||
combinedState$: Observable<CombinedState<T>>;
|
||||
|
||||
constructor(
|
||||
private accountService: FakeAccountService,
|
||||
private activeAccountAccessor: MinimalAccountService,
|
||||
initialValue?: T,
|
||||
updateSyncCallback?: (userId: UserId, newValue: T) => Promise<void>,
|
||||
) {
|
||||
@@ -194,14 +194,10 @@ export class FakeActiveUserState<T> implements ActiveUserState<T> {
|
||||
this.state$ = this.combinedState$.pipe(map(([_userId, state]) => state));
|
||||
}
|
||||
|
||||
get userId() {
|
||||
return this.accountService.activeUserId;
|
||||
}
|
||||
|
||||
nextState(state: T | null, { syncValue }: { syncValue: boolean } = { syncValue: true }) {
|
||||
this.stateSubject.next({
|
||||
syncValue,
|
||||
combinedState: [this.userId, state],
|
||||
combinedState: [this.activeAccountAccessor.activeUserId, state],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -216,12 +212,12 @@ export class FakeActiveUserState<T> implements ActiveUserState<T> {
|
||||
? await firstValueFrom(options.combineLatestWith.pipe(timeout(options.msTimeout)))
|
||||
: null;
|
||||
if (!options.shouldUpdate(current, combinedDependencies)) {
|
||||
return [this.userId, current];
|
||||
return [this.activeAccountAccessor.activeUserId, current];
|
||||
}
|
||||
const newState = configureState(current, combinedDependencies);
|
||||
this.nextState(newState);
|
||||
this.nextMock([this.userId, newState]);
|
||||
return [this.userId, newState];
|
||||
this.nextMock([this.activeAccountAccessor.activeUserId, newState]);
|
||||
return [this.activeAccountAccessor.activeUserId, newState];
|
||||
}
|
||||
|
||||
/** Tracks update values resolved by `FakeState.update` */
|
||||
|
||||
Reference in New Issue
Block a user