Link derived state fake to parent observable. (#7922)

This commit is contained in:
Matt Gibson 2024-02-13 15:26:56 -05:00 committed by GitHub
parent aa11feec1b
commit f0ae318f57
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 29 additions and 5 deletions

View File

@ -198,7 +198,7 @@ export class FakeDerivedStateProvider implements DerivedStateProvider {
let result = this.states.get(deriveDefinition.buildCacheKey()) as DerivedState<TTo>; let result = this.states.get(deriveDefinition.buildCacheKey()) as DerivedState<TTo>;
if (result == null) { if (result == null) {
result = new FakeDerivedState<TTo>(); result = new FakeDerivedState(parentState$, deriveDefinition, dependencies);
this.states.set(deriveDefinition.buildCacheKey(), result); this.states.set(deriveDefinition.buildCacheKey(), result);
} }
return result; return result;

View File

@ -1,4 +1,4 @@
import { Observable, ReplaySubject, firstValueFrom, map, timeout } from "rxjs"; import { Observable, ReplaySubject, concatMap, firstValueFrom, map, timeout } from "rxjs";
import { import {
DerivedState, DerivedState,
@ -6,12 +6,14 @@ import {
SingleUserState, SingleUserState,
ActiveUserState, ActiveUserState,
KeyDefinition, KeyDefinition,
DeriveDefinition,
} from "../src/platform/state"; } from "../src/platform/state";
// eslint-disable-next-line import/no-restricted-paths -- using unexposed options for clean typing in test class // 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"; 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 // eslint-disable-next-line import/no-restricted-paths -- using unexposed options for clean typing in test class
import { CombinedState, activeMarker } from "../src/platform/state/user-state"; import { CombinedState, activeMarker } from "../src/platform/state/user-state";
import { UserId } from "../src/types/guid"; import { UserId } from "../src/types/guid";
import { DerivedStateDependencies } from "../src/types/state";
import { FakeAccountService } from "./fake-account-service"; import { FakeAccountService } from "./fake-account-service";
@ -204,11 +206,33 @@ export class FakeActiveUserState<T> implements ActiveUserState<T> {
} }
} }
export class FakeDerivedState<T> implements DerivedState<T> { export class FakeDerivedState<TFrom, TTo, TDeps extends DerivedStateDependencies>
implements DerivedState<TTo>
{
// eslint-disable-next-line rxjs/no-exposed-subjects -- exposed for testing setup // eslint-disable-next-line rxjs/no-exposed-subjects -- exposed for testing setup
stateSubject = new ReplaySubject<T>(1); stateSubject = new ReplaySubject<TTo>(1);
forceValue(value: T): Promise<T> { constructor(
parentState$: Observable<TFrom>,
deriveDefinition: DeriveDefinition<TFrom, TTo, TDeps>,
dependencies: TDeps,
) {
parentState$
.pipe(
concatMap(async (v) => {
const newState = deriveDefinition.derive(v, dependencies);
if (newState instanceof Promise) {
return newState;
}
return Promise.resolve(newState);
}),
)
.subscribe((newState) => {
this.stateSubject.next(newState);
});
}
forceValue(value: TTo): Promise<TTo> {
this.stateSubject.next(value); this.stateSubject.next(value);
return Promise.resolve(value); return Promise.resolve(value);
} }