Files
element-call/src/utils/observable.test.ts
T
Robin a0209eb433 Add debug logs to generateItems
It's always worth having logs for when state holders are created or destroyed (these are often the most interesting things happening in the application), so I thought it would be nice to have generateItems always log for you when it's doing that.
2026-02-06 13:26:02 +01:00

105 lines
3.2 KiB
TypeScript

/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { expect, test } from "vitest";
import { type Observable, of, Subject, switchMap } from "rxjs";
import { withTestScheduler } from "./test";
import { filterBehavior, generateItems, pauseWhen } from "./observable";
import { type Behavior } from "../state/Behavior";
test("pauseWhen", () => {
withTestScheduler(({ behavior, expectObservable }) => {
const inputMarbles = " abcdefgh-i-jk-";
const pauseMarbles = " n-y--n-yn-y--n";
const outputMarbles = "abc--fgh-i---k";
expectObservable(
behavior(inputMarbles).pipe(
pauseWhen(behavior(pauseMarbles, { y: true, n: false })),
),
).toBe(outputMarbles);
});
});
test("generateItems", () => {
const scope1$ = new Subject<string>();
const scope2$ = new Subject<string>();
const scope3$ = new Subject<string>();
const scope4$ = new Subject<string>();
const scopeSubjects = [scope1$, scope2$, scope3$, scope4$];
withTestScheduler(({ hot, expectObservable }) => {
// Each scope should start when the input number reaches or surpasses their
// number and end when the input number drops back below their number.
// At the very end, unsubscribing should end all remaining scopes.
const inputMarbles = " 123242";
const outputMarbles = " abcbdb";
const subscriptionMarbles = "^-----!";
const scope1Marbles = " y-----n";
const scope2Marbles = " -y----n";
const scope3Marbles = " --ynyn";
const scope4Marbles = " ----yn";
expectObservable(
hot<string>(inputMarbles).pipe(
generateItems(
"test items",
function* (input) {
for (let i = 1; i <= +input; i++) {
yield { keys: [i], data: undefined };
}
},
(scope, data$, i) => {
scopeSubjects[i - 1].next("y");
scope.onEnd(() => scopeSubjects[i - 1].next("n"));
return i.toString();
},
),
),
subscriptionMarbles,
).toBe(outputMarbles, {
a: ["1"],
b: ["1", "2"],
c: ["1", "2", "3"],
d: ["1", "2", "3", "4"],
});
expectObservable(scope1$).toBe(scope1Marbles);
expectObservable(scope2$).toBe(scope2Marbles);
expectObservable(scope3$).toBe(scope3Marbles);
expectObservable(scope4$).toBe(scope4Marbles);
});
});
test("filterBehavior", () => {
withTestScheduler(({ behavior, expectObservable }) => {
// Filtering the input should segment it into 2 modes of non-null behavior.
const inputMarbles = " abcxabx";
const filteredMarbles = "a--xa-x";
const input$ = behavior(inputMarbles, {
a: "a",
b: "b",
c: "c",
x: null,
});
const filtered$: Observable<Behavior<string> | null> = input$.pipe(
filterBehavior((value) => typeof value === "string"),
);
expectObservable(filtered$).toBe(filteredMarbles, {
a: expect.any(Object),
x: null,
});
expectObservable(
filtered$.pipe(
switchMap((value$) => (value$ === null ? of(null) : value$)),
),
).toBe(inputMarbles, { a: "a", b: "b", c: "c", x: null });
});
});