Display info dialogs if unable to start voice broadcasts (#9453)
This commit is contained in:
parent
3c3df11d32
commit
bb0c175b7e
17 changed files with 546 additions and 160 deletions
|
@ -147,7 +147,7 @@ describe("MessageComposer", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
SettingsStore.setValue(setting, null, SettingLevel.DEVICE, value);
|
||||
wrapper = wrapAndRender({ room, showVoiceBroadcastButton: true });
|
||||
wrapper = wrapAndRender({ room });
|
||||
});
|
||||
|
||||
it(`should pass the prop ${prop} = ${value}`, () => {
|
||||
|
@ -174,17 +174,6 @@ describe("MessageComposer", () => {
|
|||
});
|
||||
});
|
||||
|
||||
[false, undefined].forEach((value) => {
|
||||
it(`should pass showVoiceBroadcastButton = false if the MessageComposer prop is ${value}`, () => {
|
||||
SettingsStore.setValue(Features.VoiceBroadcast, null, SettingLevel.DEVICE, true);
|
||||
const wrapper = wrapAndRender({
|
||||
room,
|
||||
showVoiceBroadcastButton: value,
|
||||
});
|
||||
expect(wrapper.find(MessageComposerButtons).props().showVoiceBroadcastButton).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it("should not render the send button", () => {
|
||||
const wrapper = wrapAndRender({ room });
|
||||
expect(wrapper.find("SendButton")).toHaveLength(0);
|
||||
|
|
|
@ -250,7 +250,6 @@ function createRoomState(room: Room, narrow: boolean): IRoomState {
|
|||
statusBarVisible: false,
|
||||
canReact: false,
|
||||
canSendMessages: false,
|
||||
canSendVoiceBroadcasts: false,
|
||||
layout: Layout.Group,
|
||||
lowBandwidth: false,
|
||||
alwaysShowTimestamps: false,
|
||||
|
|
|
@ -72,7 +72,6 @@ describe('<SendMessageComposer/>', () => {
|
|||
statusBarVisible: false,
|
||||
canReact: false,
|
||||
canSendMessages: false,
|
||||
canSendVoiceBroadcasts: false,
|
||||
layout: Layout.Group,
|
||||
lowBandwidth: false,
|
||||
alwaysShowTimestamps: false,
|
||||
|
|
|
@ -91,7 +91,6 @@ describe('WysiwygComposer', () => {
|
|||
statusBarVisible: false,
|
||||
canReact: false,
|
||||
canSendMessages: false,
|
||||
canSendVoiceBroadcasts: false,
|
||||
layout: Layout.Group,
|
||||
lowBandwidth: false,
|
||||
alwaysShowTimestamps: false,
|
||||
|
|
|
@ -123,7 +123,6 @@ describe('message', () => {
|
|||
statusBarVisible: false,
|
||||
canReact: false,
|
||||
canSendMessages: false,
|
||||
canSendVoiceBroadcasts: false,
|
||||
layout: Layout.Group,
|
||||
lowBandwidth: false,
|
||||
alwaysShowTimestamps: false,
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`startNewVoiceBroadcastRecording when the current user is allowed to send voice broadcast info state events when there already is a live broadcast of another user should show an info dialog 1`] = `
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
[Function],
|
||||
Object {
|
||||
"description": <p>
|
||||
Someone else is already recording a voice broadcast. Wait for their voice broadcast to end to start a new one.
|
||||
</p>,
|
||||
"hasCloseButton": true,
|
||||
"title": "Can't start a new voice broadcast",
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`startNewVoiceBroadcastRecording when the current user is allowed to send voice broadcast info state events when there already is a live broadcast of the current user should show an info dialog 1`] = `
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
[Function],
|
||||
Object {
|
||||
"description": <p>
|
||||
You are already recording a voice broadcast. Please end your current voice broadcast to start a new one.
|
||||
</p>,
|
||||
"hasCloseButton": true,
|
||||
"title": "Can't start a new voice broadcast",
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`startNewVoiceBroadcastRecording when the current user is not allowed to send voice broadcast info state events should show an info dialog 1`] = `
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
[Function],
|
||||
Object {
|
||||
"description": <p>
|
||||
You don't have the required permissions to start a voice broadcast in this room. Contact a room administrator to upgrade your permissions.
|
||||
</p>,
|
||||
"hasCloseButton": true,
|
||||
"title": "Can't start a new voice broadcast",
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
144
test/voice-broadcast/utils/hasRoomLiveVoiceBroadcast-test.ts
Normal file
144
test/voice-broadcast/utils/hasRoomLiveVoiceBroadcast-test.ts
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
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, Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import {
|
||||
hasRoomLiveVoiceBroadcast,
|
||||
VoiceBroadcastInfoEventType,
|
||||
VoiceBroadcastInfoState,
|
||||
} from "../../../src/voice-broadcast";
|
||||
import { mkEvent, stubClient } from "../../test-utils";
|
||||
import { mkVoiceBroadcastInfoStateEvent } from "./test-utils";
|
||||
|
||||
describe("hasRoomLiveVoiceBroadcast", () => {
|
||||
const otherUserId = "@other:example.com";
|
||||
const roomId = "!room:example.com";
|
||||
let client: MatrixClient;
|
||||
let room: Room;
|
||||
|
||||
const addVoiceBroadcastInfoEvent = (
|
||||
state: VoiceBroadcastInfoState,
|
||||
sender: string,
|
||||
) => {
|
||||
room.currentState.setStateEvents([
|
||||
mkVoiceBroadcastInfoStateEvent(room.roomId, state, sender),
|
||||
]);
|
||||
};
|
||||
|
||||
const itShouldReturnTrueTrue = () => {
|
||||
it("should return true/true", () => {
|
||||
expect(hasRoomLiveVoiceBroadcast(room, client.getUserId())).toEqual({
|
||||
hasBroadcast: true,
|
||||
startedByUser: true,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const itShouldReturnTrueFalse = () => {
|
||||
it("should return true/false", () => {
|
||||
expect(hasRoomLiveVoiceBroadcast(room, client.getUserId())).toEqual({
|
||||
hasBroadcast: true,
|
||||
startedByUser: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const itShouldReturnFalseFalse = () => {
|
||||
it("should return false/false", () => {
|
||||
expect(hasRoomLiveVoiceBroadcast(room, client.getUserId())).toEqual({
|
||||
hasBroadcast: false,
|
||||
startedByUser: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
client = stubClient();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
room = new Room(roomId, client, client.getUserId());
|
||||
});
|
||||
|
||||
describe("when there is no voice broadcast info at all", () => {
|
||||
itShouldReturnFalseFalse();
|
||||
});
|
||||
|
||||
describe("when the »state« prop is missing", () => {
|
||||
beforeEach(() => {
|
||||
room.currentState.setStateEvents([
|
||||
mkEvent({
|
||||
event: true,
|
||||
room: room.roomId,
|
||||
user: client.getUserId(),
|
||||
type: VoiceBroadcastInfoEventType,
|
||||
skey: client.getUserId(),
|
||||
content: {},
|
||||
}),
|
||||
]);
|
||||
});
|
||||
itShouldReturnFalseFalse();
|
||||
});
|
||||
|
||||
describe("when there is a live broadcast from the current and another user", () => {
|
||||
beforeEach(() => {
|
||||
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Started, client.getUserId());
|
||||
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Started, otherUserId);
|
||||
});
|
||||
|
||||
itShouldReturnTrueTrue();
|
||||
});
|
||||
|
||||
describe("when there are only stopped info events", () => {
|
||||
beforeEach(() => {
|
||||
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Stopped, client.getUserId());
|
||||
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Stopped, otherUserId);
|
||||
});
|
||||
|
||||
itShouldReturnFalseFalse();
|
||||
});
|
||||
|
||||
describe.each([
|
||||
// all there are kind of live states
|
||||
VoiceBroadcastInfoState.Started,
|
||||
VoiceBroadcastInfoState.Paused,
|
||||
VoiceBroadcastInfoState.Running,
|
||||
])("when there is a live broadcast (%s) from the current user", (state: VoiceBroadcastInfoState) => {
|
||||
beforeEach(() => {
|
||||
addVoiceBroadcastInfoEvent(state, client.getUserId());
|
||||
});
|
||||
|
||||
itShouldReturnTrueTrue();
|
||||
});
|
||||
|
||||
describe("when there was a live broadcast, that has been stopped", () => {
|
||||
beforeEach(() => {
|
||||
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Running, client.getUserId());
|
||||
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Stopped, client.getUserId());
|
||||
});
|
||||
|
||||
itShouldReturnFalseFalse();
|
||||
});
|
||||
|
||||
describe("when there is a live broadcast from another user", () => {
|
||||
beforeEach(() => {
|
||||
addVoiceBroadcastInfoEvent(VoiceBroadcastInfoState.Running, otherUserId);
|
||||
});
|
||||
|
||||
itShouldReturnTrueFalse();
|
||||
});
|
||||
});
|
|
@ -15,8 +15,9 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import { mocked } from "jest-mock";
|
||||
import { EventType, MatrixClient, MatrixEvent, Room, RoomStateEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { EventType, MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import Modal from "../../../src/Modal";
|
||||
import {
|
||||
startNewVoiceBroadcastRecording,
|
||||
VoiceBroadcastInfoEventType,
|
||||
|
@ -25,46 +26,29 @@ import {
|
|||
VoiceBroadcastRecording,
|
||||
} from "../../../src/voice-broadcast";
|
||||
import { mkEvent, stubClient } from "../../test-utils";
|
||||
import { mkVoiceBroadcastInfoStateEvent } from "./test-utils";
|
||||
|
||||
jest.mock("../../../src/voice-broadcast/models/VoiceBroadcastRecording", () => ({
|
||||
VoiceBroadcastRecording: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock("../../../src/Modal");
|
||||
|
||||
describe("startNewVoiceBroadcastRecording", () => {
|
||||
const roomId = "!room:example.com";
|
||||
const otherUserId = "@other:example.com";
|
||||
let client: MatrixClient;
|
||||
let recordingsStore: VoiceBroadcastRecordingsStore;
|
||||
let room: Room;
|
||||
let roomOnStateEventsCallbackRegistered: Promise<void>;
|
||||
let roomOnStateEventsCallbackRegisteredResolver: Function;
|
||||
let roomOnStateEventsCallback: () => void;
|
||||
let infoEvent: MatrixEvent;
|
||||
let otherEvent: MatrixEvent;
|
||||
let stateEvent: MatrixEvent;
|
||||
let result: VoiceBroadcastRecording | null;
|
||||
|
||||
beforeEach(() => {
|
||||
roomOnStateEventsCallbackRegistered = new Promise((resolve) => {
|
||||
roomOnStateEventsCallbackRegisteredResolver = resolve;
|
||||
});
|
||||
|
||||
room = {
|
||||
currentState: {
|
||||
getStateEvents: jest.fn().mockImplementation((type, userId) => {
|
||||
if (type === VoiceBroadcastInfoEventType && userId === client.getUserId()) {
|
||||
return stateEvent;
|
||||
}
|
||||
}),
|
||||
},
|
||||
on: jest.fn().mockImplementation((eventType, callback) => {
|
||||
if (eventType === RoomStateEvent.Events) {
|
||||
roomOnStateEventsCallback = callback;
|
||||
roomOnStateEventsCallbackRegisteredResolver();
|
||||
}
|
||||
}),
|
||||
off: jest.fn(),
|
||||
} as unknown as Room;
|
||||
|
||||
client = stubClient();
|
||||
room = new Room(roomId, client, client.getUserId());
|
||||
jest.spyOn(room.currentState, "maySendStateEvent");
|
||||
|
||||
mocked(client.getRoom).mockImplementation((getRoomId: string) => {
|
||||
if (getRoomId === roomId) {
|
||||
return room;
|
||||
|
@ -85,22 +69,14 @@ describe("startNewVoiceBroadcastRecording", () => {
|
|||
setCurrent: jest.fn(),
|
||||
} as unknown as VoiceBroadcastRecordingsStore;
|
||||
|
||||
infoEvent = mkEvent({
|
||||
event: true,
|
||||
type: VoiceBroadcastInfoEventType,
|
||||
content: {
|
||||
device_id: client.getDeviceId(),
|
||||
state: VoiceBroadcastInfoState.Started,
|
||||
},
|
||||
user: client.getUserId(),
|
||||
room: roomId,
|
||||
});
|
||||
infoEvent = mkVoiceBroadcastInfoStateEvent(roomId, VoiceBroadcastInfoState.Started, client.getUserId());
|
||||
otherEvent = mkEvent({
|
||||
event: true,
|
||||
type: EventType.RoomMember,
|
||||
content: {},
|
||||
user: client.getUserId(),
|
||||
room: roomId,
|
||||
skey: "",
|
||||
});
|
||||
|
||||
mocked(VoiceBroadcastRecording).mockImplementation((
|
||||
|
@ -115,29 +91,96 @@ describe("startNewVoiceBroadcastRecording", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("should create a new Voice Broadcast", (done) => {
|
||||
let ok = false;
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
startNewVoiceBroadcastRecording(roomId, client, recordingsStore).then((recording) => {
|
||||
expect(ok).toBe(true);
|
||||
expect(mocked(room.off)).toHaveBeenCalledWith(RoomStateEvent.Events, roomOnStateEventsCallback);
|
||||
expect(recording.infoEvent).toBe(infoEvent);
|
||||
expect(recording.start).toHaveBeenCalled();
|
||||
done();
|
||||
describe("when the current user is allowed to send voice broadcast info state events", () => {
|
||||
beforeEach(() => {
|
||||
mocked(room.currentState.maySendStateEvent).mockReturnValue(true);
|
||||
});
|
||||
|
||||
roomOnStateEventsCallbackRegistered.then(() => {
|
||||
// no state event, yet
|
||||
roomOnStateEventsCallback();
|
||||
describe("when there currently is no other broadcast", () => {
|
||||
it("should create a new Voice Broadcast", async () => {
|
||||
mocked(client.sendStateEvent).mockImplementation(async (
|
||||
_roomId: string,
|
||||
_eventType: string,
|
||||
_content: any,
|
||||
_stateKey = "",
|
||||
) => {
|
||||
setTimeout(() => {
|
||||
// emit state events after resolving the promise
|
||||
room.currentState.setStateEvents([otherEvent]);
|
||||
room.currentState.setStateEvents([infoEvent]);
|
||||
}, 0);
|
||||
return { event_id: infoEvent.getId() };
|
||||
});
|
||||
const recording = await startNewVoiceBroadcastRecording(room, client, recordingsStore);
|
||||
|
||||
// other state event
|
||||
stateEvent = otherEvent;
|
||||
roomOnStateEventsCallback();
|
||||
expect(client.sendStateEvent).toHaveBeenCalledWith(
|
||||
roomId,
|
||||
VoiceBroadcastInfoEventType,
|
||||
{
|
||||
chunk_length: 300,
|
||||
device_id: client.getDeviceId(),
|
||||
state: VoiceBroadcastInfoState.Started,
|
||||
},
|
||||
client.getUserId(),
|
||||
);
|
||||
expect(recording.infoEvent).toBe(infoEvent);
|
||||
expect(recording.start).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
// the expected Voice Broadcast Info event
|
||||
stateEvent = infoEvent;
|
||||
ok = true;
|
||||
roomOnStateEventsCallback();
|
||||
describe("when there already is a live broadcast of the current user", () => {
|
||||
beforeEach(async () => {
|
||||
room.currentState.setStateEvents([
|
||||
mkVoiceBroadcastInfoStateEvent(roomId, VoiceBroadcastInfoState.Running, client.getUserId()),
|
||||
]);
|
||||
|
||||
result = await startNewVoiceBroadcastRecording(room, client, recordingsStore);
|
||||
});
|
||||
|
||||
it("should not start a voice broadcast", () => {
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("should show an info dialog", () => {
|
||||
expect(Modal.createDialog).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when there already is a live broadcast of another user", () => {
|
||||
beforeEach(async () => {
|
||||
room.currentState.setStateEvents([
|
||||
mkVoiceBroadcastInfoStateEvent(roomId, VoiceBroadcastInfoState.Running, otherUserId),
|
||||
]);
|
||||
|
||||
result = await startNewVoiceBroadcastRecording(room, client, recordingsStore);
|
||||
});
|
||||
|
||||
it("should not start a voice broadcast", () => {
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("should show an info dialog", () => {
|
||||
expect(Modal.createDialog).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the current user is not allowed to send voice broadcast info state events", () => {
|
||||
beforeEach(async () => {
|
||||
mocked(room.currentState.maySendStateEvent).mockReturnValue(false);
|
||||
result = await startNewVoiceBroadcastRecording(room, client, recordingsStore);
|
||||
});
|
||||
|
||||
it("should not start a voice broadcast", () => {
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("should show an info dialog", () => {
|
||||
expect(Modal.createDialog).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
37
test/voice-broadcast/utils/test-utils.ts
Normal file
37
test/voice-broadcast/utils/test-utils.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
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 { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { VoiceBroadcastInfoEventType, VoiceBroadcastInfoState } from "../../../src/voice-broadcast";
|
||||
import { mkEvent } from "../../test-utils";
|
||||
|
||||
export const mkVoiceBroadcastInfoStateEvent = (
|
||||
roomId: string,
|
||||
state: VoiceBroadcastInfoState,
|
||||
sender: string,
|
||||
): MatrixEvent => {
|
||||
return mkEvent({
|
||||
event: true,
|
||||
room: roomId,
|
||||
user: sender,
|
||||
type: VoiceBroadcastInfoEventType,
|
||||
skey: sender,
|
||||
content: {
|
||||
state,
|
||||
},
|
||||
});
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue