Improve live voice broadcast detection by testing if the started event has been redacted (#9780)
This commit is contained in:
parent
fbc3228143
commit
b81582d045
15 changed files with 365 additions and 83 deletions
|
@ -313,3 +313,13 @@ export const concat = (...arrays: Uint8Array[]): Uint8Array => {
|
||||||
return concatenated;
|
return concatenated;
|
||||||
}, new Uint8Array(0));
|
}, new Uint8Array(0));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async version of Array.every.
|
||||||
|
*/
|
||||||
|
export async function asyncEvery<T>(values: T[], predicate: (value: T) => Promise<boolean>): Promise<boolean> {
|
||||||
|
for (const value of values) {
|
||||||
|
if (!(await predicate(value))) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -14,18 +14,34 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useContext, useEffect, useMemo, useState } from "react";
|
||||||
import { Room, RoomStateEvent } from "matrix-js-sdk/src/matrix";
|
import { Room, RoomStateEvent } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { hasRoomLiveVoiceBroadcast } from "../utils/hasRoomLiveVoiceBroadcast";
|
import { hasRoomLiveVoiceBroadcast } from "../utils/hasRoomLiveVoiceBroadcast";
|
||||||
import { useTypedEventEmitter } from "../../hooks/useEventEmitter";
|
import { useTypedEventEmitter } from "../../hooks/useEventEmitter";
|
||||||
|
import { SDKContext } from "../../contexts/SDKContext";
|
||||||
|
|
||||||
export const useHasRoomLiveVoiceBroadcast = (room: Room) => {
|
export const useHasRoomLiveVoiceBroadcast = (room: Room) => {
|
||||||
const [hasLiveVoiceBroadcast, setHasLiveVoiceBroadcast] = useState(hasRoomLiveVoiceBroadcast(room).hasBroadcast);
|
const sdkContext = useContext(SDKContext);
|
||||||
|
const [hasLiveVoiceBroadcast, setHasLiveVoiceBroadcast] = useState(false);
|
||||||
|
|
||||||
useTypedEventEmitter(room.currentState, RoomStateEvent.Update, () => {
|
const update = useMemo(() => {
|
||||||
setHasLiveVoiceBroadcast(hasRoomLiveVoiceBroadcast(room).hasBroadcast);
|
return sdkContext.client
|
||||||
});
|
? () => {
|
||||||
|
hasRoomLiveVoiceBroadcast(sdkContext.client!, room).then(
|
||||||
|
({ hasBroadcast }) => {
|
||||||
|
setHasLiveVoiceBroadcast(hasBroadcast);
|
||||||
|
},
|
||||||
|
() => {}, // no update on error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
: () => {}; // noop without client
|
||||||
|
}, [room, sdkContext, setHasLiveVoiceBroadcast]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
update();
|
||||||
|
}, [update]);
|
||||||
|
|
||||||
|
useTypedEventEmitter(room.currentState, RoomStateEvent.Update, () => update());
|
||||||
return hasLiveVoiceBroadcast;
|
return hasLiveVoiceBroadcast;
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,6 +49,7 @@ export * from "./utils/getChunkLength";
|
||||||
export * from "./utils/getMaxBroadcastLength";
|
export * from "./utils/getMaxBroadcastLength";
|
||||||
export * from "./utils/hasRoomLiveVoiceBroadcast";
|
export * from "./utils/hasRoomLiveVoiceBroadcast";
|
||||||
export * from "./utils/findRoomLiveVoiceBroadcastFromUserAndDevice";
|
export * from "./utils/findRoomLiveVoiceBroadcastFromUserAndDevice";
|
||||||
|
export * from "./utils/retrieveStartedInfoEvent";
|
||||||
export * from "./utils/shouldDisplayAsVoiceBroadcastRecordingTile";
|
export * from "./utils/shouldDisplayAsVoiceBroadcastRecordingTile";
|
||||||
export * from "./utils/shouldDisplayAsVoiceBroadcastTile";
|
export * from "./utils/shouldDisplayAsVoiceBroadcastTile";
|
||||||
export * from "./utils/shouldDisplayAsVoiceBroadcastStoppedText";
|
export * from "./utils/shouldDisplayAsVoiceBroadcastStoppedText";
|
||||||
|
|
|
@ -67,11 +67,11 @@ const showOthersAlreadyRecordingDialog = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const checkVoiceBroadcastPreConditions = (
|
export const checkVoiceBroadcastPreConditions = async (
|
||||||
room: Room,
|
room: Room,
|
||||||
client: MatrixClient,
|
client: MatrixClient,
|
||||||
recordingsStore: VoiceBroadcastRecordingsStore,
|
recordingsStore: VoiceBroadcastRecordingsStore,
|
||||||
): boolean => {
|
): Promise<boolean> => {
|
||||||
if (recordingsStore.getCurrent()) {
|
if (recordingsStore.getCurrent()) {
|
||||||
showAlreadyRecordingDialog();
|
showAlreadyRecordingDialog();
|
||||||
return false;
|
return false;
|
||||||
|
@ -86,7 +86,7 @@ export const checkVoiceBroadcastPreConditions = (
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { hasBroadcast, startedByUser } = hasRoomLiveVoiceBroadcast(room, currentUserId);
|
const { hasBroadcast, startedByUser } = await hasRoomLiveVoiceBroadcast(client, room, currentUserId);
|
||||||
|
|
||||||
if (hasBroadcast && startedByUser) {
|
if (hasBroadcast && startedByUser) {
|
||||||
showAlreadyRecordingDialog();
|
showAlreadyRecordingDialog();
|
||||||
|
|
|
@ -34,12 +34,12 @@ import {
|
||||||
* @param {VoiceBroadcastPlaybacksStore} voiceBroadcastPlaybacksStore
|
* @param {VoiceBroadcastPlaybacksStore} voiceBroadcastPlaybacksStore
|
||||||
* @param {VoiceBroadcastRecordingsStore} voiceBroadcastRecordingsStore
|
* @param {VoiceBroadcastRecordingsStore} voiceBroadcastRecordingsStore
|
||||||
*/
|
*/
|
||||||
export const doMaybeSetCurrentVoiceBroadcastPlayback = (
|
export const doMaybeSetCurrentVoiceBroadcastPlayback = async (
|
||||||
room: Room,
|
room: Room,
|
||||||
client: MatrixClient,
|
client: MatrixClient,
|
||||||
voiceBroadcastPlaybacksStore: VoiceBroadcastPlaybacksStore,
|
voiceBroadcastPlaybacksStore: VoiceBroadcastPlaybacksStore,
|
||||||
voiceBroadcastRecordingsStore: VoiceBroadcastRecordingsStore,
|
voiceBroadcastRecordingsStore: VoiceBroadcastRecordingsStore,
|
||||||
): void => {
|
): Promise<void> => {
|
||||||
// do not disturb the current recording
|
// do not disturb the current recording
|
||||||
if (voiceBroadcastRecordingsStore.hasCurrent()) return;
|
if (voiceBroadcastRecordingsStore.hasCurrent()) return;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ export const doMaybeSetCurrentVoiceBroadcastPlayback = (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { infoEvent } = hasRoomLiveVoiceBroadcast(room);
|
const { infoEvent } = await hasRoomLiveVoiceBroadcast(client, room);
|
||||||
|
|
||||||
if (infoEvent) {
|
if (infoEvent) {
|
||||||
// live broadcast in the room + no recording + not listening yet: set the current broadcast
|
// live broadcast in the room + no recording + not listening yet: set the current broadcast
|
||||||
|
|
|
@ -14,9 +14,10 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { VoiceBroadcastInfoEventType, VoiceBroadcastInfoState } from "..";
|
import { retrieveStartedInfoEvent, VoiceBroadcastInfoEventType, VoiceBroadcastInfoState } from "..";
|
||||||
|
import { asyncEvery } from "../../utils/arrays";
|
||||||
|
|
||||||
interface Result {
|
interface Result {
|
||||||
// whether there is a live broadcast in the room
|
// whether there is a live broadcast in the room
|
||||||
|
@ -27,22 +28,26 @@ interface Result {
|
||||||
startedByUser: boolean;
|
startedByUser: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hasRoomLiveVoiceBroadcast = (room: Room, userId?: string): Result => {
|
export const hasRoomLiveVoiceBroadcast = async (client: MatrixClient, room: Room, userId?: string): Promise<Result> => {
|
||||||
let hasBroadcast = false;
|
let hasBroadcast = false;
|
||||||
let startedByUser = false;
|
let startedByUser = false;
|
||||||
let infoEvent: MatrixEvent | null = null;
|
let infoEvent: MatrixEvent | null = null;
|
||||||
|
|
||||||
const stateEvents = room.currentState.getStateEvents(VoiceBroadcastInfoEventType);
|
const stateEvents = room.currentState.getStateEvents(VoiceBroadcastInfoEventType);
|
||||||
stateEvents.every((event: MatrixEvent) => {
|
await asyncEvery(stateEvents, async (event: MatrixEvent) => {
|
||||||
const state = event.getContent()?.state;
|
const state = event.getContent()?.state;
|
||||||
|
|
||||||
if (state && state !== VoiceBroadcastInfoState.Stopped) {
|
if (state && state !== VoiceBroadcastInfoState.Stopped) {
|
||||||
|
const startEvent = await retrieveStartedInfoEvent(event, client);
|
||||||
|
|
||||||
|
// skip if started voice broadcast event is redacted
|
||||||
|
if (startEvent?.isRedacted()) return true;
|
||||||
|
|
||||||
hasBroadcast = true;
|
hasBroadcast = true;
|
||||||
infoEvent = event;
|
infoEvent = startEvent;
|
||||||
|
|
||||||
// state key = sender's MXID
|
// state key = sender's MXID
|
||||||
if (event.getStateKey() === userId) {
|
if (event.getStateKey() === userId) {
|
||||||
infoEvent = event;
|
|
||||||
startedByUser = true;
|
startedByUser = true;
|
||||||
// break here, because more than true / true is not possible
|
// break here, because more than true / true is not possible
|
||||||
return false;
|
return false;
|
||||||
|
|
45
src/voice-broadcast/utils/retrieveStartedInfoEvent.ts
Normal file
45
src/voice-broadcast/utils/retrieveStartedInfoEvent.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
|
import { VoiceBroadcastInfoState } from "..";
|
||||||
|
|
||||||
|
export const retrieveStartedInfoEvent = async (
|
||||||
|
event: MatrixEvent,
|
||||||
|
client: MatrixClient,
|
||||||
|
): Promise<MatrixEvent | null> => {
|
||||||
|
// started event passed as argument
|
||||||
|
if (event.getContent()?.state === VoiceBroadcastInfoState.Started) return event;
|
||||||
|
|
||||||
|
const relatedEventId = event.getRelation()?.event_id;
|
||||||
|
|
||||||
|
// no related event
|
||||||
|
if (!relatedEventId) return null;
|
||||||
|
|
||||||
|
const roomId = event.getRoomId() || "";
|
||||||
|
const relatedEventFromRoom = client.getRoom(roomId)?.findEventById(relatedEventId);
|
||||||
|
|
||||||
|
// event found
|
||||||
|
if (relatedEventFromRoom) return relatedEventFromRoom;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const relatedEventData = await client.fetchRoomEvent(roomId, relatedEventId);
|
||||||
|
return new MatrixEvent(relatedEventData);
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
|
@ -38,7 +38,7 @@ const startBroadcast = async (
|
||||||
const userId = client.getUserId();
|
const userId = client.getUserId();
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
reject("unable to start voice broadcast if current user is unkonwn");
|
reject("unable to start voice broadcast if current user is unknown");
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ export const startNewVoiceBroadcastRecording = async (
|
||||||
playbacksStore: VoiceBroadcastPlaybacksStore,
|
playbacksStore: VoiceBroadcastPlaybacksStore,
|
||||||
recordingsStore: VoiceBroadcastRecordingsStore,
|
recordingsStore: VoiceBroadcastRecordingsStore,
|
||||||
): Promise<VoiceBroadcastRecording | null> => {
|
): Promise<VoiceBroadcastRecording | null> => {
|
||||||
if (!checkVoiceBroadcastPreConditions(room, client, recordingsStore)) {
|
if (!(await checkVoiceBroadcastPreConditions(room, client, recordingsStore))) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,17 +32,19 @@ import {
|
||||||
useMockedCalls,
|
useMockedCalls,
|
||||||
setupAsyncStoreWithClient,
|
setupAsyncStoreWithClient,
|
||||||
filterConsole,
|
filterConsole,
|
||||||
|
flushPromises,
|
||||||
} from "../../../test-utils";
|
} from "../../../test-utils";
|
||||||
import { CallStore } from "../../../../src/stores/CallStore";
|
import { CallStore } from "../../../../src/stores/CallStore";
|
||||||
import RoomTile from "../../../../src/components/views/rooms/RoomTile";
|
import RoomTile from "../../../../src/components/views/rooms/RoomTile";
|
||||||
import { DefaultTagID } from "../../../../src/stores/room-list/models";
|
import { DefaultTagID } from "../../../../src/stores/room-list/models";
|
||||||
import DMRoomMap from "../../../../src/utils/DMRoomMap";
|
import DMRoomMap from "../../../../src/utils/DMRoomMap";
|
||||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
|
||||||
import PlatformPeg from "../../../../src/PlatformPeg";
|
import PlatformPeg from "../../../../src/PlatformPeg";
|
||||||
import BasePlatform from "../../../../src/BasePlatform";
|
import BasePlatform from "../../../../src/BasePlatform";
|
||||||
import { WidgetMessagingStore } from "../../../../src/stores/widgets/WidgetMessagingStore";
|
import { WidgetMessagingStore } from "../../../../src/stores/widgets/WidgetMessagingStore";
|
||||||
import { VoiceBroadcastInfoState } from "../../../../src/voice-broadcast";
|
import { VoiceBroadcastInfoState } from "../../../../src/voice-broadcast";
|
||||||
import { mkVoiceBroadcastInfoStateEvent } from "../../../voice-broadcast/utils/test-utils";
|
import { mkVoiceBroadcastInfoStateEvent } from "../../../voice-broadcast/utils/test-utils";
|
||||||
|
import { TestSdkContext } from "../../../TestSdkContext";
|
||||||
|
import { SDKContext } from "../../../../src/contexts/SDKContext";
|
||||||
|
|
||||||
describe("RoomTile", () => {
|
describe("RoomTile", () => {
|
||||||
jest.spyOn(PlatformPeg, "get").mockReturnValue({
|
jest.spyOn(PlatformPeg, "get").mockReturnValue({
|
||||||
|
@ -50,22 +52,25 @@ describe("RoomTile", () => {
|
||||||
} as unknown as BasePlatform);
|
} as unknown as BasePlatform);
|
||||||
useMockedCalls();
|
useMockedCalls();
|
||||||
|
|
||||||
const setUpVoiceBroadcast = (state: VoiceBroadcastInfoState): void => {
|
const setUpVoiceBroadcast = async (state: VoiceBroadcastInfoState): Promise<void> => {
|
||||||
voiceBroadcastInfoEvent = mkVoiceBroadcastInfoStateEvent(
|
voiceBroadcastInfoEvent = mkVoiceBroadcastInfoStateEvent(
|
||||||
room.roomId,
|
room.roomId,
|
||||||
state,
|
state,
|
||||||
client.getUserId(),
|
client.getSafeUserId(),
|
||||||
client.getDeviceId(),
|
client.getDeviceId()!,
|
||||||
);
|
);
|
||||||
|
|
||||||
act(() => {
|
await act(async () => {
|
||||||
room.currentState.setStateEvents([voiceBroadcastInfoEvent]);
|
room.currentState.setStateEvents([voiceBroadcastInfoEvent]);
|
||||||
|
await flushPromises();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderRoomTile = (): void => {
|
const renderRoomTile = (): void => {
|
||||||
renderResult = render(
|
renderResult = render(
|
||||||
<RoomTile room={room} showMessagePreview={false} isMinimized={false} tag={DefaultTagID.Untagged} />,
|
<SDKContext.Provider value={sdkContext}>
|
||||||
|
<RoomTile room={room} showMessagePreview={false} isMinimized={false} tag={DefaultTagID.Untagged} />
|
||||||
|
</SDKContext.Provider>,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,15 +79,18 @@ describe("RoomTile", () => {
|
||||||
let voiceBroadcastInfoEvent: MatrixEvent;
|
let voiceBroadcastInfoEvent: MatrixEvent;
|
||||||
let room: Room;
|
let room: Room;
|
||||||
let renderResult: RenderResult;
|
let renderResult: RenderResult;
|
||||||
|
let sdkContext: TestSdkContext;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
sdkContext = new TestSdkContext();
|
||||||
|
|
||||||
restoreConsole = filterConsole(
|
restoreConsole = filterConsole(
|
||||||
// irrelevant for this test
|
// irrelevant for this test
|
||||||
"Room !1:example.org does not have an m.room.create event",
|
"Room !1:example.org does not have an m.room.create event",
|
||||||
);
|
);
|
||||||
|
|
||||||
stubClient();
|
client = mocked(stubClient());
|
||||||
client = mocked(MatrixClientPeg.get());
|
sdkContext.client = client;
|
||||||
DMRoomMap.makeShared();
|
DMRoomMap.makeShared();
|
||||||
|
|
||||||
room = new Room("!1:example.org", client, "@alice:example.org", {
|
room = new Room("!1:example.org", client, "@alice:example.org", {
|
||||||
|
@ -136,7 +144,7 @@ describe("RoomTile", () => {
|
||||||
|
|
||||||
// Insert an await point in the connection method so we can inspect
|
// Insert an await point in the connection method so we can inspect
|
||||||
// the intermediate connecting state
|
// the intermediate connecting state
|
||||||
let completeConnection: () => void;
|
let completeConnection: () => void = () => {};
|
||||||
const connectionCompleted = new Promise<void>((resolve) => (completeConnection = resolve));
|
const connectionCompleted = new Promise<void>((resolve) => (completeConnection = resolve));
|
||||||
jest.spyOn(call, "performConnection").mockReturnValue(connectionCompleted);
|
jest.spyOn(call, "performConnection").mockReturnValue(connectionCompleted);
|
||||||
|
|
||||||
|
@ -180,8 +188,8 @@ describe("RoomTile", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("and a live broadcast starts", () => {
|
describe("and a live broadcast starts", () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
setUpVoiceBroadcast(VoiceBroadcastInfoState.Started);
|
await setUpVoiceBroadcast(VoiceBroadcastInfoState.Started);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should still render the call subtitle", () => {
|
it("should still render the call subtitle", () => {
|
||||||
|
@ -192,8 +200,8 @@ describe("RoomTile", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when a live voice broadcast starts", () => {
|
describe("when a live voice broadcast starts", () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
setUpVoiceBroadcast(VoiceBroadcastInfoState.Started);
|
await setUpVoiceBroadcast(VoiceBroadcastInfoState.Started);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render the »Live« subtitle", () => {
|
it("should render the »Live« subtitle", () => {
|
||||||
|
@ -201,16 +209,17 @@ describe("RoomTile", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("and the broadcast stops", () => {
|
describe("and the broadcast stops", () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
const stopEvent = mkVoiceBroadcastInfoStateEvent(
|
const stopEvent = mkVoiceBroadcastInfoStateEvent(
|
||||||
room.roomId,
|
room.roomId,
|
||||||
VoiceBroadcastInfoState.Stopped,
|
VoiceBroadcastInfoState.Stopped,
|
||||||
client.getUserId(),
|
client.getSafeUserId(),
|
||||||
client.getDeviceId(),
|
client.getDeviceId()!,
|
||||||
voiceBroadcastInfoEvent,
|
voiceBroadcastInfoEvent,
|
||||||
);
|
);
|
||||||
act(() => {
|
await act(async () => {
|
||||||
room.currentState.setStateEvents([stopEvent]);
|
room.currentState.setStateEvents([stopEvent]);
|
||||||
|
await flushPromises();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ import {
|
||||||
wrapInMatrixClientContext,
|
wrapInMatrixClientContext,
|
||||||
wrapInSdkContext,
|
wrapInSdkContext,
|
||||||
mkRoomCreateEvent,
|
mkRoomCreateEvent,
|
||||||
|
flushPromises,
|
||||||
} from "../../../test-utils";
|
} from "../../../test-utils";
|
||||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||||
import { CallStore } from "../../../../src/stores/CallStore";
|
import { CallStore } from "../../../../src/stores/CallStore";
|
||||||
|
@ -70,6 +71,12 @@ describe("PipView", () => {
|
||||||
let voiceBroadcastPreRecordingStore: VoiceBroadcastPreRecordingStore;
|
let voiceBroadcastPreRecordingStore: VoiceBroadcastPreRecordingStore;
|
||||||
let voiceBroadcastPlaybacksStore: VoiceBroadcastPlaybacksStore;
|
let voiceBroadcastPlaybacksStore: VoiceBroadcastPlaybacksStore;
|
||||||
|
|
||||||
|
const actFlushPromises = async () => {
|
||||||
|
await act(async () => {
|
||||||
|
await flushPromises();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
stubClient();
|
stubClient();
|
||||||
client = mocked(MatrixClientPeg.get());
|
client = mocked(MatrixClientPeg.get());
|
||||||
|
@ -264,10 +271,11 @@ describe("PipView", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when there is a voice broadcast recording and pre-recording", () => {
|
describe("when there is a voice broadcast recording and pre-recording", () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
setUpVoiceBroadcastPreRecording();
|
setUpVoiceBroadcastPreRecording();
|
||||||
setUpVoiceBroadcastRecording();
|
setUpVoiceBroadcastRecording();
|
||||||
renderPip();
|
renderPip();
|
||||||
|
await actFlushPromises();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render the voice broadcast recording PiP", () => {
|
it("should render the voice broadcast recording PiP", () => {
|
||||||
|
@ -277,10 +285,11 @@ describe("PipView", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when there is a voice broadcast playback and pre-recording", () => {
|
describe("when there is a voice broadcast playback and pre-recording", () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
mkVoiceBroadcast(room);
|
mkVoiceBroadcast(room);
|
||||||
setUpVoiceBroadcastPreRecording();
|
setUpVoiceBroadcastPreRecording();
|
||||||
renderPip();
|
renderPip();
|
||||||
|
await actFlushPromises();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render the voice broadcast pre-recording PiP", () => {
|
it("should render the voice broadcast pre-recording PiP", () => {
|
||||||
|
@ -290,9 +299,10 @@ describe("PipView", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when there is a voice broadcast pre-recording", () => {
|
describe("when there is a voice broadcast pre-recording", () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
setUpVoiceBroadcastPreRecording();
|
setUpVoiceBroadcastPreRecording();
|
||||||
renderPip();
|
renderPip();
|
||||||
|
await actFlushPromises();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render the voice broadcast pre-recording PiP", () => {
|
it("should render the voice broadcast pre-recording PiP", () => {
|
||||||
|
@ -306,6 +316,10 @@ describe("PipView", () => {
|
||||||
setUpRoomViewStore();
|
setUpRoomViewStore();
|
||||||
viewRoom(room.roomId);
|
viewRoom(room.roomId);
|
||||||
mkVoiceBroadcast(room);
|
mkVoiceBroadcast(room);
|
||||||
|
await actFlushPromises();
|
||||||
|
|
||||||
|
expect(voiceBroadcastPlaybacksStore.getCurrent()).toBeTruthy();
|
||||||
|
|
||||||
await voiceBroadcastPlaybacksStore.getCurrent()?.start();
|
await voiceBroadcastPlaybacksStore.getCurrent()?.start();
|
||||||
viewRoom(room2.roomId);
|
viewRoom(room2.roomId);
|
||||||
renderPip();
|
renderPip();
|
||||||
|
@ -322,11 +336,12 @@ describe("PipView", () => {
|
||||||
describe("when viewing a room with a live voice broadcast", () => {
|
describe("when viewing a room with a live voice broadcast", () => {
|
||||||
let startEvent!: MatrixEvent;
|
let startEvent!: MatrixEvent;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
setUpRoomViewStore();
|
setUpRoomViewStore();
|
||||||
viewRoom(room.roomId);
|
viewRoom(room.roomId);
|
||||||
startEvent = mkVoiceBroadcast(room);
|
startEvent = mkVoiceBroadcast(room);
|
||||||
renderPip();
|
renderPip();
|
||||||
|
await actFlushPromises();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render the voice broadcast playback pip", () => {
|
it("should render the voice broadcast playback pip", () => {
|
||||||
|
@ -335,15 +350,16 @@ describe("PipView", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("and the broadcast stops", () => {
|
describe("and the broadcast stops", () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
act(() => {
|
const stopEvent = mkVoiceBroadcastInfoStateEvent(
|
||||||
const stopEvent = mkVoiceBroadcastInfoStateEvent(
|
room.roomId,
|
||||||
room.roomId,
|
VoiceBroadcastInfoState.Stopped,
|
||||||
VoiceBroadcastInfoState.Stopped,
|
alice.userId,
|
||||||
alice.userId,
|
client.getDeviceId() || "",
|
||||||
client.getDeviceId() || "",
|
startEvent,
|
||||||
startEvent,
|
);
|
||||||
);
|
|
||||||
|
await act(async () => {
|
||||||
room.currentState.setStateEvents([stopEvent]);
|
room.currentState.setStateEvents([stopEvent]);
|
||||||
defaultDispatcher.dispatch<IRoomStateEventsActionPayload>(
|
defaultDispatcher.dispatch<IRoomStateEventsActionPayload>(
|
||||||
{
|
{
|
||||||
|
@ -354,6 +370,7 @@ describe("PipView", () => {
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
await flushPromises();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -364,9 +381,10 @@ describe("PipView", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("and leaving the room", () => {
|
describe("and leaving the room", () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
act(() => {
|
await act(async () => {
|
||||||
viewRoom(room2.roomId);
|
viewRoom(room2.roomId);
|
||||||
|
await flushPromises();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -186,7 +186,7 @@ export function createTestClient(): MatrixClient {
|
||||||
hasLazyLoadMembersEnabled: jest.fn().mockReturnValue(false),
|
hasLazyLoadMembersEnabled: jest.fn().mockReturnValue(false),
|
||||||
isInitialSyncComplete: jest.fn().mockReturnValue(true),
|
isInitialSyncComplete: jest.fn().mockReturnValue(true),
|
||||||
downloadKeys: jest.fn(),
|
downloadKeys: jest.fn(),
|
||||||
fetchRoomEvent: jest.fn(),
|
fetchRoomEvent: jest.fn().mockRejectedValue({}),
|
||||||
makeTxnId: jest.fn().mockImplementation(() => `t${txnId++}`),
|
makeTxnId: jest.fn().mockImplementation(() => `t${txnId++}`),
|
||||||
sendToDevice: jest.fn().mockResolvedValue(undefined),
|
sendToDevice: jest.fn().mockResolvedValue(undefined),
|
||||||
queueToDevice: jest.fn().mockResolvedValue(undefined),
|
queueToDevice: jest.fn().mockResolvedValue(undefined),
|
||||||
|
|
|
@ -29,6 +29,7 @@ import {
|
||||||
ArrayUtil,
|
ArrayUtil,
|
||||||
GroupedArray,
|
GroupedArray,
|
||||||
concat,
|
concat,
|
||||||
|
asyncEvery,
|
||||||
} from "../../src/utils/arrays";
|
} from "../../src/utils/arrays";
|
||||||
|
|
||||||
type TestParams = { input: number[]; output: number[] };
|
type TestParams = { input: number[]; output: number[] };
|
||||||
|
@ -413,4 +414,34 @@ describe("arrays", () => {
|
||||||
expect(concat(array1(), array2(), array3())).toEqual(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9]));
|
expect(concat(array1(), array2(), array3())).toEqual(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("asyncEvery", () => {
|
||||||
|
it("when called with an empty array, it should return true", async () => {
|
||||||
|
expect(await asyncEvery([], jest.fn().mockResolvedValue(true))).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when called with some items and the predicate resolves to true for all of them, it should return true", async () => {
|
||||||
|
const predicate = jest.fn().mockResolvedValue(true);
|
||||||
|
expect(await asyncEvery([1, 2, 3], predicate)).toBe(true);
|
||||||
|
expect(predicate).toHaveBeenCalledTimes(3);
|
||||||
|
expect(predicate).toHaveBeenCalledWith(1);
|
||||||
|
expect(predicate).toHaveBeenCalledWith(2);
|
||||||
|
expect(predicate).toHaveBeenCalledWith(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when called with some items and the predicate resolves to false for all of them, it should return false", async () => {
|
||||||
|
const predicate = jest.fn().mockResolvedValue(false);
|
||||||
|
expect(await asyncEvery([1, 2, 3], predicate)).toBe(false);
|
||||||
|
expect(predicate).toHaveBeenCalledTimes(1);
|
||||||
|
expect(predicate).toHaveBeenCalledWith(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when called with some items and the predicate resolves to false for one of them, it should return false", async () => {
|
||||||
|
const predicate = jest.fn().mockResolvedValueOnce(true).mockResolvedValueOnce(false);
|
||||||
|
expect(await asyncEvery([1, 2, 3], predicate)).toBe(false);
|
||||||
|
expect(predicate).toHaveBeenCalledTimes(2);
|
||||||
|
expect(predicate).toHaveBeenCalledWith(1);
|
||||||
|
expect(predicate).toHaveBeenCalledWith(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { mocked } from "jest-mock";
|
||||||
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -26,20 +27,28 @@ import { mkVoiceBroadcastInfoStateEvent } from "./test-utils";
|
||||||
|
|
||||||
describe("hasRoomLiveVoiceBroadcast", () => {
|
describe("hasRoomLiveVoiceBroadcast", () => {
|
||||||
const otherUserId = "@other:example.com";
|
const otherUserId = "@other:example.com";
|
||||||
|
const otherDeviceId = "ASD123";
|
||||||
const roomId = "!room:example.com";
|
const roomId = "!room:example.com";
|
||||||
let client: MatrixClient;
|
let client: MatrixClient;
|
||||||
let room: Room;
|
let room: Room;
|
||||||
let expectedEvent: MatrixEvent | null = null;
|
let expectedEvent: MatrixEvent | null = null;
|
||||||
|
|
||||||
const addVoiceBroadcastInfoEvent = (state: VoiceBroadcastInfoState, sender: string): MatrixEvent => {
|
const addVoiceBroadcastInfoEvent = (
|
||||||
const infoEvent = mkVoiceBroadcastInfoStateEvent(room.roomId, state, sender, "ASD123");
|
state: VoiceBroadcastInfoState,
|
||||||
|
userId: string,
|
||||||
|
deviceId: string,
|
||||||
|
startedEvent?: MatrixEvent,
|
||||||
|
): MatrixEvent => {
|
||||||
|
const infoEvent = mkVoiceBroadcastInfoStateEvent(room.roomId, state, userId, deviceId, startedEvent);
|
||||||
|
room.addLiveEvents([infoEvent]);
|
||||||
room.currentState.setStateEvents([infoEvent]);
|
room.currentState.setStateEvents([infoEvent]);
|
||||||
|
room.relations.aggregateChildEvent(infoEvent);
|
||||||
return infoEvent;
|
return infoEvent;
|
||||||
};
|
};
|
||||||
|
|
||||||
const itShouldReturnTrueTrue = () => {
|
const itShouldReturnTrueTrue = () => {
|
||||||
it("should return true/true", () => {
|
it("should return true/true", async () => {
|
||||||
expect(hasRoomLiveVoiceBroadcast(room, client.getUserId())).toEqual({
|
expect(await hasRoomLiveVoiceBroadcast(client, room, client.getSafeUserId())).toEqual({
|
||||||
hasBroadcast: true,
|
hasBroadcast: true,
|
||||||
infoEvent: expectedEvent,
|
infoEvent: expectedEvent,
|
||||||
startedByUser: true,
|
startedByUser: true,
|
||||||
|
@ -48,8 +57,8 @@ describe("hasRoomLiveVoiceBroadcast", () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const itShouldReturnTrueFalse = () => {
|
const itShouldReturnTrueFalse = () => {
|
||||||
it("should return true/false", () => {
|
it("should return true/false", async () => {
|
||||||
expect(hasRoomLiveVoiceBroadcast(room, client.getUserId())).toEqual({
|
expect(await hasRoomLiveVoiceBroadcast(client, room, client.getSafeUserId())).toEqual({
|
||||||
hasBroadcast: true,
|
hasBroadcast: true,
|
||||||
infoEvent: expectedEvent,
|
infoEvent: expectedEvent,
|
||||||
startedByUser: false,
|
startedByUser: false,
|
||||||
|
@ -58,8 +67,8 @@ describe("hasRoomLiveVoiceBroadcast", () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const itShouldReturnFalseFalse = () => {
|
const itShouldReturnFalseFalse = () => {
|
||||||
it("should return false/false", () => {
|
it("should return false/false", async () => {
|
||||||
expect(hasRoomLiveVoiceBroadcast(room, client.getUserId())).toEqual({
|
expect(await hasRoomLiveVoiceBroadcast(client, room, client.getSafeUserId())).toEqual({
|
||||||
hasBroadcast: false,
|
hasBroadcast: false,
|
||||||
infoEvent: null,
|
infoEvent: null,
|
||||||
startedByUser: false,
|
startedByUser: false,
|
||||||
|
@ -67,13 +76,13 @@ describe("hasRoomLiveVoiceBroadcast", () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeAll(() => {
|
|
||||||
client = stubClient();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
client = stubClient();
|
||||||
|
room = new Room(roomId, client, client.getSafeUserId());
|
||||||
|
mocked(client.getRoom).mockImplementation((roomId: string): Room | null => {
|
||||||
|
return roomId === room.roomId ? room : null;
|
||||||
|
});
|
||||||
expectedEvent = null;
|
expectedEvent = null;
|
||||||
room = new Room(roomId, client, client.getUserId());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when there is no voice broadcast info at all", () => {
|
describe("when there is no voice broadcast info at all", () => {
|
||||||
|
@ -86,9 +95,9 @@ describe("hasRoomLiveVoiceBroadcast", () => {
|
||||||
mkEvent({
|
mkEvent({
|
||||||
event: true,
|
event: true,
|
||||||
room: room.roomId,
|
room: room.roomId,
|
||||||
user: client.getUserId(),
|
user: client.getSafeUserId(),
|
||||||
type: VoiceBroadcastInfoEventType,
|
type: VoiceBroadcastInfoEventType,
|
||||||
skey: client.getUserId(),
|
skey: client.getSafeUserId(),
|
||||||
content: {},
|
content: {},
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
@ -98,8 +107,12 @@ describe("hasRoomLiveVoiceBroadcast", () => {
|
||||||
|
|
||||||
describe("when there is a live broadcast from the current and another user", () => {
|
describe("when there is a live broadcast from the current and another user", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
expectedEvent = addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Started, client.getUserId());
|
expectedEvent = addVoiceBroadcastInfoEvent(
|
||||||
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Started, otherUserId);
|
VoiceBroadcastInfoState.Started,
|
||||||
|
client.getSafeUserId(),
|
||||||
|
client.getDeviceId()!,
|
||||||
|
);
|
||||||
|
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Started, otherUserId, otherDeviceId);
|
||||||
});
|
});
|
||||||
|
|
||||||
itShouldReturnTrueTrue();
|
itShouldReturnTrueTrue();
|
||||||
|
@ -107,21 +120,56 @@ describe("hasRoomLiveVoiceBroadcast", () => {
|
||||||
|
|
||||||
describe("when there are only stopped info events", () => {
|
describe("when there are only stopped info events", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Stopped, client.getUserId());
|
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Stopped, client.getSafeUserId(), client.getDeviceId()!);
|
||||||
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Stopped, otherUserId);
|
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Stopped, otherUserId, otherDeviceId);
|
||||||
});
|
});
|
||||||
|
|
||||||
itShouldReturnFalseFalse();
|
itShouldReturnFalseFalse();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe.each([
|
describe("when there is a live, started broadcast from the current user", () => {
|
||||||
// all there are kind of live states
|
|
||||||
VoiceBroadcastInfoState.Started,
|
|
||||||
VoiceBroadcastInfoState.Paused,
|
|
||||||
VoiceBroadcastInfoState.Resumed,
|
|
||||||
])("when there is a live broadcast (%s) from the current user", (state: VoiceBroadcastInfoState) => {
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
expectedEvent = addVoiceBroadcastInfoEvent(state, client.getUserId());
|
expectedEvent = addVoiceBroadcastInfoEvent(
|
||||||
|
VoiceBroadcastInfoState.Started,
|
||||||
|
client.getSafeUserId(),
|
||||||
|
client.getDeviceId()!,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
itShouldReturnTrueTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when there is a live, paused broadcast from the current user", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
expectedEvent = addVoiceBroadcastInfoEvent(
|
||||||
|
VoiceBroadcastInfoState.Started,
|
||||||
|
client.getSafeUserId(),
|
||||||
|
client.getDeviceId()!,
|
||||||
|
);
|
||||||
|
addVoiceBroadcastInfoEvent(
|
||||||
|
VoiceBroadcastInfoState.Paused,
|
||||||
|
client.getSafeUserId(),
|
||||||
|
client.getDeviceId()!,
|
||||||
|
expectedEvent,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
itShouldReturnTrueTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when there is a live, resumed broadcast from the current user", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
expectedEvent = addVoiceBroadcastInfoEvent(
|
||||||
|
VoiceBroadcastInfoState.Started,
|
||||||
|
client.getSafeUserId(),
|
||||||
|
client.getDeviceId()!,
|
||||||
|
);
|
||||||
|
addVoiceBroadcastInfoEvent(
|
||||||
|
VoiceBroadcastInfoState.Resumed,
|
||||||
|
client.getSafeUserId(),
|
||||||
|
client.getDeviceId()!,
|
||||||
|
expectedEvent,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
itShouldReturnTrueTrue();
|
itShouldReturnTrueTrue();
|
||||||
|
@ -129,8 +177,17 @@ describe("hasRoomLiveVoiceBroadcast", () => {
|
||||||
|
|
||||||
describe("when there was a live broadcast, that has been stopped", () => {
|
describe("when there was a live broadcast, that has been stopped", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Resumed, client.getUserId());
|
const startedEvent = addVoiceBroadcastInfoEvent(
|
||||||
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Stopped, client.getUserId());
|
VoiceBroadcastInfoState.Started,
|
||||||
|
client.getSafeUserId(),
|
||||||
|
client.getDeviceId()!,
|
||||||
|
);
|
||||||
|
addVoiceBroadcastInfoEvent(
|
||||||
|
VoiceBroadcastInfoState.Stopped,
|
||||||
|
client.getSafeUserId(),
|
||||||
|
client.getDeviceId()!,
|
||||||
|
startedEvent,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
itShouldReturnFalseFalse();
|
itShouldReturnFalseFalse();
|
||||||
|
@ -138,7 +195,7 @@ describe("hasRoomLiveVoiceBroadcast", () => {
|
||||||
|
|
||||||
describe("when there is a live broadcast from another user", () => {
|
describe("when there is a live broadcast from another user", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
expectedEvent = addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Resumed, otherUserId);
|
expectedEvent = addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Started, otherUserId, otherDeviceId);
|
||||||
});
|
});
|
||||||
|
|
||||||
itShouldReturnTrueFalse();
|
itShouldReturnTrueFalse();
|
||||||
|
|
90
test/voice-broadcast/utils/retrieveStartedInfoEvent-test.ts
Normal file
90
test/voice-broadcast/utils/retrieveStartedInfoEvent-test.ts
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { mocked } from "jest-mock";
|
||||||
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
|
import { MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
|
import {
|
||||||
|
retrieveStartedInfoEvent,
|
||||||
|
VoiceBroadcastInfoEventType,
|
||||||
|
VoiceBroadcastInfoState,
|
||||||
|
} from "../../../src/voice-broadcast";
|
||||||
|
import { mkEvent, stubClient } from "../../test-utils";
|
||||||
|
import { mkVoiceBroadcastInfoStateEvent } from "./test-utils";
|
||||||
|
|
||||||
|
describe("retrieveStartedInfoEvent", () => {
|
||||||
|
let client: MatrixClient;
|
||||||
|
let room: Room;
|
||||||
|
|
||||||
|
const mkStartEvent = () => {
|
||||||
|
return mkVoiceBroadcastInfoStateEvent(
|
||||||
|
room.roomId,
|
||||||
|
VoiceBroadcastInfoState.Started,
|
||||||
|
client.getUserId()!,
|
||||||
|
client.deviceId!,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mkStopEvent = (startEvent: MatrixEvent) => {
|
||||||
|
return mkVoiceBroadcastInfoStateEvent(
|
||||||
|
room.roomId,
|
||||||
|
VoiceBroadcastInfoState.Stopped,
|
||||||
|
client.getUserId()!,
|
||||||
|
client.deviceId!,
|
||||||
|
startEvent,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
client = stubClient();
|
||||||
|
room = new Room("!room:example.com", client, client.getUserId()!);
|
||||||
|
mocked(client.getRoom).mockImplementation((roomId: string): Room | null => {
|
||||||
|
if (roomId === room.roomId) return room;
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when passing a started event, it should return the event", async () => {
|
||||||
|
const event = mkStartEvent();
|
||||||
|
expect(await retrieveStartedInfoEvent(event, client)).toBe(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when passing an event without relation, it should return null", async () => {
|
||||||
|
const event = mkEvent({
|
||||||
|
event: true,
|
||||||
|
type: VoiceBroadcastInfoEventType,
|
||||||
|
user: client.getUserId()!,
|
||||||
|
content: {},
|
||||||
|
});
|
||||||
|
expect(await retrieveStartedInfoEvent(event, client)).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when the room contains the event, it should return it", async () => {
|
||||||
|
const startEvent = mkStartEvent();
|
||||||
|
const stopEvent = mkStopEvent(startEvent);
|
||||||
|
room.addLiveEvents([startEvent]);
|
||||||
|
expect(await retrieveStartedInfoEvent(stopEvent, client)).toBe(startEvent);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when the room not contains the event, it should fetch it", async () => {
|
||||||
|
const startEvent = mkStartEvent();
|
||||||
|
const stopEvent = mkStopEvent(startEvent);
|
||||||
|
mocked(client.fetchRoomEvent).mockResolvedValue(startEvent.event);
|
||||||
|
expect((await retrieveStartedInfoEvent(stopEvent, client))?.getId()).toBe(startEvent.getId());
|
||||||
|
expect(client.fetchRoomEvent).toHaveBeenCalledWith(room.roomId, startEvent.getId());
|
||||||
|
});
|
||||||
|
});
|
|
@ -75,7 +75,7 @@ describe("setUpVoiceBroadcastPreRecording", () => {
|
||||||
|
|
||||||
describe("when the preconditions fail", () => {
|
describe("when the preconditions fail", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mocked(checkVoiceBroadcastPreConditions).mockReturnValue(false);
|
mocked(checkVoiceBroadcastPreConditions).mockResolvedValue(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
itShouldReturnNull();
|
itShouldReturnNull();
|
||||||
|
@ -83,7 +83,7 @@ describe("setUpVoiceBroadcastPreRecording", () => {
|
||||||
|
|
||||||
describe("when the preconditions pass", () => {
|
describe("when the preconditions pass", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mocked(checkVoiceBroadcastPreConditions).mockReturnValue(true);
|
mocked(checkVoiceBroadcastPreConditions).mockResolvedValue(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("and there is no user id", () => {
|
describe("and there is no user id", () => {
|
||||||
|
|
Loading…
Reference in a new issue