diff --git a/src/state/media/MediaViewModel.test.ts b/src/state/media/MediaViewModel.test.ts index 71475b8c..f64dd3ee 100644 --- a/src/state/media/MediaViewModel.test.ts +++ b/src/state/media/MediaViewModel.test.ts @@ -9,6 +9,7 @@ import { expect, onTestFinished, test, vi } from "vitest"; import { type LocalTrackPublication, LocalVideoTrack, + Track, TrackEvent, } from "livekit-client"; import { waitFor } from "@testing-library/dom"; @@ -21,6 +22,7 @@ import { mockRemoteMedia, withTestScheduler, mockRemoteParticipant, + mockRemoteScreenShare, } from "../../utils/test"; import { constant } from "../Behavior"; @@ -91,6 +93,73 @@ test("control a participant's volume", () => { }); }); +test("control a participant's screen share volume", () => { + const setVolumeSpy = vi.fn(); + const vm = mockRemoteScreenShare( + rtcMembership, + {}, + mockRemoteParticipant({ setVolume: setVolumeSpy }), + ); + withTestScheduler(({ expectObservable, schedule }) => { + schedule("-ab---c---d|", { + a() { + // Try muting by toggling + vm.togglePlaybackMuted(); + expect(setVolumeSpy).toHaveBeenLastCalledWith( + 0, + Track.Source.ScreenShareAudio, + ); + }, + b() { + // Try unmuting by dragging the slider back up + vm.adjustPlaybackVolume(0.6); + vm.adjustPlaybackVolume(0.8); + vm.commitPlaybackVolume(); + expect(setVolumeSpy).toHaveBeenCalledWith( + 0.6, + Track.Source.ScreenShareAudio, + ); + expect(setVolumeSpy).toHaveBeenLastCalledWith( + 0.8, + Track.Source.ScreenShareAudio, + ); + }, + c() { + // Try muting by dragging the slider back down + vm.adjustPlaybackVolume(0.2); + vm.adjustPlaybackVolume(0); + vm.commitPlaybackVolume(); + expect(setVolumeSpy).toHaveBeenCalledWith( + 0.2, + Track.Source.ScreenShareAudio, + ); + expect(setVolumeSpy).toHaveBeenLastCalledWith( + 0, + Track.Source.ScreenShareAudio, + ); + }, + d() { + // Try unmuting by toggling + vm.togglePlaybackMuted(); + // The volume should return to the last non-zero committed volume + expect(setVolumeSpy).toHaveBeenLastCalledWith( + 0.8, + Track.Source.ScreenShareAudio, + ); + }, + }); + expectObservable(vm.playbackVolume$).toBe("ab(cd)(ef)g", { + a: 1, + b: 0, + c: 0.6, + d: 0.8, + e: 0.2, + f: 0, + g: 0.8, + }); + }); +}); + test("toggle fit/contain for a participant's video", () => { const vm = mockRemoteMedia(rtcMembership, {}, mockRemoteParticipant({})); withTestScheduler(({ expectObservable, schedule }) => { diff --git a/src/utils/test.ts b/src/utils/test.ts index c1e67927..b99bfa88 100644 --- a/src/utils/test.ts +++ b/src/utils/test.ts @@ -70,6 +70,10 @@ import { createRemoteUserMedia, type RemoteUserMediaViewModel, } from "../state/media/RemoteUserMediaViewModel"; +import { + createRemoteScreenShare, + type RemoteScreenShareViewModel, +} from "../state/media/RemoteScreenShareViewModel"; export function withFakeTimers(continuation: () => void): void { vi.useFakeTimers(); @@ -393,6 +397,31 @@ export function mockRemoteMedia( }); } +export function mockRemoteScreenShare( + rtcMember: CallMembership, + roomMember: Partial, + participant: RemoteParticipant | null, + livekitRoom: LivekitRoom | undefined = mockLivekitRoom( + {}, + { + remoteParticipants$: of(participant ? [participant] : []), + }, + ), +): RemoteScreenShareViewModel { + const member = mockMatrixRoomMember(rtcMember, roomMember); + return createRemoteScreenShare(testScope(), { + id: "screenshare", + userId: member.userId, + participant$: constant(participant), + encryptionSystem: { kind: E2eeType.PER_PARTICIPANT }, + livekitRoom$: constant(livekitRoom), + focusUrl$: constant("https://rtc-example.org"), + pretendToBeDisconnected$: constant(false), + displayName$: constant(member.rawDisplayName ?? "nodisplayname"), + mxcAvatarUrl$: constant(member.getMxcAvatarUrl()), + }); +} + export function mockConfig( config: Partial = {}, ): MockInstance<() => ResolvedConfigOptions> {