Simplify some test helpers that no longer need continuations

This commit is contained in:
Robin
2025-10-17 12:34:06 -04:00
parent d5efba285b
commit 13894aaf3a
4 changed files with 175 additions and 195 deletions

View File

@@ -17,8 +17,8 @@ import {
mockLocalParticipant, mockLocalParticipant,
mockMediaDevices, mockMediaDevices,
mockRtcMembership, mockRtcMembership,
withLocalMedia, createLocalMedia,
withRemoteMedia, createRemoteMedia,
withTestScheduler, withTestScheduler,
} from "../utils/test"; } from "../utils/test";
import { getValue } from "../utils/observable"; import { getValue } from "../utils/observable";
@@ -42,9 +42,9 @@ vi.mock("../Platform", () => ({
const rtcMembership = mockRtcMembership("@alice:example.org", "AAAA"); const rtcMembership = mockRtcMembership("@alice:example.org", "AAAA");
test("control a participant's volume", async () => { test("control a participant's volume", () => {
const setVolumeSpy = vi.fn(); const setVolumeSpy = vi.fn();
await withRemoteMedia(rtcMembership, {}, { setVolume: setVolumeSpy }, (vm) => const vm = createRemoteMedia(rtcMembership, {}, { setVolume: setVolumeSpy });
withTestScheduler(({ expectObservable, schedule }) => { withTestScheduler(({ expectObservable, schedule }) => {
schedule("-ab---c---d|", { schedule("-ab---c---d|", {
a() { a() {
@@ -84,12 +84,11 @@ test("control a participant's volume", async () => {
f: 0, f: 0,
g: 0.8, g: 0.8,
}); });
}), });
);
}); });
test("toggle fit/contain for a participant's video", async () => { test("toggle fit/contain for a participant's video", () => {
await withRemoteMedia(rtcMembership, {}, {}, (vm) => const vm = createRemoteMedia(rtcMembership, {}, {});
withTestScheduler(({ expectObservable, schedule }) => { withTestScheduler(({ expectObservable, schedule }) => {
schedule("-ab|", { schedule("-ab|", {
a: () => vm.toggleFitContain(), a: () => vm.toggleFitContain(),
@@ -100,34 +99,32 @@ test("toggle fit/contain for a participant's video", async () => {
b: false, b: false,
c: true, c: true,
}); });
}), });
);
}); });
test("local media remembers whether it should always be shown", async () => { test("local media remembers whether it should always be shown", () => {
await withLocalMedia( const vm1 = createLocalMedia(
rtcMembership, rtcMembership,
{}, {},
mockLocalParticipant({}), mockLocalParticipant({}),
mockMediaDevices({}), mockMediaDevices({}),
(vm) =>
withTestScheduler(({ expectObservable, schedule }) => {
schedule("-a|", { a: () => vm.setAlwaysShow(false) });
expectObservable(vm.alwaysShow$).toBe("ab", { a: true, b: false });
}),
); );
withTestScheduler(({ expectObservable, schedule }) => {
schedule("-a|", { a: () => vm1.setAlwaysShow(false) });
expectObservable(vm1.alwaysShow$).toBe("ab", { a: true, b: false });
});
// Next local media should start out *not* always shown // Next local media should start out *not* always shown
await withLocalMedia( const vm2 = createLocalMedia(
rtcMembership, rtcMembership,
{}, {},
mockLocalParticipant({}), mockLocalParticipant({}),
mockMediaDevices({}), mockMediaDevices({}),
(vm) =>
withTestScheduler(({ expectObservable, schedule }) => {
schedule("-a|", { a: () => vm.setAlwaysShow(true) });
expectObservable(vm.alwaysShow$).toBe("ab", { a: false, b: true });
}),
); );
withTestScheduler(({ expectObservable, schedule }) => {
schedule("-a|", { a: () => vm2.setAlwaysShow(true) });
expectObservable(vm2.alwaysShow$).toBe("ab", { a: false, b: true });
});
}); });
test("switch cameras", async () => { test("switch cameras", async () => {
@@ -164,7 +161,7 @@ test("switch cameras", async () => {
const selectVideoInput = vi.fn(); const selectVideoInput = vi.fn();
await withLocalMedia( const vm = createLocalMedia(
rtcMembership, rtcMembership,
{}, {},
mockLocalParticipant({ mockLocalParticipant({
@@ -179,7 +176,8 @@ test("switch cameras", async () => {
select: selectVideoInput, select: selectVideoInput,
}, },
}), }),
async (vm) => { );
// Switch to back camera // Switch to back camera
getValue(vm.switchCamera$)!(); getValue(vm.switchCamera$)!();
expect(restartTrack).toHaveBeenCalledExactlyOnceWith({ expect(restartTrack).toHaveBeenCalledExactlyOnceWith({
@@ -200,6 +198,4 @@ test("switch cameras", async () => {
expect(selectVideoInput).toHaveBeenLastCalledWith("front camera"); expect(selectVideoInput).toHaveBeenLastCalledWith("front camera");
}); });
expect(deviceId).toBe("front camera"); expect(deviceId).toBe("front camera");
},
);
}); });

View File

@@ -12,7 +12,7 @@ import { axe } from "vitest-axe";
import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc"; import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc";
import { GridTile } from "./GridTile"; import { GridTile } from "./GridTile";
import { mockRtcMembership, withRemoteMedia } from "../utils/test"; import { mockRtcMembership, createRemoteMedia } from "../utils/test";
import { GridTileViewModel } from "../state/TileViewModel"; import { GridTileViewModel } from "../state/TileViewModel";
import { ReactionsSenderProvider } from "../reactions/useReactionsSender"; import { ReactionsSenderProvider } from "../reactions/useReactionsSender";
import type { CallViewModel } from "../state/CallViewModel"; import type { CallViewModel } from "../state/CallViewModel";
@@ -25,7 +25,7 @@ global.IntersectionObserver = class MockIntersectionObserver {
} as unknown as typeof IntersectionObserver; } as unknown as typeof IntersectionObserver;
test("GridTile is accessible", async () => { test("GridTile is accessible", async () => {
await withRemoteMedia( const vm = createRemoteMedia(
mockRtcMembership("@alice:example.org", "AAAA"), mockRtcMembership("@alice:example.org", "AAAA"),
{ {
rawDisplayName: "Alice", rawDisplayName: "Alice",
@@ -36,7 +36,8 @@ test("GridTile is accessible", async () => {
getTrackPublication: () => getTrackPublication: () =>
({}) as Partial<RemoteTrackPublication> as RemoteTrackPublication, ({}) as Partial<RemoteTrackPublication> as RemoteTrackPublication,
}, },
async (vm) => { );
const fakeRtcSession = { const fakeRtcSession = {
on: () => {}, on: () => {},
off: () => {}, off: () => {},
@@ -71,6 +72,4 @@ test("GridTile is accessible", async () => {
expect(await axe(container)).toHaveNoViolations(); expect(await axe(container)).toHaveNoViolations();
// Name should be visible // Name should be visible
screen.getByText("Alice"); screen.getByText("Alice");
},
);
}); });

View File

@@ -15,8 +15,8 @@ import {
mockLocalParticipant, mockLocalParticipant,
mockMediaDevices, mockMediaDevices,
mockRtcMembership, mockRtcMembership,
withLocalMedia, createLocalMedia,
withRemoteMedia, createRemoteMedia,
} from "../utils/test"; } from "../utils/test";
import { SpotlightTileViewModel } from "../state/TileViewModel"; import { SpotlightTileViewModel } from "../state/TileViewModel";
import { constant } from "../state/Behavior"; import { constant } from "../state/Behavior";
@@ -27,15 +27,16 @@ global.IntersectionObserver = class MockIntersectionObserver {
} as unknown as typeof IntersectionObserver; } as unknown as typeof IntersectionObserver;
test("SpotlightTile is accessible", async () => { test("SpotlightTile is accessible", async () => {
await withRemoteMedia( const vm1 = createRemoteMedia(
mockRtcMembership("@alice:example.org", "AAAA"), mockRtcMembership("@alice:example.org", "AAAA"),
{ {
rawDisplayName: "Alice", rawDisplayName: "Alice",
getMxcAvatarUrl: () => "mxc://adfsg", getMxcAvatarUrl: () => "mxc://adfsg",
}, },
{}, {},
async (vm1) => { );
await withLocalMedia(
const vm2 = createLocalMedia(
mockRtcMembership("@bob:example.org", "BBBB"), mockRtcMembership("@bob:example.org", "BBBB"),
{ {
rawDisplayName: "Bob", rawDisplayName: "Bob",
@@ -43,17 +44,13 @@ test("SpotlightTile is accessible", async () => {
}, },
mockLocalParticipant({}), mockLocalParticipant({}),
mockMediaDevices({}), mockMediaDevices({}),
async (vm2) => { );
const user = userEvent.setup(); const user = userEvent.setup();
const toggleExpanded = vi.fn(); const toggleExpanded = vi.fn();
const { container } = render( const { container } = render(
<SpotlightTile <SpotlightTile
vm={ vm={new SpotlightTileViewModel(constant([vm1, vm2]), constant(false))}
new SpotlightTileViewModel(
constant([vm1, vm2]),
constant(false),
)
}
targetWidth={300} targetWidth={300}
targetHeight={200} targetHeight={200}
expanded={false} expanded={false}
@@ -68,9 +65,7 @@ test("SpotlightTile is accessible", async () => {
// first page // first page
screen.getByText("Alice"); screen.getByText("Alice");
const aliceAvatar = screen.getByRole("img"); const aliceAvatar = screen.getByRole("img");
expect(screen.queryByRole("button", { name: "common.back" })).toBe( expect(screen.queryByRole("button", { name: "common.back" })).toBe(null);
null,
);
// Bob should be out of the spotlight, and therefore invisible // Bob should be out of the spotlight, and therefore invisible
expect(isInaccessible(screen.getByText("Bob"))).toBe(true); expect(isInaccessible(screen.getByText("Bob"))).toBe(true);
// Now navigate to Bob // Now navigate to Bob
@@ -81,8 +76,4 @@ test("SpotlightTile is accessible", async () => {
// Can toggle whether the tile is expanded // Can toggle whether the tile is expanded
await user.click(screen.getByRole("button", { name: "Expand" })); await user.click(screen.getByRole("button", { name: "Expand" }));
expect(toggleExpanded).toHaveBeenCalled(); expect(toggleExpanded).toHaveBeenCalled();
},
);
},
);
}); });

View File

@@ -268,14 +268,13 @@ export function mockLocalParticipant(
} as Partial<LocalParticipant> as LocalParticipant; } as Partial<LocalParticipant> as LocalParticipant;
} }
export async function withLocalMedia( export function createLocalMedia(
localRtcMember: CallMembership, localRtcMember: CallMembership,
roomMember: Partial<RoomMember>, roomMember: Partial<RoomMember>,
localParticipant: LocalParticipant, localParticipant: LocalParticipant,
mediaDevices: MediaDevices, mediaDevices: MediaDevices,
continuation: (vm: LocalUserMediaViewModel) => void | Promise<void>, ): LocalUserMediaViewModel {
): Promise<void> { return new LocalUserMediaViewModel(
const vm = new LocalUserMediaViewModel(
testScope(), testScope(),
"local", "local",
mockMatrixRoomMember(localRtcMember, roomMember), mockMatrixRoomMember(localRtcMember, roomMember),
@@ -290,8 +289,6 @@ export async function withLocalMedia(
constant(null), constant(null),
constant(null), constant(null),
); );
// TODO: Simplify to just return the view model
await continuation(vm);
} }
export function mockRemoteParticipant( export function mockRemoteParticipant(
@@ -307,14 +304,13 @@ export function mockRemoteParticipant(
} as RemoteParticipant; } as RemoteParticipant;
} }
export async function withRemoteMedia( export function createRemoteMedia(
localRtcMember: CallMembership, localRtcMember: CallMembership,
roomMember: Partial<RoomMember>, roomMember: Partial<RoomMember>,
participant: Partial<RemoteParticipant>, participant: Partial<RemoteParticipant>,
continuation: (vm: RemoteUserMediaViewModel) => void | Promise<void>, ): RemoteUserMediaViewModel {
): Promise<void> {
const remoteParticipant = mockRemoteParticipant(participant); const remoteParticipant = mockRemoteParticipant(participant);
const vm = new RemoteUserMediaViewModel( return new RemoteUserMediaViewModel(
testScope(), testScope(),
"remote", "remote",
mockMatrixRoomMember(localRtcMember, roomMember), mockMatrixRoomMember(localRtcMember, roomMember),
@@ -329,8 +325,6 @@ export async function withRemoteMedia(
constant(null), constant(null),
constant(null), constant(null),
); );
// TODO: Simplify to just return the view model
await continuation(vm);
} }
export function mockConfig(config: Partial<ResolvedConfigOptions> = {}): void { export function mockConfig(config: Partial<ResolvedConfigOptions> = {}): void {