Apply prettier formatting
This commit is contained in:
parent
1cac306093
commit
526645c791
1576 changed files with 65385 additions and 62478 deletions
|
@ -14,43 +14,44 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { screen, render, fireEvent, waitFor, within, act } from '@testing-library/react';
|
||||
import React from "react";
|
||||
import { screen, render, fireEvent, waitFor, within, act } from "@testing-library/react";
|
||||
|
||||
import * as TestUtils from '../../test-utils';
|
||||
import AutocompleteProvider from '../../../src/autocomplete/AutocompleteProvider';
|
||||
import { ICompletion } from '../../../src/autocomplete/Autocompleter';
|
||||
import * as TestUtils from "../../test-utils";
|
||||
import AutocompleteProvider from "../../../src/autocomplete/AutocompleteProvider";
|
||||
import { ICompletion } from "../../../src/autocomplete/Autocompleter";
|
||||
import { AutocompleteInput } from "../../../src/components/structures/AutocompleteInput";
|
||||
|
||||
describe('AutocompleteInput', () => {
|
||||
describe("AutocompleteInput", () => {
|
||||
const mockCompletion: ICompletion[] = [
|
||||
{ type: 'user', completion: 'user_1', completionId: '@user_1:host.local', range: { start: 1, end: 1 } },
|
||||
{ type: 'user', completion: 'user_2', completionId: '@user_2:host.local', range: { start: 1, end: 1 } },
|
||||
{ type: "user", completion: "user_1", completionId: "@user_1:host.local", range: { start: 1, end: 1 } },
|
||||
{ type: "user", completion: "user_2", completionId: "@user_2:host.local", range: { start: 1, end: 1 } },
|
||||
];
|
||||
|
||||
const constructMockProvider = (data: ICompletion[]) => ({
|
||||
getCompletions: jest.fn().mockImplementation(async () => data),
|
||||
}) as unknown as AutocompleteProvider;
|
||||
const constructMockProvider = (data: ICompletion[]) =>
|
||||
({
|
||||
getCompletions: jest.fn().mockImplementation(async () => data),
|
||||
} as unknown as AutocompleteProvider);
|
||||
|
||||
beforeEach(() => {
|
||||
TestUtils.stubClient();
|
||||
});
|
||||
|
||||
const getEditorInput = () => {
|
||||
const input = screen.getByTestId('autocomplete-input');
|
||||
const input = screen.getByTestId("autocomplete-input");
|
||||
expect(input).toBeDefined();
|
||||
|
||||
return input;
|
||||
};
|
||||
|
||||
it('should render suggestions when a query is set', async () => {
|
||||
it("should render suggestions when a query is set", async () => {
|
||||
const mockProvider = constructMockProvider(mockCompletion);
|
||||
const onSelectionChangeMock = jest.fn();
|
||||
|
||||
render(
|
||||
<AutocompleteInput
|
||||
provider={mockProvider}
|
||||
placeholder='Search ...'
|
||||
placeholder="Search ..."
|
||||
selection={[]}
|
||||
onSelectionChange={onSelectionChangeMock}
|
||||
/>,
|
||||
|
@ -60,45 +61,45 @@ describe('AutocompleteInput', () => {
|
|||
|
||||
act(() => {
|
||||
fireEvent.focus(input);
|
||||
fireEvent.change(input, { target: { value: 'user' } });
|
||||
fireEvent.change(input, { target: { value: "user" } });
|
||||
});
|
||||
|
||||
await waitFor(() => expect(mockProvider.getCompletions).toHaveBeenCalledTimes(1));
|
||||
expect(screen.getByTestId('autocomplete-matches').childNodes).toHaveLength(mockCompletion.length);
|
||||
expect(screen.getByTestId("autocomplete-matches").childNodes).toHaveLength(mockCompletion.length);
|
||||
});
|
||||
|
||||
it('should render selected items passed in via props', () => {
|
||||
it("should render selected items passed in via props", () => {
|
||||
const mockProvider = constructMockProvider(mockCompletion);
|
||||
const onSelectionChangeMock = jest.fn();
|
||||
|
||||
render(
|
||||
<AutocompleteInput
|
||||
provider={mockProvider}
|
||||
placeholder='Search ...'
|
||||
placeholder="Search ..."
|
||||
selection={mockCompletion}
|
||||
onSelectionChange={onSelectionChangeMock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const editor = screen.getByTestId('autocomplete-editor');
|
||||
const editor = screen.getByTestId("autocomplete-editor");
|
||||
const selection = within(editor).getAllByTestId("autocomplete-selection-item", { exact: false });
|
||||
expect(selection).toHaveLength(mockCompletion.length);
|
||||
});
|
||||
|
||||
it('should call onSelectionChange() when an item is removed from selection', () => {
|
||||
it("should call onSelectionChange() when an item is removed from selection", () => {
|
||||
const mockProvider = constructMockProvider(mockCompletion);
|
||||
const onSelectionChangeMock = jest.fn();
|
||||
|
||||
render(
|
||||
<AutocompleteInput
|
||||
provider={mockProvider}
|
||||
placeholder='Search ...'
|
||||
placeholder="Search ..."
|
||||
selection={mockCompletion}
|
||||
onSelectionChange={onSelectionChangeMock}
|
||||
/>,
|
||||
);
|
||||
|
||||
const editor = screen.getByTestId('autocomplete-editor');
|
||||
const editor = screen.getByTestId("autocomplete-editor");
|
||||
const removeButtons = within(editor).getAllByTestId("autocomplete-selection-remove-button", { exact: false });
|
||||
expect(removeButtons).toHaveLength(mockCompletion.length);
|
||||
|
||||
|
@ -110,39 +111,35 @@ describe('AutocompleteInput', () => {
|
|||
expect(onSelectionChangeMock).toHaveBeenCalledWith([mockCompletion[1]]);
|
||||
});
|
||||
|
||||
it('should render custom selection element when renderSelection() is defined', () => {
|
||||
it("should render custom selection element when renderSelection() is defined", () => {
|
||||
const mockProvider = constructMockProvider(mockCompletion);
|
||||
const onSelectionChangeMock = jest.fn();
|
||||
|
||||
const renderSelection = () => (
|
||||
<span data-testid='custom-selection-element'>custom selection element</span>
|
||||
);
|
||||
const renderSelection = () => <span data-testid="custom-selection-element">custom selection element</span>;
|
||||
|
||||
render(
|
||||
<AutocompleteInput
|
||||
provider={mockProvider}
|
||||
placeholder='Search ...'
|
||||
placeholder="Search ..."
|
||||
selection={mockCompletion}
|
||||
onSelectionChange={onSelectionChangeMock}
|
||||
renderSelection={renderSelection}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getAllByTestId('custom-selection-element')).toHaveLength(mockCompletion.length);
|
||||
expect(screen.getAllByTestId("custom-selection-element")).toHaveLength(mockCompletion.length);
|
||||
});
|
||||
|
||||
it('should render custom suggestion element when renderSuggestion() is defined', async () => {
|
||||
it("should render custom suggestion element when renderSuggestion() is defined", async () => {
|
||||
const mockProvider = constructMockProvider(mockCompletion);
|
||||
const onSelectionChangeMock = jest.fn();
|
||||
|
||||
const renderSuggestion = () => (
|
||||
<span data-testid='custom-suggestion-element'>custom suggestion element</span>
|
||||
);
|
||||
const renderSuggestion = () => <span data-testid="custom-suggestion-element">custom suggestion element</span>;
|
||||
|
||||
render(
|
||||
<AutocompleteInput
|
||||
provider={mockProvider}
|
||||
placeholder='Search ...'
|
||||
placeholder="Search ..."
|
||||
selection={mockCompletion}
|
||||
onSelectionChange={onSelectionChangeMock}
|
||||
renderSuggestion={renderSuggestion}
|
||||
|
@ -153,21 +150,21 @@ describe('AutocompleteInput', () => {
|
|||
|
||||
act(() => {
|
||||
fireEvent.focus(input);
|
||||
fireEvent.change(input, { target: { value: 'user' } });
|
||||
fireEvent.change(input, { target: { value: "user" } });
|
||||
});
|
||||
|
||||
await waitFor(() => expect(mockProvider.getCompletions).toHaveBeenCalledTimes(1));
|
||||
expect(screen.getAllByTestId('custom-suggestion-element')).toHaveLength(mockCompletion.length);
|
||||
expect(screen.getAllByTestId("custom-suggestion-element")).toHaveLength(mockCompletion.length);
|
||||
});
|
||||
|
||||
it('should mark selected suggestions as selected', async () => {
|
||||
it("should mark selected suggestions as selected", async () => {
|
||||
const mockProvider = constructMockProvider(mockCompletion);
|
||||
const onSelectionChangeMock = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<AutocompleteInput
|
||||
provider={mockProvider}
|
||||
placeholder='Search ...'
|
||||
placeholder="Search ..."
|
||||
selection={mockCompletion}
|
||||
onSelectionChange={onSelectionChangeMock}
|
||||
/>,
|
||||
|
@ -177,23 +174,23 @@ describe('AutocompleteInput', () => {
|
|||
|
||||
act(() => {
|
||||
fireEvent.focus(input);
|
||||
fireEvent.change(input, { target: { value: 'user' } });
|
||||
fireEvent.change(input, { target: { value: "user" } });
|
||||
});
|
||||
|
||||
await waitFor(() => expect(mockProvider.getCompletions).toHaveBeenCalledTimes(1));
|
||||
const suggestions = await within(container).findAllByTestId('autocomplete-suggestion-item', { exact: false });
|
||||
const suggestions = await within(container).findAllByTestId("autocomplete-suggestion-item", { exact: false });
|
||||
expect(suggestions).toHaveLength(mockCompletion.length);
|
||||
suggestions.map(suggestion => expect(suggestion).toHaveClass('mx_AutocompleteInput_suggestion--selected'));
|
||||
suggestions.map((suggestion) => expect(suggestion).toHaveClass("mx_AutocompleteInput_suggestion--selected"));
|
||||
});
|
||||
|
||||
it('should remove the last added selection when backspace is pressed in empty input', () => {
|
||||
it("should remove the last added selection when backspace is pressed in empty input", () => {
|
||||
const mockProvider = constructMockProvider(mockCompletion);
|
||||
const onSelectionChangeMock = jest.fn();
|
||||
|
||||
render(
|
||||
<AutocompleteInput
|
||||
provider={mockProvider}
|
||||
placeholder='Search ...'
|
||||
placeholder="Search ..."
|
||||
selection={mockCompletion}
|
||||
onSelectionChange={onSelectionChangeMock}
|
||||
/>,
|
||||
|
@ -202,20 +199,20 @@ describe('AutocompleteInput', () => {
|
|||
const input = getEditorInput();
|
||||
|
||||
act(() => {
|
||||
fireEvent.keyDown(input, { key: 'Backspace' });
|
||||
fireEvent.keyDown(input, { key: "Backspace" });
|
||||
});
|
||||
|
||||
expect(onSelectionChangeMock).toHaveBeenCalledWith([mockCompletion[0]]);
|
||||
});
|
||||
|
||||
it('should toggle a selected item when a suggestion is clicked', async () => {
|
||||
it("should toggle a selected item when a suggestion is clicked", async () => {
|
||||
const mockProvider = constructMockProvider(mockCompletion);
|
||||
const onSelectionChangeMock = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<AutocompleteInput
|
||||
provider={mockProvider}
|
||||
placeholder='Search ...'
|
||||
placeholder="Search ..."
|
||||
selection={[]}
|
||||
onSelectionChange={onSelectionChangeMock}
|
||||
/>,
|
||||
|
@ -225,10 +222,10 @@ describe('AutocompleteInput', () => {
|
|||
|
||||
act(() => {
|
||||
fireEvent.focus(input);
|
||||
fireEvent.change(input, { target: { value: 'user' } });
|
||||
fireEvent.change(input, { target: { value: "user" } });
|
||||
});
|
||||
|
||||
const suggestions = await within(container).findAllByTestId('autocomplete-suggestion-item', { exact: false });
|
||||
const suggestions = await within(container).findAllByTestId("autocomplete-suggestion-item", { exact: false });
|
||||
|
||||
act(() => {
|
||||
fireEvent.mouseDown(suggestions[0]);
|
||||
|
|
|
@ -85,4 +85,3 @@ describe("ContextMenu", () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -14,12 +14,12 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { MatrixClient, MatrixEvent } from 'matrix-js-sdk/src/matrix';
|
||||
import { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { EventType } from "matrix-js-sdk/src/@types/event";
|
||||
import { CallState } from "matrix-js-sdk/src/webrtc/call";
|
||||
|
||||
import { stubClient } from '../../test-utils';
|
||||
import { MatrixClientPeg } from '../../../src/MatrixClientPeg';
|
||||
import { stubClient } from "../../test-utils";
|
||||
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
||||
import LegacyCallEventGrouper, { CustomCallState } from "../../../src/components/structures/LegacyCallEventGrouper";
|
||||
|
||||
const MY_USER_ID = "@me:here";
|
||||
|
@ -27,7 +27,7 @@ const THEIR_USER_ID = "@they:here";
|
|||
|
||||
let client: MatrixClient;
|
||||
|
||||
describe('LegacyCallEventGrouper', () => {
|
||||
describe("LegacyCallEventGrouper", () => {
|
||||
beforeEach(() => {
|
||||
stubClient();
|
||||
client = MatrixClientPeg.get();
|
||||
|
|
|
@ -15,13 +15,13 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { EventEmitter } from "events";
|
||||
import { Room, RoomMember } from 'matrix-js-sdk/src/matrix';
|
||||
import FakeTimers from '@sinonjs/fake-timers';
|
||||
import { render } from '@testing-library/react';
|
||||
import { Thread } from 'matrix-js-sdk/src/models/thread';
|
||||
import { Room, RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
import FakeTimers from "@sinonjs/fake-timers";
|
||||
import { render } from "@testing-library/react";
|
||||
import { Thread } from "matrix-js-sdk/src/models/thread";
|
||||
|
||||
import MessagePanel, { shouldFormContinuation } from "../../../src/components/structures/MessagePanel";
|
||||
import SettingsStore from "../../../src/settings/SettingsStore";
|
||||
|
@ -34,21 +34,21 @@ import {
|
|||
makeBeaconInfoEvent,
|
||||
mockClientMethodsEvents,
|
||||
mockClientMethodsUser,
|
||||
} from '../../test-utils';
|
||||
import ResizeNotifier from '../../../src/utils/ResizeNotifier';
|
||||
import { IRoomState } from '../../../src/components/structures/RoomView';
|
||||
} from "../../test-utils";
|
||||
import ResizeNotifier from "../../../src/utils/ResizeNotifier";
|
||||
import { IRoomState } from "../../../src/components/structures/RoomView";
|
||||
|
||||
jest.mock('../../../src/utils/beacon', () => ({
|
||||
jest.mock("../../../src/utils/beacon", () => ({
|
||||
useBeacon: jest.fn(),
|
||||
}));
|
||||
|
||||
const roomId = "!roomId:server_name";
|
||||
|
||||
describe('MessagePanel', function() {
|
||||
describe("MessagePanel", function () {
|
||||
let clock = null;
|
||||
const realSetTimeout = window.setTimeout;
|
||||
const events = mkEvents();
|
||||
const userId = '@me:here';
|
||||
const userId = "@me:here";
|
||||
const client = getMockClientWithEventEmitter({
|
||||
...mockClientMethodsUser(userId),
|
||||
...mockClientMethodsEvents(),
|
||||
|
@ -61,22 +61,22 @@ describe('MessagePanel', function() {
|
|||
|
||||
const room = new Room(roomId, client, userId);
|
||||
|
||||
const bobMember = new RoomMember(roomId, '@bob:id');
|
||||
bobMember.name = 'Bob';
|
||||
jest.spyOn(bobMember, 'getAvatarUrl').mockReturnValue('avatar.jpeg');
|
||||
jest.spyOn(bobMember, 'getMxcAvatarUrl').mockReturnValue('mxc://avatar.url/image.png');
|
||||
const bobMember = new RoomMember(roomId, "@bob:id");
|
||||
bobMember.name = "Bob";
|
||||
jest.spyOn(bobMember, "getAvatarUrl").mockReturnValue("avatar.jpeg");
|
||||
jest.spyOn(bobMember, "getMxcAvatarUrl").mockReturnValue("mxc://avatar.url/image.png");
|
||||
|
||||
const alice = "@alice:example.org";
|
||||
const aliceMember = new RoomMember(roomId, alice);
|
||||
aliceMember.name = 'Alice';
|
||||
jest.spyOn(aliceMember, 'getAvatarUrl').mockReturnValue('avatar.jpeg');
|
||||
jest.spyOn(aliceMember, 'getMxcAvatarUrl').mockReturnValue('mxc://avatar.url/image.png');
|
||||
aliceMember.name = "Alice";
|
||||
jest.spyOn(aliceMember, "getAvatarUrl").mockReturnValue("avatar.jpeg");
|
||||
jest.spyOn(aliceMember, "getMxcAvatarUrl").mockReturnValue("mxc://avatar.url/image.png");
|
||||
|
||||
const defaultProps = {
|
||||
resizeNotifier: new EventEmitter as unknown as ResizeNotifier,
|
||||
resizeNotifier: new EventEmitter() as unknown as ResizeNotifier,
|
||||
callEventGroupers: new Map(),
|
||||
room,
|
||||
className: 'cls',
|
||||
className: "cls",
|
||||
events: [],
|
||||
};
|
||||
|
||||
|
@ -95,24 +95,26 @@ describe('MessagePanel', function() {
|
|||
showHiddenEvents: false,
|
||||
} as unknown as IRoomState;
|
||||
|
||||
const getComponent = (props = {}, roomContext: Partial<IRoomState> = {}) =>
|
||||
const getComponent = (props = {}, roomContext: Partial<IRoomState> = {}) => (
|
||||
<MatrixClientContext.Provider value={client}>
|
||||
<RoomContext.Provider value={{ ...defaultRoomContext, ...roomContext }}>
|
||||
<MessagePanel {...defaultProps} {...props} />
|
||||
</RoomContext.Provider>);
|
||||
</MatrixClientContext.Provider>;
|
||||
</RoomContext.Provider>
|
||||
);
|
||||
</MatrixClientContext.Provider>
|
||||
);
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
jest.clearAllMocks();
|
||||
// HACK: We assume all settings want to be disabled
|
||||
jest.spyOn(SettingsStore, 'getValue').mockImplementation((arg) => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((arg) => {
|
||||
return arg === "showDisplaynameChanges";
|
||||
});
|
||||
|
||||
DMRoomMap.makeShared();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
afterEach(function () {
|
||||
if (clock) {
|
||||
clock.uninstall();
|
||||
clock = null;
|
||||
|
@ -123,11 +125,14 @@ describe('MessagePanel', function() {
|
|||
const events = [];
|
||||
const ts0 = Date.now();
|
||||
for (let i = 0; i < 10; i++) {
|
||||
events.push(TestUtilsMatrix.mkMessage(
|
||||
{
|
||||
event: true, room: "!room:id", user: "@user:id",
|
||||
events.push(
|
||||
TestUtilsMatrix.mkMessage({
|
||||
event: true,
|
||||
room: "!room:id",
|
||||
user: "@user:id",
|
||||
ts: ts0 + i * 1000,
|
||||
}));
|
||||
}),
|
||||
);
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
@ -135,13 +140,16 @@ describe('MessagePanel', function() {
|
|||
// Just to avoid breaking Dateseparator tests that might run at 00hrs
|
||||
function mkOneDayEvents() {
|
||||
const events = [];
|
||||
const ts0 = Date.parse('09 May 2004 00:12:00 GMT');
|
||||
const ts0 = Date.parse("09 May 2004 00:12:00 GMT");
|
||||
for (let i = 0; i < 10; i++) {
|
||||
events.push(TestUtilsMatrix.mkMessage(
|
||||
{
|
||||
event: true, room: "!room:id", user: "@user:id",
|
||||
events.push(
|
||||
TestUtilsMatrix.mkMessage({
|
||||
event: true,
|
||||
room: "!room:id",
|
||||
user: "@user:id",
|
||||
ts: ts0 + i * 1000,
|
||||
}));
|
||||
}),
|
||||
);
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
@ -152,26 +160,38 @@ describe('MessagePanel', function() {
|
|||
const ts0 = Date.now();
|
||||
|
||||
let i = 0;
|
||||
events.push(TestUtilsMatrix.mkMessage({
|
||||
event: true, room: "!room:id", user: "@user:id",
|
||||
ts: ts0 + ++i * 1000,
|
||||
}));
|
||||
events.push(
|
||||
TestUtilsMatrix.mkMessage({
|
||||
event: true,
|
||||
room: "!room:id",
|
||||
user: "@user:id",
|
||||
ts: ts0 + ++i * 1000,
|
||||
}),
|
||||
);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
events.push(TestUtilsMatrix.mkMembership({
|
||||
event: true, room: "!room:id", user: "@user:id",
|
||||
target: bobMember,
|
||||
ts: ts0 + i*1000,
|
||||
mship: 'join',
|
||||
prevMship: 'join',
|
||||
name: 'A user',
|
||||
}));
|
||||
events.push(
|
||||
TestUtilsMatrix.mkMembership({
|
||||
event: true,
|
||||
room: "!room:id",
|
||||
user: "@user:id",
|
||||
target: bobMember,
|
||||
ts: ts0 + i * 1000,
|
||||
mship: "join",
|
||||
prevMship: "join",
|
||||
name: "A user",
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
events.push(TestUtilsMatrix.mkMessage({
|
||||
event: true, room: "!room:id", user: "@user:id",
|
||||
ts: ts0 + ++i*1000,
|
||||
}));
|
||||
events.push(
|
||||
TestUtilsMatrix.mkMessage({
|
||||
event: true,
|
||||
room: "!room:id",
|
||||
user: "@user:id",
|
||||
ts: ts0 + ++i * 1000,
|
||||
}),
|
||||
);
|
||||
|
||||
return events;
|
||||
}
|
||||
|
@ -184,14 +204,18 @@ describe('MessagePanel', function() {
|
|||
let i = 0;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
events.push(TestUtilsMatrix.mkMembership({
|
||||
event: true, room: "!room:id", user: "@user:id",
|
||||
target: bobMember,
|
||||
ts: ts0 + i * 1000,
|
||||
mship: 'join',
|
||||
prevMship: 'join',
|
||||
name: 'A user',
|
||||
}));
|
||||
events.push(
|
||||
TestUtilsMatrix.mkMembership({
|
||||
event: true,
|
||||
room: "!room:id",
|
||||
user: "@user:id",
|
||||
target: bobMember,
|
||||
ts: ts0 + i * 1000,
|
||||
mship: "join",
|
||||
prevMship: "join",
|
||||
name: "A user",
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return events;
|
||||
|
@ -227,8 +251,8 @@ describe('MessagePanel', function() {
|
|||
user: alice,
|
||||
target: aliceMember,
|
||||
ts: ts0 + 1,
|
||||
mship: 'join',
|
||||
name: 'Alice',
|
||||
mship: "join",
|
||||
name: "Alice",
|
||||
}),
|
||||
mkEvent({
|
||||
event: true,
|
||||
|
@ -236,7 +260,7 @@ describe('MessagePanel', function() {
|
|||
room: roomId,
|
||||
user: alice,
|
||||
content: {
|
||||
"join_rule": "invite",
|
||||
join_rule: "invite",
|
||||
},
|
||||
ts: ts0 + 2,
|
||||
}),
|
||||
|
@ -246,7 +270,7 @@ describe('MessagePanel', function() {
|
|||
room: roomId,
|
||||
user: alice,
|
||||
content: {
|
||||
"history_visibility": "invited",
|
||||
history_visibility: "invited",
|
||||
},
|
||||
ts: ts0 + 3,
|
||||
}),
|
||||
|
@ -256,7 +280,7 @@ describe('MessagePanel', function() {
|
|||
room: roomId,
|
||||
user: alice,
|
||||
content: {
|
||||
"algorithm": "m.megolm.v1.aes-sha2",
|
||||
algorithm: "m.megolm.v1.aes-sha2",
|
||||
},
|
||||
ts: ts0 + 4,
|
||||
}),
|
||||
|
@ -267,8 +291,8 @@ describe('MessagePanel', function() {
|
|||
skey: "@bob:example.org",
|
||||
target: bobMember,
|
||||
ts: ts0 + 5,
|
||||
mship: 'invite',
|
||||
name: 'Bob',
|
||||
mship: "invite",
|
||||
name: "Bob",
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
@ -300,52 +324,58 @@ describe('MessagePanel', function() {
|
|||
return rmContainer && rmContainer.children.length > 0;
|
||||
}
|
||||
|
||||
it('should show the events', function() {
|
||||
it("should show the events", function () {
|
||||
const { container } = render(getComponent({ events }));
|
||||
|
||||
// just check we have the right number of tiles for now
|
||||
const tiles = container.getElementsByClassName('mx_EventTile');
|
||||
const tiles = container.getElementsByClassName("mx_EventTile");
|
||||
expect(tiles.length).toEqual(10);
|
||||
});
|
||||
|
||||
it('should collapse adjacent member events', function() {
|
||||
it("should collapse adjacent member events", function () {
|
||||
const { container } = render(getComponent({ events: mkMelsEvents() }));
|
||||
|
||||
// just check we have the right number of tiles for now
|
||||
const tiles = container.getElementsByClassName('mx_EventTile');
|
||||
const tiles = container.getElementsByClassName("mx_EventTile");
|
||||
expect(tiles.length).toEqual(2);
|
||||
|
||||
const summaryTiles = container.getElementsByClassName('mx_GenericEventListSummary');
|
||||
const summaryTiles = container.getElementsByClassName("mx_GenericEventListSummary");
|
||||
expect(summaryTiles.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should insert the read-marker in the right place', function() {
|
||||
const { container } = render(getComponent({
|
||||
events, readMarkerEventId: events[4].getId(), readMarkerVisible: true,
|
||||
}));
|
||||
it("should insert the read-marker in the right place", function () {
|
||||
const { container } = render(
|
||||
getComponent({
|
||||
events,
|
||||
readMarkerEventId: events[4].getId(),
|
||||
readMarkerVisible: true,
|
||||
}),
|
||||
);
|
||||
|
||||
const tiles = container.getElementsByClassName('mx_EventTile');
|
||||
const tiles = container.getElementsByClassName("mx_EventTile");
|
||||
|
||||
// find the <li> which wraps the read marker
|
||||
const [rm] = container.getElementsByClassName('mx_RoomView_myReadMarker_container');
|
||||
const [rm] = container.getElementsByClassName("mx_RoomView_myReadMarker_container");
|
||||
|
||||
// it should follow the <li> which wraps the event tile for event 4
|
||||
const eventContainer = ReactDOM.findDOMNode(tiles[4]);
|
||||
expect(rm.previousSibling).toEqual(eventContainer);
|
||||
});
|
||||
|
||||
it('should show the read-marker that fall in summarised events after the summary', function() {
|
||||
it("should show the read-marker that fall in summarised events after the summary", function () {
|
||||
const melsEvents = mkMelsEvents();
|
||||
const { container } = render(getComponent({
|
||||
events: melsEvents,
|
||||
readMarkerEventId: melsEvents[4].getId(),
|
||||
readMarkerVisible: true,
|
||||
}));
|
||||
const { container } = render(
|
||||
getComponent({
|
||||
events: melsEvents,
|
||||
readMarkerEventId: melsEvents[4].getId(),
|
||||
readMarkerVisible: true,
|
||||
}),
|
||||
);
|
||||
|
||||
const [summary] = container.getElementsByClassName('mx_GenericEventListSummary');
|
||||
const [summary] = container.getElementsByClassName("mx_GenericEventListSummary");
|
||||
|
||||
// find the <li> which wraps the read marker
|
||||
const [rm] = container.getElementsByClassName('mx_RoomView_myReadMarker_container');
|
||||
const [rm] = container.getElementsByClassName("mx_RoomView_myReadMarker_container");
|
||||
|
||||
expect(rm.previousSibling).toEqual(summary);
|
||||
|
||||
|
@ -353,19 +383,21 @@ describe('MessagePanel', function() {
|
|||
expect(isReadMarkerVisible(rm)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should hide the read-marker at the end of summarised events', function() {
|
||||
it("should hide the read-marker at the end of summarised events", function () {
|
||||
const melsEvents = mkMelsEventsOnly();
|
||||
|
||||
const { container } = render(getComponent({
|
||||
events: melsEvents,
|
||||
readMarkerEventId: melsEvents[9].getId(),
|
||||
readMarkerVisible: true,
|
||||
}));
|
||||
const { container } = render(
|
||||
getComponent({
|
||||
events: melsEvents,
|
||||
readMarkerEventId: melsEvents[9].getId(),
|
||||
readMarkerVisible: true,
|
||||
}),
|
||||
);
|
||||
|
||||
const [summary] = container.getElementsByClassName('mx_GenericEventListSummary');
|
||||
const [summary] = container.getElementsByClassName("mx_GenericEventListSummary");
|
||||
|
||||
// find the <li> which wraps the read marker
|
||||
const [rm] = container.getElementsByClassName('mx_RoomView_myReadMarker_container');
|
||||
const [rm] = container.getElementsByClassName("mx_RoomView_myReadMarker_container");
|
||||
|
||||
expect(rm.previousSibling).toEqual(summary);
|
||||
|
||||
|
@ -373,34 +405,38 @@ describe('MessagePanel', function() {
|
|||
expect(isReadMarkerVisible(rm)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('shows a ghost read-marker when the read-marker moves', function(done) {
|
||||
it("shows a ghost read-marker when the read-marker moves", function (done) {
|
||||
// fake the clock so that we can test the velocity animation.
|
||||
clock = FakeTimers.install();
|
||||
|
||||
const { container, rerender } = render(<div>
|
||||
{ getComponent({
|
||||
events,
|
||||
readMarkerEventId: events[4].getId(),
|
||||
readMarkerVisible: true,
|
||||
}) }
|
||||
</div>);
|
||||
const { container, rerender } = render(
|
||||
<div>
|
||||
{getComponent({
|
||||
events,
|
||||
readMarkerEventId: events[4].getId(),
|
||||
readMarkerVisible: true,
|
||||
})}
|
||||
</div>,
|
||||
);
|
||||
|
||||
const tiles = container.getElementsByClassName('mx_EventTile');
|
||||
const tiles = container.getElementsByClassName("mx_EventTile");
|
||||
|
||||
// find the <li> which wraps the read marker
|
||||
const [rm] = container.getElementsByClassName('mx_RoomView_myReadMarker_container');
|
||||
const [rm] = container.getElementsByClassName("mx_RoomView_myReadMarker_container");
|
||||
expect(rm.previousSibling).toEqual(tiles[4]);
|
||||
|
||||
rerender(<div>
|
||||
{ getComponent({
|
||||
events,
|
||||
readMarkerEventId: events[6].getId(),
|
||||
readMarkerVisible: true,
|
||||
}) }
|
||||
</div>);
|
||||
rerender(
|
||||
<div>
|
||||
{getComponent({
|
||||
events,
|
||||
readMarkerEventId: events[6].getId(),
|
||||
readMarkerVisible: true,
|
||||
})}
|
||||
</div>,
|
||||
);
|
||||
|
||||
// now there should be two RM containers
|
||||
const readMarkers = container.getElementsByClassName('mx_RoomView_myReadMarker_container');
|
||||
const readMarkers = container.getElementsByClassName("mx_RoomView_myReadMarker_container");
|
||||
|
||||
expect(readMarkers.length).toEqual(2);
|
||||
|
||||
|
@ -420,72 +456,72 @@ describe('MessagePanel', function() {
|
|||
clock.tick(1000);
|
||||
realSetTimeout(() => {
|
||||
// the ghost should now have finished
|
||||
expect(hr.style.opacity).toEqual('0');
|
||||
expect(hr.style.opacity).toEqual("0");
|
||||
done();
|
||||
}, 100);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it('should collapse creation events', function() {
|
||||
it("should collapse creation events", function () {
|
||||
const events = mkCreationEvents();
|
||||
TestUtilsMatrix.upsertRoomStateEvents(room, events);
|
||||
const { container } = render(getComponent({ events }));
|
||||
|
||||
const createEvent = events.find(event => event.getType() === 'm.room.create');
|
||||
const encryptionEvent = events.find(event => event.getType() === 'm.room.encryption');
|
||||
const createEvent = events.find((event) => event.getType() === "m.room.create");
|
||||
const encryptionEvent = events.find((event) => event.getType() === "m.room.encryption");
|
||||
|
||||
// we expect that
|
||||
// - the room creation event, the room encryption event, and Alice inviting Bob,
|
||||
// should be outside of the room creation summary
|
||||
// - all other events should be inside the room creation summary
|
||||
|
||||
const tiles = container.getElementsByClassName('mx_EventTile');
|
||||
const tiles = container.getElementsByClassName("mx_EventTile");
|
||||
|
||||
expect(tiles[0].getAttribute('data-event-id')).toEqual(createEvent.getId());
|
||||
expect(tiles[1].getAttribute('data-event-id')).toEqual(encryptionEvent.getId());
|
||||
expect(tiles[0].getAttribute("data-event-id")).toEqual(createEvent.getId());
|
||||
expect(tiles[1].getAttribute("data-event-id")).toEqual(encryptionEvent.getId());
|
||||
|
||||
const [summaryTile] = container.getElementsByClassName('mx_GenericEventListSummary');
|
||||
const [summaryTile] = container.getElementsByClassName("mx_GenericEventListSummary");
|
||||
|
||||
const summaryEventTiles = summaryTile.getElementsByClassName('mx_EventTile');
|
||||
const summaryEventTiles = summaryTile.getElementsByClassName("mx_EventTile");
|
||||
// every event except for the room creation, room encryption, and Bob's
|
||||
// invite event should be in the event summary
|
||||
expect(summaryEventTiles.length).toEqual(tiles.length - 3);
|
||||
});
|
||||
|
||||
it('should not collapse beacons as part of creation events', function() {
|
||||
it("should not collapse beacons as part of creation events", function () {
|
||||
const events = mkCreationEvents();
|
||||
const creationEvent = events.find(event => event.getType() === 'm.room.create');
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(
|
||||
creationEvent.getSender(),
|
||||
creationEvent.getRoomId(),
|
||||
{ isLive: true },
|
||||
);
|
||||
const creationEvent = events.find((event) => event.getType() === "m.room.create");
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(creationEvent.getSender(), creationEvent.getRoomId(), {
|
||||
isLive: true,
|
||||
});
|
||||
const combinedEvents = [...events, beaconInfoEvent];
|
||||
TestUtilsMatrix.upsertRoomStateEvents(room, combinedEvents);
|
||||
const { container } = render(getComponent({ events: combinedEvents }));
|
||||
|
||||
const [summaryTile] = container.getElementsByClassName('mx_GenericEventListSummary');
|
||||
const [summaryTile] = container.getElementsByClassName("mx_GenericEventListSummary");
|
||||
|
||||
// beacon body is not in the summary
|
||||
expect(summaryTile.getElementsByClassName('mx_MBeaconBody').length).toBe(0);
|
||||
expect(summaryTile.getElementsByClassName("mx_MBeaconBody").length).toBe(0);
|
||||
// beacon tile is rendered
|
||||
expect(container.getElementsByClassName('mx_MBeaconBody').length).toBe(1);
|
||||
expect(container.getElementsByClassName("mx_MBeaconBody").length).toBe(1);
|
||||
});
|
||||
|
||||
it('should hide read-marker at the end of creation event summary', function() {
|
||||
it("should hide read-marker at the end of creation event summary", function () {
|
||||
const events = mkCreationEvents();
|
||||
TestUtilsMatrix.upsertRoomStateEvents(room, events);
|
||||
|
||||
const { container } = render(getComponent({
|
||||
events,
|
||||
readMarkerEventId: events[5].getId(),
|
||||
readMarkerVisible: true,
|
||||
}));
|
||||
const { container } = render(
|
||||
getComponent({
|
||||
events,
|
||||
readMarkerEventId: events[5].getId(),
|
||||
readMarkerVisible: true,
|
||||
}),
|
||||
);
|
||||
|
||||
// find the <li> which wraps the read marker
|
||||
const [rm] = container.getElementsByClassName('mx_RoomView_myReadMarker_container');
|
||||
const [rm] = container.getElementsByClassName("mx_RoomView_myReadMarker_container");
|
||||
|
||||
const [messageList] = container.getElementsByClassName('mx_RoomView_MessageList');
|
||||
const [messageList] = container.getElementsByClassName("mx_RoomView_MessageList");
|
||||
const rows = messageList.children;
|
||||
expect(rows.length).toEqual(7); // 6 events + the NewRoomIntro
|
||||
expect(rm.previousSibling).toEqual(rows[5]);
|
||||
|
@ -494,22 +530,22 @@ describe('MessagePanel', function() {
|
|||
expect(isReadMarkerVisible(rm)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should render Date separators for the events', function() {
|
||||
it("should render Date separators for the events", function () {
|
||||
const events = mkOneDayEvents();
|
||||
const { queryAllByRole } = render(getComponent({ events }));
|
||||
const dates = queryAllByRole('separator');
|
||||
const dates = queryAllByRole("separator");
|
||||
|
||||
expect(dates.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('appends events into summaries during forward pagination without changing key', () => {
|
||||
it("appends events into summaries during forward pagination without changing key", () => {
|
||||
const events = mkMelsEvents().slice(1, 11);
|
||||
|
||||
const { container, rerender } = render(getComponent({ events }));
|
||||
let els = container.getElementsByClassName('mx_GenericEventListSummary');
|
||||
let els = container.getElementsByClassName("mx_GenericEventListSummary");
|
||||
expect(els.length).toEqual(1);
|
||||
expect(els[0].getAttribute('data-testid')).toEqual("eventlistsummary-" + events[0].getId());
|
||||
expect(els[0].getAttribute("data-scroll-tokens").split(',').length).toEqual(10);
|
||||
expect(els[0].getAttribute("data-testid")).toEqual("eventlistsummary-" + events[0].getId());
|
||||
expect(els[0].getAttribute("data-scroll-tokens").split(",").length).toEqual(10);
|
||||
|
||||
const updatedEvents = [
|
||||
...events,
|
||||
|
@ -519,27 +555,27 @@ describe('MessagePanel', function() {
|
|||
user: "@user:id",
|
||||
target: bobMember,
|
||||
ts: Date.now(),
|
||||
mship: 'join',
|
||||
prevMship: 'join',
|
||||
name: 'A user',
|
||||
mship: "join",
|
||||
prevMship: "join",
|
||||
name: "A user",
|
||||
}),
|
||||
];
|
||||
rerender(getComponent({ events: updatedEvents }));
|
||||
|
||||
els = container.getElementsByClassName('mx_GenericEventListSummary');
|
||||
els = container.getElementsByClassName("mx_GenericEventListSummary");
|
||||
expect(els.length).toEqual(1);
|
||||
expect(els[0].getAttribute('data-testid')).toEqual("eventlistsummary-" + events[0].getId());
|
||||
expect(els[0].getAttribute("data-scroll-tokens").split(',').length).toEqual(11);
|
||||
expect(els[0].getAttribute("data-testid")).toEqual("eventlistsummary-" + events[0].getId());
|
||||
expect(els[0].getAttribute("data-scroll-tokens").split(",").length).toEqual(11);
|
||||
});
|
||||
|
||||
it('prepends events into summaries during backward pagination without changing key', () => {
|
||||
it("prepends events into summaries during backward pagination without changing key", () => {
|
||||
const events = mkMelsEvents().slice(1, 11);
|
||||
|
||||
const { container, rerender } = render(getComponent({ events }));
|
||||
let els = container.getElementsByClassName('mx_GenericEventListSummary');
|
||||
let els = container.getElementsByClassName("mx_GenericEventListSummary");
|
||||
expect(els.length).toEqual(1);
|
||||
expect(els[0].getAttribute('data-testid')).toEqual("eventlistsummary-" + events[0].getId());
|
||||
expect(els[0].getAttribute("data-scroll-tokens").split(',').length).toEqual(10);
|
||||
expect(els[0].getAttribute("data-testid")).toEqual("eventlistsummary-" + events[0].getId());
|
||||
expect(els[0].getAttribute("data-scroll-tokens").split(",").length).toEqual(10);
|
||||
|
||||
const updatedEvents = [
|
||||
TestUtilsMatrix.mkMembership({
|
||||
|
@ -548,28 +584,28 @@ describe('MessagePanel', function() {
|
|||
user: "@user:id",
|
||||
target: bobMember,
|
||||
ts: Date.now(),
|
||||
mship: 'join',
|
||||
prevMship: 'join',
|
||||
name: 'A user',
|
||||
mship: "join",
|
||||
prevMship: "join",
|
||||
name: "A user",
|
||||
}),
|
||||
...events,
|
||||
];
|
||||
rerender(getComponent({ events: updatedEvents }));
|
||||
|
||||
els = container.getElementsByClassName('mx_GenericEventListSummary');
|
||||
els = container.getElementsByClassName("mx_GenericEventListSummary");
|
||||
expect(els.length).toEqual(1);
|
||||
expect(els[0].getAttribute('data-testid')).toEqual("eventlistsummary-" + events[0].getId());
|
||||
expect(els[0].getAttribute("data-scroll-tokens").split(',').length).toEqual(11);
|
||||
expect(els[0].getAttribute("data-testid")).toEqual("eventlistsummary-" + events[0].getId());
|
||||
expect(els[0].getAttribute("data-scroll-tokens").split(",").length).toEqual(11);
|
||||
});
|
||||
|
||||
it('assigns different keys to summaries that get split up', () => {
|
||||
it("assigns different keys to summaries that get split up", () => {
|
||||
const events = mkMelsEvents().slice(1, 11);
|
||||
|
||||
const { container, rerender } = render(getComponent({ events }));
|
||||
let els = container.getElementsByClassName('mx_GenericEventListSummary');
|
||||
let els = container.getElementsByClassName("mx_GenericEventListSummary");
|
||||
expect(els.length).toEqual(1);
|
||||
expect(els[0].getAttribute('data-testid')).toEqual(`eventlistsummary-${events[0].getId()}`);
|
||||
expect(els[0].getAttribute("data-scroll-tokens").split(',').length).toEqual(10);
|
||||
expect(els[0].getAttribute("data-testid")).toEqual(`eventlistsummary-${events[0].getId()}`);
|
||||
expect(els[0].getAttribute("data-scroll-tokens").split(",").length).toEqual(10);
|
||||
|
||||
const updatedEvents = [
|
||||
...events.slice(0, 5),
|
||||
|
@ -584,13 +620,13 @@ describe('MessagePanel', function() {
|
|||
rerender(getComponent({ events: updatedEvents }));
|
||||
|
||||
// summaries split becuase room messages are not summarised
|
||||
els = container.getElementsByClassName('mx_GenericEventListSummary');
|
||||
els = container.getElementsByClassName("mx_GenericEventListSummary");
|
||||
expect(els.length).toEqual(2);
|
||||
expect(els[0].getAttribute('data-testid')).toEqual(`eventlistsummary-${events[0].getId()}`);
|
||||
expect(els[0].getAttribute("data-scroll-tokens").split(',').length).toEqual(5);
|
||||
expect(els[0].getAttribute("data-testid")).toEqual(`eventlistsummary-${events[0].getId()}`);
|
||||
expect(els[0].getAttribute("data-scroll-tokens").split(",").length).toEqual(5);
|
||||
|
||||
expect(els[1].getAttribute('data-testid')).toEqual(`eventlistsummary-${events[5].getId()}`);
|
||||
expect(els[1].getAttribute("data-scroll-tokens").split(',').length).toEqual(5);
|
||||
expect(els[1].getAttribute("data-testid")).toEqual(`eventlistsummary-${events[5].getId()}`);
|
||||
expect(els[1].getAttribute("data-scroll-tokens").split(",").length).toEqual(5);
|
||||
});
|
||||
|
||||
// We test this because setting lookups can be *slow*, and we don't want
|
||||
|
@ -638,9 +674,9 @@ describe('MessagePanel', function() {
|
|||
];
|
||||
const { container } = render(getComponent({ events }, { showHiddenEvents: true }));
|
||||
|
||||
const els = container.getElementsByClassName('mx_GenericEventListSummary');
|
||||
const els = container.getElementsByClassName("mx_GenericEventListSummary");
|
||||
expect(els.length).toEqual(1);
|
||||
expect(els[0].getAttribute("data-scroll-tokens").split(',').length).toEqual(3);
|
||||
expect(els[0].getAttribute("data-scroll-tokens").split(",").length).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -55,8 +55,8 @@ describe("RightPanel", () => {
|
|||
});
|
||||
|
||||
afterEach(async () => {
|
||||
const roomChanged = new Promise<void>(resolve => {
|
||||
const ref = dis.register(payload => {
|
||||
const roomChanged = new Promise<void>((resolve) => {
|
||||
const ref = dis.register((payload) => {
|
||||
if (payload.action === Action.ActiveRoomChanged) {
|
||||
dis.unregister(ref);
|
||||
resolve();
|
||||
|
@ -84,12 +84,11 @@ describe("RightPanel", () => {
|
|||
await RightPanelStore.instance.onReady();
|
||||
};
|
||||
|
||||
const waitForRpsUpdate = () =>
|
||||
new Promise<void>(resolve => RightPanelStore.instance.once(UPDATE_EVENT, resolve));
|
||||
const waitForRpsUpdate = () => new Promise<void>((resolve) => RightPanelStore.instance.once(UPDATE_EVENT, resolve));
|
||||
|
||||
it("navigates from room summary to member list", async () => {
|
||||
const r1 = mkRoom(cli, "r1");
|
||||
cli.getRoom.mockImplementation(roomId => roomId === "r1" ? r1 : null);
|
||||
cli.getRoom.mockImplementation((roomId) => (roomId === "r1" ? r1 : null));
|
||||
|
||||
// Set up right panel state
|
||||
const realGetValue = SettingsStore.getValue;
|
||||
|
@ -127,7 +126,7 @@ describe("RightPanel", () => {
|
|||
const r1 = mkRoom(cli, "r1");
|
||||
const r2 = mkRoom(cli, "r2");
|
||||
|
||||
cli.getRoom.mockImplementation(roomId => {
|
||||
cli.getRoom.mockImplementation((roomId) => {
|
||||
if (roomId === "r1") return r1;
|
||||
if (roomId === "r2") return r2;
|
||||
return null;
|
||||
|
@ -168,7 +167,7 @@ describe("RightPanel", () => {
|
|||
// We want to verify that as we change to room 2, we should always have
|
||||
// the correct right panel state for whichever room we are showing.
|
||||
const instance = wrapper.find(_RightPanel).instance() as _RightPanel;
|
||||
const rendered = new Promise<void>(resolve => {
|
||||
const rendered = new Promise<void>((resolve) => {
|
||||
jest.spyOn(instance, "render").mockImplementation(() => {
|
||||
const { props, state } = instance;
|
||||
if (props.room.roomId === "r2" && state.phase === RightPanelPhases.RoomMemberList) {
|
||||
|
|
|
@ -63,7 +63,7 @@ describe("<RoomSearchView/>", () => {
|
|||
it("should show a spinner before the promise resolves", async () => {
|
||||
const deferred = defer<ISearchResults>();
|
||||
|
||||
render((
|
||||
render(
|
||||
<RoomSearchView
|
||||
term="search term"
|
||||
scope={SearchScope.All}
|
||||
|
@ -72,50 +72,57 @@ describe("<RoomSearchView/>", () => {
|
|||
permalinkCreator={permalinkCreator}
|
||||
className="someClass"
|
||||
onUpdate={jest.fn()}
|
||||
/>
|
||||
));
|
||||
/>,
|
||||
);
|
||||
|
||||
await screen.findByTestId("messagePanelSearchSpinner");
|
||||
});
|
||||
|
||||
it("should render results when the promise resolves", async () => {
|
||||
render((
|
||||
render(
|
||||
<MatrixClientContext.Provider value={client}>
|
||||
<RoomSearchView
|
||||
term="search term"
|
||||
scope={SearchScope.All}
|
||||
promise={Promise.resolve<ISearchResults>({
|
||||
results: [
|
||||
SearchResult.fromJson({
|
||||
rank: 1,
|
||||
result: {
|
||||
room_id: room.roomId,
|
||||
event_id: "$2",
|
||||
sender: client.getUserId(),
|
||||
origin_server_ts: 1,
|
||||
content: { body: "Foo Test Bar", msgtype: "m.text" },
|
||||
type: EventType.RoomMessage,
|
||||
},
|
||||
context: {
|
||||
profile_info: {},
|
||||
events_before: [{
|
||||
SearchResult.fromJson(
|
||||
{
|
||||
rank: 1,
|
||||
result: {
|
||||
room_id: room.roomId,
|
||||
event_id: "$1",
|
||||
event_id: "$2",
|
||||
sender: client.getUserId(),
|
||||
origin_server_ts: 1,
|
||||
content: { body: "Before", msgtype: "m.text" },
|
||||
content: { body: "Foo Test Bar", msgtype: "m.text" },
|
||||
type: EventType.RoomMessage,
|
||||
}],
|
||||
events_after: [{
|
||||
room_id: room.roomId,
|
||||
event_id: "$3",
|
||||
sender: client.getUserId(),
|
||||
origin_server_ts: 1,
|
||||
content: { body: "After", msgtype: "m.text" },
|
||||
type: EventType.RoomMessage,
|
||||
}],
|
||||
},
|
||||
context: {
|
||||
profile_info: {},
|
||||
events_before: [
|
||||
{
|
||||
room_id: room.roomId,
|
||||
event_id: "$1",
|
||||
sender: client.getUserId(),
|
||||
origin_server_ts: 1,
|
||||
content: { body: "Before", msgtype: "m.text" },
|
||||
type: EventType.RoomMessage,
|
||||
},
|
||||
],
|
||||
events_after: [
|
||||
{
|
||||
room_id: room.roomId,
|
||||
event_id: "$3",
|
||||
sender: client.getUserId(),
|
||||
origin_server_ts: 1,
|
||||
content: { body: "After", msgtype: "m.text" },
|
||||
type: EventType.RoomMessage,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}, eventMapper),
|
||||
eventMapper,
|
||||
),
|
||||
],
|
||||
highlights: [],
|
||||
count: 1,
|
||||
|
@ -125,8 +132,8 @@ describe("<RoomSearchView/>", () => {
|
|||
className="someClass"
|
||||
onUpdate={jest.fn()}
|
||||
/>
|
||||
</MatrixClientContext.Provider>
|
||||
));
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
|
||||
await screen.findByText("Before");
|
||||
await screen.findByText("Foo Test Bar");
|
||||
|
@ -134,29 +141,32 @@ describe("<RoomSearchView/>", () => {
|
|||
});
|
||||
|
||||
it("should highlight words correctly", async () => {
|
||||
render((
|
||||
render(
|
||||
<MatrixClientContext.Provider value={client}>
|
||||
<RoomSearchView
|
||||
term="search term"
|
||||
scope={SearchScope.Room}
|
||||
promise={Promise.resolve<ISearchResults>({
|
||||
results: [
|
||||
SearchResult.fromJson({
|
||||
rank: 1,
|
||||
result: {
|
||||
room_id: room.roomId,
|
||||
event_id: "$2",
|
||||
sender: client.getUserId(),
|
||||
origin_server_ts: 1,
|
||||
content: { body: "Foo Test Bar", msgtype: "m.text" },
|
||||
type: EventType.RoomMessage,
|
||||
SearchResult.fromJson(
|
||||
{
|
||||
rank: 1,
|
||||
result: {
|
||||
room_id: room.roomId,
|
||||
event_id: "$2",
|
||||
sender: client.getUserId(),
|
||||
origin_server_ts: 1,
|
||||
content: { body: "Foo Test Bar", msgtype: "m.text" },
|
||||
type: EventType.RoomMessage,
|
||||
},
|
||||
context: {
|
||||
profile_info: {},
|
||||
events_before: [],
|
||||
events_after: [],
|
||||
},
|
||||
},
|
||||
context: {
|
||||
profile_info: {},
|
||||
events_before: [],
|
||||
events_after: [],
|
||||
},
|
||||
}, eventMapper),
|
||||
eventMapper,
|
||||
),
|
||||
],
|
||||
highlights: ["test"],
|
||||
count: 1,
|
||||
|
@ -166,8 +176,8 @@ describe("<RoomSearchView/>", () => {
|
|||
className="someClass"
|
||||
onUpdate={jest.fn()}
|
||||
/>
|
||||
</MatrixClientContext.Provider>
|
||||
));
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
|
||||
const text = await screen.findByText("Test");
|
||||
expect(text).toHaveClass("mx_EventTile_searchHighlight");
|
||||
|
@ -176,22 +186,25 @@ describe("<RoomSearchView/>", () => {
|
|||
it("should show spinner above results when backpaginating", async () => {
|
||||
const searchResults: ISearchResults = {
|
||||
results: [
|
||||
SearchResult.fromJson({
|
||||
rank: 1,
|
||||
result: {
|
||||
room_id: room.roomId,
|
||||
event_id: "$2",
|
||||
sender: client.getUserId(),
|
||||
origin_server_ts: 1,
|
||||
content: { body: "Foo Test Bar", msgtype: "m.text" },
|
||||
type: EventType.RoomMessage,
|
||||
SearchResult.fromJson(
|
||||
{
|
||||
rank: 1,
|
||||
result: {
|
||||
room_id: room.roomId,
|
||||
event_id: "$2",
|
||||
sender: client.getUserId(),
|
||||
origin_server_ts: 1,
|
||||
content: { body: "Foo Test Bar", msgtype: "m.text" },
|
||||
type: EventType.RoomMessage,
|
||||
},
|
||||
context: {
|
||||
profile_info: {},
|
||||
events_before: [],
|
||||
events_after: [],
|
||||
},
|
||||
},
|
||||
context: {
|
||||
profile_info: {},
|
||||
events_before: [],
|
||||
events_after: [],
|
||||
},
|
||||
}, eventMapper),
|
||||
eventMapper,
|
||||
),
|
||||
],
|
||||
highlights: ["test"],
|
||||
next_batch: "next_batch",
|
||||
|
@ -202,27 +215,30 @@ describe("<RoomSearchView/>", () => {
|
|||
...searchResults,
|
||||
results: [
|
||||
...searchResults.results,
|
||||
SearchResult.fromJson({
|
||||
rank: 1,
|
||||
result: {
|
||||
room_id: room.roomId,
|
||||
event_id: "$4",
|
||||
sender: client.getUserId(),
|
||||
origin_server_ts: 4,
|
||||
content: { body: "Potato", msgtype: "m.text" },
|
||||
type: EventType.RoomMessage,
|
||||
SearchResult.fromJson(
|
||||
{
|
||||
rank: 1,
|
||||
result: {
|
||||
room_id: room.roomId,
|
||||
event_id: "$4",
|
||||
sender: client.getUserId(),
|
||||
origin_server_ts: 4,
|
||||
content: { body: "Potato", msgtype: "m.text" },
|
||||
type: EventType.RoomMessage,
|
||||
},
|
||||
context: {
|
||||
profile_info: {},
|
||||
events_before: [],
|
||||
events_after: [],
|
||||
},
|
||||
},
|
||||
context: {
|
||||
profile_info: {},
|
||||
events_before: [],
|
||||
events_after: [],
|
||||
},
|
||||
}, eventMapper),
|
||||
eventMapper,
|
||||
),
|
||||
],
|
||||
next_batch: undefined,
|
||||
});
|
||||
|
||||
render((
|
||||
render(
|
||||
<MatrixClientContext.Provider value={client}>
|
||||
<RoomSearchView
|
||||
term="search term"
|
||||
|
@ -233,8 +249,8 @@ describe("<RoomSearchView/>", () => {
|
|||
className="someClass"
|
||||
onUpdate={jest.fn()}
|
||||
/>
|
||||
</MatrixClientContext.Provider>
|
||||
));
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
|
||||
await screen.findByRole("progressbar");
|
||||
await screen.findByText("Potato");
|
||||
|
@ -244,7 +260,7 @@ describe("<RoomSearchView/>", () => {
|
|||
it("should handle resolutions after unmounting sanely", async () => {
|
||||
const deferred = defer<ISearchResults>();
|
||||
|
||||
const { unmount } = render((
|
||||
const { unmount } = render(
|
||||
<MatrixClientContext.Provider value={client}>
|
||||
<RoomSearchView
|
||||
term="search term"
|
||||
|
@ -255,8 +271,8 @@ describe("<RoomSearchView/>", () => {
|
|||
className="someClass"
|
||||
onUpdate={jest.fn()}
|
||||
/>
|
||||
</MatrixClientContext.Provider>
|
||||
));
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
|
||||
unmount();
|
||||
deferred.resolve({
|
||||
|
@ -268,7 +284,7 @@ describe("<RoomSearchView/>", () => {
|
|||
it("should handle rejections after unmounting sanely", async () => {
|
||||
const deferred = defer<ISearchResults>();
|
||||
|
||||
const { unmount } = render((
|
||||
const { unmount } = render(
|
||||
<MatrixClientContext.Provider value={client}>
|
||||
<RoomSearchView
|
||||
term="search term"
|
||||
|
@ -279,8 +295,8 @@ describe("<RoomSearchView/>", () => {
|
|||
className="someClass"
|
||||
onUpdate={jest.fn()}
|
||||
/>
|
||||
</MatrixClientContext.Provider>
|
||||
));
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
|
||||
unmount();
|
||||
deferred.reject({
|
||||
|
@ -292,7 +308,7 @@ describe("<RoomSearchView/>", () => {
|
|||
it("should show modal if error is encountered", async () => {
|
||||
const deferred = defer<ISearchResults>();
|
||||
|
||||
render((
|
||||
render(
|
||||
<MatrixClientContext.Provider value={client}>
|
||||
<RoomSearchView
|
||||
term="search term"
|
||||
|
@ -303,8 +319,8 @@ describe("<RoomSearchView/>", () => {
|
|||
className="someClass"
|
||||
onUpdate={jest.fn()}
|
||||
/>
|
||||
</MatrixClientContext.Provider>
|
||||
));
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
deferred.reject(new Error("Some error"));
|
||||
|
||||
await screen.findByText("Search failed");
|
||||
|
|
|
@ -85,7 +85,7 @@ describe("RoomStatusBar", () => {
|
|||
expect(pendingEvents[2].threadRootId).toBe(rootEvent.getId());
|
||||
|
||||
// Filters out the non thread events
|
||||
expect(pendingEvents.every(ev => ev.getId() !== event.getId())).toBe(true);
|
||||
expect(pendingEvents.every((ev) => ev.getId() !== event.getId())).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -24,7 +24,7 @@ describe("RoomStatusBarUnsentMessages", () => {
|
|||
const title = "test title";
|
||||
const description = "test description";
|
||||
const buttonsText = "test buttons";
|
||||
const buttons = <div>{ buttonsText }</div>;
|
||||
const buttons = <div>{buttonsText}</div>;
|
||||
|
||||
beforeEach(() => {
|
||||
render(
|
||||
|
|
|
@ -75,7 +75,7 @@ describe("RoomView", () => {
|
|||
stores.client = cli;
|
||||
stores.rightPanelStore.useUnitTestClient(cli);
|
||||
|
||||
jest.spyOn(VoipUserMapper.sharedInstance(), 'getVirtualRoomForRoom').mockResolvedValue(null);
|
||||
jest.spyOn(VoipUserMapper.sharedInstance(), "getVirtualRoomForRoom").mockResolvedValue(null);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
|
@ -85,7 +85,7 @@ describe("RoomView", () => {
|
|||
|
||||
const mountRoomView = async (): Promise<ReactWrapper> => {
|
||||
if (stores.roomViewStore.getRoomId() !== room.roomId) {
|
||||
const switchedRoom = new Promise<void>(resolve => {
|
||||
const switchedRoom = new Promise<void>((resolve) => {
|
||||
const subFn = () => {
|
||||
if (stores.roomViewStore.getRoomId()) {
|
||||
stores.roomViewStore.off(UPDATE_EVENT, subFn);
|
||||
|
@ -121,7 +121,7 @@ describe("RoomView", () => {
|
|||
|
||||
const renderRoomView = async (): Promise<ReturnType<typeof render>> => {
|
||||
if (stores.roomViewStore.getRoomId() !== room.roomId) {
|
||||
const switchedRoom = new Promise<void>(resolve => {
|
||||
const switchedRoom = new Promise<void>((resolve) => {
|
||||
const subFn = () => {
|
||||
if (stores.roomViewStore.getRoomId()) {
|
||||
stores.roomViewStore.off(UPDATE_EVENT, subFn);
|
||||
|
@ -180,13 +180,15 @@ describe("RoomView", () => {
|
|||
cli.isRoomEncrypted.mockReturnValue(true);
|
||||
|
||||
// and fake an encryption event into the room to prompt it to re-check
|
||||
room.addLiveEvents([new MatrixEvent({
|
||||
type: "m.room.encryption",
|
||||
sender: cli.getUserId()!,
|
||||
content: {},
|
||||
event_id: "someid",
|
||||
room_id: room.roomId,
|
||||
})]);
|
||||
room.addLiveEvents([
|
||||
new MatrixEvent({
|
||||
type: "m.room.encryption",
|
||||
sender: cli.getUserId()!,
|
||||
content: {},
|
||||
event_id: "someid",
|
||||
room_id: room.roomId,
|
||||
}),
|
||||
]);
|
||||
|
||||
// URL previews should now be disabled
|
||||
expect(roomViewInstance.state.showUrlPreview).toBe(false);
|
||||
|
@ -200,13 +202,13 @@ describe("RoomView", () => {
|
|||
expect(roomViewInstance.state.liveTimeline).not.toEqual(oldTimeline);
|
||||
});
|
||||
|
||||
describe('with virtual rooms', () => {
|
||||
describe("with virtual rooms", () => {
|
||||
it("checks for a virtual room on initial load", async () => {
|
||||
const { container } = await renderRoomView();
|
||||
expect(VoipUserMapper.sharedInstance().getVirtualRoomForRoom).toHaveBeenCalledWith(room.roomId);
|
||||
|
||||
// quick check that rendered without error
|
||||
expect(container.querySelector('.mx_ErrorBoundary')).toBeFalsy();
|
||||
expect(container.querySelector(".mx_ErrorBoundary")).toBeFalsy();
|
||||
});
|
||||
|
||||
it("checks for a virtual room on room event", async () => {
|
||||
|
@ -307,7 +309,7 @@ describe("RoomView", () => {
|
|||
it("clicking retry should set the room state to new dispatch a local room event", async () => {
|
||||
jest.spyOn(defaultDispatcher, "dispatch");
|
||||
const { getByText } = await renderRoomView();
|
||||
fireEvent.click(getByText('Retry'));
|
||||
fireEvent.click(getByText("Retry"));
|
||||
expect(localRoom.state).toBe(LocalRoomState.NEW);
|
||||
expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({
|
||||
action: "local_room_event",
|
||||
|
|
|
@ -53,17 +53,17 @@ describe("SpaceHierarchy", () => {
|
|||
it("shows room", () => {
|
||||
showRoom(client, hierarchy, "room-id2");
|
||||
expect(dispatcher.dispatch).toHaveBeenCalledWith({
|
||||
"action": Action.ViewRoom,
|
||||
"should_peek": true,
|
||||
"room_alias": "canonical-alias",
|
||||
"room_id": "room-id2",
|
||||
"via_servers": [],
|
||||
"oob_data": {
|
||||
action: Action.ViewRoom,
|
||||
should_peek: true,
|
||||
room_alias: "canonical-alias",
|
||||
room_id: "room-id2",
|
||||
via_servers: [],
|
||||
oob_data: {
|
||||
avatarUrl: undefined,
|
||||
name: "canonical-alias",
|
||||
},
|
||||
"roomType": undefined,
|
||||
"metricsTrigger": "RoomDirectory",
|
||||
roomType: undefined,
|
||||
metricsTrigger: "RoomDirectory",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,31 +14,16 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { act } from "react-dom/test-utils";
|
||||
|
||||
import TabbedView, { Tab, TabLocation } from "../../../src/components/structures/TabbedView";
|
||||
|
||||
describe('<TabbedView />', () => {
|
||||
const generalTab = new Tab(
|
||||
'GENERAL',
|
||||
'General',
|
||||
'general',
|
||||
<div>general</div>,
|
||||
);
|
||||
const labsTab = new Tab(
|
||||
'LABS',
|
||||
'Labs',
|
||||
'labs',
|
||||
<div>labs</div>,
|
||||
);
|
||||
const securityTab = new Tab(
|
||||
'SECURITY',
|
||||
'Security',
|
||||
'security',
|
||||
<div>security</div>,
|
||||
);
|
||||
describe("<TabbedView />", () => {
|
||||
const generalTab = new Tab("GENERAL", "General", "general", <div>general</div>);
|
||||
const labsTab = new Tab("LABS", "Labs", "labs", <div>labs</div>);
|
||||
const securityTab = new Tab("SECURITY", "Security", "security", <div>security</div>);
|
||||
const defaultProps = {
|
||||
tabLocation: TabLocation.LEFT,
|
||||
tabs: [generalTab, labsTab, securityTab],
|
||||
|
@ -47,39 +32,39 @@ describe('<TabbedView />', () => {
|
|||
|
||||
const getTabTestId = (tab: Tab): string => `settings-tab-${tab.id}`;
|
||||
const getActiveTab = (container: HTMLElement): Element | undefined =>
|
||||
container.getElementsByClassName('mx_TabbedView_tabLabel_active')[0];
|
||||
container.getElementsByClassName("mx_TabbedView_tabLabel_active")[0];
|
||||
const getActiveTabBody = (container: HTMLElement): Element | undefined =>
|
||||
container.getElementsByClassName('mx_TabbedView_tabPanel')[0];
|
||||
container.getElementsByClassName("mx_TabbedView_tabPanel")[0];
|
||||
|
||||
it('renders tabs', () => {
|
||||
it("renders tabs", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders first tab as active tab when no initialTabId', () => {
|
||||
it("renders first tab as active tab when no initialTabId", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(getActiveTab(container).textContent).toEqual(generalTab.label);
|
||||
expect(getActiveTabBody(container).textContent).toEqual('general');
|
||||
expect(getActiveTabBody(container).textContent).toEqual("general");
|
||||
});
|
||||
|
||||
it('renders first tab as active tab when initialTabId is not valid', () => {
|
||||
const { container } = render(getComponent({ initialTabId: 'bad-tab-id' }));
|
||||
it("renders first tab as active tab when initialTabId is not valid", () => {
|
||||
const { container } = render(getComponent({ initialTabId: "bad-tab-id" }));
|
||||
expect(getActiveTab(container).textContent).toEqual(generalTab.label);
|
||||
expect(getActiveTabBody(container).textContent).toEqual('general');
|
||||
expect(getActiveTabBody(container).textContent).toEqual("general");
|
||||
});
|
||||
|
||||
it('renders initialTabId tab as active when valid', () => {
|
||||
it("renders initialTabId tab as active when valid", () => {
|
||||
const { container } = render(getComponent({ initialTabId: securityTab.id }));
|
||||
expect(getActiveTab(container).textContent).toEqual(securityTab.label);
|
||||
expect(getActiveTabBody(container).textContent).toEqual('security');
|
||||
expect(getActiveTabBody(container).textContent).toEqual("security");
|
||||
});
|
||||
|
||||
it('renders without error when there are no tabs', () => {
|
||||
it("renders without error when there are no tabs", () => {
|
||||
const { container } = render(getComponent({ tabs: [] }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('sets active tab on tab click', () => {
|
||||
it("sets active tab on tab click", () => {
|
||||
const { container, getByTestId } = render(getComponent());
|
||||
|
||||
act(() => {
|
||||
|
@ -87,10 +72,10 @@ describe('<TabbedView />', () => {
|
|||
});
|
||||
|
||||
expect(getActiveTab(container).textContent).toEqual(securityTab.label);
|
||||
expect(getActiveTabBody(container).textContent).toEqual('security');
|
||||
expect(getActiveTabBody(container).textContent).toEqual("security");
|
||||
});
|
||||
|
||||
it('calls onchange on on tab click', () => {
|
||||
it("calls onchange on on tab click", () => {
|
||||
const onChange = jest.fn();
|
||||
const { getByTestId } = render(getComponent({ onChange }));
|
||||
|
||||
|
@ -101,7 +86,7 @@ describe('<TabbedView />', () => {
|
|||
expect(onChange).toHaveBeenCalledWith(securityTab.id);
|
||||
});
|
||||
|
||||
it('keeps same tab active when order of tabs changes', () => {
|
||||
it("keeps same tab active when order of tabs changes", () => {
|
||||
// start with middle tab active
|
||||
const { container, rerender } = render(getComponent({ initialTabId: labsTab.id }));
|
||||
|
||||
|
@ -113,7 +98,7 @@ describe('<TabbedView />', () => {
|
|||
expect(getActiveTab(container).textContent).toEqual(labsTab.label);
|
||||
});
|
||||
|
||||
it('does not reactivate inititalTabId on rerender', () => {
|
||||
it("does not reactivate inititalTabId on rerender", () => {
|
||||
const { container, getByTestId, rerender } = render(getComponent());
|
||||
|
||||
expect(getActiveTab(container).textContent).toEqual(generalTab.label);
|
||||
|
|
|
@ -14,22 +14,22 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import { mocked } from "jest-mock";
|
||||
import 'focus-visible'; // to fix context menus
|
||||
import "focus-visible"; // to fix context menus
|
||||
|
||||
import ThreadPanel, { ThreadFilterType, ThreadPanelHeader } from '../../../src/components/structures/ThreadPanel';
|
||||
import { _t } from '../../../src/languageHandler';
|
||||
import ResizeNotifier from '../../../src/utils/ResizeNotifier';
|
||||
import { RoomPermalinkCreator } from '../../../src/utils/permalinks/Permalinks';
|
||||
import { createTestClient, mkStubRoom } from '../../test-utils';
|
||||
import ThreadPanel, { ThreadFilterType, ThreadPanelHeader } from "../../../src/components/structures/ThreadPanel";
|
||||
import { _t } from "../../../src/languageHandler";
|
||||
import ResizeNotifier from "../../../src/utils/ResizeNotifier";
|
||||
import { RoomPermalinkCreator } from "../../../src/utils/permalinks/Permalinks";
|
||||
import { createTestClient, mkStubRoom } from "../../test-utils";
|
||||
import { shouldShowFeedback } from "../../../src/utils/Feedback";
|
||||
import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
|
||||
|
||||
jest.mock("../../../src/utils/Feedback");
|
||||
|
||||
describe('ThreadPanel', () => {
|
||||
describe("ThreadPanel", () => {
|
||||
describe("Feedback prompt", () => {
|
||||
const cli = createTestClient();
|
||||
const room = mkStubRoom("!room:server", "room", cli);
|
||||
|
@ -38,59 +38,66 @@ describe('ThreadPanel', () => {
|
|||
it("should show feedback prompt if feedback is enabled", () => {
|
||||
mocked(shouldShowFeedback).mockReturnValue(true);
|
||||
|
||||
render(<MatrixClientContext.Provider value={cli}>
|
||||
<ThreadPanel
|
||||
roomId="!room:server"
|
||||
onClose={jest.fn()}
|
||||
resizeNotifier={new ResizeNotifier()}
|
||||
permalinkCreator={new RoomPermalinkCreator(room)}
|
||||
/>
|
||||
</MatrixClientContext.Provider>);
|
||||
render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<ThreadPanel
|
||||
roomId="!room:server"
|
||||
onClose={jest.fn()}
|
||||
resizeNotifier={new ResizeNotifier()}
|
||||
permalinkCreator={new RoomPermalinkCreator(room)}
|
||||
/>
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
expect(screen.queryByText("Give feedback")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should hide feedback prompt if feedback is disabled", () => {
|
||||
mocked(shouldShowFeedback).mockReturnValue(false);
|
||||
|
||||
render(<MatrixClientContext.Provider value={cli}>
|
||||
<ThreadPanel
|
||||
roomId="!room:server"
|
||||
onClose={jest.fn()}
|
||||
resizeNotifier={new ResizeNotifier()}
|
||||
permalinkCreator={new RoomPermalinkCreator(room)}
|
||||
/>
|
||||
</MatrixClientContext.Provider>);
|
||||
render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<ThreadPanel
|
||||
roomId="!room:server"
|
||||
onClose={jest.fn()}
|
||||
resizeNotifier={new ResizeNotifier()}
|
||||
permalinkCreator={new RoomPermalinkCreator(room)}
|
||||
/>
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
expect(screen.queryByText("Give feedback")).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Header', () => {
|
||||
it('expect that All filter for ThreadPanelHeader properly renders Show: All threads', () => {
|
||||
describe("Header", () => {
|
||||
it("expect that All filter for ThreadPanelHeader properly renders Show: All threads", () => {
|
||||
const { asFragment } = render(
|
||||
<ThreadPanelHeader
|
||||
empty={false}
|
||||
filterOption={ThreadFilterType.All}
|
||||
setFilterOption={() => undefined} />,
|
||||
setFilterOption={() => undefined}
|
||||
/>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('expect that My filter for ThreadPanelHeader properly renders Show: My threads', () => {
|
||||
it("expect that My filter for ThreadPanelHeader properly renders Show: My threads", () => {
|
||||
const { asFragment } = render(
|
||||
<ThreadPanelHeader
|
||||
empty={false}
|
||||
filterOption={ThreadFilterType.My}
|
||||
setFilterOption={() => undefined} />,
|
||||
setFilterOption={() => undefined}
|
||||
/>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('expect that ThreadPanelHeader properly opens a context menu when clicked on the button', () => {
|
||||
it("expect that ThreadPanelHeader properly opens a context menu when clicked on the button", () => {
|
||||
const { container } = render(
|
||||
<ThreadPanelHeader
|
||||
empty={false}
|
||||
filterOption={ThreadFilterType.All}
|
||||
setFilterOption={() => undefined} />,
|
||||
setFilterOption={() => undefined}
|
||||
/>,
|
||||
);
|
||||
const found = container.querySelector(".mx_ThreadPanel_dropdown");
|
||||
expect(found).toBeTruthy();
|
||||
|
@ -99,18 +106,19 @@ describe('ThreadPanel', () => {
|
|||
expect(screen.queryByRole("menu")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('expect that ThreadPanelHeader has the correct option selected in the context menu', () => {
|
||||
it("expect that ThreadPanelHeader has the correct option selected in the context menu", () => {
|
||||
const { container } = render(
|
||||
<ThreadPanelHeader
|
||||
empty={false}
|
||||
filterOption={ThreadFilterType.All}
|
||||
setFilterOption={() => undefined} />,
|
||||
setFilterOption={() => undefined}
|
||||
/>,
|
||||
);
|
||||
fireEvent.click(container.querySelector(".mx_ThreadPanel_dropdown"));
|
||||
const found = screen.queryAllByRole("menuitemradio");
|
||||
expect(found).toHaveLength(2);
|
||||
const foundButton = screen.queryByRole("menuitemradio", { checked: true });
|
||||
expect(foundButton.textContent).toEqual(`${_t("All threads")}${_t('Shows all threads from current room')}`);
|
||||
expect(foundButton.textContent).toEqual(`${_t("All threads")}${_t("Shows all threads from current room")}`);
|
||||
expect(foundButton).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -51,27 +51,25 @@ describe("ThreadView", () => {
|
|||
const [event, setEvent] = useState(rootEvent);
|
||||
changeEvent = setEvent;
|
||||
|
||||
return <MatrixClientContext.Provider value={mockClient}>
|
||||
<RoomContext.Provider value={getRoomContext(room, {
|
||||
canSendMessages: true,
|
||||
})}>
|
||||
<ThreadView
|
||||
room={room}
|
||||
onClose={jest.fn()}
|
||||
mxEvent={event}
|
||||
resizeNotifier={new ResizeNotifier()}
|
||||
/>
|
||||
</RoomContext.Provider>,
|
||||
</MatrixClientContext.Provider>;
|
||||
return (
|
||||
<MatrixClientContext.Provider value={mockClient}>
|
||||
<RoomContext.Provider
|
||||
value={getRoomContext(room, {
|
||||
canSendMessages: true,
|
||||
})}
|
||||
>
|
||||
<ThreadView room={room} onClose={jest.fn()} mxEvent={event} resizeNotifier={new ResizeNotifier()} />
|
||||
</RoomContext.Provider>
|
||||
,
|
||||
</MatrixClientContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
async function getComponent(): Promise<RenderResult> {
|
||||
const renderResult = render(
|
||||
<TestThreadView />,
|
||||
);
|
||||
const renderResult = render(<TestThreadView />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(() => getByTestId(renderResult.container, 'spinner')).toThrow();
|
||||
expect(() => getByTestId(renderResult.container, "spinner")).toThrow();
|
||||
});
|
||||
|
||||
return renderResult;
|
||||
|
@ -92,9 +90,12 @@ describe("ThreadView", () => {
|
|||
"event_id": rootEvent.getId(),
|
||||
"is_falling_back": true,
|
||||
"m.in_reply_to": {
|
||||
"event_id": rootEvent.getThread().lastReply((ev: MatrixEvent) => {
|
||||
return ev.isRelation(THREAD_RELATION_TYPE.name);
|
||||
}).getId(),
|
||||
event_id: rootEvent
|
||||
.getThread()
|
||||
.lastReply((ev: MatrixEvent) => {
|
||||
return ev.isRelation(THREAD_RELATION_TYPE.name);
|
||||
})
|
||||
.getId(),
|
||||
},
|
||||
"rel_type": RelationType.Thread,
|
||||
},
|
||||
|
@ -133,7 +134,9 @@ describe("ThreadView", () => {
|
|||
await sendMessage(container, "Hello world!");
|
||||
|
||||
expect(mockClient.sendMessage).toHaveBeenCalledWith(
|
||||
ROOM_ID, rootEvent.getId(), expectedMessageBody(rootEvent, "Hello world!"),
|
||||
ROOM_ID,
|
||||
rootEvent.getId(),
|
||||
expectedMessageBody(rootEvent, "Hello world!"),
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -154,7 +157,9 @@ describe("ThreadView", () => {
|
|||
await sendMessage(container, "yolo");
|
||||
|
||||
expect(mockClient.sendMessage).toHaveBeenCalledWith(
|
||||
ROOM_ID, rootEvent2.getId(), expectedMessageBody(rootEvent2, "yolo"),
|
||||
ROOM_ID,
|
||||
rootEvent2.getId(),
|
||||
expectedMessageBody(rootEvent2, "yolo"),
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||
import { render, RenderResult } from "@testing-library/react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { MessageEvent } from 'matrix-events-sdk';
|
||||
import { MessageEvent } from "matrix-events-sdk";
|
||||
import { ReceiptType } from "matrix-js-sdk/src/@types/read_receipts";
|
||||
import {
|
||||
EventTimelineSet,
|
||||
|
@ -28,7 +28,7 @@ import {
|
|||
Room,
|
||||
RoomEvent,
|
||||
TimelineWindow,
|
||||
} from 'matrix-js-sdk/src/matrix';
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { EventTimeline } from "matrix-js-sdk/src/models/event-timeline";
|
||||
import {
|
||||
FeatureSupport,
|
||||
|
@ -37,13 +37,13 @@ import {
|
|||
ThreadEvent,
|
||||
ThreadFilterType,
|
||||
} from "matrix-js-sdk/src/models/thread";
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
|
||||
import TimelinePanel from '../../../src/components/structures/TimelinePanel';
|
||||
import TimelinePanel from "../../../src/components/structures/TimelinePanel";
|
||||
import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
|
||||
import { MatrixClientPeg } from '../../../src/MatrixClientPeg';
|
||||
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
||||
import SettingsStore from "../../../src/settings/SettingsStore";
|
||||
import { isCallEvent } from '../../../src/components/structures/LegacyCallEventGrouper';
|
||||
import { isCallEvent } from "../../../src/components/structures/LegacyCallEventGrouper";
|
||||
import { flushPromises, mkRoom, stubClient } from "../../test-utils";
|
||||
|
||||
const newReceipt = (eventId: string, userId: string, readTs: number, fullyReadTs: number): MatrixEvent => {
|
||||
|
@ -81,13 +81,15 @@ const renderPanel = (room: Room, events: MatrixEvent[]): RenderResult => {
|
|||
const mockEvents = (room: Room, count = 2): MatrixEvent[] => {
|
||||
const events: MatrixEvent[] = [];
|
||||
for (let index = 0; index < count; index++) {
|
||||
events.push(new MatrixEvent({
|
||||
room_id: room.roomId,
|
||||
event_id: `${room.roomId}_event_${index}`,
|
||||
type: EventType.RoomMessage,
|
||||
user_id: "userId",
|
||||
content: MessageEvent.from(`Event${index}`).serialize().content,
|
||||
}));
|
||||
events.push(
|
||||
new MatrixEvent({
|
||||
room_id: room.roomId,
|
||||
event_id: `${room.roomId}_event_${index}`,
|
||||
type: EventType.RoomMessage,
|
||||
user_id: "userId",
|
||||
content: MessageEvent.from(`Event${index}`).serialize().content,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return events;
|
||||
|
@ -100,13 +102,13 @@ const setupTestData = (): [MatrixClient, Room, MatrixEvent[]] => {
|
|||
return [client, room, events];
|
||||
};
|
||||
|
||||
describe('TimelinePanel', () => {
|
||||
describe("TimelinePanel", () => {
|
||||
beforeEach(() => {
|
||||
stubClient();
|
||||
});
|
||||
|
||||
describe('read receipts and markers', () => {
|
||||
it('should forget the read marker when asked to', () => {
|
||||
describe("read receipts and markers", () => {
|
||||
it("should forget the read marker when asked to", () => {
|
||||
const cli = MatrixClientPeg.get();
|
||||
const readMarkersSent: string[] = [];
|
||||
|
||||
|
@ -131,22 +133,19 @@ describe('TimelinePanel', () => {
|
|||
|
||||
const roomId = "#room:example.com";
|
||||
const userId = cli.credentials.userId!;
|
||||
const room = new Room(
|
||||
roomId,
|
||||
cli,
|
||||
userId,
|
||||
{ pendingEventOrdering: PendingEventOrdering.Detached },
|
||||
);
|
||||
const room = new Room(roomId, cli, userId, { pendingEventOrdering: PendingEventOrdering.Detached });
|
||||
|
||||
// Create a TimelinePanel with ev0 already present
|
||||
const timelineSet = new EventTimelineSet(room, {});
|
||||
timelineSet.addLiveEvent(ev0);
|
||||
const component: ReactWrapper<TimelinePanel> = mount(<TimelinePanel
|
||||
timelineSet={timelineSet}
|
||||
manageReadMarkers={true}
|
||||
manageReadReceipts={true}
|
||||
eventId={ev0.getId()}
|
||||
/>);
|
||||
const component: ReactWrapper<TimelinePanel> = mount(
|
||||
<TimelinePanel
|
||||
timelineSet={timelineSet}
|
||||
manageReadMarkers={true}
|
||||
manageReadReceipts={true}
|
||||
eventId={ev0.getId()}
|
||||
/>,
|
||||
);
|
||||
const timelinePanel = component.instance() as TimelinePanel;
|
||||
|
||||
// An event arrived, and we read it
|
||||
|
@ -208,8 +207,8 @@ describe('TimelinePanel', () => {
|
|||
expect(props.onEventScrolledIntoView).toHaveBeenCalledWith(events[1].getId());
|
||||
});
|
||||
|
||||
describe('onRoomTimeline', () => {
|
||||
it('ignores events for other timelines', () => {
|
||||
describe("onRoomTimeline", () => {
|
||||
it("ignores events for other timelines", () => {
|
||||
const [client, room, events] = setupTestData();
|
||||
|
||||
const otherTimelineSet = { room: room as Room } as EventTimelineSet;
|
||||
|
@ -220,7 +219,7 @@ describe('TimelinePanel', () => {
|
|||
onEventScrolledIntoView: jest.fn(),
|
||||
};
|
||||
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, 'paginate').mockClear();
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, "paginate").mockClear();
|
||||
|
||||
render(<TimelinePanel {...props} />);
|
||||
|
||||
|
@ -231,12 +230,12 @@ describe('TimelinePanel', () => {
|
|||
expect(paginateSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('ignores timeline updates without a live event', () => {
|
||||
it("ignores timeline updates without a live event", () => {
|
||||
const [client, room, events] = setupTestData();
|
||||
|
||||
const props = getProps(room, events);
|
||||
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, 'paginate').mockClear();
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, "paginate").mockClear();
|
||||
|
||||
render(<TimelinePanel {...props} />);
|
||||
|
||||
|
@ -247,12 +246,12 @@ describe('TimelinePanel', () => {
|
|||
expect(paginateSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('ignores timeline where toStartOfTimeline is true', () => {
|
||||
it("ignores timeline where toStartOfTimeline is true", () => {
|
||||
const [client, room, events] = setupTestData();
|
||||
|
||||
const props = getProps(room, events);
|
||||
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, 'paginate').mockClear();
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, "paginate").mockClear();
|
||||
|
||||
render(<TimelinePanel {...props} />);
|
||||
|
||||
|
@ -264,12 +263,12 @@ describe('TimelinePanel', () => {
|
|||
expect(paginateSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('advances the timeline window', () => {
|
||||
it("advances the timeline window", () => {
|
||||
const [client, room, events] = setupTestData();
|
||||
|
||||
const props = getProps(room, events);
|
||||
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, 'paginate').mockClear();
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, "paginate").mockClear();
|
||||
|
||||
render(<TimelinePanel {...props} />);
|
||||
|
||||
|
@ -280,7 +279,7 @@ describe('TimelinePanel', () => {
|
|||
expect(paginateSpy).toHaveBeenCalledWith(EventTimeline.FORWARDS, 1, false);
|
||||
});
|
||||
|
||||
it('advances the overlay timeline window', async () => {
|
||||
it("advances the overlay timeline window", async () => {
|
||||
const [client, room, events] = setupTestData();
|
||||
|
||||
const virtualRoom = mkRoom(client, "virtualRoomId");
|
||||
|
@ -292,7 +291,7 @@ describe('TimelinePanel', () => {
|
|||
overlayTimelineSet,
|
||||
};
|
||||
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, 'paginate').mockClear();
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, "paginate").mockClear();
|
||||
|
||||
render(<TimelinePanel {...props} />);
|
||||
|
||||
|
@ -306,25 +305,21 @@ describe('TimelinePanel', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('with overlayTimeline', () => {
|
||||
it('renders merged timeline', () => {
|
||||
describe("with overlayTimeline", () => {
|
||||
it("renders merged timeline", () => {
|
||||
const [client, room, events] = setupTestData();
|
||||
const virtualRoom = mkRoom(client, "virtualRoomId");
|
||||
const virtualCallInvite = new MatrixEvent({
|
||||
type: 'm.call.invite',
|
||||
type: "m.call.invite",
|
||||
room_id: virtualRoom.roomId,
|
||||
event_id: `virtualCallEvent1`,
|
||||
});
|
||||
const virtualCallMetaEvent = new MatrixEvent({
|
||||
type: 'org.matrix.call.sdp_stream_metadata_changed',
|
||||
type: "org.matrix.call.sdp_stream_metadata_changed",
|
||||
room_id: virtualRoom.roomId,
|
||||
event_id: `virtualCallEvent2`,
|
||||
});
|
||||
const virtualEvents = [
|
||||
virtualCallInvite,
|
||||
...mockEvents(virtualRoom),
|
||||
virtualCallMetaEvent,
|
||||
];
|
||||
const virtualEvents = [virtualCallInvite, ...mockEvents(virtualRoom), virtualCallMetaEvent];
|
||||
const { timelineSet: overlayTimelineSet } = getProps(virtualRoom, virtualEvents);
|
||||
|
||||
const props = {
|
||||
|
@ -335,8 +330,8 @@ describe('TimelinePanel', () => {
|
|||
|
||||
const { container } = render(<TimelinePanel {...props} />);
|
||||
|
||||
const eventTiles = container.querySelectorAll('.mx_EventTile');
|
||||
const eventTileIds = [...eventTiles].map(tileElement => tileElement.getAttribute('data-event-id'));
|
||||
const eventTiles = container.querySelectorAll(".mx_EventTile");
|
||||
const eventTileIds = [...eventTiles].map((tileElement) => tileElement.getAttribute("data-event-id"));
|
||||
expect(eventTileIds).toEqual([
|
||||
// main timeline events are included
|
||||
events[1].getId(),
|
||||
|
@ -368,16 +363,22 @@ describe('TimelinePanel', () => {
|
|||
});
|
||||
|
||||
room = new Room("roomId", client, "userId");
|
||||
allThreads = new EventTimelineSet(room, {
|
||||
pendingEvents: false,
|
||||
}, undefined, undefined, ThreadFilterType.All);
|
||||
allThreads = new EventTimelineSet(
|
||||
room,
|
||||
{
|
||||
pendingEvents: false,
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
ThreadFilterType.All,
|
||||
);
|
||||
const timeline = new EventTimeline(allThreads);
|
||||
allThreads.getLiveTimeline = () => timeline;
|
||||
allThreads.getTimelineForEvent = () => timeline;
|
||||
|
||||
reply1 = new MatrixEvent({
|
||||
room_id: room.roomId,
|
||||
event_id: 'event_reply_1',
|
||||
event_id: "event_reply_1",
|
||||
type: EventType.RoomMessage,
|
||||
user_id: "userId",
|
||||
content: MessageEvent.from(`ReplyEvent1`).serialize().content,
|
||||
|
@ -385,7 +386,7 @@ describe('TimelinePanel', () => {
|
|||
|
||||
reply2 = new MatrixEvent({
|
||||
room_id: room.roomId,
|
||||
event_id: 'event_reply_2',
|
||||
event_id: "event_reply_2",
|
||||
type: EventType.RoomMessage,
|
||||
user_id: "userId",
|
||||
content: MessageEvent.from(`ReplyEvent2`).serialize().content,
|
||||
|
@ -393,7 +394,7 @@ describe('TimelinePanel', () => {
|
|||
|
||||
root = new MatrixEvent({
|
||||
room_id: room.roomId,
|
||||
event_id: 'event_root_1',
|
||||
event_id: "event_root_1",
|
||||
type: EventType.RoomMessage,
|
||||
user_id: "userId",
|
||||
content: MessageEvent.from(`RootEvent`).serialize().content,
|
||||
|
@ -410,13 +411,13 @@ describe('TimelinePanel', () => {
|
|||
roomId === room.roomId ? eventMap[eventId]?.event : {};
|
||||
});
|
||||
|
||||
it('updates thread previews', async () => {
|
||||
it("updates thread previews", async () => {
|
||||
root.setUnsigned({
|
||||
"m.relations": {
|
||||
[THREAD_RELATION_TYPE.name]: {
|
||||
"latest_event": reply1.event,
|
||||
"count": 1,
|
||||
"current_user_participated": true,
|
||||
latest_event: reply1.event,
|
||||
count: 1,
|
||||
current_user_participated: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -432,11 +433,7 @@ describe('TimelinePanel', () => {
|
|||
|
||||
const dom = render(
|
||||
<MatrixClientContext.Provider value={client}>
|
||||
<TimelinePanel
|
||||
timelineSet={allThreads}
|
||||
manageReadReceipts
|
||||
sendReadReceiptOnLoad
|
||||
/>
|
||||
<TimelinePanel timelineSet={allThreads} manageReadReceipts sendReadReceiptOnLoad />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await dom.findByText("RootEvent");
|
||||
|
@ -446,9 +443,9 @@ describe('TimelinePanel', () => {
|
|||
root.setUnsigned({
|
||||
"m.relations": {
|
||||
[THREAD_RELATION_TYPE.name]: {
|
||||
"latest_event": reply2.event,
|
||||
"count": 2,
|
||||
"current_user_participated": true,
|
||||
latest_event: reply2.event,
|
||||
count: 2,
|
||||
current_user_participated: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -460,13 +457,13 @@ describe('TimelinePanel', () => {
|
|||
expect(replyToEvent).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('ignores thread updates for unknown threads', async () => {
|
||||
it("ignores thread updates for unknown threads", async () => {
|
||||
root.setUnsigned({
|
||||
"m.relations": {
|
||||
[THREAD_RELATION_TYPE.name]: {
|
||||
"latest_event": reply1.event,
|
||||
"count": 1,
|
||||
"current_user_participated": true,
|
||||
latest_event: reply1.event,
|
||||
count: 1,
|
||||
current_user_participated: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -499,11 +496,7 @@ describe('TimelinePanel', () => {
|
|||
|
||||
const dom = render(
|
||||
<MatrixClientContext.Provider value={client}>
|
||||
<TimelinePanel
|
||||
timelineSet={allThreads}
|
||||
manageReadReceipts
|
||||
sendReadReceiptOnLoad
|
||||
/>
|
||||
<TimelinePanel timelineSet={allThreads} manageReadReceipts sendReadReceiptOnLoad />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await dom.findByText("RootEvent");
|
||||
|
|
|
@ -42,10 +42,7 @@ describe("<UserMenu>", () => {
|
|||
client.getUserId() || "",
|
||||
client.getDeviceId() || "",
|
||||
);
|
||||
voiceBroadcastRecording = new VoiceBroadcastRecording(
|
||||
voiceBroadcastInfoEvent,
|
||||
client,
|
||||
);
|
||||
voiceBroadcastRecording = new VoiceBroadcastRecording(voiceBroadcastInfoEvent, client);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -100,11 +100,9 @@ describe("<ForgotPassword>", () => {
|
|||
|
||||
describe("when starting a password reset flow", () => {
|
||||
beforeEach(() => {
|
||||
renderResult = render(<ForgotPassword
|
||||
serverConfig={serverConfig}
|
||||
onComplete={onComplete}
|
||||
onLoginClick={onLoginClick}
|
||||
/>);
|
||||
renderResult = render(
|
||||
<ForgotPassword serverConfig={serverConfig} onComplete={onComplete} onLoginClick={onLoginClick} />,
|
||||
);
|
||||
});
|
||||
|
||||
it("should show the email input and mention the homeserver", () => {
|
||||
|
@ -115,11 +113,9 @@ describe("<ForgotPassword>", () => {
|
|||
describe("and updating the server config", () => {
|
||||
beforeEach(() => {
|
||||
serverConfig.hsName = "example2.com";
|
||||
renderResult.rerender(<ForgotPassword
|
||||
serverConfig={serverConfig}
|
||||
onComplete={onComplete}
|
||||
onLoginClick={onLoginClick}
|
||||
/>);
|
||||
renderResult.rerender(
|
||||
<ForgotPassword serverConfig={serverConfig} onComplete={onComplete} onLoginClick={onLoginClick} />,
|
||||
);
|
||||
});
|
||||
|
||||
it("should show the new homeserver server name", () => {
|
||||
|
@ -171,10 +167,12 @@ describe("<ForgotPassword>", () => {
|
|||
});
|
||||
|
||||
it("should show an info about that", () => {
|
||||
expect(screen.getByText(
|
||||
"Cannot reach homeserver: "
|
||||
+ "Ensure you have a stable internet connection, or get in touch with the server admin",
|
||||
)).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
"Cannot reach homeserver: " +
|
||||
"Ensure you have a stable internet connection, or get in touch with the server admin",
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -14,13 +14,13 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import { fireEvent, render, screen, waitForElementToBeRemoved } from "@testing-library/react";
|
||||
import { mocked, MockedObject } from 'jest-mock';
|
||||
import { mocked, MockedObject } from "jest-mock";
|
||||
import { createClient, MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import fetchMock from "fetch-mock-jest";
|
||||
|
||||
import SdkConfig from '../../../../src/SdkConfig';
|
||||
import SdkConfig from "../../../../src/SdkConfig";
|
||||
import { mkServerConfig, mockPlatformPeg, unmockPlatformPeg } from "../../../test-utils";
|
||||
import Login from "../../../../src/components/structures/auth/Login";
|
||||
import BasePlatform from "../../../../src/BasePlatform";
|
||||
|
@ -29,7 +29,7 @@ jest.mock("matrix-js-sdk/src/matrix");
|
|||
|
||||
jest.useRealTimers();
|
||||
|
||||
describe('Login', function() {
|
||||
describe("Login", function () {
|
||||
let platform: MockedObject<BasePlatform>;
|
||||
|
||||
const mockClient = mocked({
|
||||
|
@ -37,14 +37,14 @@ describe('Login', function() {
|
|||
loginFlows: jest.fn(),
|
||||
} as unknown as MatrixClient);
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
SdkConfig.put({
|
||||
brand: "test-brand",
|
||||
disable_custom_urls: true,
|
||||
});
|
||||
mockClient.login.mockClear().mockResolvedValue({});
|
||||
mockClient.loginFlows.mockClear().mockResolvedValue({ flows: [{ type: "m.login.password" }] });
|
||||
mocked(createClient).mockImplementation(opts => {
|
||||
mocked(createClient).mockImplementation((opts) => {
|
||||
mockClient.idBaseUrl = opts.idBaseUrl;
|
||||
mockClient.baseUrl = opts.baseUrl;
|
||||
return mockClient;
|
||||
|
@ -58,26 +58,28 @@ describe('Login', function() {
|
|||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
afterEach(function () {
|
||||
fetchMock.restore();
|
||||
SdkConfig.unset(); // we touch the config, so clean up
|
||||
unmockPlatformPeg();
|
||||
});
|
||||
|
||||
function getRawComponent(hsUrl = "https://matrix.org", isUrl = "https://vector.im") {
|
||||
return <Login
|
||||
serverConfig={mkServerConfig(hsUrl, isUrl)}
|
||||
onLoggedIn={() => { }}
|
||||
onRegisterClick={() => { }}
|
||||
onServerConfigChange={() => { }}
|
||||
/>;
|
||||
return (
|
||||
<Login
|
||||
serverConfig={mkServerConfig(hsUrl, isUrl)}
|
||||
onLoggedIn={() => {}}
|
||||
onRegisterClick={() => {}}
|
||||
onServerConfigChange={() => {}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function getComponent(hsUrl?: string, isUrl?: string) {
|
||||
return render(getRawComponent(hsUrl, isUrl));
|
||||
}
|
||||
|
||||
it('should show form with change server link', async () => {
|
||||
it("should show form with change server link", async () => {
|
||||
SdkConfig.put({
|
||||
brand: "test-brand",
|
||||
disable_custom_urls: false,
|
||||
|
@ -90,7 +92,7 @@ describe('Login', function() {
|
|||
expect(container.querySelector(".mx_ServerPicker_change")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show form without change server link when custom URLs disabled', async () => {
|
||||
it("should show form without change server link when custom URLs disabled", async () => {
|
||||
const { container } = getComponent();
|
||||
await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading..."));
|
||||
|
||||
|
@ -122,19 +124,25 @@ describe('Login', function() {
|
|||
|
||||
it("should show multiple SSO buttons if multiple identity_providers are available", async () => {
|
||||
mockClient.loginFlows.mockResolvedValue({
|
||||
flows: [{
|
||||
"type": "m.login.sso",
|
||||
"identity_providers": [{
|
||||
id: "a",
|
||||
name: "Provider 1",
|
||||
}, {
|
||||
id: "b",
|
||||
name: "Provider 2",
|
||||
}, {
|
||||
id: "c",
|
||||
name: "Provider 3",
|
||||
}],
|
||||
}],
|
||||
flows: [
|
||||
{
|
||||
type: "m.login.sso",
|
||||
identity_providers: [
|
||||
{
|
||||
id: "a",
|
||||
name: "Provider 1",
|
||||
},
|
||||
{
|
||||
id: "b",
|
||||
name: "Provider 2",
|
||||
},
|
||||
{
|
||||
id: "c",
|
||||
name: "Provider 3",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { container } = getComponent();
|
||||
|
@ -146,9 +154,11 @@ describe('Login', function() {
|
|||
|
||||
it("should show single SSO button if identity_providers is null", async () => {
|
||||
mockClient.loginFlows.mockResolvedValue({
|
||||
flows: [{
|
||||
"type": "m.login.sso",
|
||||
}],
|
||||
flows: [
|
||||
{
|
||||
type: "m.login.sso",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { container } = getComponent();
|
||||
|
@ -160,9 +170,11 @@ describe('Login', function() {
|
|||
|
||||
it("should handle serverConfig updates correctly", async () => {
|
||||
mockClient.loginFlows.mockResolvedValue({
|
||||
flows: [{
|
||||
"type": "m.login.sso",
|
||||
}],
|
||||
flows: [
|
||||
{
|
||||
type: "m.login.sso",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { container, rerender } = render(getRawComponent());
|
||||
|
|
|
@ -15,37 +15,42 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import { fireEvent, render, screen, waitForElementToBeRemoved } from "@testing-library/react";
|
||||
import { createClient, MatrixClient } from 'matrix-js-sdk/src/matrix';
|
||||
import { MatrixError } from 'matrix-js-sdk/src/http-api/errors';
|
||||
import { mocked } from 'jest-mock';
|
||||
import { createClient, MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { MatrixError } from "matrix-js-sdk/src/http-api/errors";
|
||||
import { mocked } from "jest-mock";
|
||||
import fetchMock from "fetch-mock-jest";
|
||||
|
||||
import SdkConfig, { DEFAULTS } from '../../../../src/SdkConfig';
|
||||
import SdkConfig, { DEFAULTS } from "../../../../src/SdkConfig";
|
||||
import { mkServerConfig, mockPlatformPeg, unmockPlatformPeg } from "../../../test-utils";
|
||||
import Registration from "../../../../src/components/structures/auth/Registration";
|
||||
|
||||
jest.mock('matrix-js-sdk/src/matrix');
|
||||
jest.mock("matrix-js-sdk/src/matrix");
|
||||
jest.useFakeTimers();
|
||||
|
||||
describe('Registration', function() {
|
||||
describe("Registration", function () {
|
||||
const registerRequest = jest.fn();
|
||||
const mockClient = mocked({
|
||||
registerRequest,
|
||||
loginFlows: jest.fn(),
|
||||
} as unknown as MatrixClient);
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
SdkConfig.put({
|
||||
...DEFAULTS,
|
||||
disable_custom_urls: true,
|
||||
});
|
||||
mockClient.registerRequest.mockRejectedValueOnce(new MatrixError({
|
||||
flows: [{ stages: [] }],
|
||||
}, 401));
|
||||
mockClient.registerRequest.mockRejectedValueOnce(
|
||||
new MatrixError(
|
||||
{
|
||||
flows: [{ stages: [] }],
|
||||
},
|
||||
401,
|
||||
),
|
||||
);
|
||||
mockClient.loginFlows.mockClear().mockResolvedValue({ flows: [{ type: "m.login.password" }] });
|
||||
mocked(createClient).mockImplementation(opts => {
|
||||
mocked(createClient).mockImplementation((opts) => {
|
||||
mockClient.idBaseUrl = opts.idBaseUrl;
|
||||
mockClient.baseUrl = opts.baseUrl;
|
||||
return mockClient;
|
||||
|
@ -59,14 +64,14 @@ describe('Registration', function() {
|
|||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
afterEach(function () {
|
||||
fetchMock.restore();
|
||||
SdkConfig.unset(); // we touch the config, so clean up
|
||||
unmockPlatformPeg();
|
||||
});
|
||||
|
||||
const defaultProps = {
|
||||
defaultDeviceDisplayName: 'test-device-display-name',
|
||||
defaultDeviceDisplayName: "test-device-display-name",
|
||||
makeRegistrationUrl: jest.fn(),
|
||||
onLoggedIn: jest.fn(),
|
||||
onLoginClick: jest.fn(),
|
||||
|
@ -74,22 +79,19 @@ describe('Registration', function() {
|
|||
};
|
||||
|
||||
function getRawComponent(hsUrl = "https://matrix.org", isUrl = "https://vector.im") {
|
||||
return <Registration
|
||||
{...defaultProps}
|
||||
serverConfig={mkServerConfig(hsUrl, isUrl)}
|
||||
/>;
|
||||
return <Registration {...defaultProps} serverConfig={mkServerConfig(hsUrl, isUrl)} />;
|
||||
}
|
||||
|
||||
function getComponent(hsUrl?: string, isUrl?: string) {
|
||||
return render(getRawComponent(hsUrl, isUrl));
|
||||
}
|
||||
|
||||
it('should show server picker', async function() {
|
||||
it("should show server picker", async function () {
|
||||
const { container } = getComponent();
|
||||
expect(container.querySelector(".mx_ServerPicker")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show form when custom URLs disabled', async function() {
|
||||
it("should show form when custom URLs disabled", async function () {
|
||||
const { container } = getComponent();
|
||||
await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading..."));
|
||||
expect(container.querySelector("form")).toBeTruthy();
|
||||
|
@ -106,9 +108,11 @@ describe('Registration', function() {
|
|||
|
||||
it("should handle serverConfig updates correctly", async () => {
|
||||
mockClient.loginFlows.mockResolvedValue({
|
||||
flows: [{
|
||||
"type": "m.login.sso",
|
||||
}],
|
||||
flows: [
|
||||
{
|
||||
type: "m.login.sso",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { container, rerender } = render(getRawComponent());
|
||||
|
|
|
@ -21,11 +21,15 @@ describe("Validation", () => {
|
|||
const handler = withValidation({
|
||||
rules: [],
|
||||
});
|
||||
return expect(handler({
|
||||
value: "value",
|
||||
focused: true,
|
||||
})).resolves.toEqual(expect.objectContaining({
|
||||
valid: true,
|
||||
}));
|
||||
return expect(
|
||||
handler({
|
||||
value: "value",
|
||||
focused: true,
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
valid: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,28 +14,28 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { mocked } from 'jest-mock';
|
||||
import { logger } from 'matrix-js-sdk/src/logger';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { mount } from "enzyme";
|
||||
import { mocked } from "jest-mock";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { act } from "react-dom/test-utils";
|
||||
|
||||
import RecordingPlayback, { PlaybackLayout } from '../../../../src/components/views/audio_messages/RecordingPlayback';
|
||||
import { Playback } from '../../../../src/audio/Playback';
|
||||
import RoomContext, { TimelineRenderingType } from '../../../../src/contexts/RoomContext';
|
||||
import { createAudioContext } from '../../../../src/audio/compat';
|
||||
import { findByTestId, flushPromises } from '../../../test-utils';
|
||||
import PlaybackWaveform from '../../../../src/components/views/audio_messages/PlaybackWaveform';
|
||||
import RecordingPlayback, { PlaybackLayout } from "../../../../src/components/views/audio_messages/RecordingPlayback";
|
||||
import { Playback } from "../../../../src/audio/Playback";
|
||||
import RoomContext, { TimelineRenderingType } from "../../../../src/contexts/RoomContext";
|
||||
import { createAudioContext } from "../../../../src/audio/compat";
|
||||
import { findByTestId, flushPromises } from "../../../test-utils";
|
||||
import PlaybackWaveform from "../../../../src/components/views/audio_messages/PlaybackWaveform";
|
||||
import SeekBar from "../../../../src/components/views/audio_messages/SeekBar";
|
||||
import PlaybackClock from "../../../../src/components/views/audio_messages/PlaybackClock";
|
||||
|
||||
jest.mock('../../../../src/audio/compat', () => ({
|
||||
jest.mock("../../../../src/audio/compat", () => ({
|
||||
createAudioContext: jest.fn(),
|
||||
decodeOgg: jest.fn().mockResolvedValue({}),
|
||||
}));
|
||||
|
||||
describe('<RecordingPlayback />', () => {
|
||||
describe("<RecordingPlayback />", () => {
|
||||
const mockAudioBufferSourceNode = {
|
||||
addEventListener: jest.fn(),
|
||||
connect: jest.fn(),
|
||||
|
@ -57,7 +57,7 @@ describe('<RecordingPlayback />', () => {
|
|||
|
||||
const mockChannelData = new Float32Array();
|
||||
|
||||
const defaultRoom = { roomId: '!room:server.org', timelineRenderingType: TimelineRenderingType.File };
|
||||
const defaultRoom = { roomId: "!room:server.org", timelineRenderingType: TimelineRenderingType.File };
|
||||
const getComponent = (props: React.ComponentProps<typeof RecordingPlayback>, room = defaultRoom) =>
|
||||
mount(<RecordingPlayback {...props} />, {
|
||||
wrappingComponent: RoomContext.Provider,
|
||||
|
@ -65,29 +65,27 @@ describe('<RecordingPlayback />', () => {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(logger, 'error').mockRestore();
|
||||
jest.spyOn(logger, "error").mockRestore();
|
||||
mockAudioBuffer.getChannelData.mockClear().mockReturnValue(mockChannelData);
|
||||
mockAudioContext.decodeAudioData.mockReset().mockImplementation(
|
||||
(_b, callback) => callback(mockAudioBuffer),
|
||||
);
|
||||
mockAudioContext.decodeAudioData.mockReset().mockImplementation((_b, callback) => callback(mockAudioBuffer));
|
||||
mocked(createAudioContext).mockReturnValue(mockAudioContext as unknown as AudioContext);
|
||||
});
|
||||
|
||||
const getPlayButton = component => findByTestId(component, 'play-pause-button').at(0);
|
||||
const getPlayButton = (component) => findByTestId(component, "play-pause-button").at(0);
|
||||
|
||||
it('renders recording playback', () => {
|
||||
it("renders recording playback", () => {
|
||||
const playback = new Playback(new ArrayBuffer(8));
|
||||
const component = getComponent({ playback });
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('disables play button while playback is decoding', async () => {
|
||||
it("disables play button while playback is decoding", async () => {
|
||||
const playback = new Playback(new ArrayBuffer(8));
|
||||
const component = getComponent({ playback });
|
||||
expect(getPlayButton(component).props().disabled).toBeTruthy();
|
||||
});
|
||||
|
||||
it('enables play button when playback is finished decoding', async () => {
|
||||
it("enables play button when playback is finished decoding", async () => {
|
||||
const playback = new Playback(new ArrayBuffer(8));
|
||||
const component = getComponent({ playback });
|
||||
await flushPromises();
|
||||
|
@ -95,43 +93,41 @@ describe('<RecordingPlayback />', () => {
|
|||
expect(getPlayButton(component).props().disabled).toBeFalsy();
|
||||
});
|
||||
|
||||
it('displays error when playback decoding fails', async () => {
|
||||
it("displays error when playback decoding fails", async () => {
|
||||
// stub logger to keep console clean from expected error
|
||||
jest.spyOn(logger, 'error').mockReturnValue(undefined);
|
||||
jest.spyOn(logger, 'warn').mockReturnValue(undefined);
|
||||
mockAudioContext.decodeAudioData.mockImplementation(
|
||||
(_b, _cb, error) => error(new Error('oh no')),
|
||||
);
|
||||
jest.spyOn(logger, "error").mockReturnValue(undefined);
|
||||
jest.spyOn(logger, "warn").mockReturnValue(undefined);
|
||||
mockAudioContext.decodeAudioData.mockImplementation((_b, _cb, error) => error(new Error("oh no")));
|
||||
const playback = new Playback(new ArrayBuffer(8));
|
||||
const component = getComponent({ playback });
|
||||
await flushPromises();
|
||||
expect(component.find('.text-warning').length).toBeFalsy();
|
||||
expect(component.find(".text-warning").length).toBeFalsy();
|
||||
});
|
||||
|
||||
it('displays pre-prepared playback with correct playback phase', async () => {
|
||||
it("displays pre-prepared playback with correct playback phase", async () => {
|
||||
const playback = new Playback(new ArrayBuffer(8));
|
||||
await playback.prepare();
|
||||
const component = getComponent({ playback });
|
||||
// playback already decoded, button is not disabled
|
||||
expect(getPlayButton(component).props().disabled).toBeFalsy();
|
||||
expect(component.find('.text-warning').length).toBeFalsy();
|
||||
expect(component.find(".text-warning").length).toBeFalsy();
|
||||
});
|
||||
|
||||
it('toggles playback on play pause button click', async () => {
|
||||
it("toggles playback on play pause button click", async () => {
|
||||
const playback = new Playback(new ArrayBuffer(8));
|
||||
jest.spyOn(playback, 'toggle').mockResolvedValue(undefined);
|
||||
jest.spyOn(playback, "toggle").mockResolvedValue(undefined);
|
||||
await playback.prepare();
|
||||
const component = getComponent({ playback });
|
||||
|
||||
act(() => {
|
||||
getPlayButton(component).simulate('click');
|
||||
getPlayButton(component).simulate("click");
|
||||
});
|
||||
|
||||
expect(playback.toggle).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('Composer Layout', () => {
|
||||
it('should have a waveform, no seek bar, and clock', () => {
|
||||
describe("Composer Layout", () => {
|
||||
it("should have a waveform, no seek bar, and clock", () => {
|
||||
const playback = new Playback(new ArrayBuffer(8));
|
||||
const component = getComponent({ playback, layout: PlaybackLayout.Composer });
|
||||
|
||||
|
@ -141,8 +137,8 @@ describe('<RecordingPlayback />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Timeline Layout', () => {
|
||||
it('should have a waveform, a seek bar, and clock', () => {
|
||||
describe("Timeline Layout", () => {
|
||||
it("should have a waveform, a seek bar, and clock", () => {
|
||||
const playback = new Playback(new ArrayBuffer(8));
|
||||
const component = getComponent({ playback, layout: PlaybackLayout.Timeline });
|
||||
|
||||
|
@ -151,7 +147,7 @@ describe('<RecordingPlayback />', () => {
|
|||
expect(component.find(SeekBar).length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should be the default', () => {
|
||||
it("should be the default", () => {
|
||||
const playback = new Playback(new ArrayBuffer(8));
|
||||
const component = getComponent({ playback }); // no layout set for test
|
||||
|
||||
|
|
|
@ -30,9 +30,10 @@ describe("SeekBar", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
seekBarRef = createRef();
|
||||
jest.spyOn(window, "requestAnimationFrame").mockImplementation(
|
||||
(callback: FrameRequestCallback) => { frameRequestCallback = callback; return 0; },
|
||||
);
|
||||
jest.spyOn(window, "requestAnimationFrame").mockImplementation((callback: FrameRequestCallback) => {
|
||||
frameRequestCallback = callback;
|
||||
return 0;
|
||||
});
|
||||
playback = createTestPlayback();
|
||||
});
|
||||
|
||||
|
|
|
@ -36,14 +36,11 @@ describe("MemberAvatar", () => {
|
|||
let member: RoomMember;
|
||||
|
||||
function getComponent(props) {
|
||||
return <RoomContext.Provider value={getRoomContext(room, {})}>
|
||||
<MemberAvatar
|
||||
member={null}
|
||||
width={35}
|
||||
height={35}
|
||||
{...props}
|
||||
/>
|
||||
</RoomContext.Provider>;
|
||||
return (
|
||||
<RoomContext.Provider value={getRoomContext(room, {})}>
|
||||
<MemberAvatar member={null} width={35} height={35} {...props} />
|
||||
</RoomContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -14,32 +14,28 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
import {
|
||||
Beacon,
|
||||
RoomMember,
|
||||
MatrixEvent,
|
||||
} from 'matrix-js-sdk/src/matrix';
|
||||
import { LocationAssetType } from 'matrix-js-sdk/src/@types/location';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { Beacon, RoomMember, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { LocationAssetType } from "matrix-js-sdk/src/@types/location";
|
||||
import { act } from "react-dom/test-utils";
|
||||
|
||||
import BeaconListItem from '../../../../src/components/views/beacon/BeaconListItem';
|
||||
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
||||
import BeaconListItem from "../../../../src/components/views/beacon/BeaconListItem";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import {
|
||||
getMockClientWithEventEmitter,
|
||||
makeBeaconEvent,
|
||||
makeBeaconInfoEvent,
|
||||
makeRoomWithBeacons,
|
||||
} from '../../../test-utils';
|
||||
} from "../../../test-utils";
|
||||
|
||||
describe('<BeaconListItem />', () => {
|
||||
describe("<BeaconListItem />", () => {
|
||||
// 14.03.2022 16:15
|
||||
const now = 1647270879403;
|
||||
// go back in time to create beacons and locations in the past
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(now - 600000);
|
||||
const roomId = '!room:server';
|
||||
const aliceId = '@alice:server';
|
||||
jest.spyOn(global.Date, "now").mockReturnValue(now - 600000);
|
||||
const roomId = "!room:server";
|
||||
const aliceId = "@alice:server";
|
||||
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getUserId: jest.fn().mockReturnValue(aliceId),
|
||||
|
@ -47,36 +43,41 @@ describe('<BeaconListItem />', () => {
|
|||
isGuest: jest.fn().mockReturnValue(false),
|
||||
});
|
||||
|
||||
const aliceBeaconEvent = makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ isLive: true },
|
||||
'$alice-room1-1',
|
||||
);
|
||||
const alicePinBeaconEvent = makeBeaconInfoEvent(aliceId,
|
||||
const aliceBeaconEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: true }, "$alice-room1-1");
|
||||
const alicePinBeaconEvent = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
roomId,
|
||||
{ isLive: true, assetType: LocationAssetType.Pin, description: "Alice's car" },
|
||||
'$alice-room1-1',
|
||||
"$alice-room1-1",
|
||||
);
|
||||
const pinBeaconWithoutDescription = makeBeaconInfoEvent(aliceId,
|
||||
const pinBeaconWithoutDescription = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
roomId,
|
||||
{ isLive: true, assetType: LocationAssetType.Pin },
|
||||
'$alice-room1-1',
|
||||
"$alice-room1-1",
|
||||
);
|
||||
|
||||
const aliceLocation1 = makeBeaconEvent(
|
||||
aliceId, { beaconInfoId: aliceBeaconEvent.getId(), geoUri: 'geo:51,41', timestamp: now - 1 },
|
||||
);
|
||||
const aliceLocation2 = makeBeaconEvent(
|
||||
aliceId, { beaconInfoId: aliceBeaconEvent.getId(), geoUri: 'geo:52,42', timestamp: now - 500000 },
|
||||
);
|
||||
const aliceLocation1 = makeBeaconEvent(aliceId, {
|
||||
beaconInfoId: aliceBeaconEvent.getId(),
|
||||
geoUri: "geo:51,41",
|
||||
timestamp: now - 1,
|
||||
});
|
||||
const aliceLocation2 = makeBeaconEvent(aliceId, {
|
||||
beaconInfoId: aliceBeaconEvent.getId(),
|
||||
geoUri: "geo:52,42",
|
||||
timestamp: now - 500000,
|
||||
});
|
||||
|
||||
const defaultProps = {
|
||||
beacon: new Beacon(aliceBeaconEvent),
|
||||
};
|
||||
|
||||
const getComponent = (props = {}) => render(<MatrixClientContext.Provider value={mockClient}>
|
||||
<BeaconListItem {...defaultProps} {...props} />
|
||||
</MatrixClientContext.Provider>);
|
||||
const getComponent = (props = {}) =>
|
||||
render(
|
||||
<MatrixClientContext.Provider value={mockClient}>
|
||||
<BeaconListItem {...defaultProps} {...props} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
|
||||
const setupRoomWithBeacons = (beaconInfoEvents: MatrixEvent[], locationEvents?: MatrixEvent[]): Beacon[] => {
|
||||
const beacons = makeRoomWithBeacons(roomId, mockClient, beaconInfoEvents, locationEvents);
|
||||
|
@ -84,102 +85,101 @@ describe('<BeaconListItem />', () => {
|
|||
const member = new RoomMember(roomId, aliceId);
|
||||
member.name = `Alice`;
|
||||
const room = mockClient.getRoom(roomId);
|
||||
jest.spyOn(room, 'getMember').mockReturnValue(member);
|
||||
jest.spyOn(room, "getMember").mockReturnValue(member);
|
||||
|
||||
return beacons;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.spyOn(Date, 'now').mockReturnValue(now);
|
||||
jest.spyOn(Date, "now").mockReturnValue(now);
|
||||
});
|
||||
|
||||
it('renders null when beacon is not live', () => {
|
||||
const notLiveBeacon = makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ isLive: false },
|
||||
);
|
||||
it("renders null when beacon is not live", () => {
|
||||
const notLiveBeacon = makeBeaconInfoEvent(aliceId, roomId, { isLive: false });
|
||||
const [beacon] = setupRoomWithBeacons([notLiveBeacon]);
|
||||
const { container } = getComponent({ beacon });
|
||||
expect(container.innerHTML).toBeFalsy();
|
||||
});
|
||||
|
||||
it('renders null when beacon has no location', () => {
|
||||
it("renders null when beacon has no location", () => {
|
||||
const [beacon] = setupRoomWithBeacons([aliceBeaconEvent]);
|
||||
const { container } = getComponent({ beacon });
|
||||
expect(container.innerHTML).toBeFalsy();
|
||||
});
|
||||
|
||||
describe('when a beacon is live and has locations', () => {
|
||||
it('renders beacon info', () => {
|
||||
describe("when a beacon is live and has locations", () => {
|
||||
it("renders beacon info", () => {
|
||||
const [beacon] = setupRoomWithBeacons([alicePinBeaconEvent], [aliceLocation1]);
|
||||
const { asFragment } = getComponent({ beacon });
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('non-self beacons', () => {
|
||||
it('uses beacon description as beacon name', () => {
|
||||
describe("non-self beacons", () => {
|
||||
it("uses beacon description as beacon name", () => {
|
||||
const [beacon] = setupRoomWithBeacons([alicePinBeaconEvent], [aliceLocation1]);
|
||||
const { container } = getComponent({ beacon });
|
||||
expect(container.querySelector('.mx_BeaconStatus_label')).toHaveTextContent("Alice's car");
|
||||
expect(container.querySelector(".mx_BeaconStatus_label")).toHaveTextContent("Alice's car");
|
||||
});
|
||||
|
||||
it('uses beacon owner mxid as beacon name for a beacon without description', () => {
|
||||
it("uses beacon owner mxid as beacon name for a beacon without description", () => {
|
||||
const [beacon] = setupRoomWithBeacons([pinBeaconWithoutDescription], [aliceLocation1]);
|
||||
const { container } = getComponent({ beacon });
|
||||
expect(container.querySelector('.mx_BeaconStatus_label')).toHaveTextContent(aliceId);
|
||||
expect(container.querySelector(".mx_BeaconStatus_label")).toHaveTextContent(aliceId);
|
||||
});
|
||||
|
||||
it('renders location icon', () => {
|
||||
it("renders location icon", () => {
|
||||
const [beacon] = setupRoomWithBeacons([alicePinBeaconEvent], [aliceLocation1]);
|
||||
const { container } = getComponent({ beacon });
|
||||
expect(container.querySelector('.mx_StyledLiveBeaconIcon')).toBeTruthy();
|
||||
expect(container.querySelector(".mx_StyledLiveBeaconIcon")).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('self locations', () => {
|
||||
it('renders beacon owner avatar', () => {
|
||||
describe("self locations", () => {
|
||||
it("renders beacon owner avatar", () => {
|
||||
const [beacon] = setupRoomWithBeacons([aliceBeaconEvent], [aliceLocation1]);
|
||||
const { container } = getComponent({ beacon });
|
||||
expect(container.querySelector('.mx_BaseAvatar')).toBeTruthy();
|
||||
expect(container.querySelector(".mx_BaseAvatar")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('uses beacon owner name as beacon name', () => {
|
||||
it("uses beacon owner name as beacon name", () => {
|
||||
const [beacon] = setupRoomWithBeacons([aliceBeaconEvent], [aliceLocation1]);
|
||||
const { container } = getComponent({ beacon });
|
||||
expect(container.querySelector('.mx_BeaconStatus_label')).toHaveTextContent("Alice");
|
||||
expect(container.querySelector(".mx_BeaconStatus_label")).toHaveTextContent("Alice");
|
||||
});
|
||||
});
|
||||
|
||||
describe('on location updates', () => {
|
||||
it('updates last updated time on location updated', () => {
|
||||
describe("on location updates", () => {
|
||||
it("updates last updated time on location updated", () => {
|
||||
const [beacon] = setupRoomWithBeacons([aliceBeaconEvent], [aliceLocation2]);
|
||||
const { container } = getComponent({ beacon });
|
||||
|
||||
expect(container.querySelector('.mx_BeaconListItem_lastUpdated'))
|
||||
.toHaveTextContent('Updated 9 minutes ago');
|
||||
expect(container.querySelector(".mx_BeaconListItem_lastUpdated")).toHaveTextContent(
|
||||
"Updated 9 minutes ago",
|
||||
);
|
||||
|
||||
// update to a newer location
|
||||
act(() => {
|
||||
beacon.addLocations([aliceLocation1]);
|
||||
});
|
||||
|
||||
expect(container.querySelector('.mx_BeaconListItem_lastUpdated'))
|
||||
.toHaveTextContent('Updated a few seconds ago');
|
||||
expect(container.querySelector(".mx_BeaconListItem_lastUpdated")).toHaveTextContent(
|
||||
"Updated a few seconds ago",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('interactions', () => {
|
||||
it('does not call onClick handler when clicking share button', () => {
|
||||
describe("interactions", () => {
|
||||
it("does not call onClick handler when clicking share button", () => {
|
||||
const [beacon] = setupRoomWithBeacons([alicePinBeaconEvent], [aliceLocation1]);
|
||||
const onClick = jest.fn();
|
||||
const { getByTestId } = getComponent({ beacon, onClick });
|
||||
|
||||
fireEvent.click(getByTestId('open-location-in-osm'));
|
||||
fireEvent.click(getByTestId("open-location-in-osm"));
|
||||
expect(onClick).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls onClick handler when clicking outside of share buttons', () => {
|
||||
it("calls onClick handler when clicking outside of share buttons", () => {
|
||||
const [beacon] = setupRoomWithBeacons([alicePinBeaconEvent], [aliceLocation1]);
|
||||
const onClick = jest.fn();
|
||||
const { container } = getComponent({ beacon, onClick });
|
||||
|
|
|
@ -14,36 +14,30 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import {
|
||||
Beacon,
|
||||
Room,
|
||||
RoomMember,
|
||||
MatrixEvent,
|
||||
getBeaconInfoIdentifier,
|
||||
} from 'matrix-js-sdk/src/matrix';
|
||||
import { mount } from "enzyme";
|
||||
import maplibregl from "maplibre-gl";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { Beacon, Room, RoomMember, MatrixEvent, getBeaconInfoIdentifier } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import BeaconMarker from '../../../../src/components/views/beacon/BeaconMarker';
|
||||
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
||||
import BeaconMarker from "../../../../src/components/views/beacon/BeaconMarker";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import {
|
||||
getMockClientWithEventEmitter,
|
||||
makeBeaconEvent,
|
||||
makeBeaconInfoEvent,
|
||||
makeRoomWithStateEvents,
|
||||
} from '../../../test-utils';
|
||||
import { TILE_SERVER_WK_KEY } from '../../../../src/utils/WellKnownUtils';
|
||||
} from "../../../test-utils";
|
||||
import { TILE_SERVER_WK_KEY } from "../../../../src/utils/WellKnownUtils";
|
||||
|
||||
describe('<BeaconMarker />', () => {
|
||||
describe("<BeaconMarker />", () => {
|
||||
// 14.03.2022 16:15
|
||||
const now = 1647270879403;
|
||||
// stable date for snapshots
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(now);
|
||||
const roomId = '!room:server';
|
||||
const aliceId = '@alice:server';
|
||||
jest.spyOn(global.Date, "now").mockReturnValue(now);
|
||||
const roomId = "!room:server";
|
||||
const aliceId = "@alice:server";
|
||||
|
||||
const aliceMember = new RoomMember(roomId, aliceId);
|
||||
|
||||
|
@ -51,7 +45,7 @@ describe('<BeaconMarker />', () => {
|
|||
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getClientWellKnown: jest.fn().mockReturnValue({
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: 'maps.com' },
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: "maps.com" },
|
||||
}),
|
||||
getUserId: jest.fn().mockReturnValue(aliceId),
|
||||
getRoom: jest.fn(),
|
||||
|
@ -62,27 +56,23 @@ describe('<BeaconMarker />', () => {
|
|||
// as we update room state
|
||||
const setupRoom = (stateEvents: MatrixEvent[] = []): Room => {
|
||||
const room1 = makeRoomWithStateEvents(stateEvents, { roomId, mockClient });
|
||||
jest.spyOn(room1, 'getMember').mockReturnValue(aliceMember);
|
||||
jest.spyOn(room1, "getMember").mockReturnValue(aliceMember);
|
||||
return room1;
|
||||
};
|
||||
|
||||
const defaultEvent = makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ isLive: true },
|
||||
'$alice-room1-1',
|
||||
);
|
||||
const notLiveEvent = makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ isLive: false },
|
||||
'$alice-room1-2',
|
||||
);
|
||||
const defaultEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: true }, "$alice-room1-1");
|
||||
const notLiveEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: false }, "$alice-room1-2");
|
||||
|
||||
const location1 = makeBeaconEvent(
|
||||
aliceId, { beaconInfoId: defaultEvent.getId(), geoUri: 'geo:51,41', timestamp: now + 1 },
|
||||
);
|
||||
const location2 = makeBeaconEvent(
|
||||
aliceId, { beaconInfoId: defaultEvent.getId(), geoUri: 'geo:52,42', timestamp: now + 10000 },
|
||||
);
|
||||
const location1 = makeBeaconEvent(aliceId, {
|
||||
beaconInfoId: defaultEvent.getId(),
|
||||
geoUri: "geo:51,41",
|
||||
timestamp: now + 1,
|
||||
});
|
||||
const location2 = makeBeaconEvent(aliceId, {
|
||||
beaconInfoId: defaultEvent.getId(),
|
||||
geoUri: "geo:52,42",
|
||||
timestamp: now + 10000,
|
||||
});
|
||||
|
||||
const defaultProps = {
|
||||
map: mockMap,
|
||||
|
@ -99,21 +89,21 @@ describe('<BeaconMarker />', () => {
|
|||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders nothing when beacon is not live', () => {
|
||||
it("renders nothing when beacon is not live", () => {
|
||||
const room = setupRoom([notLiveEvent]);
|
||||
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(notLiveEvent));
|
||||
const component = getComponent({ beacon });
|
||||
expect(component.html()).toBe(null);
|
||||
});
|
||||
|
||||
it('renders nothing when beacon has no location', () => {
|
||||
it("renders nothing when beacon has no location", () => {
|
||||
const room = setupRoom([defaultEvent]);
|
||||
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
|
||||
const component = getComponent({ beacon });
|
||||
expect(component.html()).toBe(null);
|
||||
});
|
||||
|
||||
it('renders marker when beacon has location', () => {
|
||||
it("renders marker when beacon has location", () => {
|
||||
const room = setupRoom([defaultEvent]);
|
||||
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
|
||||
beacon.addLocations([location1]);
|
||||
|
@ -121,12 +111,12 @@ describe('<BeaconMarker />', () => {
|
|||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('updates with new locations', () => {
|
||||
it("updates with new locations", () => {
|
||||
const room = setupRoom([defaultEvent]);
|
||||
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
|
||||
beacon.addLocations([location1]);
|
||||
const component = getComponent({ beacon });
|
||||
expect(component.find('SmartMarker').props()['geoUri']).toEqual('geo:51,41');
|
||||
expect(component.find("SmartMarker").props()["geoUri"]).toEqual("geo:51,41");
|
||||
|
||||
act(() => {
|
||||
beacon.addLocations([location2]);
|
||||
|
@ -134,6 +124,6 @@ describe('<BeaconMarker />', () => {
|
|||
component.setProps({});
|
||||
|
||||
// updated to latest location
|
||||
expect(component.find('SmartMarker').props()['geoUri']).toEqual('geo:52,42');
|
||||
expect(component.find("SmartMarker").props()["geoUri"]).toEqual("geo:52,42");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,75 +14,75 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { Beacon } from 'matrix-js-sdk/src/matrix';
|
||||
import { mount } from "enzyme";
|
||||
import { Beacon } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import BeaconStatus from '../../../../src/components/views/beacon/BeaconStatus';
|
||||
import { BeaconDisplayStatus } from '../../../../src/components/views/beacon/displayStatus';
|
||||
import { findByTestId, makeBeaconInfoEvent } from '../../../test-utils';
|
||||
import BeaconStatus from "../../../../src/components/views/beacon/BeaconStatus";
|
||||
import { BeaconDisplayStatus } from "../../../../src/components/views/beacon/displayStatus";
|
||||
import { findByTestId, makeBeaconInfoEvent } from "../../../test-utils";
|
||||
|
||||
describe('<BeaconStatus />', () => {
|
||||
describe("<BeaconStatus />", () => {
|
||||
const defaultProps = {
|
||||
displayStatus: BeaconDisplayStatus.Loading,
|
||||
label: 'test label',
|
||||
label: "test label",
|
||||
withIcon: true,
|
||||
};
|
||||
const getComponent = (props = {}) =>
|
||||
mount(<BeaconStatus {...defaultProps} {...props} />);
|
||||
const getComponent = (props = {}) => mount(<BeaconStatus {...defaultProps} {...props} />);
|
||||
|
||||
it('renders loading state', () => {
|
||||
it("renders loading state", () => {
|
||||
const component = getComponent({ displayStatus: BeaconDisplayStatus.Loading });
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders stopped state', () => {
|
||||
it("renders stopped state", () => {
|
||||
const component = getComponent({ displayStatus: BeaconDisplayStatus.Stopped });
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders without icon', () => {
|
||||
it("renders without icon", () => {
|
||||
const component = getComponent({ withIcon: false, displayStatus: BeaconDisplayStatus.Stopped });
|
||||
expect(component.find('StyledLiveBeaconIcon').length).toBeFalsy();
|
||||
expect(component.find("StyledLiveBeaconIcon").length).toBeFalsy();
|
||||
});
|
||||
|
||||
describe('active state', () => {
|
||||
it('renders without children', () => {
|
||||
describe("active state", () => {
|
||||
it("renders without children", () => {
|
||||
// mock for stable snapshot
|
||||
jest.spyOn(Date, 'now').mockReturnValue(123456789);
|
||||
const beacon = new Beacon(makeBeaconInfoEvent('@user:server', '!room:server', { isLive: false }, '$1'));
|
||||
jest.spyOn(Date, "now").mockReturnValue(123456789);
|
||||
const beacon = new Beacon(makeBeaconInfoEvent("@user:server", "!room:server", { isLive: false }, "$1"));
|
||||
const component = getComponent({ beacon, displayStatus: BeaconDisplayStatus.Active });
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders with children', () => {
|
||||
const beacon = new Beacon(makeBeaconInfoEvent('@user:server', '!room:sever', { isLive: false }));
|
||||
it("renders with children", () => {
|
||||
const beacon = new Beacon(makeBeaconInfoEvent("@user:server", "!room:sever", { isLive: false }));
|
||||
const component = getComponent({
|
||||
beacon,
|
||||
children: <span data-test-id='test'>test</span>,
|
||||
children: <span data-test-id="test">test</span>,
|
||||
displayStatus: BeaconDisplayStatus.Active,
|
||||
});
|
||||
expect(findByTestId(component, 'test-child')).toMatchSnapshot();
|
||||
expect(findByTestId(component, "test-child")).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders static remaining time when displayLiveTimeRemaining is falsy', () => {
|
||||
it("renders static remaining time when displayLiveTimeRemaining is falsy", () => {
|
||||
// mock for stable snapshot
|
||||
jest.spyOn(Date, 'now').mockReturnValue(123456789);
|
||||
const beacon = new Beacon(makeBeaconInfoEvent('@user:server', '!room:server', { isLive: false }, '$1'));
|
||||
jest.spyOn(Date, "now").mockReturnValue(123456789);
|
||||
const beacon = new Beacon(makeBeaconInfoEvent("@user:server", "!room:server", { isLive: false }, "$1"));
|
||||
const component = getComponent({ beacon, displayStatus: BeaconDisplayStatus.Active });
|
||||
expect(component.text().includes('Live until 11:17')).toBeTruthy();
|
||||
expect(component.text().includes("Live until 11:17")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders live time remaining when displayLiveTimeRemaining is truthy', () => {
|
||||
it("renders live time remaining when displayLiveTimeRemaining is truthy", () => {
|
||||
// mock for stable snapshot
|
||||
jest.spyOn(Date, 'now').mockReturnValue(123456789);
|
||||
const beacon = new Beacon(makeBeaconInfoEvent('@user:server', '!room:server', { isLive: false }, '$1'));
|
||||
jest.spyOn(Date, "now").mockReturnValue(123456789);
|
||||
const beacon = new Beacon(makeBeaconInfoEvent("@user:server", "!room:server", { isLive: false }, "$1"));
|
||||
const component = getComponent({
|
||||
beacon, displayStatus: BeaconDisplayStatus.Active,
|
||||
beacon,
|
||||
displayStatus: BeaconDisplayStatus.Active,
|
||||
displayLiveTimeRemaining: true,
|
||||
});
|
||||
expect(component.text().includes('1h left')).toBeTruthy();
|
||||
expect(component.text().includes("1h left")).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,21 +14,15 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import {
|
||||
MatrixClient,
|
||||
MatrixEvent,
|
||||
Room,
|
||||
RoomMember,
|
||||
getBeaconInfoIdentifier,
|
||||
} from 'matrix-js-sdk/src/matrix';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import { mocked } from 'jest-mock';
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { MatrixClient, MatrixEvent, Room, RoomMember, getBeaconInfoIdentifier } from "matrix-js-sdk/src/matrix";
|
||||
import maplibregl from "maplibre-gl";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import BeaconViewDialog from '../../../../src/components/views/beacon/BeaconViewDialog';
|
||||
import BeaconViewDialog from "../../../../src/components/views/beacon/BeaconViewDialog";
|
||||
import {
|
||||
findByAttr,
|
||||
findByTestId,
|
||||
|
@ -37,26 +31,26 @@ import {
|
|||
makeBeaconInfoEvent,
|
||||
makeRoomWithBeacons,
|
||||
makeRoomWithStateEvents,
|
||||
} from '../../../test-utils';
|
||||
import { TILE_SERVER_WK_KEY } from '../../../../src/utils/WellKnownUtils';
|
||||
import { OwnBeaconStore } from '../../../../src/stores/OwnBeaconStore';
|
||||
import { BeaconDisplayStatus } from '../../../../src/components/views/beacon/displayStatus';
|
||||
import BeaconListItem from '../../../../src/components/views/beacon/BeaconListItem';
|
||||
} from "../../../test-utils";
|
||||
import { TILE_SERVER_WK_KEY } from "../../../../src/utils/WellKnownUtils";
|
||||
import { OwnBeaconStore } from "../../../../src/stores/OwnBeaconStore";
|
||||
import { BeaconDisplayStatus } from "../../../../src/components/views/beacon/displayStatus";
|
||||
import BeaconListItem from "../../../../src/components/views/beacon/BeaconListItem";
|
||||
|
||||
describe('<BeaconViewDialog />', () => {
|
||||
describe("<BeaconViewDialog />", () => {
|
||||
// 14.03.2022 16:15
|
||||
const now = 1647270879403;
|
||||
// stable date for snapshots
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(now);
|
||||
const roomId = '!room:server';
|
||||
const aliceId = '@alice:server';
|
||||
const bobId = '@bob:server';
|
||||
jest.spyOn(global.Date, "now").mockReturnValue(now);
|
||||
const roomId = "!room:server";
|
||||
const aliceId = "@alice:server";
|
||||
const bobId = "@bob:server";
|
||||
|
||||
const aliceMember = new RoomMember(roomId, aliceId);
|
||||
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getClientWellKnown: jest.fn().mockReturnValue({
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: 'maps.com' },
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: "maps.com" },
|
||||
}),
|
||||
getUserId: jest.fn().mockReturnValue(bobId),
|
||||
getRoom: jest.fn(),
|
||||
|
@ -70,20 +64,18 @@ describe('<BeaconViewDialog />', () => {
|
|||
// as we update room state
|
||||
const setupRoom = (stateEvents: MatrixEvent[] = []): Room => {
|
||||
const room1 = makeRoomWithStateEvents(stateEvents, { roomId, mockClient });
|
||||
jest.spyOn(room1, 'getMember').mockReturnValue(aliceMember);
|
||||
jest.spyOn(room1, "getMember").mockReturnValue(aliceMember);
|
||||
|
||||
return room1;
|
||||
};
|
||||
|
||||
const defaultEvent = makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ isLive: true },
|
||||
'$alice-room1-1',
|
||||
);
|
||||
const defaultEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: true }, "$alice-room1-1");
|
||||
|
||||
const location1 = makeBeaconEvent(
|
||||
aliceId, { beaconInfoId: defaultEvent.getId(), geoUri: 'geo:51,41', timestamp: now + 1 },
|
||||
);
|
||||
const location1 = makeBeaconEvent(aliceId, {
|
||||
beaconInfoId: defaultEvent.getId(),
|
||||
geoUri: "geo:51,41",
|
||||
timestamp: now + 1,
|
||||
});
|
||||
|
||||
const defaultProps = {
|
||||
onFinished: jest.fn(),
|
||||
|
@ -91,74 +83,73 @@ describe('<BeaconViewDialog />', () => {
|
|||
matrixClient: mockClient as MatrixClient,
|
||||
};
|
||||
|
||||
const getComponent = (props = {}) =>
|
||||
mount(<BeaconViewDialog {...defaultProps} {...props} />);
|
||||
const getComponent = (props = {}) => mount(<BeaconViewDialog {...defaultProps} {...props} />);
|
||||
|
||||
const openSidebar = (component: ReactWrapper) => act(() => {
|
||||
findByTestId(component, 'beacon-view-dialog-open-sidebar').at(0).simulate('click');
|
||||
component.setProps({});
|
||||
});
|
||||
const openSidebar = (component: ReactWrapper) =>
|
||||
act(() => {
|
||||
findByTestId(component, "beacon-view-dialog-open-sidebar").at(0).simulate("click");
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
maplibregl.AttributionControl = jest.fn();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(OwnBeaconStore.instance, 'getLiveBeaconIds').mockRestore();
|
||||
jest.spyOn(OwnBeaconStore.instance, 'getBeaconById').mockRestore();
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(now);
|
||||
jest.spyOn(OwnBeaconStore.instance, "getLiveBeaconIds").mockRestore();
|
||||
jest.spyOn(OwnBeaconStore.instance, "getBeaconById").mockRestore();
|
||||
jest.spyOn(global.Date, "now").mockReturnValue(now);
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders a map with markers', () => {
|
||||
it("renders a map with markers", () => {
|
||||
const room = setupRoom([defaultEvent]);
|
||||
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
|
||||
beacon.addLocations([location1]);
|
||||
const component = getComponent();
|
||||
expect(component.find('Map').props()).toEqual(expect.objectContaining({
|
||||
centerGeoUri: 'geo:51,41',
|
||||
interactive: true,
|
||||
}));
|
||||
expect(component.find('SmartMarker').length).toEqual(1);
|
||||
expect(component.find("Map").props()).toEqual(
|
||||
expect.objectContaining({
|
||||
centerGeoUri: "geo:51,41",
|
||||
interactive: true,
|
||||
}),
|
||||
);
|
||||
expect(component.find("SmartMarker").length).toEqual(1);
|
||||
});
|
||||
|
||||
it('does not render any own beacon status when user is not live sharing', () => {
|
||||
it("does not render any own beacon status when user is not live sharing", () => {
|
||||
// default event belongs to alice, we are bob
|
||||
const room = setupRoom([defaultEvent]);
|
||||
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
|
||||
beacon.addLocations([location1]);
|
||||
const component = getComponent();
|
||||
expect(component.find('DialogOwnBeaconStatus').html()).toBeNull();
|
||||
expect(component.find("DialogOwnBeaconStatus").html()).toBeNull();
|
||||
});
|
||||
|
||||
it('renders own beacon status when user is live sharing', () => {
|
||||
it("renders own beacon status when user is live sharing", () => {
|
||||
// default event belongs to alice
|
||||
const room = setupRoom([defaultEvent]);
|
||||
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
|
||||
beacon.addLocations([location1]);
|
||||
// mock own beacon store to show default event as alice's live beacon
|
||||
jest.spyOn(OwnBeaconStore.instance, 'getLiveBeaconIds').mockReturnValue([beacon.identifier]);
|
||||
jest.spyOn(OwnBeaconStore.instance, 'getBeaconById').mockReturnValue(beacon);
|
||||
jest.spyOn(OwnBeaconStore.instance, "getLiveBeaconIds").mockReturnValue([beacon.identifier]);
|
||||
jest.spyOn(OwnBeaconStore.instance, "getBeaconById").mockReturnValue(beacon);
|
||||
const component = getComponent();
|
||||
expect(component.find('MemberAvatar').length).toBeTruthy();
|
||||
expect(component.find('OwnBeaconStatus').props()).toEqual({
|
||||
beacon, displayStatus: BeaconDisplayStatus.Active,
|
||||
className: 'mx_DialogOwnBeaconStatus_status',
|
||||
expect(component.find("MemberAvatar").length).toBeTruthy();
|
||||
expect(component.find("OwnBeaconStatus").props()).toEqual({
|
||||
beacon,
|
||||
displayStatus: BeaconDisplayStatus.Active,
|
||||
className: "mx_DialogOwnBeaconStatus_status",
|
||||
});
|
||||
});
|
||||
|
||||
it('updates markers on changes to beacons', () => {
|
||||
it("updates markers on changes to beacons", () => {
|
||||
const room = setupRoom([defaultEvent]);
|
||||
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
|
||||
beacon.addLocations([location1]);
|
||||
const component = getComponent();
|
||||
expect(component.find('BeaconMarker').length).toEqual(1);
|
||||
expect(component.find("BeaconMarker").length).toEqual(1);
|
||||
|
||||
const anotherBeaconEvent = makeBeaconInfoEvent(bobId,
|
||||
roomId,
|
||||
{ isLive: true },
|
||||
'$bob-room1-1',
|
||||
);
|
||||
const anotherBeaconEvent = makeBeaconInfoEvent(bobId, roomId, { isLive: true }, "$bob-room1-1");
|
||||
|
||||
act(() => {
|
||||
// emits RoomStateEvent.BeaconLiveness
|
||||
|
@ -168,21 +159,17 @@ describe('<BeaconViewDialog />', () => {
|
|||
component.setProps({});
|
||||
|
||||
// two markers now!
|
||||
expect(component.find('BeaconMarker').length).toEqual(2);
|
||||
expect(component.find("BeaconMarker").length).toEqual(2);
|
||||
});
|
||||
|
||||
it('does not update bounds or center on changing beacons', () => {
|
||||
it("does not update bounds or center on changing beacons", () => {
|
||||
const room = setupRoom([defaultEvent]);
|
||||
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
|
||||
beacon.addLocations([location1]);
|
||||
const component = getComponent();
|
||||
expect(component.find('BeaconMarker').length).toEqual(1);
|
||||
expect(component.find("BeaconMarker").length).toEqual(1);
|
||||
|
||||
const anotherBeaconEvent = makeBeaconInfoEvent(bobId,
|
||||
roomId,
|
||||
{ isLive: true },
|
||||
'$bob-room1-1',
|
||||
);
|
||||
const anotherBeaconEvent = makeBeaconInfoEvent(bobId, roomId, { isLive: true }, "$bob-room1-1");
|
||||
|
||||
act(() => {
|
||||
// emits RoomStateEvent.BeaconLiveness
|
||||
|
@ -196,7 +183,7 @@ describe('<BeaconViewDialog />', () => {
|
|||
expect(mockMap.fitBounds).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('renders a fallback when there are no locations', () => {
|
||||
it("renders a fallback when there are no locations", () => {
|
||||
// this is a cornercase, should not be a reachable state in UI anymore
|
||||
const onFinished = jest.fn();
|
||||
const room = setupRoom([defaultEvent]);
|
||||
|
@ -204,30 +191,26 @@ describe('<BeaconViewDialog />', () => {
|
|||
const component = getComponent({ onFinished });
|
||||
|
||||
// map placeholder
|
||||
expect(findByTestId(component, 'beacon-view-dialog-map-fallback')).toMatchSnapshot();
|
||||
expect(findByTestId(component, "beacon-view-dialog-map-fallback")).toMatchSnapshot();
|
||||
|
||||
act(() => {
|
||||
findByTestId(component, 'beacon-view-dialog-fallback-close').at(0).simulate('click');
|
||||
findByTestId(component, "beacon-view-dialog-fallback-close").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('renders map without markers when no live beacons remain', () => {
|
||||
it("renders map without markers when no live beacons remain", () => {
|
||||
const onFinished = jest.fn();
|
||||
const room = setupRoom([defaultEvent]);
|
||||
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
|
||||
beacon.addLocations([location1]);
|
||||
const component = getComponent({ onFinished });
|
||||
expect(component.find('BeaconMarker').length).toEqual(1);
|
||||
expect(component.find("BeaconMarker").length).toEqual(1);
|
||||
|
||||
// this will replace the defaultEvent
|
||||
// leading to no more live beacons
|
||||
const anotherBeaconEvent = makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ isLive: false },
|
||||
'$alice-room1-2',
|
||||
);
|
||||
const anotherBeaconEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: false }, "$alice-room1-2");
|
||||
|
||||
expect(mockMap.setCenter).toHaveBeenCalledWith({ lat: 51, lon: 41 });
|
||||
// reset call counts
|
||||
|
@ -242,16 +225,16 @@ describe('<BeaconViewDialog />', () => {
|
|||
component.setProps({});
|
||||
|
||||
// no more avatars
|
||||
expect(component.find('MemberAvatar').length).toBeFalsy();
|
||||
expect(component.find("MemberAvatar").length).toBeFalsy();
|
||||
// map still rendered
|
||||
expect(component.find('Map').length).toBeTruthy();
|
||||
expect(component.find("Map").length).toBeTruthy();
|
||||
// map location unchanged
|
||||
expect(mockMap.setCenter).not.toHaveBeenCalled();
|
||||
expect(mockMap.fitBounds).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('sidebar', () => {
|
||||
it('opens sidebar on view list button click', () => {
|
||||
describe("sidebar", () => {
|
||||
it("opens sidebar on view list button click", () => {
|
||||
const room = setupRoom([defaultEvent]);
|
||||
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
|
||||
beacon.addLocations([location1]);
|
||||
|
@ -259,10 +242,10 @@ describe('<BeaconViewDialog />', () => {
|
|||
|
||||
openSidebar(component);
|
||||
|
||||
expect(component.find('DialogSidebar').length).toBeTruthy();
|
||||
expect(component.find("DialogSidebar").length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('closes sidebar on close button click', () => {
|
||||
it("closes sidebar on close button click", () => {
|
||||
const room = setupRoom([defaultEvent]);
|
||||
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
|
||||
beacon.addLocations([location1]);
|
||||
|
@ -271,34 +254,35 @@ describe('<BeaconViewDialog />', () => {
|
|||
// open the sidebar
|
||||
openSidebar(component);
|
||||
|
||||
expect(component.find('DialogSidebar').length).toBeTruthy();
|
||||
expect(component.find("DialogSidebar").length).toBeTruthy();
|
||||
|
||||
// now close it
|
||||
act(() => {
|
||||
findByAttr('data-testid')(component, 'dialog-sidebar-close').at(0).simulate('click');
|
||||
findByAttr("data-testid")(component, "dialog-sidebar-close").at(0).simulate("click");
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
expect(component.find('DialogSidebar').length).toBeFalsy();
|
||||
expect(component.find("DialogSidebar").length).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('focused beacons', () => {
|
||||
const beacon2Event = makeBeaconInfoEvent(bobId,
|
||||
roomId,
|
||||
{ isLive: true },
|
||||
'$bob-room1-2',
|
||||
);
|
||||
describe("focused beacons", () => {
|
||||
const beacon2Event = makeBeaconInfoEvent(bobId, roomId, { isLive: true }, "$bob-room1-2");
|
||||
|
||||
const location2 = makeBeaconEvent(
|
||||
bobId, { beaconInfoId: beacon2Event.getId(), geoUri: 'geo:33,22', timestamp: now + 1 },
|
||||
);
|
||||
const location2 = makeBeaconEvent(bobId, {
|
||||
beaconInfoId: beacon2Event.getId(),
|
||||
geoUri: "geo:33,22",
|
||||
timestamp: now + 1,
|
||||
});
|
||||
|
||||
const fitBoundsOptions = { maxZoom: 15, padding: 100 };
|
||||
|
||||
it('opens map with both beacons in view on first load without initialFocusedBeacon', () => {
|
||||
it("opens map with both beacons in view on first load without initialFocusedBeacon", () => {
|
||||
const [beacon1, beacon2] = makeRoomWithBeacons(
|
||||
roomId, mockClient, [defaultEvent, beacon2Event], [location1, location2],
|
||||
roomId,
|
||||
mockClient,
|
||||
[defaultEvent, beacon2Event],
|
||||
[location1, location2],
|
||||
);
|
||||
|
||||
getComponent({ beacons: [beacon1, beacon2] });
|
||||
|
@ -308,15 +292,19 @@ describe('<BeaconViewDialog />', () => {
|
|||
// only called once
|
||||
expect(mockMap.setCenter).toHaveBeenCalledTimes(1);
|
||||
// bounds fit both beacons, only called once
|
||||
expect(mockMap.fitBounds).toHaveBeenCalledWith(new maplibregl.LngLatBounds(
|
||||
[22, 33], [41, 51],
|
||||
), fitBoundsOptions);
|
||||
expect(mockMap.fitBounds).toHaveBeenCalledWith(
|
||||
new maplibregl.LngLatBounds([22, 33], [41, 51]),
|
||||
fitBoundsOptions,
|
||||
);
|
||||
expect(mockMap.fitBounds).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('opens map with both beacons in view on first load with an initially focused beacon', () => {
|
||||
it("opens map with both beacons in view on first load with an initially focused beacon", () => {
|
||||
const [beacon1, beacon2] = makeRoomWithBeacons(
|
||||
roomId, mockClient, [defaultEvent, beacon2Event], [location1, location2],
|
||||
roomId,
|
||||
mockClient,
|
||||
[defaultEvent, beacon2Event],
|
||||
[location1, location2],
|
||||
);
|
||||
|
||||
getComponent({ beacons: [beacon1, beacon2], initialFocusedBeacon: beacon1 });
|
||||
|
@ -326,15 +314,19 @@ describe('<BeaconViewDialog />', () => {
|
|||
// only called once
|
||||
expect(mockMap.setCenter).toHaveBeenCalledTimes(1);
|
||||
// bounds fit both beacons, only called once
|
||||
expect(mockMap.fitBounds).toHaveBeenCalledWith(new maplibregl.LngLatBounds(
|
||||
[22, 33], [41, 51],
|
||||
), fitBoundsOptions);
|
||||
expect(mockMap.fitBounds).toHaveBeenCalledWith(
|
||||
new maplibregl.LngLatBounds([22, 33], [41, 51]),
|
||||
fitBoundsOptions,
|
||||
);
|
||||
expect(mockMap.fitBounds).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('focuses on beacon location on sidebar list item click', () => {
|
||||
it("focuses on beacon location on sidebar list item click", () => {
|
||||
const [beacon1, beacon2] = makeRoomWithBeacons(
|
||||
roomId, mockClient, [defaultEvent, beacon2Event], [location1, location2],
|
||||
roomId,
|
||||
mockClient,
|
||||
[defaultEvent, beacon2Event],
|
||||
[location1, location2],
|
||||
);
|
||||
|
||||
const component = getComponent({ beacons: [beacon1, beacon2] });
|
||||
|
@ -346,7 +338,7 @@ describe('<BeaconViewDialog />', () => {
|
|||
|
||||
act(() => {
|
||||
// click on the first beacon in the list
|
||||
component.find(BeaconListItem).at(0).simulate('click');
|
||||
component.find(BeaconListItem).at(0).simulate("click");
|
||||
});
|
||||
|
||||
// centered on clicked beacon
|
||||
|
@ -354,16 +346,20 @@ describe('<BeaconViewDialog />', () => {
|
|||
// only called once
|
||||
expect(mockMap.setCenter).toHaveBeenCalledTimes(1);
|
||||
// bounds fitted just to clicked beacon
|
||||
expect(mockMap.fitBounds).toHaveBeenCalledWith(new maplibregl.LngLatBounds(
|
||||
[41, 51], [41, 51],
|
||||
), fitBoundsOptions);
|
||||
expect(mockMap.fitBounds).toHaveBeenCalledWith(
|
||||
new maplibregl.LngLatBounds([41, 51], [41, 51]),
|
||||
fitBoundsOptions,
|
||||
);
|
||||
expect(mockMap.fitBounds).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('refocuses on same beacon when clicking list item again', () => {
|
||||
it("refocuses on same beacon when clicking list item again", () => {
|
||||
// test the map responds to refocusing the same beacon
|
||||
const [beacon1, beacon2] = makeRoomWithBeacons(
|
||||
roomId, mockClient, [defaultEvent, beacon2Event], [location1, location2],
|
||||
roomId,
|
||||
mockClient,
|
||||
[defaultEvent, beacon2Event],
|
||||
[location1, location2],
|
||||
);
|
||||
|
||||
const component = getComponent({ beacons: [beacon1, beacon2] });
|
||||
|
@ -375,19 +371,17 @@ describe('<BeaconViewDialog />', () => {
|
|||
|
||||
act(() => {
|
||||
// click on the second beacon in the list
|
||||
component.find(BeaconListItem).at(1).simulate('click');
|
||||
component.find(BeaconListItem).at(1).simulate("click");
|
||||
});
|
||||
|
||||
const expectedBounds = new maplibregl.LngLatBounds(
|
||||
[22, 33], [22, 33],
|
||||
);
|
||||
const expectedBounds = new maplibregl.LngLatBounds([22, 33], [22, 33]);
|
||||
|
||||
// date is mocked but this relies on timestamp, manually mock a tick
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(now + 1);
|
||||
jest.spyOn(global.Date, "now").mockReturnValue(now + 1);
|
||||
|
||||
act(() => {
|
||||
// click on the second beacon in the list
|
||||
component.find(BeaconListItem).at(1).simulate('click');
|
||||
component.find(BeaconListItem).at(1).simulate("click");
|
||||
});
|
||||
|
||||
// centered on clicked beacon
|
||||
|
|
|
@ -14,21 +14,21 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import React from "react";
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
import { act } from "react-dom/test-utils";
|
||||
|
||||
import DialogSidebar from '../../../../src/components/views/beacon/DialogSidebar';
|
||||
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
||||
import DialogSidebar from "../../../../src/components/views/beacon/DialogSidebar";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import {
|
||||
getMockClientWithEventEmitter,
|
||||
makeBeaconEvent,
|
||||
makeBeaconInfoEvent,
|
||||
makeRoomWithBeacons,
|
||||
mockClientMethodsUser,
|
||||
} from '../../../test-utils';
|
||||
} from "../../../test-utils";
|
||||
|
||||
describe('<DialogSidebar />', () => {
|
||||
describe("<DialogSidebar />", () => {
|
||||
const defaultProps = {
|
||||
beacons: [],
|
||||
requestClose: jest.fn(),
|
||||
|
@ -37,66 +37,66 @@ describe('<DialogSidebar />', () => {
|
|||
|
||||
const now = 1647270879403;
|
||||
|
||||
const roomId = '!room:server.org';
|
||||
const aliceId = '@alice:server.org';
|
||||
const roomId = "!room:server.org";
|
||||
const aliceId = "@alice:server.org";
|
||||
const client = getMockClientWithEventEmitter({
|
||||
...mockClientMethodsUser(aliceId),
|
||||
getRoom: jest.fn(),
|
||||
});
|
||||
|
||||
const beaconEvent = makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ isLive: true, timestamp: now },
|
||||
'$alice-room1-1',
|
||||
);
|
||||
const location1 = makeBeaconEvent(
|
||||
aliceId, { beaconInfoId: beaconEvent.getId(), geoUri: 'geo:51,41', timestamp: now },
|
||||
);
|
||||
const beaconEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: true, timestamp: now }, "$alice-room1-1");
|
||||
const location1 = makeBeaconEvent(aliceId, {
|
||||
beaconInfoId: beaconEvent.getId(),
|
||||
geoUri: "geo:51,41",
|
||||
timestamp: now,
|
||||
});
|
||||
|
||||
const getComponent = (props = {}) => (
|
||||
<MatrixClientContext.Provider value={client}>
|
||||
<DialogSidebar {...defaultProps} {...props} />);
|
||||
</MatrixClientContext.Provider>);
|
||||
<DialogSidebar {...defaultProps} {...props} />
|
||||
);
|
||||
</MatrixClientContext.Provider>
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
// mock now so time based text in snapshots is stable
|
||||
jest.spyOn(Date, 'now').mockReturnValue(now);
|
||||
jest.spyOn(Date, "now").mockReturnValue(now);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(Date, 'now').mockRestore();
|
||||
jest.spyOn(Date, "now").mockRestore();
|
||||
});
|
||||
|
||||
it('renders sidebar correctly without beacons', () => {
|
||||
it("renders sidebar correctly without beacons", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders sidebar correctly with beacons', () => {
|
||||
it("renders sidebar correctly with beacons", () => {
|
||||
const [beacon] = makeRoomWithBeacons(roomId, client, [beaconEvent], [location1]);
|
||||
const { container } = render(getComponent({ beacons: [beacon] }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('calls on beacon click', () => {
|
||||
it("calls on beacon click", () => {
|
||||
const onBeaconClick = jest.fn();
|
||||
const [beacon] = makeRoomWithBeacons(roomId, client, [beaconEvent], [location1]);
|
||||
const { container } = render(getComponent({ beacons: [beacon], onBeaconClick }));
|
||||
|
||||
act(() => {
|
||||
const [listItem] = container.getElementsByClassName('mx_BeaconListItem');
|
||||
const [listItem] = container.getElementsByClassName("mx_BeaconListItem");
|
||||
fireEvent.click(listItem);
|
||||
});
|
||||
|
||||
expect(onBeaconClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('closes on close button click', () => {
|
||||
it("closes on close button click", () => {
|
||||
const requestClose = jest.fn();
|
||||
const { getByTestId } = render(getComponent({ requestClose }));
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByTestId('dialog-sidebar-close'));
|
||||
fireEvent.click(getByTestId("dialog-sidebar-close"));
|
||||
});
|
||||
expect(requestClose).toHaveBeenCalled();
|
||||
});
|
||||
|
|
|
@ -14,19 +14,19 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { mocked } from 'jest-mock';
|
||||
import React from "react";
|
||||
import { mocked } from "jest-mock";
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { Beacon, BeaconIdentifier } from 'matrix-js-sdk/src/matrix';
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { Beacon, BeaconIdentifier } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import LeftPanelLiveShareWarning from '../../../../src/components/views/beacon/LeftPanelLiveShareWarning';
|
||||
import { OwnBeaconStore, OwnBeaconStoreEvent } from '../../../../src/stores/OwnBeaconStore';
|
||||
import { flushPromises, makeBeaconInfoEvent } from '../../../test-utils';
|
||||
import dispatcher from '../../../../src/dispatcher/dispatcher';
|
||||
import { Action } from '../../../../src/dispatcher/actions';
|
||||
import LeftPanelLiveShareWarning from "../../../../src/components/views/beacon/LeftPanelLiveShareWarning";
|
||||
import { OwnBeaconStore, OwnBeaconStoreEvent } from "../../../../src/stores/OwnBeaconStore";
|
||||
import { flushPromises, makeBeaconInfoEvent } from "../../../test-utils";
|
||||
import dispatcher from "../../../../src/dispatcher/dispatcher";
|
||||
import { Action } from "../../../../src/dispatcher/actions";
|
||||
|
||||
jest.mock('../../../../src/stores/OwnBeaconStore', () => {
|
||||
jest.mock("../../../../src/stores/OwnBeaconStore", () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const EventEmitter = require("events");
|
||||
class MockOwnBeaconStore extends EventEmitter {
|
||||
|
@ -38,57 +38,52 @@ jest.mock('../../../../src/stores/OwnBeaconStore', () => {
|
|||
}
|
||||
return {
|
||||
// @ts-ignore
|
||||
...jest.requireActual('../../../../src/stores/OwnBeaconStore'),
|
||||
...jest.requireActual("../../../../src/stores/OwnBeaconStore"),
|
||||
OwnBeaconStore: {
|
||||
instance: new MockOwnBeaconStore() as unknown as OwnBeaconStore,
|
||||
},
|
||||
};
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('<LeftPanelLiveShareWarning />', () => {
|
||||
describe("<LeftPanelLiveShareWarning />", () => {
|
||||
const getComponent = (props = {}) => render(<LeftPanelLiveShareWarning {...props} />);
|
||||
|
||||
const roomId1 = '!room1:server';
|
||||
const roomId2 = '!room2:server';
|
||||
const aliceId = '@alive:server';
|
||||
const roomId1 = "!room1:server";
|
||||
const roomId2 = "!room2:server";
|
||||
const aliceId = "@alive:server";
|
||||
|
||||
const now = 1647270879403;
|
||||
const HOUR_MS = 3600000;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(now);
|
||||
jest.spyOn(dispatcher, 'dispatch').mockClear().mockImplementation(() => { });
|
||||
jest.spyOn(global.Date, "now").mockReturnValue(now);
|
||||
jest.spyOn(dispatcher, "dispatch")
|
||||
.mockClear()
|
||||
.mockImplementation(() => {});
|
||||
|
||||
OwnBeaconStore.instance.beaconUpdateErrors.clear();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(global.Date, 'now').mockRestore();
|
||||
jest.spyOn(global.Date, "now").mockRestore();
|
||||
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
// 12h old, 12h left
|
||||
const beacon1 = new Beacon(makeBeaconInfoEvent(aliceId,
|
||||
roomId1,
|
||||
{ timeout: HOUR_MS * 24, timestamp: now - 12 * HOUR_MS },
|
||||
'$1',
|
||||
));
|
||||
const beacon1 = new Beacon(
|
||||
makeBeaconInfoEvent(aliceId, roomId1, { timeout: HOUR_MS * 24, timestamp: now - 12 * HOUR_MS }, "$1"),
|
||||
);
|
||||
// 10h left
|
||||
const beacon2 = new Beacon(makeBeaconInfoEvent(aliceId,
|
||||
roomId2,
|
||||
{ timeout: HOUR_MS * 10, timestamp: now },
|
||||
'$2',
|
||||
));
|
||||
const beacon2 = new Beacon(makeBeaconInfoEvent(aliceId, roomId2, { timeout: HOUR_MS * 10, timestamp: now }, "$2"));
|
||||
|
||||
it('renders nothing when user has no live beacons', () => {
|
||||
it("renders nothing when user has no live beacons", () => {
|
||||
const { container } = getComponent();
|
||||
expect(container.innerHTML).toBeFalsy();
|
||||
});
|
||||
|
||||
describe('when user has live location monitor', () => {
|
||||
describe("when user has live location monitor", () => {
|
||||
beforeAll(() => {
|
||||
mocked(OwnBeaconStore.instance).getBeaconById.mockImplementation(beaconId => {
|
||||
mocked(OwnBeaconStore.instance).getBeaconById.mockImplementation((beaconId) => {
|
||||
if (beaconId === beacon1.identifier) {
|
||||
return beacon1;
|
||||
}
|
||||
|
@ -104,17 +99,17 @@ describe('<LeftPanelLiveShareWarning />', () => {
|
|||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(document, 'addEventListener').mockRestore();
|
||||
jest.spyOn(document, "addEventListener").mockRestore();
|
||||
});
|
||||
|
||||
it('renders correctly when not minimized', () => {
|
||||
it("renders correctly when not minimized", () => {
|
||||
const { asFragment } = getComponent();
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('goes to room of latest beacon when clicked', () => {
|
||||
it("goes to room of latest beacon when clicked", () => {
|
||||
const { container } = getComponent();
|
||||
const dispatchSpy = jest.spyOn(dispatcher, 'dispatch');
|
||||
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
|
||||
|
||||
fireEvent.click(container.querySelector("[role=button]"));
|
||||
|
||||
|
@ -129,25 +124,25 @@ describe('<LeftPanelLiveShareWarning />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('renders correctly when minimized', () => {
|
||||
it("renders correctly when minimized", () => {
|
||||
const { asFragment } = getComponent({ isMinimized: true });
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders location publish error', () => {
|
||||
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue(
|
||||
[beacon1.identifier],
|
||||
);
|
||||
it("renders location publish error", () => {
|
||||
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue([
|
||||
beacon1.identifier,
|
||||
]);
|
||||
const { asFragment } = getComponent();
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('goes to room of latest beacon with location publish error when clicked', () => {
|
||||
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue(
|
||||
[beacon1.identifier],
|
||||
);
|
||||
it("goes to room of latest beacon with location publish error when clicked", () => {
|
||||
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue([
|
||||
beacon1.identifier,
|
||||
]);
|
||||
const { container } = getComponent();
|
||||
const dispatchSpy = jest.spyOn(dispatcher, 'dispatch');
|
||||
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
|
||||
|
||||
fireEvent.click(container.querySelector("[role=button]"));
|
||||
|
||||
|
@ -162,30 +157,30 @@ describe('<LeftPanelLiveShareWarning />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('goes back to default style when wire errors are cleared', () => {
|
||||
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue(
|
||||
[beacon1.identifier],
|
||||
);
|
||||
it("goes back to default style when wire errors are cleared", () => {
|
||||
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue([
|
||||
beacon1.identifier,
|
||||
]);
|
||||
const { container, rerender } = getComponent();
|
||||
// error mode
|
||||
expect(container.querySelector('.mx_LeftPanelLiveShareWarning').textContent).toEqual(
|
||||
'An error occurred whilst sharing your live location',
|
||||
expect(container.querySelector(".mx_LeftPanelLiveShareWarning").textContent).toEqual(
|
||||
"An error occurred whilst sharing your live location",
|
||||
);
|
||||
|
||||
act(() => {
|
||||
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue([]);
|
||||
OwnBeaconStore.instance.emit(OwnBeaconStoreEvent.LocationPublishError, 'abc');
|
||||
OwnBeaconStore.instance.emit(OwnBeaconStoreEvent.LocationPublishError, "abc");
|
||||
});
|
||||
|
||||
rerender(<LeftPanelLiveShareWarning />);
|
||||
|
||||
// default mode
|
||||
expect(container.querySelector('.mx_LeftPanelLiveShareWarning').textContent).toEqual(
|
||||
'You are sharing your live location',
|
||||
expect(container.querySelector(".mx_LeftPanelLiveShareWarning").textContent).toEqual(
|
||||
"You are sharing your live location",
|
||||
);
|
||||
});
|
||||
|
||||
it('removes itself when user stops having live beacons', async () => {
|
||||
it("removes itself when user stops having live beacons", async () => {
|
||||
const { container, rerender } = getComponent({ isMinimized: true });
|
||||
// started out rendered
|
||||
expect(container.innerHTML).toBeTruthy();
|
||||
|
@ -202,14 +197,14 @@ describe('<LeftPanelLiveShareWarning />', () => {
|
|||
expect(container.innerHTML).toBeFalsy();
|
||||
});
|
||||
|
||||
it('refreshes beacon liveness monitors when pagevisibilty changes to visible', () => {
|
||||
it("refreshes beacon liveness monitors when pagevisibilty changes to visible", () => {
|
||||
OwnBeaconStore.instance.beacons.set(beacon1.identifier, beacon1);
|
||||
OwnBeaconStore.instance.beacons.set(beacon2.identifier, beacon2);
|
||||
const beacon1MonitorSpy = jest.spyOn(beacon1, 'monitorLiveness');
|
||||
const beacon2MonitorSpy = jest.spyOn(beacon1, 'monitorLiveness');
|
||||
const beacon1MonitorSpy = jest.spyOn(beacon1, "monitorLiveness");
|
||||
const beacon2MonitorSpy = jest.spyOn(beacon1, "monitorLiveness");
|
||||
|
||||
jest.spyOn(document, 'addEventListener').mockImplementation(
|
||||
(_e, listener) => (listener as EventListener)(new Event('')),
|
||||
jest.spyOn(document, "addEventListener").mockImplementation((_e, listener) =>
|
||||
(listener as EventListener)(new Event("")),
|
||||
);
|
||||
|
||||
expect(beacon1MonitorSpy).not.toHaveBeenCalled();
|
||||
|
@ -220,42 +215,42 @@ describe('<LeftPanelLiveShareWarning />', () => {
|
|||
expect(beacon2MonitorSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('stopping errors', () => {
|
||||
it('renders stopping error', () => {
|
||||
OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error('error'));
|
||||
describe("stopping errors", () => {
|
||||
it("renders stopping error", () => {
|
||||
OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error("error"));
|
||||
const { container } = getComponent();
|
||||
expect(container.textContent).toEqual('An error occurred while stopping your live location');
|
||||
expect(container.textContent).toEqual("An error occurred while stopping your live location");
|
||||
});
|
||||
|
||||
it('starts rendering stopping error on beaconUpdateError emit', () => {
|
||||
it("starts rendering stopping error on beaconUpdateError emit", () => {
|
||||
const { container } = getComponent();
|
||||
// no error
|
||||
expect(container.textContent).toEqual('You are sharing your live location');
|
||||
expect(container.textContent).toEqual("You are sharing your live location");
|
||||
|
||||
act(() => {
|
||||
OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error('error'));
|
||||
OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error("error"));
|
||||
OwnBeaconStore.instance.emit(OwnBeaconStoreEvent.BeaconUpdateError, beacon2.identifier, true);
|
||||
});
|
||||
|
||||
expect(container.textContent).toEqual('An error occurred while stopping your live location');
|
||||
expect(container.textContent).toEqual("An error occurred while stopping your live location");
|
||||
});
|
||||
|
||||
it('renders stopping error when beacons have stopping and location errors', () => {
|
||||
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue(
|
||||
[beacon1.identifier],
|
||||
);
|
||||
OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error('error'));
|
||||
it("renders stopping error when beacons have stopping and location errors", () => {
|
||||
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue([
|
||||
beacon1.identifier,
|
||||
]);
|
||||
OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error("error"));
|
||||
const { container } = getComponent();
|
||||
expect(container.textContent).toEqual('An error occurred while stopping your live location');
|
||||
expect(container.textContent).toEqual("An error occurred while stopping your live location");
|
||||
});
|
||||
|
||||
it('goes to room of latest beacon with stopping error when clicked', () => {
|
||||
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue(
|
||||
[beacon1.identifier],
|
||||
);
|
||||
OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error('error'));
|
||||
it("goes to room of latest beacon with stopping error when clicked", () => {
|
||||
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue([
|
||||
beacon1.identifier,
|
||||
]);
|
||||
OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error("error"));
|
||||
const { container } = getComponent();
|
||||
const dispatchSpy = jest.spyOn(dispatcher, 'dispatch');
|
||||
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
|
||||
|
||||
fireEvent.click(container.querySelector("[role=button]"));
|
||||
|
||||
|
|
|
@ -14,62 +14,61 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { mocked } from 'jest-mock';
|
||||
import { Beacon } from 'matrix-js-sdk/src/matrix';
|
||||
import { mount } from "enzyme";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { mocked } from "jest-mock";
|
||||
import { Beacon } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import OwnBeaconStatus from '../../../../src/components/views/beacon/OwnBeaconStatus';
|
||||
import { BeaconDisplayStatus } from '../../../../src/components/views/beacon/displayStatus';
|
||||
import { useOwnLiveBeacons } from '../../../../src/utils/beacon';
|
||||
import { findByTestId, makeBeaconInfoEvent } from '../../../test-utils';
|
||||
import OwnBeaconStatus from "../../../../src/components/views/beacon/OwnBeaconStatus";
|
||||
import { BeaconDisplayStatus } from "../../../../src/components/views/beacon/displayStatus";
|
||||
import { useOwnLiveBeacons } from "../../../../src/utils/beacon";
|
||||
import { findByTestId, makeBeaconInfoEvent } from "../../../test-utils";
|
||||
|
||||
jest.mock('../../../../src/utils/beacon/useOwnLiveBeacons', () => ({
|
||||
jest.mock("../../../../src/utils/beacon/useOwnLiveBeacons", () => ({
|
||||
useOwnLiveBeacons: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('<OwnBeaconStatus />', () => {
|
||||
describe("<OwnBeaconStatus />", () => {
|
||||
const defaultProps = {
|
||||
displayStatus: BeaconDisplayStatus.Loading,
|
||||
};
|
||||
const userId = '@user:server';
|
||||
const roomId = '!room:server';
|
||||
const userId = "@user:server";
|
||||
const roomId = "!room:server";
|
||||
let defaultBeacon;
|
||||
const getComponent = (props = {}) =>
|
||||
mount(<OwnBeaconStatus {...defaultProps} {...props} />);
|
||||
const getComponent = (props = {}) => mount(<OwnBeaconStatus {...defaultProps} {...props} />);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(123456789);
|
||||
jest.spyOn(global.Date, "now").mockReturnValue(123456789);
|
||||
mocked(useOwnLiveBeacons).mockClear().mockReturnValue({});
|
||||
|
||||
defaultBeacon = new Beacon(makeBeaconInfoEvent(userId, roomId));
|
||||
});
|
||||
|
||||
it('renders without a beacon instance', () => {
|
||||
it("renders without a beacon instance", () => {
|
||||
const component = getComponent();
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders loading state correctly', () => {
|
||||
it("renders loading state correctly", () => {
|
||||
const component = getComponent();
|
||||
expect(component.find('BeaconStatus').props()).toBeTruthy();
|
||||
expect(component.find("BeaconStatus").props()).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('Active state', () => {
|
||||
it('renders stop button', () => {
|
||||
describe("Active state", () => {
|
||||
it("renders stop button", () => {
|
||||
const displayStatus = BeaconDisplayStatus.Active;
|
||||
mocked(useOwnLiveBeacons).mockReturnValue({
|
||||
onStopSharing: jest.fn(),
|
||||
});
|
||||
const component = getComponent({ displayStatus, beacon: defaultBeacon });
|
||||
expect(component.text()).toContain('Live location enabled');
|
||||
expect(component.text()).toContain("Live location enabled");
|
||||
|
||||
expect(findByTestId(component, 'beacon-status-stop-beacon').length).toBeTruthy();
|
||||
expect(findByTestId(component, "beacon-status-stop-beacon").length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('stops sharing on stop button click', () => {
|
||||
it("stops sharing on stop button click", () => {
|
||||
const displayStatus = BeaconDisplayStatus.Active;
|
||||
const onStopSharing = jest.fn();
|
||||
mocked(useOwnLiveBeacons).mockReturnValue({
|
||||
|
@ -78,37 +77,37 @@ describe('<OwnBeaconStatus />', () => {
|
|||
const component = getComponent({ displayStatus, beacon: defaultBeacon });
|
||||
|
||||
act(() => {
|
||||
findByTestId(component, 'beacon-status-stop-beacon').at(0).simulate('click');
|
||||
findByTestId(component, "beacon-status-stop-beacon").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(onStopSharing).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('errors', () => {
|
||||
it('renders in error mode when displayStatus is error', () => {
|
||||
describe("errors", () => {
|
||||
it("renders in error mode when displayStatus is error", () => {
|
||||
const displayStatus = BeaconDisplayStatus.Error;
|
||||
const component = getComponent({ displayStatus });
|
||||
expect(component.text()).toEqual('Live location error');
|
||||
expect(component.text()).toEqual("Live location error");
|
||||
|
||||
// no actions for plain error
|
||||
expect(component.find('AccessibleButton').length).toBeFalsy();
|
||||
expect(component.find("AccessibleButton").length).toBeFalsy();
|
||||
});
|
||||
|
||||
describe('with location publish error', () => {
|
||||
it('renders in error mode', () => {
|
||||
describe("with location publish error", () => {
|
||||
it("renders in error mode", () => {
|
||||
const displayStatus = BeaconDisplayStatus.Active;
|
||||
mocked(useOwnLiveBeacons).mockReturnValue({
|
||||
hasLocationPublishError: true,
|
||||
onResetLocationPublishError: jest.fn(),
|
||||
});
|
||||
const component = getComponent({ displayStatus, beacon: defaultBeacon });
|
||||
expect(component.text()).toContain('Live location error');
|
||||
expect(component.text()).toContain("Live location error");
|
||||
// retry button
|
||||
expect(findByTestId(component, 'beacon-status-reset-wire-error').length).toBeTruthy();
|
||||
expect(findByTestId(component, "beacon-status-reset-wire-error").length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('retry button resets location publish error', () => {
|
||||
it("retry button resets location publish error", () => {
|
||||
const displayStatus = BeaconDisplayStatus.Active;
|
||||
const onResetLocationPublishError = jest.fn();
|
||||
mocked(useOwnLiveBeacons).mockReturnValue({
|
||||
|
@ -117,15 +116,15 @@ describe('<OwnBeaconStatus />', () => {
|
|||
});
|
||||
const component = getComponent({ displayStatus, beacon: defaultBeacon });
|
||||
act(() => {
|
||||
findByTestId(component, 'beacon-status-reset-wire-error').at(0).simulate('click');
|
||||
findByTestId(component, "beacon-status-reset-wire-error").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(onResetLocationPublishError).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with stopping error', () => {
|
||||
it('renders in error mode', () => {
|
||||
describe("with stopping error", () => {
|
||||
it("renders in error mode", () => {
|
||||
const displayStatus = BeaconDisplayStatus.Active;
|
||||
mocked(useOwnLiveBeacons).mockReturnValue({
|
||||
hasLocationPublishError: false,
|
||||
|
@ -133,12 +132,12 @@ describe('<OwnBeaconStatus />', () => {
|
|||
onStopSharing: jest.fn(),
|
||||
});
|
||||
const component = getComponent({ displayStatus, beacon: defaultBeacon });
|
||||
expect(component.text()).toContain('Live location error');
|
||||
expect(component.text()).toContain("Live location error");
|
||||
// retry button
|
||||
expect(findByTestId(component, 'beacon-status-stop-beacon-retry').length).toBeTruthy();
|
||||
expect(findByTestId(component, "beacon-status-stop-beacon-retry").length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('retry button retries stop sharing', () => {
|
||||
it("retry button retries stop sharing", () => {
|
||||
const displayStatus = BeaconDisplayStatus.Active;
|
||||
const onStopSharing = jest.fn();
|
||||
mocked(useOwnLiveBeacons).mockReturnValue({
|
||||
|
@ -147,7 +146,7 @@ describe('<OwnBeaconStatus />', () => {
|
|||
});
|
||||
const component = getComponent({ displayStatus, beacon: defaultBeacon });
|
||||
act(() => {
|
||||
findByTestId(component, 'beacon-status-stop-beacon-retry').at(0).simulate('click');
|
||||
findByTestId(component, "beacon-status-stop-beacon-retry").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(onStopSharing).toHaveBeenCalled();
|
||||
|
@ -155,7 +154,7 @@ describe('<OwnBeaconStatus />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('renders loading state correctly', () => {
|
||||
it("renders loading state correctly", () => {
|
||||
const component = getComponent();
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
|
|
@ -16,28 +16,12 @@ limitations under the License.
|
|||
|
||||
import React from "react";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import {
|
||||
Room,
|
||||
PendingEventOrdering,
|
||||
MatrixClient,
|
||||
RoomMember,
|
||||
RoomStateEvent,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { Room, PendingEventOrdering, MatrixClient, RoomMember, RoomStateEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { ClientWidgetApi, Widget } from "matrix-widget-api";
|
||||
import {
|
||||
cleanup,
|
||||
render,
|
||||
screen,
|
||||
} from "@testing-library/react";
|
||||
import { cleanup, render, screen } from "@testing-library/react";
|
||||
import { mocked, Mocked } from "jest-mock";
|
||||
|
||||
import {
|
||||
mkRoomMember,
|
||||
MockedCall,
|
||||
setupAsyncStoreWithClient,
|
||||
stubClient,
|
||||
useMockedCalls,
|
||||
} from "../../../test-utils";
|
||||
import { mkRoomMember, MockedCall, setupAsyncStoreWithClient, stubClient, useMockedCalls } from "../../../test-utils";
|
||||
import RoomCallBanner from "../../../../src/components/views/beacon/RoomCallBanner";
|
||||
import { CallStore } from "../../../../src/stores/CallStore";
|
||||
import { WidgetMessagingStore } from "../../../../src/stores/widgets/WidgetMessagingStore";
|
||||
|
@ -64,13 +48,9 @@ describe("<RoomCallBanner />", () => {
|
|||
pendingEventOrdering: PendingEventOrdering.Detached,
|
||||
});
|
||||
alice = mkRoomMember(room.roomId, "@alice:example.org");
|
||||
jest.spyOn(room, "getMember").mockImplementation((userId) =>
|
||||
userId === alice.userId ? alice : null,
|
||||
);
|
||||
jest.spyOn(room, "getMember").mockImplementation((userId) => (userId === alice.userId ? alice : null));
|
||||
|
||||
client.getRoom.mockImplementation((roomId) =>
|
||||
roomId === room.roomId ? room : null,
|
||||
);
|
||||
client.getRoom.mockImplementation((roomId) => (roomId === room.roomId ? room : null));
|
||||
client.getRooms.mockReturnValue([room]);
|
||||
client.reEmitter.reEmit(room, [RoomStateEvent.Events]);
|
||||
|
||||
|
@ -100,7 +80,9 @@ describe("<RoomCallBanner />", () => {
|
|||
beforeEach(() => {
|
||||
MockedCall.create(room, "1");
|
||||
const maybeCall = CallStore.instance.getCall(room.roomId);
|
||||
if (!(maybeCall instanceof MockedCall)) {throw new Error("Failed to create call");}
|
||||
if (!(maybeCall instanceof MockedCall)) {
|
||||
throw new Error("Failed to create call");
|
||||
}
|
||||
call = maybeCall;
|
||||
|
||||
widget = new Widget(call.widget);
|
||||
|
|
|
@ -14,15 +14,15 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import React from "react";
|
||||
import { act } from "react-dom/test-utils";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { Room, Beacon, BeaconEvent, getBeaconInfoIdentifier } from 'matrix-js-sdk/src/matrix';
|
||||
import { logger } from 'matrix-js-sdk/src/logger';
|
||||
import { mount } from "enzyme";
|
||||
import { Room, Beacon, BeaconEvent, getBeaconInfoIdentifier } from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import RoomLiveShareWarning from '../../../../src/components/views/beacon/RoomLiveShareWarning';
|
||||
import { OwnBeaconStore, OwnBeaconStoreEvent } from '../../../../src/stores/OwnBeaconStore';
|
||||
import RoomLiveShareWarning from "../../../../src/components/views/beacon/RoomLiveShareWarning";
|
||||
import { OwnBeaconStore, OwnBeaconStoreEvent } from "../../../../src/stores/OwnBeaconStore";
|
||||
import {
|
||||
advanceDateAndTime,
|
||||
findByTestId,
|
||||
|
@ -32,20 +32,20 @@ import {
|
|||
mockGeolocation,
|
||||
resetAsyncStoreWithClient,
|
||||
setupAsyncStoreWithClient,
|
||||
} from '../../../test-utils';
|
||||
import defaultDispatcher from '../../../../src/dispatcher/dispatcher';
|
||||
import { Action } from '../../../../src/dispatcher/actions';
|
||||
} from "../../../test-utils";
|
||||
import defaultDispatcher from "../../../../src/dispatcher/dispatcher";
|
||||
import { Action } from "../../../../src/dispatcher/actions";
|
||||
|
||||
jest.useFakeTimers();
|
||||
describe('<RoomLiveShareWarning />', () => {
|
||||
const aliceId = '@alice:server.org';
|
||||
const room1Id = '$room1:server.org';
|
||||
const room2Id = '$room2:server.org';
|
||||
const room3Id = '$room3:server.org';
|
||||
describe("<RoomLiveShareWarning />", () => {
|
||||
const aliceId = "@alice:server.org";
|
||||
const room1Id = "$room1:server.org";
|
||||
const room2Id = "$room2:server.org";
|
||||
const room3Id = "$room3:server.org";
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getVisibleRooms: jest.fn().mockReturnValue([]),
|
||||
getUserId: jest.fn().mockReturnValue(aliceId),
|
||||
unstable_setLiveBeacon: jest.fn().mockResolvedValue({ event_id: '1' }),
|
||||
unstable_setLiveBeacon: jest.fn().mockResolvedValue({ event_id: "1" }),
|
||||
sendEvent: jest.fn(),
|
||||
});
|
||||
|
||||
|
@ -54,14 +54,19 @@ describe('<RoomLiveShareWarning />', () => {
|
|||
const MINUTE_MS = 60000;
|
||||
const HOUR_MS = 3600000;
|
||||
// mock the date so events are stable for snapshots etc
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(now);
|
||||
const room1Beacon1 = makeBeaconInfoEvent(aliceId, room1Id, {
|
||||
isLive: true,
|
||||
timeout: HOUR_MS,
|
||||
}, '$0');
|
||||
const room2Beacon1 = makeBeaconInfoEvent(aliceId, room2Id, { isLive: true, timeout: HOUR_MS }, '$1');
|
||||
const room2Beacon2 = makeBeaconInfoEvent(aliceId, room2Id, { isLive: true, timeout: HOUR_MS * 12 }, '$2');
|
||||
const room3Beacon1 = makeBeaconInfoEvent(aliceId, room3Id, { isLive: true, timeout: HOUR_MS }, '$3');
|
||||
jest.spyOn(global.Date, "now").mockReturnValue(now);
|
||||
const room1Beacon1 = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
room1Id,
|
||||
{
|
||||
isLive: true,
|
||||
timeout: HOUR_MS,
|
||||
},
|
||||
"$0",
|
||||
);
|
||||
const room2Beacon1 = makeBeaconInfoEvent(aliceId, room2Id, { isLive: true, timeout: HOUR_MS }, "$1");
|
||||
const room2Beacon2 = makeBeaconInfoEvent(aliceId, room2Id, { isLive: true, timeout: HOUR_MS * 12 }, "$2");
|
||||
const room3Beacon1 = makeBeaconInfoEvent(aliceId, room3Id, { isLive: true, timeout: HOUR_MS }, "$3");
|
||||
|
||||
// make fresh rooms every time
|
||||
// as we update room state
|
||||
|
@ -96,42 +101,39 @@ describe('<RoomLiveShareWarning />', () => {
|
|||
return component;
|
||||
};
|
||||
|
||||
const localStorageSpy = jest.spyOn(localStorage.__proto__, 'getItem').mockReturnValue(undefined);
|
||||
const localStorageSpy = jest.spyOn(localStorage.__proto__, "getItem").mockReturnValue(undefined);
|
||||
|
||||
beforeEach(() => {
|
||||
mockGeolocation();
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(now);
|
||||
mockClient.unstable_setLiveBeacon.mockReset().mockResolvedValue({ event_id: '1' });
|
||||
jest.spyOn(global.Date, "now").mockReturnValue(now);
|
||||
mockClient.unstable_setLiveBeacon.mockReset().mockResolvedValue({ event_id: "1" });
|
||||
|
||||
// assume all beacons were created on this device
|
||||
localStorageSpy.mockReturnValue(JSON.stringify([
|
||||
room1Beacon1.getId(),
|
||||
room2Beacon1.getId(),
|
||||
room2Beacon2.getId(),
|
||||
room3Beacon1.getId(),
|
||||
]));
|
||||
localStorageSpy.mockReturnValue(
|
||||
JSON.stringify([room1Beacon1.getId(), room2Beacon1.getId(), room2Beacon2.getId(), room3Beacon1.getId()]),
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
jest.spyOn(OwnBeaconStore.instance, 'beaconHasLocationPublishError').mockRestore();
|
||||
jest.spyOn(OwnBeaconStore.instance, "beaconHasLocationPublishError").mockRestore();
|
||||
await resetAsyncStoreWithClient(OwnBeaconStore.instance);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(global.Date, 'now').mockRestore();
|
||||
jest.spyOn(global.Date, "now").mockRestore();
|
||||
localStorageSpy.mockRestore();
|
||||
jest.spyOn(defaultDispatcher, 'dispatch').mockRestore();
|
||||
jest.spyOn(defaultDispatcher, "dispatch").mockRestore();
|
||||
});
|
||||
|
||||
const getExpiryText = wrapper => findByTestId(wrapper, 'room-live-share-expiry').text();
|
||||
const getExpiryText = (wrapper) => findByTestId(wrapper, "room-live-share-expiry").text();
|
||||
|
||||
it('renders nothing when user has no live beacons at all', async () => {
|
||||
it("renders nothing when user has no live beacons at all", async () => {
|
||||
await makeOwnBeaconStore();
|
||||
const component = getComponent();
|
||||
expect(component.html()).toBe(null);
|
||||
});
|
||||
|
||||
it('renders nothing when user has no live beacons in room', async () => {
|
||||
it("renders nothing when user has no live beacons in room", async () => {
|
||||
await act(async () => {
|
||||
await makeRoomsWithStateEvents([room2Beacon1]);
|
||||
await makeOwnBeaconStore();
|
||||
|
@ -140,8 +142,8 @@ describe('<RoomLiveShareWarning />', () => {
|
|||
expect(component.html()).toBe(null);
|
||||
});
|
||||
|
||||
it('does not render when geolocation is not working', async () => {
|
||||
jest.spyOn(logger, 'error').mockImplementation(() => { });
|
||||
it("does not render when geolocation is not working", async () => {
|
||||
jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||
// @ts-ignore
|
||||
navigator.geolocation = undefined;
|
||||
await act(async () => {
|
||||
|
@ -155,7 +157,7 @@ describe('<RoomLiveShareWarning />', () => {
|
|||
expect(component.html()).toBeNull();
|
||||
});
|
||||
|
||||
describe('when user has live beacons and geolocation is available', () => {
|
||||
describe("when user has live beacons and geolocation is available", () => {
|
||||
beforeEach(async () => {
|
||||
await act(async () => {
|
||||
await makeRoomsWithStateEvents([room1Beacon1, room2Beacon1, room2Beacon2]);
|
||||
|
@ -163,23 +165,23 @@ describe('<RoomLiveShareWarning />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('renders correctly with one live beacon in room', () => {
|
||||
it("renders correctly with one live beacon in room", () => {
|
||||
const component = getComponent({ roomId: room1Id });
|
||||
// beacons have generated ids that break snapshots
|
||||
// assert on html
|
||||
expect(component.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders correctly with two live beacons in room', () => {
|
||||
it("renders correctly with two live beacons in room", () => {
|
||||
const component = getComponent({ roomId: room2Id });
|
||||
// beacons have generated ids that break snapshots
|
||||
// assert on html
|
||||
expect(component.html()).toMatchSnapshot();
|
||||
// later expiry displayed
|
||||
expect(getExpiryText(component)).toEqual('12h left');
|
||||
expect(getExpiryText(component)).toEqual("12h left");
|
||||
});
|
||||
|
||||
it('removes itself when user stops having live beacons', async () => {
|
||||
it("removes itself when user stops having live beacons", async () => {
|
||||
const component = getComponent({ roomId: room1Id });
|
||||
// started out rendered
|
||||
expect(component.html()).toBeTruthy();
|
||||
|
@ -196,7 +198,7 @@ describe('<RoomLiveShareWarning />', () => {
|
|||
expect(component.html()).toBe(null);
|
||||
});
|
||||
|
||||
it('removes itself when user stops monitoring live position', async () => {
|
||||
it("removes itself when user stops monitoring live position", async () => {
|
||||
const component = getComponent({ roomId: room1Id });
|
||||
// started out rendered
|
||||
expect(component.html()).toBeTruthy();
|
||||
|
@ -212,7 +214,7 @@ describe('<RoomLiveShareWarning />', () => {
|
|||
expect(component.html()).toBe(null);
|
||||
});
|
||||
|
||||
it('renders when user adds a live beacon', async () => {
|
||||
it("renders when user adds a live beacon", async () => {
|
||||
const component = getComponent({ roomId: room3Id });
|
||||
// started out not rendered
|
||||
expect(component.html()).toBeFalsy();
|
||||
|
@ -225,40 +227,45 @@ describe('<RoomLiveShareWarning />', () => {
|
|||
expect(component.html()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('updates beacon time left periodically', () => {
|
||||
it("updates beacon time left periodically", () => {
|
||||
const component = getComponent({ roomId: room1Id });
|
||||
expect(getExpiryText(component)).toEqual('1h left');
|
||||
expect(getExpiryText(component)).toEqual("1h left");
|
||||
|
||||
act(() => {
|
||||
advanceDateAndTime(MINUTE_MS * 25);
|
||||
});
|
||||
|
||||
expect(getExpiryText(component)).toEqual('35m left');
|
||||
expect(getExpiryText(component)).toEqual("35m left");
|
||||
});
|
||||
|
||||
it('updates beacon time left when beacon updates', () => {
|
||||
it("updates beacon time left when beacon updates", () => {
|
||||
const component = getComponent({ roomId: room1Id });
|
||||
expect(getExpiryText(component)).toEqual('1h left');
|
||||
expect(getExpiryText(component)).toEqual("1h left");
|
||||
|
||||
expect(getExpiryText(component)).toEqual('1h left');
|
||||
expect(getExpiryText(component)).toEqual("1h left");
|
||||
|
||||
act(() => {
|
||||
const beacon = OwnBeaconStore.instance.getBeaconById(getBeaconInfoIdentifier(room1Beacon1));
|
||||
const room1Beacon1Update = makeBeaconInfoEvent(aliceId, room1Id, {
|
||||
isLive: true,
|
||||
timeout: 3 * HOUR_MS,
|
||||
}, '$0');
|
||||
const room1Beacon1Update = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
room1Id,
|
||||
{
|
||||
isLive: true,
|
||||
timeout: 3 * HOUR_MS,
|
||||
},
|
||||
"$0",
|
||||
);
|
||||
beacon.update(room1Beacon1Update);
|
||||
});
|
||||
|
||||
// update to expiry of new beacon
|
||||
expect(getExpiryText(component)).toEqual('3h left');
|
||||
expect(getExpiryText(component)).toEqual("3h left");
|
||||
});
|
||||
|
||||
it('clears expiry time interval on unmount', () => {
|
||||
const clearIntervalSpy = jest.spyOn(global, 'clearInterval');
|
||||
it("clears expiry time interval on unmount", () => {
|
||||
const clearIntervalSpy = jest.spyOn(global, "clearInterval");
|
||||
const component = getComponent({ roomId: room1Id });
|
||||
expect(getExpiryText(component)).toEqual('1h left');
|
||||
expect(getExpiryText(component)).toEqual("1h left");
|
||||
|
||||
act(() => {
|
||||
component.unmount();
|
||||
|
@ -267,12 +274,12 @@ describe('<RoomLiveShareWarning />', () => {
|
|||
expect(clearIntervalSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('navigates to beacon tile on click', () => {
|
||||
const dispatcherSpy = jest.spyOn(defaultDispatcher, 'dispatch');
|
||||
it("navigates to beacon tile on click", () => {
|
||||
const dispatcherSpy = jest.spyOn(defaultDispatcher, "dispatch");
|
||||
const component = getComponent({ roomId: room1Id });
|
||||
|
||||
act(() => {
|
||||
component.simulate('click');
|
||||
component.simulate("click");
|
||||
});
|
||||
|
||||
expect(dispatcherSpy).toHaveBeenCalledWith({
|
||||
|
@ -285,30 +292,30 @@ describe('<RoomLiveShareWarning />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('stopping beacons', () => {
|
||||
it('stops beacon on stop sharing click', () => {
|
||||
describe("stopping beacons", () => {
|
||||
it("stops beacon on stop sharing click", () => {
|
||||
const component = getComponent({ roomId: room2Id });
|
||||
|
||||
act(() => {
|
||||
findByTestId(component, 'room-live-share-primary-button').at(0).simulate('click');
|
||||
findByTestId(component, "room-live-share-primary-button").at(0).simulate("click");
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
expect(mockClient.unstable_setLiveBeacon).toHaveBeenCalled();
|
||||
expect(component.find('Spinner').length).toBeTruthy();
|
||||
expect(findByTestId(component, 'room-live-share-primary-button').at(0).props().disabled).toBeTruthy();
|
||||
expect(component.find("Spinner").length).toBeTruthy();
|
||||
expect(findByTestId(component, "room-live-share-primary-button").at(0).props().disabled).toBeTruthy();
|
||||
});
|
||||
|
||||
it('displays error when stop sharing fails', async () => {
|
||||
it("displays error when stop sharing fails", async () => {
|
||||
const component = getComponent({ roomId: room1Id });
|
||||
|
||||
// fail first time
|
||||
mockClient.unstable_setLiveBeacon
|
||||
.mockRejectedValueOnce(new Error('oups'))
|
||||
.mockResolvedValue(({ event_id: '1' }));
|
||||
.mockRejectedValueOnce(new Error("oups"))
|
||||
.mockResolvedValue({ event_id: "1" });
|
||||
|
||||
await act(async () => {
|
||||
findByTestId(component, 'room-live-share-primary-button').at(0).simulate('click');
|
||||
findByTestId(component, "room-live-share-primary-button").at(0).simulate("click");
|
||||
await flushPromisesWithFakeTimers();
|
||||
});
|
||||
component.setProps({});
|
||||
|
@ -316,20 +323,20 @@ describe('<RoomLiveShareWarning />', () => {
|
|||
expect(component.html()).toMatchSnapshot();
|
||||
|
||||
act(() => {
|
||||
findByTestId(component, 'room-live-share-primary-button').at(0).simulate('click');
|
||||
findByTestId(component, "room-live-share-primary-button").at(0).simulate("click");
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
expect(mockClient.unstable_setLiveBeacon).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('displays again with correct state after stopping a beacon', () => {
|
||||
it("displays again with correct state after stopping a beacon", () => {
|
||||
// make sure the loading state is reset correctly after removing a beacon
|
||||
const component = getComponent({ roomId: room1Id });
|
||||
|
||||
// stop the beacon
|
||||
act(() => {
|
||||
findByTestId(component, 'room-live-share-primary-button').at(0).simulate('click');
|
||||
findByTestId(component, "room-live-share-primary-button").at(0).simulate("click");
|
||||
});
|
||||
// time travel until room1Beacon1 is expired
|
||||
act(() => {
|
||||
|
@ -345,28 +352,30 @@ describe('<RoomLiveShareWarning />', () => {
|
|||
});
|
||||
|
||||
// button not disabled and expiry time shown
|
||||
expect(findByTestId(component, 'room-live-share-primary-button').at(0).props().disabled).toBeFalsy();
|
||||
expect(findByTestId(component, 'room-live-share-expiry').text()).toEqual('1h left');
|
||||
expect(findByTestId(component, "room-live-share-primary-button").at(0).props().disabled).toBeFalsy();
|
||||
expect(findByTestId(component, "room-live-share-expiry").text()).toEqual("1h left");
|
||||
});
|
||||
});
|
||||
|
||||
describe('with location publish errors', () => {
|
||||
it('displays location publish error when mounted with location publish errors', async () => {
|
||||
const locationPublishErrorSpy = jest.spyOn(OwnBeaconStore.instance, 'beaconHasLocationPublishError')
|
||||
describe("with location publish errors", () => {
|
||||
it("displays location publish error when mounted with location publish errors", async () => {
|
||||
const locationPublishErrorSpy = jest
|
||||
.spyOn(OwnBeaconStore.instance, "beaconHasLocationPublishError")
|
||||
.mockReturnValue(true);
|
||||
const component = getComponent({ roomId: room2Id });
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
expect(locationPublishErrorSpy).toHaveBeenCalledWith(
|
||||
getBeaconInfoIdentifier(room2Beacon1), 0, [getBeaconInfoIdentifier(room2Beacon1)],
|
||||
);
|
||||
expect(locationPublishErrorSpy).toHaveBeenCalledWith(getBeaconInfoIdentifier(room2Beacon1), 0, [
|
||||
getBeaconInfoIdentifier(room2Beacon1),
|
||||
]);
|
||||
});
|
||||
|
||||
it(
|
||||
'displays location publish error when locationPublishError event is emitted' +
|
||||
' and beacons have errors',
|
||||
"displays location publish error when locationPublishError event is emitted" +
|
||||
" and beacons have errors",
|
||||
async () => {
|
||||
const locationPublishErrorSpy = jest.spyOn(OwnBeaconStore.instance, 'beaconHasLocationPublishError')
|
||||
const locationPublishErrorSpy = jest
|
||||
.spyOn(OwnBeaconStore.instance, "beaconHasLocationPublishError")
|
||||
.mockReturnValue(false);
|
||||
const component = getComponent({ roomId: room2Id });
|
||||
|
||||
|
@ -374,20 +383,23 @@ describe('<RoomLiveShareWarning />', () => {
|
|||
act(() => {
|
||||
locationPublishErrorSpy.mockReturnValue(true);
|
||||
OwnBeaconStore.instance.emit(
|
||||
OwnBeaconStoreEvent.LocationPublishError, getBeaconInfoIdentifier(room2Beacon1),
|
||||
OwnBeaconStoreEvent.LocationPublishError,
|
||||
getBeaconInfoIdentifier(room2Beacon1),
|
||||
);
|
||||
});
|
||||
component.setProps({});
|
||||
|
||||
// renders wire error ui
|
||||
expect(component.find('.mx_RoomLiveShareWarning_label').text()).toEqual(
|
||||
'An error occurred whilst sharing your live location, please try again',
|
||||
expect(component.find(".mx_RoomLiveShareWarning_label").text()).toEqual(
|
||||
"An error occurred whilst sharing your live location, please try again",
|
||||
);
|
||||
expect(findByTestId(component, 'room-live-share-wire-error-close-button').length).toBeTruthy();
|
||||
});
|
||||
expect(findByTestId(component, "room-live-share-wire-error-close-button").length).toBeTruthy();
|
||||
},
|
||||
);
|
||||
|
||||
it('stops displaying wire error when errors are cleared', async () => {
|
||||
const locationPublishErrorSpy = jest.spyOn(OwnBeaconStore.instance, 'beaconHasLocationPublishError')
|
||||
it("stops displaying wire error when errors are cleared", async () => {
|
||||
const locationPublishErrorSpy = jest
|
||||
.spyOn(OwnBeaconStore.instance, "beaconHasLocationPublishError")
|
||||
.mockReturnValue(true);
|
||||
const component = getComponent({ roomId: room2Id });
|
||||
|
||||
|
@ -395,39 +407,40 @@ describe('<RoomLiveShareWarning />', () => {
|
|||
act(() => {
|
||||
locationPublishErrorSpy.mockReturnValue(false);
|
||||
OwnBeaconStore.instance.emit(
|
||||
OwnBeaconStoreEvent.LocationPublishError, getBeaconInfoIdentifier(room2Beacon1),
|
||||
OwnBeaconStoreEvent.LocationPublishError,
|
||||
getBeaconInfoIdentifier(room2Beacon1),
|
||||
);
|
||||
});
|
||||
component.setProps({});
|
||||
|
||||
// renders error-free ui
|
||||
expect(component.find('.mx_RoomLiveShareWarning_label').text()).toEqual(
|
||||
'You are sharing your live location',
|
||||
expect(component.find(".mx_RoomLiveShareWarning_label").text()).toEqual(
|
||||
"You are sharing your live location",
|
||||
);
|
||||
expect(findByTestId(component, 'room-live-share-wire-error-close-button').length).toBeFalsy();
|
||||
expect(findByTestId(component, "room-live-share-wire-error-close-button").length).toBeFalsy();
|
||||
});
|
||||
|
||||
it('clicking retry button resets location publish errors', async () => {
|
||||
jest.spyOn(OwnBeaconStore.instance, 'beaconHasLocationPublishError').mockReturnValue(true);
|
||||
const resetErrorSpy = jest.spyOn(OwnBeaconStore.instance, 'resetLocationPublishError');
|
||||
it("clicking retry button resets location publish errors", async () => {
|
||||
jest.spyOn(OwnBeaconStore.instance, "beaconHasLocationPublishError").mockReturnValue(true);
|
||||
const resetErrorSpy = jest.spyOn(OwnBeaconStore.instance, "resetLocationPublishError");
|
||||
|
||||
const component = getComponent({ roomId: room2Id });
|
||||
|
||||
act(() => {
|
||||
findByTestId(component, 'room-live-share-primary-button').at(0).simulate('click');
|
||||
findByTestId(component, "room-live-share-primary-button").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(resetErrorSpy).toHaveBeenCalledWith(getBeaconInfoIdentifier(room2Beacon1));
|
||||
});
|
||||
|
||||
it('clicking close button stops beacons', async () => {
|
||||
jest.spyOn(OwnBeaconStore.instance, 'beaconHasLocationPublishError').mockReturnValue(true);
|
||||
const stopBeaconSpy = jest.spyOn(OwnBeaconStore.instance, 'stopBeacon');
|
||||
it("clicking close button stops beacons", async () => {
|
||||
jest.spyOn(OwnBeaconStore.instance, "beaconHasLocationPublishError").mockReturnValue(true);
|
||||
const stopBeaconSpy = jest.spyOn(OwnBeaconStore.instance, "stopBeacon");
|
||||
|
||||
const component = getComponent({ roomId: room2Id });
|
||||
|
||||
act(() => {
|
||||
findByTestId(component, 'room-live-share-wire-error-close-button').at(0).simulate('click');
|
||||
findByTestId(component, "room-live-share-wire-error-close-button").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(stopBeaconSpy).toHaveBeenCalledWith(getBeaconInfoIdentifier(room2Beacon1));
|
||||
|
|
|
@ -14,21 +14,21 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
|
||||
import ShareLatestLocation from '../../../../src/components/views/beacon/ShareLatestLocation';
|
||||
import { copyPlaintext } from '../../../../src/utils/strings';
|
||||
import { flushPromises } from '../../../test-utils';
|
||||
import ShareLatestLocation from "../../../../src/components/views/beacon/ShareLatestLocation";
|
||||
import { copyPlaintext } from "../../../../src/utils/strings";
|
||||
import { flushPromises } from "../../../test-utils";
|
||||
|
||||
jest.mock('../../../../src/utils/strings', () => ({
|
||||
jest.mock("../../../../src/utils/strings", () => ({
|
||||
copyPlaintext: jest.fn().mockResolvedValue(undefined),
|
||||
}));
|
||||
|
||||
describe('<ShareLatestLocation />', () => {
|
||||
describe("<ShareLatestLocation />", () => {
|
||||
const defaultProps = {
|
||||
latestLocationState: {
|
||||
uri: 'geo:51,42;u=35',
|
||||
uri: "geo:51,42;u=35",
|
||||
timestamp: 123,
|
||||
},
|
||||
};
|
||||
|
@ -38,18 +38,18 @@ describe('<ShareLatestLocation />', () => {
|
|||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders null when no location', () => {
|
||||
it("renders null when no location", () => {
|
||||
const { container } = getComponent({ latestLocationState: undefined });
|
||||
expect(container.innerHTML).toBeFalsy();
|
||||
});
|
||||
|
||||
it('renders share buttons when there is a location', async () => {
|
||||
it("renders share buttons when there is a location", async () => {
|
||||
const { container, asFragment } = getComponent();
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
|
||||
fireEvent.click(container.querySelector('.mx_CopyableText_copyButton'));
|
||||
fireEvent.click(container.querySelector(".mx_CopyableText_copyButton"));
|
||||
await flushPromises();
|
||||
|
||||
expect(copyPlaintext).toHaveBeenCalledWith('51,42');
|
||||
expect(copyPlaintext).toHaveBeenCalledWith("51,42");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,16 +14,16 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import { render } from "@testing-library/react";
|
||||
|
||||
import StyledLiveBeaconIcon from '../../../../src/components/views/beacon/StyledLiveBeaconIcon';
|
||||
import StyledLiveBeaconIcon from "../../../../src/components/views/beacon/StyledLiveBeaconIcon";
|
||||
|
||||
describe('<StyledLiveBeaconIcon />', () => {
|
||||
describe("<StyledLiveBeaconIcon />", () => {
|
||||
const defaultProps = {};
|
||||
const getComponent = (props = {}) => render(<StyledLiveBeaconIcon {...defaultProps} {...props} />);
|
||||
|
||||
it('renders', () => {
|
||||
it("renders", () => {
|
||||
const { asFragment } = getComponent();
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -25,7 +25,7 @@ import SettingsStore from "../../../../src/settings/SettingsStore";
|
|||
jest.mock("../../../../src/utils/Feedback");
|
||||
jest.mock("../../../../src/settings/SettingsStore");
|
||||
|
||||
describe('<BetaCard />', () => {
|
||||
describe("<BetaCard />", () => {
|
||||
describe("Feedback prompt", () => {
|
||||
const featureId = "featureId";
|
||||
|
||||
|
|
|
@ -27,10 +27,13 @@ describe("<ContextMenu />", () => {
|
|||
// Hardcode window and menu dimensions
|
||||
const windowSize = 300;
|
||||
const menuSize = 200;
|
||||
jest.spyOn(UIStore, "instance", "get").mockImplementation(() => ({
|
||||
windowWidth: windowSize,
|
||||
windowHeight: windowSize,
|
||||
}) as unknown as UIStore);
|
||||
jest.spyOn(UIStore, "instance", "get").mockImplementation(
|
||||
() =>
|
||||
({
|
||||
windowWidth: windowSize,
|
||||
windowHeight: windowSize,
|
||||
} as unknown as UIStore),
|
||||
);
|
||||
window.Element.prototype.getBoundingClientRect = jest.fn().mockReturnValue({
|
||||
width: menuSize,
|
||||
height: menuSize,
|
||||
|
|
|
@ -14,33 +14,33 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import { EventStatus, MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { EventStatus, MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import {
|
||||
PendingEventOrdering,
|
||||
BeaconIdentifier,
|
||||
Beacon,
|
||||
getBeaconInfoIdentifier,
|
||||
EventType,
|
||||
} from 'matrix-js-sdk/src/matrix';
|
||||
import { ExtensibleEvent, MessageEvent, M_POLL_KIND_DISCLOSED, PollStartEvent } from 'matrix-events-sdk';
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { ExtensibleEvent, MessageEvent, M_POLL_KIND_DISCLOSED, PollStartEvent } from "matrix-events-sdk";
|
||||
import { FeatureSupport, Thread } from "matrix-js-sdk/src/models/thread";
|
||||
import { mocked } from "jest-mock";
|
||||
import { act } from '@testing-library/react';
|
||||
import { act } from "@testing-library/react";
|
||||
|
||||
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import RoomContext, { TimelineRenderingType } from "../../../../src/contexts/RoomContext";
|
||||
import { IRoomState } from "../../../../src/components/structures/RoomView";
|
||||
import { canEditContent } from "../../../../src/utils/EventUtils";
|
||||
import { copyPlaintext, getSelectedText } from "../../../../src/utils/strings";
|
||||
import MessageContextMenu from "../../../../src/components/views/context_menus/MessageContextMenu";
|
||||
import { makeBeaconEvent, makeBeaconInfoEvent, makeLocationEvent, stubClient } from '../../../test-utils';
|
||||
import dispatcher from '../../../../src/dispatcher/dispatcher';
|
||||
import SettingsStore from '../../../../src/settings/SettingsStore';
|
||||
import { ReadPinsEventId } from '../../../../src/components/views/right_panel/types';
|
||||
import { makeBeaconEvent, makeBeaconInfoEvent, makeLocationEvent, stubClient } from "../../../test-utils";
|
||||
import dispatcher from "../../../../src/dispatcher/dispatcher";
|
||||
import SettingsStore from "../../../../src/settings/SettingsStore";
|
||||
import { ReadPinsEventId } from "../../../../src/components/views/right_panel/types";
|
||||
import { Action } from "../../../../src/dispatcher/actions";
|
||||
|
||||
jest.mock("../../../../src/utils/strings", () => ({
|
||||
|
@ -52,17 +52,17 @@ jest.mock("../../../../src/utils/EventUtils", () => ({
|
|||
...jest.requireActual("../../../../src/utils/EventUtils"),
|
||||
canEditContent: jest.fn(),
|
||||
}));
|
||||
jest.mock('../../../../src/dispatcher/dispatcher');
|
||||
jest.mock("../../../../src/dispatcher/dispatcher");
|
||||
|
||||
const roomId = 'roomid';
|
||||
const roomId = "roomid";
|
||||
|
||||
describe('MessageContextMenu', () => {
|
||||
describe("MessageContextMenu", () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
stubClient();
|
||||
});
|
||||
|
||||
it('does show copy link button when supplied a link', () => {
|
||||
it("does show copy link button when supplied a link", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const props = {
|
||||
link: "https://google.com/",
|
||||
|
@ -73,119 +73,123 @@ describe('MessageContextMenu', () => {
|
|||
expect(copyLinkButton.props().href).toBe(props.link);
|
||||
});
|
||||
|
||||
it('does not show copy link button when not supplied a link', () => {
|
||||
it("does not show copy link button when not supplied a link", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const menu = createMenuWithContent(eventContent);
|
||||
const copyLinkButton = menu.find('a[aria-label="Copy link"]');
|
||||
expect(copyLinkButton).toHaveLength(0);
|
||||
});
|
||||
|
||||
describe('message pinning', () => {
|
||||
describe("message pinning", () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(SettingsStore, 'getValue').mockReturnValue(true);
|
||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(true);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(SettingsStore, 'getValue').mockRestore();
|
||||
jest.spyOn(SettingsStore, "getValue").mockRestore();
|
||||
});
|
||||
|
||||
it('does not show pin option when user does not have rights to pin', () => {
|
||||
it("does not show pin option when user does not have rights to pin", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const event = new MatrixEvent(eventContent.serialize());
|
||||
|
||||
const room = makeDefaultRoom();
|
||||
// mock permission to disallow adding pinned messages to room
|
||||
jest.spyOn(room.currentState, 'mayClientSendStateEvent').mockReturnValue(false);
|
||||
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(false);
|
||||
|
||||
const menu = createMenu(event, {}, {}, undefined, room);
|
||||
|
||||
expect(menu.find('div[aria-label="Pin"]')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('does not show pin option for beacon_info event', () => {
|
||||
const deadBeaconEvent = makeBeaconInfoEvent('@alice:server.org', roomId, { isLive: false });
|
||||
it("does not show pin option for beacon_info event", () => {
|
||||
const deadBeaconEvent = makeBeaconInfoEvent("@alice:server.org", roomId, { isLive: false });
|
||||
|
||||
const room = makeDefaultRoom();
|
||||
// mock permission to allow adding pinned messages to room
|
||||
jest.spyOn(room.currentState, 'mayClientSendStateEvent').mockReturnValue(true);
|
||||
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
|
||||
|
||||
const menu = createMenu(deadBeaconEvent, {}, {}, undefined, room);
|
||||
|
||||
expect(menu.find('div[aria-label="Pin"]')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('does not show pin option when pinning feature is disabled', () => {
|
||||
it("does not show pin option when pinning feature is disabled", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const pinnableEvent = new MatrixEvent({ ...eventContent.serialize(), room_id: roomId });
|
||||
|
||||
const room = makeDefaultRoom();
|
||||
// mock permission to allow adding pinned messages to room
|
||||
jest.spyOn(room.currentState, 'mayClientSendStateEvent').mockReturnValue(true);
|
||||
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
|
||||
// disable pinning feature
|
||||
jest.spyOn(SettingsStore, 'getValue').mockReturnValue(false);
|
||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
|
||||
|
||||
const menu = createMenu(pinnableEvent, {}, {}, undefined, room);
|
||||
|
||||
expect(menu.find('div[aria-label="Pin"]')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('shows pin option when pinning feature is enabled', () => {
|
||||
it("shows pin option when pinning feature is enabled", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const pinnableEvent = new MatrixEvent({ ...eventContent.serialize(), room_id: roomId });
|
||||
|
||||
const room = makeDefaultRoom();
|
||||
// mock permission to allow adding pinned messages to room
|
||||
jest.spyOn(room.currentState, 'mayClientSendStateEvent').mockReturnValue(true);
|
||||
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
|
||||
|
||||
const menu = createMenu(pinnableEvent, {}, {}, undefined, room);
|
||||
|
||||
expect(menu.find('div[aria-label="Pin"]')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('pins event on pin option click', () => {
|
||||
it("pins event on pin option click", () => {
|
||||
const onFinished = jest.fn();
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const pinnableEvent = new MatrixEvent({ ...eventContent.serialize(), room_id: roomId });
|
||||
pinnableEvent.event.event_id = '!3';
|
||||
pinnableEvent.event.event_id = "!3";
|
||||
const client = MatrixClientPeg.get();
|
||||
const room = makeDefaultRoom();
|
||||
|
||||
// mock permission to allow adding pinned messages to room
|
||||
jest.spyOn(room.currentState, 'mayClientSendStateEvent').mockReturnValue(true);
|
||||
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
|
||||
|
||||
// mock read pins account data
|
||||
const pinsAccountData = new MatrixEvent({ content: { event_ids: ['!1', '!2'] } });
|
||||
jest.spyOn(room, 'getAccountData').mockReturnValue(pinsAccountData);
|
||||
const pinsAccountData = new MatrixEvent({ content: { event_ids: ["!1", "!2"] } });
|
||||
jest.spyOn(room, "getAccountData").mockReturnValue(pinsAccountData);
|
||||
|
||||
const menu = createMenu(pinnableEvent, { onFinished }, {}, undefined, room);
|
||||
|
||||
act(() => {
|
||||
menu.find('div[aria-label="Pin"]').simulate('click');
|
||||
menu.find('div[aria-label="Pin"]').simulate("click");
|
||||
});
|
||||
|
||||
// added to account data
|
||||
expect(client.setRoomAccountData).toHaveBeenCalledWith(
|
||||
roomId,
|
||||
ReadPinsEventId,
|
||||
{ event_ids: [
|
||||
expect(client.setRoomAccountData).toHaveBeenCalledWith(roomId, ReadPinsEventId, {
|
||||
event_ids: [
|
||||
// from account data
|
||||
'!1', '!2',
|
||||
"!1",
|
||||
"!2",
|
||||
pinnableEvent.getId(),
|
||||
],
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
// add to room's pins
|
||||
expect(client.sendStateEvent).toHaveBeenCalledWith(roomId, EventType.RoomPinnedEvents, {
|
||||
pinned: [pinnableEvent.getId()] }, "");
|
||||
expect(client.sendStateEvent).toHaveBeenCalledWith(
|
||||
roomId,
|
||||
EventType.RoomPinnedEvents,
|
||||
{
|
||||
pinned: [pinnableEvent.getId()],
|
||||
},
|
||||
"",
|
||||
);
|
||||
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('unpins event on pin option click when event is pinned', () => {
|
||||
it("unpins event on pin option click when event is pinned", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const pinnableEvent = new MatrixEvent({ ...eventContent.serialize(), room_id: roomId });
|
||||
pinnableEvent.event.event_id = '!3';
|
||||
pinnableEvent.event.event_id = "!3";
|
||||
const client = MatrixClientPeg.get();
|
||||
const room = makeDefaultRoom();
|
||||
|
||||
|
@ -194,52 +198,53 @@ describe('MessageContextMenu', () => {
|
|||
type: EventType.RoomPinnedEvents,
|
||||
room_id: roomId,
|
||||
state_key: "",
|
||||
content: { pinned: [pinnableEvent.getId(), '!another-event'] },
|
||||
content: { pinned: [pinnableEvent.getId(), "!another-event"] },
|
||||
});
|
||||
room.currentState.setStateEvents([pinEvent]);
|
||||
|
||||
// mock permission to allow adding pinned messages to room
|
||||
jest.spyOn(room.currentState, 'mayClientSendStateEvent').mockReturnValue(true);
|
||||
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
|
||||
|
||||
// mock read pins account data
|
||||
const pinsAccountData = new MatrixEvent({ content: { event_ids: ['!1', '!2'] } });
|
||||
jest.spyOn(room, 'getAccountData').mockReturnValue(pinsAccountData);
|
||||
const pinsAccountData = new MatrixEvent({ content: { event_ids: ["!1", "!2"] } });
|
||||
jest.spyOn(room, "getAccountData").mockReturnValue(pinsAccountData);
|
||||
|
||||
const menu = createMenu(pinnableEvent, {}, {}, undefined, room);
|
||||
|
||||
act(() => {
|
||||
menu.find('div[aria-label="Unpin"]').simulate('click');
|
||||
menu.find('div[aria-label="Unpin"]').simulate("click");
|
||||
});
|
||||
|
||||
expect(client.setRoomAccountData).not.toHaveBeenCalled();
|
||||
|
||||
// add to room's pins
|
||||
expect(client.sendStateEvent).toHaveBeenCalledWith(
|
||||
roomId, EventType.RoomPinnedEvents,
|
||||
roomId,
|
||||
EventType.RoomPinnedEvents,
|
||||
// pinnableEvent's id removed, other pins intact
|
||||
{ pinned: ['!another-event'] },
|
||||
{ pinned: ["!another-event"] },
|
||||
"",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('message forwarding', () => {
|
||||
it('allows forwarding a room message', () => {
|
||||
describe("message forwarding", () => {
|
||||
it("allows forwarding a room message", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const menu = createMenuWithContent(eventContent);
|
||||
expect(menu.find('div[aria-label="Forward"]')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('does not allow forwarding a poll', () => {
|
||||
it("does not allow forwarding a poll", () => {
|
||||
const eventContent = PollStartEvent.from("why?", ["42"], M_POLL_KIND_DISCLOSED);
|
||||
const menu = createMenuWithContent(eventContent);
|
||||
expect(menu.find('div[aria-label="Forward"]')).toHaveLength(0);
|
||||
});
|
||||
|
||||
describe('forwarding beacons', () => {
|
||||
describe("forwarding beacons", () => {
|
||||
const aliceId = "@alice:server.org";
|
||||
|
||||
it('does not allow forwarding a beacon that is not live', () => {
|
||||
it("does not allow forwarding a beacon that is not live", () => {
|
||||
const deadBeaconEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: false });
|
||||
const beacon = new Beacon(deadBeaconEvent);
|
||||
const beacons = new Map<BeaconIdentifier, Beacon>();
|
||||
|
@ -248,11 +253,12 @@ describe('MessageContextMenu', () => {
|
|||
expect(menu.find('div[aria-label="Forward"]')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('does not allow forwarding a beacon that is not live but has a latestLocation', () => {
|
||||
it("does not allow forwarding a beacon that is not live but has a latestLocation", () => {
|
||||
const deadBeaconEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: false });
|
||||
const beaconLocation = makeBeaconEvent(
|
||||
aliceId, { beaconInfoId: deadBeaconEvent.getId(), geoUri: 'geo:51,41' },
|
||||
);
|
||||
const beaconLocation = makeBeaconEvent(aliceId, {
|
||||
beaconInfoId: deadBeaconEvent.getId(),
|
||||
geoUri: "geo:51,41",
|
||||
});
|
||||
const beacon = new Beacon(deadBeaconEvent);
|
||||
// @ts-ignore illegally set private prop
|
||||
beacon._latestLocationEvent = beaconLocation;
|
||||
|
@ -262,7 +268,7 @@ describe('MessageContextMenu', () => {
|
|||
expect(menu.find('div[aria-label="Forward"]')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('does not allow forwarding a live beacon that does not have a latestLocation', () => {
|
||||
it("does not allow forwarding a live beacon that does not have a latestLocation", () => {
|
||||
const beaconEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: true });
|
||||
|
||||
const beacon = new Beacon(beaconEvent);
|
||||
|
@ -272,11 +278,12 @@ describe('MessageContextMenu', () => {
|
|||
expect(menu.find('div[aria-label="Forward"]')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('allows forwarding a live beacon that has a location', () => {
|
||||
it("allows forwarding a live beacon that has a location", () => {
|
||||
const liveBeaconEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: true });
|
||||
const beaconLocation = makeBeaconEvent(
|
||||
aliceId, { beaconInfoId: liveBeaconEvent.getId(), geoUri: 'geo:51,41' },
|
||||
);
|
||||
const beaconLocation = makeBeaconEvent(aliceId, {
|
||||
beaconInfoId: liveBeaconEvent.getId(),
|
||||
geoUri: "geo:51,41",
|
||||
});
|
||||
const beacon = new Beacon(liveBeaconEvent);
|
||||
// @ts-ignore illegally set private prop
|
||||
beacon._latestLocationEvent = beaconLocation;
|
||||
|
@ -286,12 +293,13 @@ describe('MessageContextMenu', () => {
|
|||
expect(menu.find('div[aria-label="Forward"]')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('opens forward dialog with correct event', () => {
|
||||
const dispatchSpy = jest.spyOn(dispatcher, 'dispatch');
|
||||
it("opens forward dialog with correct event", () => {
|
||||
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
|
||||
const liveBeaconEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: true });
|
||||
const beaconLocation = makeBeaconEvent(
|
||||
aliceId, { beaconInfoId: liveBeaconEvent.getId(), geoUri: 'geo:51,41' },
|
||||
);
|
||||
const beaconLocation = makeBeaconEvent(aliceId, {
|
||||
beaconInfoId: liveBeaconEvent.getId(),
|
||||
geoUri: "geo:51,41",
|
||||
});
|
||||
const beacon = new Beacon(liveBeaconEvent);
|
||||
// @ts-ignore illegally set private prop
|
||||
beacon._latestLocationEvent = beaconLocation;
|
||||
|
@ -300,26 +308,28 @@ describe('MessageContextMenu', () => {
|
|||
const menu = createMenu(liveBeaconEvent, {}, {}, beacons);
|
||||
|
||||
act(() => {
|
||||
menu.find('div[aria-label="Forward"]').simulate('click');
|
||||
menu.find('div[aria-label="Forward"]').simulate("click");
|
||||
});
|
||||
|
||||
// called with forwardableEvent, not beaconInfo event
|
||||
expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({
|
||||
event: beaconLocation,
|
||||
}));
|
||||
expect(dispatchSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
event: beaconLocation,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('open as map link', () => {
|
||||
it('does not allow opening a plain message in open street maps', () => {
|
||||
describe("open as map link", () => {
|
||||
it("does not allow opening a plain message in open street maps", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const menu = createMenuWithContent(eventContent);
|
||||
expect(menu.find('a[aria-label="Open in OpenStreetMap"]')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('does not allow opening a beacon that does not have a shareable location event', () => {
|
||||
const deadBeaconEvent = makeBeaconInfoEvent('@alice', roomId, { isLive: false });
|
||||
it("does not allow opening a beacon that does not have a shareable location event", () => {
|
||||
const deadBeaconEvent = makeBeaconInfoEvent("@alice", roomId, { isLive: false });
|
||||
const beacon = new Beacon(deadBeaconEvent);
|
||||
const beacons = new Map<BeaconIdentifier, Beacon>();
|
||||
beacons.set(getBeaconInfoIdentifier(deadBeaconEvent), beacon);
|
||||
|
@ -327,20 +337,21 @@ describe('MessageContextMenu', () => {
|
|||
expect(menu.find('a[aria-label="Open in OpenStreetMap"]')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('allows opening a location event in open street map', () => {
|
||||
const locationEvent = makeLocationEvent('geo:50,50');
|
||||
it("allows opening a location event in open street map", () => {
|
||||
const locationEvent = makeLocationEvent("geo:50,50");
|
||||
const menu = createMenu(locationEvent);
|
||||
// exists with a href with the lat/lon from the location event
|
||||
expect(
|
||||
menu.find('a[aria-label="Open in OpenStreetMap"]').at(0).props().href,
|
||||
).toEqual('https://www.openstreetmap.org/?mlat=50&mlon=50#map=16/50/50');
|
||||
expect(menu.find('a[aria-label="Open in OpenStreetMap"]').at(0).props().href).toEqual(
|
||||
"https://www.openstreetmap.org/?mlat=50&mlon=50#map=16/50/50",
|
||||
);
|
||||
});
|
||||
|
||||
it('allows opening a beacon that has a shareable location event', () => {
|
||||
const liveBeaconEvent = makeBeaconInfoEvent('@alice', roomId, { isLive: true });
|
||||
const beaconLocation = makeBeaconEvent(
|
||||
'@alice', { beaconInfoId: liveBeaconEvent.getId(), geoUri: 'geo:51,41' },
|
||||
);
|
||||
it("allows opening a beacon that has a shareable location event", () => {
|
||||
const liveBeaconEvent = makeBeaconInfoEvent("@alice", roomId, { isLive: true });
|
||||
const beaconLocation = makeBeaconEvent("@alice", {
|
||||
beaconInfoId: liveBeaconEvent.getId(),
|
||||
geoUri: "geo:51,41",
|
||||
});
|
||||
const beacon = new Beacon(liveBeaconEvent);
|
||||
// @ts-ignore illegally set private prop
|
||||
beacon._latestLocationEvent = beaconLocation;
|
||||
|
@ -348,14 +359,14 @@ describe('MessageContextMenu', () => {
|
|||
beacons.set(getBeaconInfoIdentifier(liveBeaconEvent), beacon);
|
||||
const menu = createMenu(liveBeaconEvent, {}, {}, beacons);
|
||||
// exists with a href with the lat/lon from the location event
|
||||
expect(
|
||||
menu.find('a[aria-label="Open in OpenStreetMap"]').at(0).props().href,
|
||||
).toEqual('https://www.openstreetmap.org/?mlat=51&mlon=41#map=16/51/41');
|
||||
expect(menu.find('a[aria-label="Open in OpenStreetMap"]').at(0).props().href).toEqual(
|
||||
"https://www.openstreetmap.org/?mlat=51&mlon=41#map=16/51/41",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("right click", () => {
|
||||
it('copy button does work as expected', () => {
|
||||
it("copy button does work as expected", () => {
|
||||
const text = "hello";
|
||||
const eventContent = MessageEvent.from(text);
|
||||
mocked(getSelectedText).mockReturnValue(text);
|
||||
|
@ -366,7 +377,7 @@ describe('MessageContextMenu', () => {
|
|||
expect(copyPlaintext).toHaveBeenCalledWith(text);
|
||||
});
|
||||
|
||||
it('copy button is not shown when there is nothing to copy', () => {
|
||||
it("copy button is not shown when there is nothing to copy", () => {
|
||||
const text = "hello";
|
||||
const eventContent = MessageEvent.from(text);
|
||||
mocked(getSelectedText).mockReturnValue("");
|
||||
|
@ -376,7 +387,7 @@ describe('MessageContextMenu', () => {
|
|||
expect(copyButton).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('shows edit button when we can edit', () => {
|
||||
it("shows edit button when we can edit", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
mocked(canEditContent).mockReturnValue(true);
|
||||
|
||||
|
@ -385,7 +396,7 @@ describe('MessageContextMenu', () => {
|
|||
expect(editButton).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('does not show edit button when we cannot edit', () => {
|
||||
it("does not show edit button when we cannot edit", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
mocked(canEditContent).mockReturnValue(false);
|
||||
|
||||
|
@ -394,7 +405,7 @@ describe('MessageContextMenu', () => {
|
|||
expect(editButton).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('shows reply button when we can reply', () => {
|
||||
it("shows reply button when we can reply", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const context = {
|
||||
canSendMessages: true,
|
||||
|
@ -405,7 +416,7 @@ describe('MessageContextMenu', () => {
|
|||
expect(replyButton).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('does not show reply button when we cannot reply', () => {
|
||||
it("does not show reply button when we cannot reply", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const context = {
|
||||
canSendMessages: true,
|
||||
|
@ -419,7 +430,7 @@ describe('MessageContextMenu', () => {
|
|||
expect(replyButton).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('shows react button when we can react', () => {
|
||||
it("shows react button when we can react", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const context = {
|
||||
canReact: true,
|
||||
|
@ -430,7 +441,7 @@ describe('MessageContextMenu', () => {
|
|||
expect(reactButton).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('does not show react button when we cannot react', () => {
|
||||
it("does not show react button when we cannot react", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const context = {
|
||||
canReact: false,
|
||||
|
@ -441,10 +452,10 @@ describe('MessageContextMenu', () => {
|
|||
expect(reactButton).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('shows view in room button when the event is a thread root', () => {
|
||||
it("shows view in room button when the event is a thread root", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const mxEvent = new MatrixEvent(eventContent.serialize());
|
||||
mxEvent.getThread = () => ({ rootEvent: mxEvent }) as Thread;
|
||||
mxEvent.getThread = () => ({ rootEvent: mxEvent } as Thread);
|
||||
const props = {
|
||||
rightClick: true,
|
||||
};
|
||||
|
@ -457,7 +468,7 @@ describe('MessageContextMenu', () => {
|
|||
expect(reactButton).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('does not show view in room button when the event is not a thread root', () => {
|
||||
it("does not show view in room button when the event is not a thread root", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
|
||||
const menu = createRightClickMenuWithContent(eventContent);
|
||||
|
@ -465,7 +476,7 @@ describe('MessageContextMenu', () => {
|
|||
expect(reactButton).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('creates a new thread on reply in thread click', () => {
|
||||
it("creates a new thread on reply in thread click", () => {
|
||||
const eventContent = MessageEvent.from("hello");
|
||||
const mxEvent = new MatrixEvent(eventContent.serialize());
|
||||
|
||||
|
@ -473,7 +484,7 @@ describe('MessageContextMenu', () => {
|
|||
const context = {
|
||||
canSendMessages: true,
|
||||
};
|
||||
jest.spyOn(SettingsStore, 'getValue').mockReturnValue(true);
|
||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(true);
|
||||
|
||||
const menu = createRightClickMenu(mxEvent, context);
|
||||
|
||||
|
@ -490,10 +501,7 @@ describe('MessageContextMenu', () => {
|
|||
});
|
||||
});
|
||||
|
||||
function createRightClickMenuWithContent(
|
||||
eventContent: ExtensibleEvent,
|
||||
context?: Partial<IRoomState>,
|
||||
): ReactWrapper {
|
||||
function createRightClickMenuWithContent(eventContent: ExtensibleEvent, context?: Partial<IRoomState>): ReactWrapper {
|
||||
return createMenuWithContent(eventContent, { rightClick: true }, context);
|
||||
}
|
||||
|
||||
|
@ -511,14 +519,9 @@ function createMenuWithContent(
|
|||
}
|
||||
|
||||
function makeDefaultRoom(): Room {
|
||||
return new Room(
|
||||
roomId,
|
||||
MatrixClientPeg.get(),
|
||||
"@user:example.com",
|
||||
{
|
||||
pendingEventOrdering: PendingEventOrdering.Detached,
|
||||
},
|
||||
);
|
||||
return new Room(roomId, MatrixClientPeg.get(), "@user:example.com", {
|
||||
pendingEventOrdering: PendingEventOrdering.Detached,
|
||||
});
|
||||
}
|
||||
|
||||
function createMenu(
|
||||
|
@ -540,12 +543,7 @@ function createMenu(
|
|||
|
||||
return mount(
|
||||
<RoomContext.Provider value={context as IRoomState}>
|
||||
<MessageContextMenu
|
||||
chevronFace={null}
|
||||
mxEvent={mxEvent}
|
||||
onFinished={jest.fn()}
|
||||
{...props}
|
||||
/>
|
||||
<MessageContextMenu chevronFace={null} mxEvent={mxEvent} onFinished={jest.fn()} {...props} />
|
||||
</RoomContext.Provider>,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -14,33 +14,33 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { Room } from 'matrix-js-sdk/src/matrix';
|
||||
import { mocked } from 'jest-mock';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import 'focus-visible'; // to fix context menus
|
||||
import { mount } from "enzyme";
|
||||
import { Room } from "matrix-js-sdk/src/matrix";
|
||||
import { mocked } from "jest-mock";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import "focus-visible"; // to fix context menus
|
||||
|
||||
import SpaceContextMenu from '../../../../src/components/views/context_menus/SpaceContextMenu';
|
||||
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
||||
import { findByTestId } from '../../../test-utils';
|
||||
import SpaceContextMenu from "../../../../src/components/views/context_menus/SpaceContextMenu";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import { findByTestId } from "../../../test-utils";
|
||||
import {
|
||||
shouldShowSpaceSettings,
|
||||
showCreateNewRoom,
|
||||
showCreateNewSubspace,
|
||||
showSpaceInvite,
|
||||
showSpaceSettings,
|
||||
} from '../../../../src/utils/space';
|
||||
} from "../../../../src/utils/space";
|
||||
import { leaveSpace } from "../../../../src/utils/leave-behaviour";
|
||||
import { shouldShowComponent } from '../../../../src/customisations/helpers/UIComponents';
|
||||
import { UIComponent } from '../../../../src/settings/UIFeature';
|
||||
import { shouldShowComponent } from "../../../../src/customisations/helpers/UIComponents";
|
||||
import { UIComponent } from "../../../../src/settings/UIFeature";
|
||||
|
||||
jest.mock('../../../../src/customisations/helpers/UIComponents', () => ({
|
||||
jest.mock("../../../../src/customisations/helpers/UIComponents", () => ({
|
||||
shouldShowComponent: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../../src/utils/space', () => ({
|
||||
jest.mock("../../../../src/utils/space", () => ({
|
||||
shouldShowSpaceSettings: jest.fn(),
|
||||
showCreateNewRoom: jest.fn(),
|
||||
showCreateNewSubspace: jest.fn(),
|
||||
|
@ -49,172 +49,172 @@ jest.mock('../../../../src/utils/space', () => ({
|
|||
showSpaceSettings: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../../src/utils/leave-behaviour', () => ({
|
||||
jest.mock("../../../../src/utils/leave-behaviour", () => ({
|
||||
leaveSpace: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('<SpaceContextMenu />', () => {
|
||||
const userId = '@test:server';
|
||||
describe("<SpaceContextMenu />", () => {
|
||||
const userId = "@test:server";
|
||||
const mockClient = {
|
||||
getUserId: jest.fn().mockReturnValue(userId),
|
||||
};
|
||||
const makeMockSpace = (props = {}) => ({
|
||||
name: 'test space',
|
||||
getJoinRule: jest.fn(),
|
||||
canInvite: jest.fn(),
|
||||
currentState: {
|
||||
maySendStateEvent: jest.fn(),
|
||||
},
|
||||
client: mockClient,
|
||||
getMyMembership: jest.fn(),
|
||||
...props,
|
||||
}) as unknown as Room;
|
||||
const makeMockSpace = (props = {}) =>
|
||||
({
|
||||
name: "test space",
|
||||
getJoinRule: jest.fn(),
|
||||
canInvite: jest.fn(),
|
||||
currentState: {
|
||||
maySendStateEvent: jest.fn(),
|
||||
},
|
||||
client: mockClient,
|
||||
getMyMembership: jest.fn(),
|
||||
...props,
|
||||
} as unknown as Room);
|
||||
const defaultProps = {
|
||||
space: makeMockSpace(),
|
||||
onFinished: jest.fn(),
|
||||
};
|
||||
const getComponent = (props = {}) =>
|
||||
mount(<SpaceContextMenu {...defaultProps} {...props} />,
|
||||
{
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: {
|
||||
value: mockClient,
|
||||
},
|
||||
});
|
||||
mount(<SpaceContextMenu {...defaultProps} {...props} />, {
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: {
|
||||
value: mockClient,
|
||||
},
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
mockClient.getUserId.mockReturnValue(userId);
|
||||
});
|
||||
|
||||
it('renders menu correctly', () => {
|
||||
it("renders menu correctly", () => {
|
||||
const component = getComponent();
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders invite option when space is public', () => {
|
||||
it("renders invite option when space is public", () => {
|
||||
const space = makeMockSpace({
|
||||
getJoinRule: jest.fn().mockReturnValue('public'),
|
||||
getJoinRule: jest.fn().mockReturnValue("public"),
|
||||
});
|
||||
const component = getComponent({ space });
|
||||
expect(findByTestId(component, 'invite-option').length).toBeTruthy();
|
||||
expect(findByTestId(component, "invite-option").length).toBeTruthy();
|
||||
});
|
||||
it('renders invite option when user is has invite rights for space', () => {
|
||||
it("renders invite option when user is has invite rights for space", () => {
|
||||
const space = makeMockSpace({
|
||||
canInvite: jest.fn().mockReturnValue(true),
|
||||
});
|
||||
const component = getComponent({ space });
|
||||
expect(space.canInvite).toHaveBeenCalledWith(userId);
|
||||
expect(findByTestId(component, 'invite-option').length).toBeTruthy();
|
||||
expect(findByTestId(component, "invite-option").length).toBeTruthy();
|
||||
});
|
||||
it('opens invite dialog when invite option is clicked', () => {
|
||||
it("opens invite dialog when invite option is clicked", () => {
|
||||
const space = makeMockSpace({
|
||||
getJoinRule: jest.fn().mockReturnValue('public'),
|
||||
getJoinRule: jest.fn().mockReturnValue("public"),
|
||||
});
|
||||
const onFinished = jest.fn();
|
||||
const component = getComponent({ space, onFinished });
|
||||
|
||||
act(() => {
|
||||
findByTestId(component, 'invite-option').at(0).simulate('click');
|
||||
findByTestId(component, "invite-option").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(showSpaceInvite).toHaveBeenCalledWith(space);
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
});
|
||||
it('renders space settings option when user has rights', () => {
|
||||
it("renders space settings option when user has rights", () => {
|
||||
mocked(shouldShowSpaceSettings).mockReturnValue(true);
|
||||
const component = getComponent();
|
||||
expect(shouldShowSpaceSettings).toHaveBeenCalledWith(defaultProps.space);
|
||||
expect(findByTestId(component, 'settings-option').length).toBeTruthy();
|
||||
expect(findByTestId(component, "settings-option").length).toBeTruthy();
|
||||
});
|
||||
it('opens space settings when space settings option is clicked', () => {
|
||||
it("opens space settings when space settings option is clicked", () => {
|
||||
mocked(shouldShowSpaceSettings).mockReturnValue(true);
|
||||
const onFinished = jest.fn();
|
||||
const component = getComponent({ onFinished });
|
||||
|
||||
act(() => {
|
||||
findByTestId(component, 'settings-option').at(0).simulate('click');
|
||||
findByTestId(component, "settings-option").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(showSpaceSettings).toHaveBeenCalledWith(defaultProps.space);
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
});
|
||||
it('renders leave option when user does not have rights to see space settings', () => {
|
||||
it("renders leave option when user does not have rights to see space settings", () => {
|
||||
const component = getComponent();
|
||||
expect(findByTestId(component, 'leave-option').length).toBeTruthy();
|
||||
expect(findByTestId(component, "leave-option").length).toBeTruthy();
|
||||
});
|
||||
it('leaves space when leave option is clicked', () => {
|
||||
it("leaves space when leave option is clicked", () => {
|
||||
const onFinished = jest.fn();
|
||||
const component = getComponent({ onFinished });
|
||||
act(() => {
|
||||
findByTestId(component, 'leave-option').at(0).simulate('click');
|
||||
findByTestId(component, "leave-option").at(0).simulate("click");
|
||||
});
|
||||
expect(leaveSpace).toHaveBeenCalledWith(defaultProps.space);
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
});
|
||||
describe('add children section', () => {
|
||||
describe("add children section", () => {
|
||||
const space = makeMockSpace();
|
||||
beforeEach(() => {
|
||||
// set space to allow adding children to space
|
||||
mocked(space.currentState.maySendStateEvent).mockReturnValue(true);
|
||||
mocked(shouldShowComponent).mockReturnValue(true);
|
||||
});
|
||||
it('does not render section when user does not have permission to add children', () => {
|
||||
it("does not render section when user does not have permission to add children", () => {
|
||||
mocked(space.currentState.maySendStateEvent).mockReturnValue(false);
|
||||
const component = getComponent({ space });
|
||||
|
||||
expect(findByTestId(component, 'add-to-space-header').length).toBeFalsy();
|
||||
expect(findByTestId(component, 'new-room-option').length).toBeFalsy();
|
||||
expect(findByTestId(component, 'new-subspace-option').length).toBeFalsy();
|
||||
expect(findByTestId(component, "add-to-space-header").length).toBeFalsy();
|
||||
expect(findByTestId(component, "new-room-option").length).toBeFalsy();
|
||||
expect(findByTestId(component, "new-subspace-option").length).toBeFalsy();
|
||||
});
|
||||
it('does not render section when UIComponent customisations disable room and space creation', () => {
|
||||
it("does not render section when UIComponent customisations disable room and space creation", () => {
|
||||
mocked(shouldShowComponent).mockReturnValue(false);
|
||||
const component = getComponent({ space });
|
||||
|
||||
expect(shouldShowComponent).toHaveBeenCalledWith(UIComponent.CreateRooms);
|
||||
expect(shouldShowComponent).toHaveBeenCalledWith(UIComponent.CreateSpaces);
|
||||
|
||||
expect(findByTestId(component, 'add-to-space-header').length).toBeFalsy();
|
||||
expect(findByTestId(component, 'new-room-option').length).toBeFalsy();
|
||||
expect(findByTestId(component, 'new-subspace-option').length).toBeFalsy();
|
||||
expect(findByTestId(component, "add-to-space-header").length).toBeFalsy();
|
||||
expect(findByTestId(component, "new-room-option").length).toBeFalsy();
|
||||
expect(findByTestId(component, "new-subspace-option").length).toBeFalsy();
|
||||
});
|
||||
|
||||
it('renders section with add room button when UIComponent customisation allows CreateRoom', () => {
|
||||
it("renders section with add room button when UIComponent customisation allows CreateRoom", () => {
|
||||
// only allow CreateRoom
|
||||
mocked(shouldShowComponent).mockImplementation(feature => feature === UIComponent.CreateRooms);
|
||||
mocked(shouldShowComponent).mockImplementation((feature) => feature === UIComponent.CreateRooms);
|
||||
const component = getComponent({ space });
|
||||
|
||||
expect(findByTestId(component, 'add-to-space-header').length).toBeTruthy();
|
||||
expect(findByTestId(component, 'new-room-option').length).toBeTruthy();
|
||||
expect(findByTestId(component, 'new-subspace-option').length).toBeFalsy();
|
||||
expect(findByTestId(component, "add-to-space-header").length).toBeTruthy();
|
||||
expect(findByTestId(component, "new-room-option").length).toBeTruthy();
|
||||
expect(findByTestId(component, "new-subspace-option").length).toBeFalsy();
|
||||
});
|
||||
|
||||
it('renders section with add space button when UIComponent customisation allows CreateSpace', () => {
|
||||
it("renders section with add space button when UIComponent customisation allows CreateSpace", () => {
|
||||
// only allow CreateSpaces
|
||||
mocked(shouldShowComponent).mockImplementation(feature => feature === UIComponent.CreateSpaces);
|
||||
mocked(shouldShowComponent).mockImplementation((feature) => feature === UIComponent.CreateSpaces);
|
||||
const component = getComponent({ space });
|
||||
|
||||
expect(findByTestId(component, 'add-to-space-header').length).toBeTruthy();
|
||||
expect(findByTestId(component, 'new-room-option').length).toBeFalsy();
|
||||
expect(findByTestId(component, 'new-subspace-option').length).toBeTruthy();
|
||||
expect(findByTestId(component, "add-to-space-header").length).toBeTruthy();
|
||||
expect(findByTestId(component, "new-room-option").length).toBeFalsy();
|
||||
expect(findByTestId(component, "new-subspace-option").length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('opens create room dialog on add room button click', () => {
|
||||
it("opens create room dialog on add room button click", () => {
|
||||
const onFinished = jest.fn();
|
||||
const component = getComponent({ space, onFinished });
|
||||
|
||||
act(() => {
|
||||
findByTestId(component, 'new-room-option').at(0).simulate('click');
|
||||
findByTestId(component, "new-room-option").at(0).simulate("click");
|
||||
});
|
||||
expect(showCreateNewRoom).toHaveBeenCalledWith(space);
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
});
|
||||
it('opens create space dialog on add space button click', () => {
|
||||
it("opens create space dialog on add space button click", () => {
|
||||
const onFinished = jest.fn();
|
||||
const component = getComponent({ space, onFinished });
|
||||
|
||||
act(() => {
|
||||
findByTestId(component, 'new-subspace-option').at(0).simulate('click');
|
||||
findByTestId(component, "new-subspace-option").at(0).simulate("click");
|
||||
});
|
||||
expect(showCreateNewSubspace).toHaveBeenCalledWith(space);
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
|
|
|
@ -38,10 +38,7 @@ describe("ThreadListContextMenu", () => {
|
|||
let event: MatrixEvent;
|
||||
|
||||
function getComponent(props: Partial<ThreadListContextMenuProps>) {
|
||||
return render(<ThreadListContextMenu
|
||||
mxEvent={event}
|
||||
{...props}
|
||||
/>);
|
||||
return render(<ThreadListContextMenu mxEvent={event} {...props} />);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -14,14 +14,14 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { IPassphraseInfo } from 'matrix-js-sdk/src/crypto/api';
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { IPassphraseInfo } from "matrix-js-sdk/src/crypto/api";
|
||||
|
||||
import { findByAttr, getMockClientWithEventEmitter, unmockClientPeg } from '../../../test-utils';
|
||||
import { findById, flushPromises } from '../../../test-utils';
|
||||
import { findByAttr, getMockClientWithEventEmitter, unmockClientPeg } from "../../../test-utils";
|
||||
import { findById, flushPromises } from "../../../test-utils";
|
||||
import AccessSecretStorageDialog from "../../../../src/components/views/dialogs/security/AccessSecretStorageDialog";
|
||||
|
||||
describe("AccessSecretStorageDialog", () => {
|
||||
|
@ -35,12 +35,12 @@ describe("AccessSecretStorageDialog", () => {
|
|||
checkPrivateKey: jest.fn(),
|
||||
keyInfo: undefined,
|
||||
};
|
||||
const getComponent = (props ={}): ReactWrapper =>
|
||||
const getComponent = (props = {}): ReactWrapper =>
|
||||
mount(<AccessSecretStorageDialog {...defaultProps} {...props} />);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockClient.keyBackupKeyFromRecoveryKey.mockReturnValue('a raw key' as unknown as Uint8Array);
|
||||
mockClient.keyBackupKeyFromRecoveryKey.mockReturnValue("a raw key" as unknown as Uint8Array);
|
||||
mockClient.isValidRecoveryKey.mockReturnValue(false);
|
||||
});
|
||||
|
||||
|
@ -63,7 +63,7 @@ describe("AccessSecretStorageDialog", () => {
|
|||
const e = { preventDefault: () => {} };
|
||||
|
||||
act(() => {
|
||||
wrapper.find('form').simulate('submit', e);
|
||||
wrapper.find("form").simulate("submit", e);
|
||||
});
|
||||
|
||||
await flushPromises();
|
||||
|
@ -75,13 +75,13 @@ describe("AccessSecretStorageDialog", () => {
|
|||
it("Considers a valid key to be valid", async () => {
|
||||
const checkPrivateKey = jest.fn().mockResolvedValue(true);
|
||||
const wrapper = getComponent({ checkPrivateKey });
|
||||
mockClient.keyBackupKeyFromRecoveryKey.mockReturnValue('a raw key' as unknown as Uint8Array);
|
||||
mockClient.keyBackupKeyFromRecoveryKey.mockReturnValue("a raw key" as unknown as Uint8Array);
|
||||
mockClient.checkSecretStorageKey.mockResolvedValue(true);
|
||||
|
||||
const v = "asdf";
|
||||
const e = { target: { value: v } };
|
||||
act(() => {
|
||||
findById(wrapper, 'mx_securityKey').find('input').simulate('change', e);
|
||||
findById(wrapper, "mx_securityKey").find("input").simulate("change", e);
|
||||
wrapper.setProps({});
|
||||
});
|
||||
await act(async () => {
|
||||
|
@ -91,10 +91,10 @@ describe("AccessSecretStorageDialog", () => {
|
|||
wrapper.setProps({});
|
||||
});
|
||||
|
||||
const submitButton = findByAttr('data-testid')(wrapper, 'dialog-primary-button').at(0);
|
||||
const submitButton = findByAttr("data-testid")(wrapper, "dialog-primary-button").at(0);
|
||||
// submit button is enabled when key is valid
|
||||
expect(submitButton.props().disabled).toBeFalsy();
|
||||
expect(wrapper.find('.mx_AccessSecretStorageDialog_recoveryKeyFeedback').text()).toEqual('Looks good!');
|
||||
expect(wrapper.find(".mx_AccessSecretStorageDialog_recoveryKeyFeedback").text()).toEqual("Looks good!");
|
||||
});
|
||||
|
||||
it("Notifies the user if they input an invalid Security Key", async () => {
|
||||
|
@ -106,36 +106,36 @@ describe("AccessSecretStorageDialog", () => {
|
|||
});
|
||||
|
||||
act(() => {
|
||||
findById(wrapper, 'mx_securityKey').find('input').simulate('change', e);
|
||||
findById(wrapper, "mx_securityKey").find("input").simulate("change", e);
|
||||
});
|
||||
// force a validation now because it debounces
|
||||
// @ts-ignore private
|
||||
await wrapper.instance().validateRecoveryKey();
|
||||
|
||||
const submitButton = findByAttr('data-testid')(wrapper, 'dialog-primary-button').at(0);
|
||||
const submitButton = findByAttr("data-testid")(wrapper, "dialog-primary-button").at(0);
|
||||
// submit button is disabled when recovery key is invalid
|
||||
expect(submitButton.props().disabled).toBeTruthy();
|
||||
expect(
|
||||
wrapper.find('.mx_AccessSecretStorageDialog_recoveryKeyFeedback').text(),
|
||||
).toEqual('Invalid Security Key');
|
||||
expect(wrapper.find(".mx_AccessSecretStorageDialog_recoveryKeyFeedback").text()).toEqual(
|
||||
"Invalid Security Key",
|
||||
);
|
||||
|
||||
wrapper.setProps({});
|
||||
const notification = wrapper.find(".mx_AccessSecretStorageDialog_recoveryKeyFeedback");
|
||||
expect(notification.props().children).toEqual("Invalid Security Key");
|
||||
});
|
||||
|
||||
it("Notifies the user if they input an invalid passphrase", async function() {
|
||||
it("Notifies the user if they input an invalid passphrase", async function () {
|
||||
const keyInfo = {
|
||||
name: 'test',
|
||||
algorithm: 'test',
|
||||
iv: 'test',
|
||||
mac: '1:2:3:4',
|
||||
name: "test",
|
||||
algorithm: "test",
|
||||
iv: "test",
|
||||
mac: "1:2:3:4",
|
||||
passphrase: {
|
||||
// this type is weird in js-sdk
|
||||
// cast 'm.pbkdf2' to itself
|
||||
algorithm: 'm.pbkdf2' as IPassphraseInfo['algorithm'],
|
||||
algorithm: "m.pbkdf2" as IPassphraseInfo["algorithm"],
|
||||
iterations: 2,
|
||||
salt: 'nonempty',
|
||||
salt: "nonempty",
|
||||
},
|
||||
};
|
||||
const checkPrivateKey = jest.fn().mockResolvedValue(false);
|
||||
|
@ -145,23 +145,24 @@ describe("AccessSecretStorageDialog", () => {
|
|||
// update passphrase
|
||||
act(() => {
|
||||
const e = { target: { value: "a" } };
|
||||
findById(wrapper, 'mx_passPhraseInput').at(1).simulate('change', e);
|
||||
findById(wrapper, "mx_passPhraseInput").at(1).simulate("change", e);
|
||||
});
|
||||
wrapper.setProps({});
|
||||
|
||||
// input updated
|
||||
expect(findById(wrapper, 'mx_passPhraseInput').at(0).props().value).toEqual('a');
|
||||
expect(findById(wrapper, "mx_passPhraseInput").at(0).props().value).toEqual("a");
|
||||
|
||||
// submit the form
|
||||
act(() => {
|
||||
wrapper.find('form').at(0).simulate('submit');
|
||||
wrapper.find("form").at(0).simulate("submit");
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
wrapper.setProps({});
|
||||
const notification = wrapper.find(".mx_AccessSecretStorageDialog_keyStatus");
|
||||
expect(notification.props().children).toEqual(
|
||||
["\uD83D\uDC4E ", "Unable to access secret storage. Please verify that you " +
|
||||
"entered the correct Security Phrase."]);
|
||||
expect(notification.props().children).toEqual([
|
||||
"\uD83D\uDC4E ",
|
||||
"Unable to access secret storage. Please verify that you " + "entered the correct Security Phrase.",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -35,11 +35,13 @@ describe("<ChangelogDialog />", () => {
|
|||
ahead_by: 24,
|
||||
behind_by: 0,
|
||||
total_commits: 24,
|
||||
commits: [{
|
||||
sha: "commit-sha",
|
||||
html_url: "https://api.github.com/repos/vector-im/element-web/commit/commit-sha",
|
||||
commit: { message: "This is the first commit message" },
|
||||
}],
|
||||
commits: [
|
||||
{
|
||||
sha: "commit-sha",
|
||||
html_url: "https://api.github.com/repos/vector-im/element-web/commit/commit-sha",
|
||||
commit: { message: "This is the first commit message" },
|
||||
},
|
||||
],
|
||||
files: [],
|
||||
});
|
||||
const reactUrl = "https://riot.im/github/repos/matrix-org/matrix-react-sdk/compare/oldsha2...newsha2";
|
||||
|
@ -55,11 +57,13 @@ describe("<ChangelogDialog />", () => {
|
|||
ahead_by: 83,
|
||||
behind_by: 0,
|
||||
total_commits: 83,
|
||||
commits: [{
|
||||
sha: "commit-sha0",
|
||||
html_url: "https://api.github.com/repos/matrix-org/matrix-react-sdk/commit/commit-sha",
|
||||
commit: { message: "This is a commit message" },
|
||||
}],
|
||||
commits: [
|
||||
{
|
||||
sha: "commit-sha0",
|
||||
html_url: "https://api.github.com/repos/matrix-org/matrix-react-sdk/commit/commit-sha",
|
||||
commit: { message: "This is a commit message" },
|
||||
},
|
||||
],
|
||||
files: [],
|
||||
});
|
||||
const jsUrl = "https://riot.im/github/repos/matrix-org/matrix-js-sdk/compare/oldsha3...newsha3";
|
||||
|
@ -75,23 +79,26 @@ describe("<ChangelogDialog />", () => {
|
|||
ahead_by: 48,
|
||||
behind_by: 0,
|
||||
total_commits: 48,
|
||||
commits: [{
|
||||
sha: "commit-sha1",
|
||||
html_url: "https://api.github.com/repos/matrix-org/matrix-js-sdk/commit/commit-sha1",
|
||||
commit: { message: "This is a commit message" },
|
||||
}, {
|
||||
sha: "commit-sha2",
|
||||
html_url: "https://api.github.com/repos/matrix-org/matrix-js-sdk/commit/commit-sha2",
|
||||
commit: { message: "This is another commit message" },
|
||||
}],
|
||||
commits: [
|
||||
{
|
||||
sha: "commit-sha1",
|
||||
html_url: "https://api.github.com/repos/matrix-org/matrix-js-sdk/commit/commit-sha1",
|
||||
commit: { message: "This is a commit message" },
|
||||
},
|
||||
{
|
||||
sha: "commit-sha2",
|
||||
html_url: "https://api.github.com/repos/matrix-org/matrix-js-sdk/commit/commit-sha2",
|
||||
commit: { message: "This is another commit message" },
|
||||
},
|
||||
],
|
||||
files: [],
|
||||
});
|
||||
|
||||
const newVersion = "newsha1-react-newsha2-js-newsha3";
|
||||
const oldVersion = "oldsha1-react-oldsha2-js-oldsha3";
|
||||
const { asFragment } = render((
|
||||
<ChangelogDialog newVersion={newVersion} version={oldVersion} onFinished={jest.fn()} />
|
||||
));
|
||||
const { asFragment } = render(
|
||||
<ChangelogDialog newVersion={newVersion} version={oldVersion} onFinished={jest.fn()} />,
|
||||
);
|
||||
|
||||
// Wait for spinners to go away
|
||||
await waitForElementToBeRemoved(screen.getAllByRole("progressbar"));
|
||||
|
|
|
@ -14,33 +14,33 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { mocked } from 'jest-mock';
|
||||
import { mount } from "enzyme";
|
||||
import { mocked } from "jest-mock";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { Room } from 'matrix-js-sdk/src/matrix';
|
||||
import { Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import ExportDialog from '../../../../src/components/views/dialogs/ExportDialog';
|
||||
import { ExportType, ExportFormat } from '../../../../src/utils/exportUtils/exportUtils';
|
||||
import { createTestClient, mkStubRoom } from '../../../test-utils';
|
||||
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||
import ExportDialog from "../../../../src/components/views/dialogs/ExportDialog";
|
||||
import { ExportType, ExportFormat } from "../../../../src/utils/exportUtils/exportUtils";
|
||||
import { createTestClient, mkStubRoom } from "../../../test-utils";
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import HTMLExporter from "../../../../src/utils/exportUtils/HtmlExport";
|
||||
import ChatExport from '../../../../src/customisations/ChatExport';
|
||||
import PlainTextExporter from '../../../../src/utils/exportUtils/PlainTextExport';
|
||||
import ChatExport from "../../../../src/customisations/ChatExport";
|
||||
import PlainTextExporter from "../../../../src/utils/exportUtils/PlainTextExport";
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
const htmlExporterInstance = ({
|
||||
const htmlExporterInstance = {
|
||||
export: jest.fn().mockResolvedValue({}),
|
||||
});
|
||||
const plainTextExporterInstance = ({
|
||||
};
|
||||
const plainTextExporterInstance = {
|
||||
export: jest.fn().mockResolvedValue({}),
|
||||
});
|
||||
};
|
||||
jest.mock("../../../../src/utils/exportUtils/HtmlExport", () => jest.fn());
|
||||
jest.mock("../../../../src/utils/exportUtils/PlainTextExport", () => jest.fn());
|
||||
|
||||
jest.mock('../../../../src/customisations/ChatExport', () => ({
|
||||
jest.mock("../../../../src/customisations/ChatExport", () => ({
|
||||
getForceChatExportParameters: jest.fn().mockReturnValue({}),
|
||||
}));
|
||||
|
||||
|
@ -48,13 +48,13 @@ const ChatExportMock = mocked(ChatExport);
|
|||
const HTMLExporterMock = mocked(HTMLExporter);
|
||||
const PlainTextExporterMock = mocked(PlainTextExporter);
|
||||
|
||||
describe('<ExportDialog />', () => {
|
||||
describe("<ExportDialog />", () => {
|
||||
const mockClient = createTestClient();
|
||||
jest.spyOn(MatrixClientPeg, 'get').mockReturnValue(mockClient);
|
||||
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient);
|
||||
|
||||
const roomId = 'test:test.org';
|
||||
const roomId = "test:test.org";
|
||||
const defaultProps = {
|
||||
room: mkStubRoom(roomId, 'test', mockClient) as unknown as Room,
|
||||
room: mkStubRoom(roomId, "test", mockClient) as unknown as Room,
|
||||
onFinished: jest.fn(),
|
||||
};
|
||||
|
||||
|
@ -68,32 +68,38 @@ describe('<ExportDialog />', () => {
|
|||
const getPrimaryButton = (component) => component.find('[data-testid="dialog-primary-button"]');
|
||||
const getSecondaryButton = (component) => component.find('[data-testid="dialog-cancel-button"]');
|
||||
|
||||
const submitForm = async (component) => act(async () => {
|
||||
getPrimaryButton(component).simulate('click');
|
||||
component.setProps({});
|
||||
});
|
||||
const selectExportFormat = async (component, format: ExportFormat) => act(async () => {
|
||||
getExportFormatInput(component, format).simulate('change');
|
||||
component.setProps({});
|
||||
});
|
||||
const selectExportType = async (component, type: ExportType) => act(async () => {
|
||||
getExportTypeInput(component).simulate('change', { target: { value: type } });
|
||||
component.setProps({});
|
||||
});
|
||||
const setMessageCount = async (component, count: number) => act(async () => {
|
||||
getMessageCountInput(component).simulate('change', { target: { value: count } });
|
||||
component.setProps({});
|
||||
});
|
||||
const submitForm = async (component) =>
|
||||
act(async () => {
|
||||
getPrimaryButton(component).simulate("click");
|
||||
component.setProps({});
|
||||
});
|
||||
const selectExportFormat = async (component, format: ExportFormat) =>
|
||||
act(async () => {
|
||||
getExportFormatInput(component, format).simulate("change");
|
||||
component.setProps({});
|
||||
});
|
||||
const selectExportType = async (component, type: ExportType) =>
|
||||
act(async () => {
|
||||
getExportTypeInput(component).simulate("change", { target: { value: type } });
|
||||
component.setProps({});
|
||||
});
|
||||
const setMessageCount = async (component, count: number) =>
|
||||
act(async () => {
|
||||
getMessageCountInput(component).simulate("change", { target: { value: count } });
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
const setSizeLimit = async (component, limit: number) => act(async () => {
|
||||
getSizeInput(component).simulate('change', { target: { value: limit } });
|
||||
component.setProps({});
|
||||
});
|
||||
const setSizeLimit = async (component, limit: number) =>
|
||||
act(async () => {
|
||||
getSizeInput(component).simulate("change", { target: { value: limit } });
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
const setIncludeAttachments = async (component, checked) => act(async () => {
|
||||
getAttachmentsCheckbox(component).simulate('change', { target: { checked } });
|
||||
component.setProps({});
|
||||
});
|
||||
const setIncludeAttachments = async (component, checked) =>
|
||||
act(async () => {
|
||||
getAttachmentsCheckbox(component).simulate("change", { target: { checked } });
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
HTMLExporterMock.mockClear().mockImplementation(jest.fn().mockReturnValue(htmlExporterInstance));
|
||||
|
@ -105,21 +111,21 @@ describe('<ExportDialog />', () => {
|
|||
ChatExportMock.getForceChatExportParameters.mockClear().mockReturnValue({});
|
||||
});
|
||||
|
||||
it('renders export dialog', () => {
|
||||
it("renders export dialog", () => {
|
||||
const component = getComponent();
|
||||
expect(component.find('.mx_ExportDialog')).toMatchSnapshot();
|
||||
expect(component.find(".mx_ExportDialog")).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('calls onFinished when cancel button is clicked', () => {
|
||||
it("calls onFinished when cancel button is clicked", () => {
|
||||
const onFinished = jest.fn();
|
||||
const component = getComponent({ onFinished });
|
||||
act(() => {
|
||||
getSecondaryButton(component).simulate('click');
|
||||
getSecondaryButton(component).simulate("click");
|
||||
});
|
||||
expect(onFinished).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it('exports room on submit', async () => {
|
||||
it("exports room on submit", async () => {
|
||||
const component = getComponent();
|
||||
await submitForm(component);
|
||||
|
||||
|
@ -137,7 +143,7 @@ describe('<ExportDialog />', () => {
|
|||
expect(htmlExporterInstance.export).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('exports room using values set from ForceRoomExportParameters', async () => {
|
||||
it("exports room using values set from ForceRoomExportParameters", async () => {
|
||||
ChatExportMock.getForceChatExportParameters.mockReturnValue({
|
||||
format: ExportFormat.PlainText,
|
||||
range: ExportType.Beginning,
|
||||
|
@ -162,35 +168,35 @@ describe('<ExportDialog />', () => {
|
|||
expect(plainTextExporterInstance.export).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('renders success screen when export is finished', async () => {
|
||||
it("renders success screen when export is finished", async () => {
|
||||
const component = getComponent();
|
||||
await submitForm(component);
|
||||
component.setProps({});
|
||||
|
||||
jest.runAllTimers();
|
||||
|
||||
expect(component.find('.mx_InfoDialog .mx_Dialog_content')).toMatchSnapshot();
|
||||
expect(component.find(".mx_InfoDialog .mx_Dialog_content")).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('export format', () => {
|
||||
it('renders export format with html selected by default', () => {
|
||||
describe("export format", () => {
|
||||
it("renders export format with html selected by default", () => {
|
||||
const component = getComponent();
|
||||
expect(getExportFormatInput(component, ExportFormat.Html).props().checked).toBeTruthy();
|
||||
});
|
||||
|
||||
it('sets export format on radio button click', async () => {
|
||||
it("sets export format on radio button click", async () => {
|
||||
const component = getComponent();
|
||||
await selectExportFormat(component, ExportFormat.PlainText);
|
||||
expect(getExportFormatInput(component, ExportFormat.PlainText).props().checked).toBeTruthy();
|
||||
expect(getExportFormatInput(component, ExportFormat.Html).props().checked).toBeFalsy();
|
||||
});
|
||||
|
||||
it('hides export format input when format is valid in ForceRoomExportParameters', () => {
|
||||
it("hides export format input when format is valid in ForceRoomExportParameters", () => {
|
||||
const component = getComponent();
|
||||
expect(getExportFormatInput(component, ExportFormat.Html).props().checked).toBeTruthy();
|
||||
});
|
||||
|
||||
it('does not render export format when set in ForceRoomExportParameters', () => {
|
||||
it("does not render export format when set in ForceRoomExportParameters", () => {
|
||||
ChatExportMock.getForceChatExportParameters.mockReturnValue({
|
||||
format: ExportFormat.PlainText,
|
||||
});
|
||||
|
@ -199,19 +205,19 @@ describe('<ExportDialog />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('export type', () => {
|
||||
it('renders export type with timeline selected by default', () => {
|
||||
describe("export type", () => {
|
||||
it("renders export type with timeline selected by default", () => {
|
||||
const component = getComponent();
|
||||
expect(getExportTypeInput(component).props().value).toEqual(ExportType.Timeline);
|
||||
});
|
||||
|
||||
it('sets export type on change', async () => {
|
||||
it("sets export type on change", async () => {
|
||||
const component = getComponent();
|
||||
await selectExportType(component, ExportType.Beginning);
|
||||
expect(getExportTypeInput(component).props().value).toEqual(ExportType.Beginning);
|
||||
});
|
||||
|
||||
it('does not render export type when set in ForceRoomExportParameters', () => {
|
||||
it("does not render export type when set in ForceRoomExportParameters", () => {
|
||||
ChatExportMock.getForceChatExportParameters.mockReturnValue({
|
||||
range: ExportType.Beginning,
|
||||
});
|
||||
|
@ -219,25 +225,25 @@ describe('<ExportDialog />', () => {
|
|||
expect(getExportTypeInput(component).length).toBeFalsy();
|
||||
});
|
||||
|
||||
it('does not render message count input', async () => {
|
||||
it("does not render message count input", async () => {
|
||||
const component = getComponent();
|
||||
expect(getMessageCountInput(component).length).toBeFalsy();
|
||||
});
|
||||
|
||||
it('renders message count input with default value 100 when export type is lastNMessages', async () => {
|
||||
it("renders message count input with default value 100 when export type is lastNMessages", async () => {
|
||||
const component = getComponent();
|
||||
await selectExportType(component, ExportType.LastNMessages);
|
||||
expect(getMessageCountInput(component).props().value).toEqual("100");
|
||||
});
|
||||
|
||||
it('sets message count on change', async () => {
|
||||
it("sets message count on change", async () => {
|
||||
const component = getComponent();
|
||||
await selectExportType(component, ExportType.LastNMessages);
|
||||
await setMessageCount(component, 10);
|
||||
expect(getMessageCountInput(component).props().value).toEqual("10");
|
||||
});
|
||||
|
||||
it('does not export when export type is lastNMessages and message count is falsy', async () => {
|
||||
it("does not export when export type is lastNMessages and message count is falsy", async () => {
|
||||
const component = getComponent();
|
||||
await selectExportType(component, ExportType.LastNMessages);
|
||||
await setMessageCount(component, 0);
|
||||
|
@ -246,7 +252,7 @@ describe('<ExportDialog />', () => {
|
|||
expect(htmlExporterInstance.export).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not export when export type is lastNMessages and message count is more than max', async () => {
|
||||
it("does not export when export type is lastNMessages and message count is more than max", async () => {
|
||||
const component = getComponent();
|
||||
await selectExportType(component, ExportType.LastNMessages);
|
||||
await setMessageCount(component, 99999999999);
|
||||
|
@ -255,7 +261,7 @@ describe('<ExportDialog />', () => {
|
|||
expect(htmlExporterInstance.export).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('exports when export type is NOT lastNMessages and message count is falsy', async () => {
|
||||
it("exports when export type is NOT lastNMessages and message count is falsy", async () => {
|
||||
const component = getComponent();
|
||||
await selectExportType(component, ExportType.LastNMessages);
|
||||
await setMessageCount(component, 0);
|
||||
|
@ -266,19 +272,19 @@ describe('<ExportDialog />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('size limit', () => {
|
||||
it('renders size limit input with default value', () => {
|
||||
describe("size limit", () => {
|
||||
it("renders size limit input with default value", () => {
|
||||
const component = getComponent();
|
||||
expect(getSizeInput(component).props().value).toEqual("8");
|
||||
});
|
||||
|
||||
it('updates size limit on change', async () => {
|
||||
it("updates size limit on change", async () => {
|
||||
const component = getComponent();
|
||||
await setSizeLimit(component, 20);
|
||||
expect(getSizeInput(component).props().value).toEqual("20");
|
||||
});
|
||||
|
||||
it('does not export when size limit is falsy', async () => {
|
||||
it("does not export when size limit is falsy", async () => {
|
||||
const component = getComponent();
|
||||
await setSizeLimit(component, 0);
|
||||
await submitForm(component);
|
||||
|
@ -286,7 +292,7 @@ describe('<ExportDialog />', () => {
|
|||
expect(htmlExporterInstance.export).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not export when size limit is larger than max', async () => {
|
||||
it("does not export when size limit is larger than max", async () => {
|
||||
const component = getComponent();
|
||||
await setSizeLimit(component, 2001);
|
||||
await submitForm(component);
|
||||
|
@ -294,7 +300,7 @@ describe('<ExportDialog />', () => {
|
|||
expect(htmlExporterInstance.export).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('exports when size limit is max', async () => {
|
||||
it("exports when size limit is max", async () => {
|
||||
const component = getComponent();
|
||||
await setSizeLimit(component, 2000);
|
||||
await submitForm(component);
|
||||
|
@ -302,7 +308,7 @@ describe('<ExportDialog />', () => {
|
|||
expect(htmlExporterInstance.export).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not render size limit input when set in ForceRoomExportParameters', () => {
|
||||
it("does not render size limit input when set in ForceRoomExportParameters", () => {
|
||||
ChatExportMock.getForceChatExportParameters.mockReturnValue({
|
||||
sizeMb: 10000,
|
||||
});
|
||||
|
@ -313,7 +319,7 @@ describe('<ExportDialog />', () => {
|
|||
/**
|
||||
* 2000mb size limit does not apply when higher limit is configured in config
|
||||
*/
|
||||
it('exports when size limit set in ForceRoomExportParameters is larger than 2000', async () => {
|
||||
it("exports when size limit set in ForceRoomExportParameters is larger than 2000", async () => {
|
||||
ChatExportMock.getForceChatExportParameters.mockReturnValue({
|
||||
sizeMb: 10000,
|
||||
});
|
||||
|
@ -324,19 +330,19 @@ describe('<ExportDialog />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('include attachments', () => {
|
||||
it('renders input with default value of false', () => {
|
||||
describe("include attachments", () => {
|
||||
it("renders input with default value of false", () => {
|
||||
const component = getComponent();
|
||||
expect(getAttachmentsCheckbox(component).props().checked).toEqual(false);
|
||||
});
|
||||
|
||||
it('updates include attachments on change', async () => {
|
||||
it("updates include attachments on change", async () => {
|
||||
const component = getComponent();
|
||||
await setIncludeAttachments(component, true);
|
||||
expect(getAttachmentsCheckbox(component).props().checked).toEqual(true);
|
||||
});
|
||||
|
||||
it('does not render input when set in ForceRoomExportParameters', () => {
|
||||
it("does not render input when set in ForceRoomExportParameters", () => {
|
||||
ChatExportMock.getForceChatExportParameters.mockReturnValue({
|
||||
includeAttachments: false,
|
||||
});
|
||||
|
@ -345,4 +351,3 @@ describe('<ExportDialog />', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -59,22 +59,22 @@ describe("ForwardDialog", () => {
|
|||
getRoom: jest.fn(),
|
||||
getAccountData: jest.fn().mockReturnValue(accountDataEvent),
|
||||
getPushActionsForEvent: jest.fn(),
|
||||
mxcUrlToHttp: jest.fn().mockReturnValue(''),
|
||||
mxcUrlToHttp: jest.fn().mockReturnValue(""),
|
||||
isRoomEncrypted: jest.fn().mockReturnValue(false),
|
||||
getProfileInfo: jest.fn().mockResolvedValue({
|
||||
displayname: 'Alice',
|
||||
displayname: "Alice",
|
||||
}),
|
||||
decryptEventIfNeeded: jest.fn(),
|
||||
sendEvent: jest.fn(),
|
||||
getClientWellKnown: jest.fn().mockReturnValue({
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: 'maps.com' },
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: "maps.com" },
|
||||
}),
|
||||
});
|
||||
const defaultRooms = ["a", "A", "b"].map(name => mkStubRoom(name, name, mockClient));
|
||||
const defaultRooms = ["a", "A", "b"].map((name) => mkStubRoom(name, name, mockClient));
|
||||
|
||||
const mountForwardDialog = (message = defaultMessage, rooms = defaultRooms) => {
|
||||
mockClient.getVisibleRooms.mockReturnValue(rooms);
|
||||
mockClient.getRoom.mockImplementation(roomId => rooms.find(room => room.roomId === roomId));
|
||||
mockClient.getRoom.mockImplementation((roomId) => rooms.find((room) => room.roomId === roomId));
|
||||
|
||||
const wrapper: RenderResult = render(
|
||||
<ForwardDialog
|
||||
|
@ -96,7 +96,7 @@ describe("ForwardDialog", () => {
|
|||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(MatrixClientPeg, 'get').mockRestore();
|
||||
jest.spyOn(MatrixClientPeg, "get").mockRestore();
|
||||
});
|
||||
|
||||
it("shows a preview with us as the sender", async () => {
|
||||
|
@ -127,10 +127,13 @@ describe("ForwardDialog", () => {
|
|||
// Make sendEvent require manual resolution so we can see the sending state
|
||||
let finishSend;
|
||||
let cancelSend;
|
||||
mockClient.sendEvent.mockImplementation(<T extends {}>() => new Promise<T>((resolve, reject) => {
|
||||
finishSend = resolve;
|
||||
cancelSend = reject;
|
||||
}));
|
||||
mockClient.sendEvent.mockImplementation(
|
||||
<T extends {}>() =>
|
||||
new Promise<T>((resolve, reject) => {
|
||||
finishSend = resolve;
|
||||
cancelSend = reject;
|
||||
}),
|
||||
);
|
||||
|
||||
let firstButton;
|
||||
let secondButton;
|
||||
|
@ -141,28 +144,32 @@ describe("ForwardDialog", () => {
|
|||
|
||||
expect(firstButton.className).toContain("mx_ForwardList_canSend");
|
||||
|
||||
act(() => { fireEvent.click(firstButton); });
|
||||
act(() => {
|
||||
fireEvent.click(firstButton);
|
||||
});
|
||||
update();
|
||||
expect(firstButton.className).toContain("mx_ForwardList_sending");
|
||||
|
||||
await act(async () => {
|
||||
cancelSend();
|
||||
// Wait one tick for the button to realize the send failed
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
});
|
||||
update();
|
||||
expect(firstButton.className).toContain("mx_ForwardList_sendFailed");
|
||||
|
||||
expect(secondButton.className).toContain("mx_ForwardList_canSend");
|
||||
|
||||
act(() => { fireEvent.click(secondButton); });
|
||||
act(() => {
|
||||
fireEvent.click(secondButton);
|
||||
});
|
||||
update();
|
||||
expect(secondButton.className).toContain("mx_ForwardList_sending");
|
||||
|
||||
await act(async () => {
|
||||
finishSend();
|
||||
// Wait one tick for the button to realize the send succeeded
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
});
|
||||
update();
|
||||
expect(secondButton.className).toContain("mx_ForwardList_sent");
|
||||
|
@ -203,7 +210,7 @@ describe("ForwardDialog", () => {
|
|||
expect(secondButton.getAttribute("aria-disabled")).toBeFalsy();
|
||||
});
|
||||
|
||||
describe('Location events', () => {
|
||||
describe("Location events", () => {
|
||||
// 14.03.2022 16:15
|
||||
const now = 1647270879403;
|
||||
const roomId = "a";
|
||||
|
@ -215,11 +222,11 @@ describe("ForwardDialog", () => {
|
|||
beforeEach(() => {
|
||||
// legacy events will default timestamp to Date.now()
|
||||
// mock a stable now for easy assertion
|
||||
jest.spyOn(Date, 'now').mockReturnValue(now);
|
||||
jest.spyOn(Date, "now").mockReturnValue(now);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(Date, 'now').mockRestore();
|
||||
jest.spyOn(Date, "now").mockRestore();
|
||||
});
|
||||
|
||||
const sendToFirstRoom = (container: HTMLElement): void =>
|
||||
|
@ -228,7 +235,7 @@ describe("ForwardDialog", () => {
|
|||
fireEvent.click(sendToFirstRoomButton!);
|
||||
});
|
||||
|
||||
it('converts legacy location events to pin drop shares', async () => {
|
||||
it("converts legacy location events to pin drop shares", async () => {
|
||||
const { container } = mountForwardDialog(legacyLocationEvent);
|
||||
|
||||
expect(container.querySelector(".mx_MLocationBody")).toBeTruthy();
|
||||
|
@ -250,11 +257,13 @@ describe("ForwardDialog", () => {
|
|||
},
|
||||
};
|
||||
expect(mockClient.sendEvent).toHaveBeenCalledWith(
|
||||
roomId, legacyLocationEvent.getType(), expectedStrippedContent,
|
||||
roomId,
|
||||
legacyLocationEvent.getType(),
|
||||
expectedStrippedContent,
|
||||
);
|
||||
});
|
||||
|
||||
it('removes personal information from static self location shares', async () => {
|
||||
it("removes personal information from static self location shares", async () => {
|
||||
const { container } = mountForwardDialog(modernLocationEvent);
|
||||
|
||||
expect(container.querySelector(".mx_MLocationBody")).toBeTruthy();
|
||||
|
@ -275,13 +284,15 @@ describe("ForwardDialog", () => {
|
|||
},
|
||||
};
|
||||
expect(mockClient.sendEvent).toHaveBeenCalledWith(
|
||||
roomId, modernLocationEvent.getType(), expectedStrippedContent,
|
||||
roomId,
|
||||
modernLocationEvent.getType(),
|
||||
expectedStrippedContent,
|
||||
);
|
||||
});
|
||||
|
||||
it('forwards beacon location as a pin drop event', async () => {
|
||||
it("forwards beacon location as a pin drop event", async () => {
|
||||
const timestamp = 123456;
|
||||
const beaconEvent = makeBeaconEvent('@alice:server.org', { geoUri, timestamp });
|
||||
const beaconEvent = makeBeaconEvent("@alice:server.org", { geoUri, timestamp });
|
||||
const text = `Location ${geoUri} at ${new Date(timestamp).toISOString()}`;
|
||||
const expectedContent = {
|
||||
msgtype: "m.location",
|
||||
|
@ -301,12 +312,10 @@ describe("ForwardDialog", () => {
|
|||
|
||||
sendToFirstRoom(container);
|
||||
|
||||
expect(mockClient.sendEvent).toHaveBeenCalledWith(
|
||||
roomId, EventType.RoomMessage, expectedContent,
|
||||
);
|
||||
expect(mockClient.sendEvent).toHaveBeenCalledWith(roomId, EventType.RoomMessage, expectedContent);
|
||||
});
|
||||
|
||||
it('forwards pin drop event', async () => {
|
||||
it("forwards pin drop event", async () => {
|
||||
const { container } = mountForwardDialog(pinDropLocationEvent);
|
||||
|
||||
expect(container.querySelector(".mx_MLocationBody")).toBeTruthy();
|
||||
|
@ -314,7 +323,9 @@ describe("ForwardDialog", () => {
|
|||
sendToFirstRoom(container);
|
||||
|
||||
expect(mockClient.sendEvent).toHaveBeenCalledWith(
|
||||
roomId, pinDropLocationEvent.getType(), pinDropLocationEvent.getContent(),
|
||||
roomId,
|
||||
pinDropLocationEvent.getType(),
|
||||
pinDropLocationEvent.getContent(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,17 +15,17 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import React from "react";
|
||||
import { act } from "react-dom/test-utils";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
|
||||
import InteractiveAuthDialog from "../../../../src/components/views/dialogs/InteractiveAuthDialog";
|
||||
import { flushPromises, getMockClientWithEventEmitter, unmockClientPeg } from '../../../test-utils';
|
||||
import { flushPromises, getMockClientWithEventEmitter, unmockClientPeg } from "../../../test-utils";
|
||||
|
||||
describe('InteractiveAuthDialog', function() {
|
||||
describe("InteractiveAuthDialog", function () {
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
generateClientSecret: jest.fn().mockReturnValue('t35tcl1Ent5ECr3T'),
|
||||
generateClientSecret: jest.fn().mockReturnValue("t35tcl1Ent5ECr3T"),
|
||||
});
|
||||
|
||||
const defaultProps = {
|
||||
|
@ -33,12 +33,9 @@ describe('InteractiveAuthDialog', function() {
|
|||
makeRequest: jest.fn().mockResolvedValue(undefined),
|
||||
onFinished: jest.fn(),
|
||||
};
|
||||
const getComponent = (props = {}) => mount(<InteractiveAuthDialog
|
||||
{...defaultProps}
|
||||
{...props}
|
||||
/>);
|
||||
const getComponent = (props = {}) => mount(<InteractiveAuthDialog {...defaultProps} {...props} />);
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
jest.clearAllMocks();
|
||||
mockClient.credentials = null;
|
||||
});
|
||||
|
@ -49,16 +46,14 @@ describe('InteractiveAuthDialog', function() {
|
|||
|
||||
const getSubmitButton = (wrapper: ReactWrapper) => wrapper.find('[type="submit"]').at(0);
|
||||
|
||||
it('Should successfully complete a password flow', async () => {
|
||||
it("Should successfully complete a password flow", async () => {
|
||||
const onFinished = jest.fn();
|
||||
const makeRequest = jest.fn().mockResolvedValue({ a: 1 });
|
||||
|
||||
mockClient.credentials = { userId: "@user:id" };
|
||||
const authData = {
|
||||
session: "sess",
|
||||
flows: [
|
||||
{ "stages": ["m.login.password"] },
|
||||
],
|
||||
flows: [{ stages: ["m.login.password"] }],
|
||||
};
|
||||
|
||||
const wrapper = getComponent({ makeRequest, onFinished, authData });
|
||||
|
@ -66,7 +61,7 @@ describe('InteractiveAuthDialog', function() {
|
|||
const passwordNode = wrapper.find('input[type="password"]').at(0);
|
||||
const submitNode = getSubmitButton(wrapper);
|
||||
|
||||
const formNode = wrapper.find('form').at(0);
|
||||
const formNode = wrapper.find("form").at(0);
|
||||
expect(passwordNode).toBeTruthy();
|
||||
expect(submitNode).toBeTruthy();
|
||||
|
||||
|
@ -75,7 +70,7 @@ describe('InteractiveAuthDialog', function() {
|
|||
|
||||
// put something in the password box
|
||||
act(() => {
|
||||
passwordNode.simulate('change', { target: { value: "s3kr3t" } });
|
||||
passwordNode.simulate("change", { target: { value: "s3kr3t" } });
|
||||
wrapper.setProps({});
|
||||
});
|
||||
|
||||
|
@ -84,22 +79,24 @@ describe('InteractiveAuthDialog', function() {
|
|||
|
||||
// hit enter; that should trigger a request
|
||||
act(() => {
|
||||
formNode.simulate('submit');
|
||||
formNode.simulate("submit");
|
||||
});
|
||||
|
||||
// wait for auth request to resolve
|
||||
await flushPromises();
|
||||
|
||||
expect(makeRequest).toHaveBeenCalledTimes(1);
|
||||
expect(makeRequest).toBeCalledWith(expect.objectContaining({
|
||||
session: "sess",
|
||||
type: "m.login.password",
|
||||
password: "s3kr3t",
|
||||
identifier: {
|
||||
type: "m.id.user",
|
||||
user: "@user:id",
|
||||
},
|
||||
}));
|
||||
expect(makeRequest).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
session: "sess",
|
||||
type: "m.login.password",
|
||||
password: "s3kr3t",
|
||||
identifier: {
|
||||
type: "m.id.user",
|
||||
user: "@user:id",
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(onFinished).toBeCalledTimes(1);
|
||||
expect(onFinished).toBeCalledWith(true, { a: 1 });
|
||||
|
|
|
@ -28,9 +28,11 @@ import { ValidatedServerConfig } from "../../../../src/utils/ValidatedServerConf
|
|||
import { IConfigOptions } from "../../../../src/IConfigOptions";
|
||||
|
||||
const mockGetAccessToken = jest.fn().mockResolvedValue("getAccessToken");
|
||||
jest.mock("../../../../src/IdentityAuthClient", () => jest.fn().mockImplementation(() => ({
|
||||
getAccessToken: mockGetAccessToken,
|
||||
})));
|
||||
jest.mock("../../../../src/IdentityAuthClient", () =>
|
||||
jest.fn().mockImplementation(() => ({
|
||||
getAccessToken: mockGetAccessToken,
|
||||
})),
|
||||
);
|
||||
|
||||
describe("InviteDialog", () => {
|
||||
const roomId = "!111111111111111111:example.org";
|
||||
|
@ -43,7 +45,7 @@ describe("InviteDialog", () => {
|
|||
getRooms: jest.fn(),
|
||||
getAccountData: jest.fn(),
|
||||
getPushActionsForEvent: jest.fn(),
|
||||
mxcUrlToHttp: jest.fn().mockReturnValue(''),
|
||||
mxcUrlToHttp: jest.fn().mockReturnValue(""),
|
||||
isRoomEncrypted: jest.fn().mockReturnValue(false),
|
||||
getProfileInfo: jest.fn().mockRejectedValue({ errcode: "" }),
|
||||
getIdentityServerUrl: jest.fn(),
|
||||
|
@ -70,58 +72,46 @@ describe("InviteDialog", () => {
|
|||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(MatrixClientPeg, 'get').mockRestore();
|
||||
jest.spyOn(MatrixClientPeg, "get").mockRestore();
|
||||
});
|
||||
|
||||
it("should label with space name", () => {
|
||||
mockClient.getRoom(roomId).isSpaceRoom = jest.fn().mockReturnValue(true);
|
||||
mockClient.getRoom(roomId).getType = jest.fn().mockReturnValue(RoomType.Space);
|
||||
mockClient.getRoom(roomId).name = "Space";
|
||||
render((
|
||||
<InviteDialog
|
||||
kind={KIND_INVITE}
|
||||
roomId={roomId}
|
||||
onFinished={jest.fn()}
|
||||
/>
|
||||
));
|
||||
render(<InviteDialog kind={KIND_INVITE} roomId={roomId} onFinished={jest.fn()} />);
|
||||
|
||||
expect(screen.queryByText("Invite to Space")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should label with room name", () => {
|
||||
render((
|
||||
<InviteDialog
|
||||
kind={KIND_INVITE}
|
||||
roomId={roomId}
|
||||
onFinished={jest.fn()}
|
||||
/>
|
||||
));
|
||||
render(<InviteDialog kind={KIND_INVITE} roomId={roomId} onFinished={jest.fn()} />);
|
||||
|
||||
expect(screen.queryByText("Invite to Room")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should suggest valid MXIDs even if unknown", async () => {
|
||||
render((
|
||||
render(
|
||||
<InviteDialog
|
||||
kind={KIND_INVITE}
|
||||
roomId={roomId}
|
||||
onFinished={jest.fn()}
|
||||
initialText="@localpart:server.tld"
|
||||
/>
|
||||
));
|
||||
/>,
|
||||
);
|
||||
|
||||
await screen.findAllByText("@localpart:server.tld"); // Using findAllByText as the MXID is used for name too
|
||||
});
|
||||
|
||||
it("should not suggest invalid MXIDs", () => {
|
||||
render((
|
||||
render(
|
||||
<InviteDialog
|
||||
kind={KIND_INVITE}
|
||||
roomId={roomId}
|
||||
onFinished={jest.fn()}
|
||||
initialText="@localpart:server:tld"
|
||||
/>
|
||||
));
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.queryByText("@localpart:server:tld")).toBeFalsy();
|
||||
});
|
||||
|
@ -138,14 +128,9 @@ describe("InviteDialog", () => {
|
|||
avatar_url: "mxc://foo/bar",
|
||||
});
|
||||
|
||||
render((
|
||||
<InviteDialog
|
||||
kind={KIND_INVITE}
|
||||
roomId={roomId}
|
||||
onFinished={jest.fn()}
|
||||
initialText="foobar@email.com"
|
||||
/>
|
||||
));
|
||||
render(
|
||||
<InviteDialog kind={KIND_INVITE} roomId={roomId} onFinished={jest.fn()} initialText="foobar@email.com" />,
|
||||
);
|
||||
|
||||
await screen.findByText("Mr. Foo");
|
||||
await screen.findByText("@foobar:server");
|
||||
|
@ -157,14 +142,9 @@ describe("InviteDialog", () => {
|
|||
mockClient.getIdentityServerUrl.mockReturnValue("https://identity-server");
|
||||
mockClient.lookupThreePid.mockResolvedValue({});
|
||||
|
||||
render((
|
||||
<InviteDialog
|
||||
kind={KIND_INVITE}
|
||||
roomId={roomId}
|
||||
onFinished={jest.fn()}
|
||||
initialText="foobar@email.com"
|
||||
/>
|
||||
));
|
||||
render(
|
||||
<InviteDialog kind={KIND_INVITE} roomId={roomId} onFinished={jest.fn()} initialText="foobar@email.com" />,
|
||||
);
|
||||
|
||||
await screen.findByText("foobar@email.com");
|
||||
await screen.findByText("Invite by email");
|
||||
|
|
|
@ -54,16 +54,14 @@ interface MockClientOptions {
|
|||
users?: IUserChunkMember[];
|
||||
}
|
||||
|
||||
function mockClient(
|
||||
{
|
||||
userId = "testuser",
|
||||
homeserver = "example.tld",
|
||||
thirdPartyProtocols = {},
|
||||
rooms = [],
|
||||
members = [],
|
||||
users = [],
|
||||
}: MockClientOptions = {},
|
||||
): MatrixClient {
|
||||
function mockClient({
|
||||
userId = "testuser",
|
||||
homeserver = "example.tld",
|
||||
thirdPartyProtocols = {},
|
||||
rooms = [],
|
||||
members = [],
|
||||
users = [],
|
||||
}: MockClientOptions = {}): MatrixClient {
|
||||
stubClient();
|
||||
const cli = MatrixClientPeg.get();
|
||||
MatrixClientPeg.getHomeserverName = jest.fn(() => homeserver);
|
||||
|
@ -72,13 +70,15 @@ function mockClient(
|
|||
cli.getThirdpartyProtocols = jest.fn(() => Promise.resolve(thirdPartyProtocols));
|
||||
cli.publicRooms = jest.fn((options) => {
|
||||
const searchTerm = options?.filter?.generic_search_term?.toLowerCase();
|
||||
const chunk = rooms.filter(it =>
|
||||
!searchTerm ||
|
||||
it.room_id.toLowerCase().includes(searchTerm) ||
|
||||
it.name?.toLowerCase().includes(searchTerm) ||
|
||||
sanitizeHtml(it?.topic, { allowedTags: [] }).toLowerCase().includes(searchTerm) ||
|
||||
it.canonical_alias?.toLowerCase().includes(searchTerm) ||
|
||||
it.aliases?.find(alias => alias.toLowerCase().includes(searchTerm)));
|
||||
const chunk = rooms.filter(
|
||||
(it) =>
|
||||
!searchTerm ||
|
||||
it.room_id.toLowerCase().includes(searchTerm) ||
|
||||
it.name?.toLowerCase().includes(searchTerm) ||
|
||||
sanitizeHtml(it?.topic, { allowedTags: [] }).toLowerCase().includes(searchTerm) ||
|
||||
it.canonical_alias?.toLowerCase().includes(searchTerm) ||
|
||||
it.aliases?.find((alias) => alias.toLowerCase().includes(searchTerm)),
|
||||
);
|
||||
return Promise.resolve({
|
||||
chunk,
|
||||
total_room_count_estimate: chunk.length,
|
||||
|
@ -86,16 +86,19 @@ function mockClient(
|
|||
});
|
||||
cli.searchUserDirectory = jest.fn(({ term, limit }) => {
|
||||
const searchTerm = term?.toLowerCase();
|
||||
const results = users.filter(it => !searchTerm ||
|
||||
it.user_id.toLowerCase().includes(searchTerm) ||
|
||||
it.display_name.toLowerCase().includes(searchTerm));
|
||||
const results = users.filter(
|
||||
(it) =>
|
||||
!searchTerm ||
|
||||
it.user_id.toLowerCase().includes(searchTerm) ||
|
||||
it.display_name.toLowerCase().includes(searchTerm),
|
||||
);
|
||||
return Promise.resolve({
|
||||
results: results.slice(0, limit ?? +Infinity),
|
||||
limited: limit && limit < results.length,
|
||||
});
|
||||
});
|
||||
cli.getProfileInfo = jest.fn(async (userId) => {
|
||||
const member = members.find(it => it.userId === userId);
|
||||
const member = members.find((it) => it.userId === userId);
|
||||
if (member) {
|
||||
return Promise.resolve({
|
||||
displayname: member.rawDisplayName,
|
||||
|
@ -144,11 +147,7 @@ describe("Spotlight Dialog", () => {
|
|||
|
||||
describe("should apply filters supplied via props", () => {
|
||||
it("without filter", async () => {
|
||||
const wrapper = mount(
|
||||
<SpotlightDialog
|
||||
initialFilter={null}
|
||||
onFinished={() => null} />,
|
||||
);
|
||||
const wrapper = mount(<SpotlightDialog initialFilter={null} onFinished={() => null} />);
|
||||
await act(async () => {
|
||||
await sleep(200);
|
||||
});
|
||||
|
@ -160,11 +159,7 @@ describe("Spotlight Dialog", () => {
|
|||
wrapper.unmount();
|
||||
});
|
||||
it("with public room filter", async () => {
|
||||
const wrapper = mount(
|
||||
<SpotlightDialog
|
||||
initialFilter={Filter.PublicRooms}
|
||||
onFinished={() => null} />,
|
||||
);
|
||||
const wrapper = mount(<SpotlightDialog initialFilter={Filter.PublicRooms} onFinished={() => null} />);
|
||||
await act(async () => {
|
||||
await sleep(200);
|
||||
});
|
||||
|
@ -186,7 +181,8 @@ describe("Spotlight Dialog", () => {
|
|||
<SpotlightDialog
|
||||
initialFilter={Filter.People}
|
||||
initialText={testPerson.display_name}
|
||||
onFinished={() => null} />,
|
||||
onFinished={() => null}
|
||||
/>,
|
||||
);
|
||||
await act(async () => {
|
||||
await sleep(200);
|
||||
|
@ -208,10 +204,7 @@ describe("Spotlight Dialog", () => {
|
|||
|
||||
describe("should apply manually selected filter", () => {
|
||||
it("with public rooms", async () => {
|
||||
const wrapper = mount(
|
||||
<SpotlightDialog
|
||||
onFinished={() => null} />,
|
||||
);
|
||||
const wrapper = mount(<SpotlightDialog onFinished={() => null} />);
|
||||
await act(async () => {
|
||||
await sleep(1);
|
||||
});
|
||||
|
@ -234,11 +227,7 @@ describe("Spotlight Dialog", () => {
|
|||
wrapper.unmount();
|
||||
});
|
||||
it("with people", async () => {
|
||||
const wrapper = mount(
|
||||
<SpotlightDialog
|
||||
initialText={testPerson.display_name}
|
||||
onFinished={() => null} />,
|
||||
);
|
||||
const wrapper = mount(<SpotlightDialog initialText={testPerson.display_name} onFinished={() => null} />);
|
||||
await act(async () => {
|
||||
await sleep(1);
|
||||
});
|
||||
|
@ -264,11 +253,7 @@ describe("Spotlight Dialog", () => {
|
|||
|
||||
describe("should allow clearing filter manually", () => {
|
||||
it("with public room filter", async () => {
|
||||
const wrapper = mount(
|
||||
<SpotlightDialog
|
||||
initialFilter={Filter.PublicRooms}
|
||||
onFinished={() => null} />,
|
||||
);
|
||||
const wrapper = mount(<SpotlightDialog initialFilter={Filter.PublicRooms} onFinished={() => null} />);
|
||||
await act(async () => {
|
||||
await sleep(200);
|
||||
});
|
||||
|
@ -294,7 +279,8 @@ describe("Spotlight Dialog", () => {
|
|||
<SpotlightDialog
|
||||
initialFilter={Filter.People}
|
||||
initialText={testPerson.display_name}
|
||||
onFinished={() => null} />,
|
||||
onFinished={() => null}
|
||||
/>,
|
||||
);
|
||||
await act(async () => {
|
||||
await sleep(200);
|
||||
|
@ -323,11 +309,7 @@ describe("Spotlight Dialog", () => {
|
|||
let options: ReactWrapper;
|
||||
|
||||
beforeAll(async () => {
|
||||
wrapper = mount(
|
||||
<SpotlightDialog
|
||||
initialText="test23"
|
||||
onFinished={() => null} />,
|
||||
);
|
||||
wrapper = mount(<SpotlightDialog initialText="test23" onFinished={() => null} />);
|
||||
await act(async () => {
|
||||
await sleep(200);
|
||||
});
|
||||
|
@ -357,7 +339,8 @@ describe("Spotlight Dialog", () => {
|
|||
<SpotlightDialog
|
||||
initialFilter={Filter.People}
|
||||
initialText={testPerson.display_name}
|
||||
onFinished={() => null} />,
|
||||
onFinished={() => null}
|
||||
/>,
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
|
|
|
@ -14,30 +14,30 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { ReactElement } from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { mocked } from 'jest-mock';
|
||||
import React, { ReactElement } from "react";
|
||||
import { render } from "@testing-library/react";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import SettingsStore, { CallbackFn } from '../../../../src/settings/SettingsStore';
|
||||
import SdkConfig from '../../../../src/SdkConfig';
|
||||
import { UserTab } from '../../../../src/components/views/dialogs/UserTab';
|
||||
import UserSettingsDialog from '../../../../src/components/views/dialogs/UserSettingsDialog';
|
||||
import { IDialogProps } from '../../../../src/components/views/dialogs/IDialogProps';
|
||||
import SettingsStore, { CallbackFn } from "../../../../src/settings/SettingsStore";
|
||||
import SdkConfig from "../../../../src/SdkConfig";
|
||||
import { UserTab } from "../../../../src/components/views/dialogs/UserTab";
|
||||
import UserSettingsDialog from "../../../../src/components/views/dialogs/UserSettingsDialog";
|
||||
import { IDialogProps } from "../../../../src/components/views/dialogs/IDialogProps";
|
||||
import {
|
||||
getMockClientWithEventEmitter,
|
||||
mockClientMethodsUser,
|
||||
mockClientMethodsServer,
|
||||
mockPlatformPeg,
|
||||
} from '../../../test-utils';
|
||||
import { UIFeature } from '../../../../src/settings/UIFeature';
|
||||
import { SettingLevel } from '../../../../src/settings/SettingLevel';
|
||||
} from "../../../test-utils";
|
||||
import { UIFeature } from "../../../../src/settings/UIFeature";
|
||||
import { SettingLevel } from "../../../../src/settings/SettingLevel";
|
||||
|
||||
mockPlatformPeg({
|
||||
supportsSpellCheckSettings: jest.fn().mockReturnValue(false),
|
||||
getAppVersion: jest.fn().mockResolvedValue('1'),
|
||||
getAppVersion: jest.fn().mockResolvedValue("1"),
|
||||
});
|
||||
|
||||
jest.mock('../../../../src/settings/SettingsStore', () => ({
|
||||
jest.mock("../../../../src/settings/SettingsStore", () => ({
|
||||
getValue: jest.fn(),
|
||||
getValueAt: jest.fn(),
|
||||
canSetValue: jest.fn(),
|
||||
|
@ -48,12 +48,12 @@ jest.mock('../../../../src/settings/SettingsStore', () => ({
|
|||
getBetaInfo: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../../src/SdkConfig', () => ({
|
||||
jest.mock("../../../../src/SdkConfig", () => ({
|
||||
get: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('<UserSettingsDialog />', () => {
|
||||
const userId = '@alice:server.org';
|
||||
describe("<UserSettingsDialog />", () => {
|
||||
const userId = "@alice:server.org";
|
||||
const mockSettingsStore = mocked(SettingsStore);
|
||||
const mockSdkConfig = mocked(SdkConfig);
|
||||
getMockClientWithEventEmitter({
|
||||
|
@ -62,7 +62,7 @@ describe('<UserSettingsDialog />', () => {
|
|||
});
|
||||
|
||||
const defaultProps = { onFinished: jest.fn() };
|
||||
const getComponent = (props: Partial<IDialogProps & {initialTabId?: UserTab}> = {}): ReactElement => (
|
||||
const getComponent = (props: Partial<IDialogProps & { initialTabId?: UserTab }> = {}): ReactElement => (
|
||||
<UserSettingsDialog {...defaultProps} {...props} />
|
||||
);
|
||||
|
||||
|
@ -70,52 +70,52 @@ describe('<UserSettingsDialog />', () => {
|
|||
jest.clearAllMocks();
|
||||
mockSettingsStore.getValue.mockReturnValue(false);
|
||||
mockSettingsStore.getFeatureSettingNames.mockReturnValue([]);
|
||||
mockSdkConfig.get.mockReturnValue({ brand: 'Test' });
|
||||
mockSdkConfig.get.mockReturnValue({ brand: "Test" });
|
||||
});
|
||||
|
||||
const getActiveTabLabel = (container) => container.querySelector('.mx_TabbedView_tabLabel_active').textContent;
|
||||
const getActiveTabHeading = (container) => container.querySelector('.mx_SettingsTab_heading').textContent;
|
||||
const getActiveTabLabel = (container) => container.querySelector(".mx_TabbedView_tabLabel_active").textContent;
|
||||
const getActiveTabHeading = (container) => container.querySelector(".mx_SettingsTab_heading").textContent;
|
||||
|
||||
it('should render general settings tab when no initialTabId', () => {
|
||||
it("should render general settings tab when no initialTabId", () => {
|
||||
const { container } = render(getComponent());
|
||||
|
||||
expect(getActiveTabLabel(container)).toEqual('General');
|
||||
expect(getActiveTabHeading(container)).toEqual('General');
|
||||
expect(getActiveTabLabel(container)).toEqual("General");
|
||||
expect(getActiveTabHeading(container)).toEqual("General");
|
||||
});
|
||||
|
||||
it('should render initial tab when initialTabId is set', () => {
|
||||
it("should render initial tab when initialTabId is set", () => {
|
||||
const { container } = render(getComponent({ initialTabId: UserTab.Help }));
|
||||
|
||||
expect(getActiveTabLabel(container)).toEqual('Help & About');
|
||||
expect(getActiveTabHeading(container)).toEqual('Help & About');
|
||||
expect(getActiveTabLabel(container)).toEqual("Help & About");
|
||||
expect(getActiveTabHeading(container)).toEqual("Help & About");
|
||||
});
|
||||
|
||||
it('should render general tab if initialTabId tab cannot be rendered', () => {
|
||||
it("should render general tab if initialTabId tab cannot be rendered", () => {
|
||||
// mjolnir tab is only rendered in some configs
|
||||
const { container } = render(getComponent({ initialTabId: UserTab.Mjolnir }));
|
||||
|
||||
expect(getActiveTabLabel(container)).toEqual('General');
|
||||
expect(getActiveTabHeading(container)).toEqual('General');
|
||||
expect(getActiveTabLabel(container)).toEqual("General");
|
||||
expect(getActiveTabHeading(container)).toEqual("General");
|
||||
});
|
||||
|
||||
it('renders tabs correctly', () => {
|
||||
it("renders tabs correctly", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container.querySelectorAll('.mx_TabbedView_tabLabel')).toMatchSnapshot();
|
||||
expect(container.querySelectorAll(".mx_TabbedView_tabLabel")).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders ignored users tab when feature_mjolnir is enabled', () => {
|
||||
it("renders ignored users tab when feature_mjolnir is enabled", () => {
|
||||
mockSettingsStore.getValue.mockImplementation((settingName): any => settingName === "feature_mjolnir");
|
||||
const { getByTestId } = render(getComponent());
|
||||
expect(getByTestId(`settings-tab-${UserTab.Mjolnir}`)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders voip tab when voip is enabled', () => {
|
||||
it("renders voip tab when voip is enabled", () => {
|
||||
mockSettingsStore.getValue.mockImplementation((settingName): any => settingName === UIFeature.Voip);
|
||||
const { getByTestId } = render(getComponent());
|
||||
expect(getByTestId(`settings-tab-${UserTab.Voice}`)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders session manager tab when enabled', () => {
|
||||
it("renders session manager tab when enabled", () => {
|
||||
mockSettingsStore.getValue.mockImplementation((settingName): any => {
|
||||
return settingName === "feature_new_device_manager";
|
||||
});
|
||||
|
@ -123,23 +123,23 @@ describe('<UserSettingsDialog />', () => {
|
|||
expect(getByTestId(`settings-tab-${UserTab.SessionManager}`)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders labs tab when show_labs_settings is enabled in config', () => {
|
||||
it("renders labs tab when show_labs_settings is enabled in config", () => {
|
||||
// @ts-ignore simplified test stub
|
||||
mockSdkConfig.get.mockImplementation((configName) => configName === "show_labs_settings");
|
||||
const { getByTestId } = render(getComponent());
|
||||
expect(getByTestId(`settings-tab-${UserTab.Labs}`)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders labs tab when some feature is in beta', () => {
|
||||
mockSettingsStore.getFeatureSettingNames.mockReturnValue(['feature_beta_setting', 'feature_just_normal_labs']);
|
||||
mockSettingsStore.getBetaInfo.mockImplementation(
|
||||
(settingName) => settingName === 'feature_beta_setting' ? {} as any : undefined,
|
||||
it("renders labs tab when some feature is in beta", () => {
|
||||
mockSettingsStore.getFeatureSettingNames.mockReturnValue(["feature_beta_setting", "feature_just_normal_labs"]);
|
||||
mockSettingsStore.getBetaInfo.mockImplementation((settingName) =>
|
||||
settingName === "feature_beta_setting" ? ({} as any) : undefined,
|
||||
);
|
||||
const { getByTestId } = render(getComponent());
|
||||
expect(getByTestId(`settings-tab-${UserTab.Labs}`)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('watches settings', () => {
|
||||
it("watches settings", () => {
|
||||
const watchSettingCallbacks: Record<string, CallbackFn> = {};
|
||||
|
||||
mockSettingsStore.watchSetting.mockImplementation((settingName, roomId, callback) => {
|
||||
|
@ -150,17 +150,21 @@ describe('<UserSettingsDialog />', () => {
|
|||
const { queryByTestId, unmount } = render(getComponent());
|
||||
expect(queryByTestId(`settings-tab-${UserTab.Mjolnir}`)).toBeFalsy();
|
||||
|
||||
expect(mockSettingsStore.watchSetting.mock.calls[0][0]).toEqual('feature_mjolnir');
|
||||
expect(mockSettingsStore.watchSetting.mock.calls[1][0]).toEqual('feature_new_device_manager');
|
||||
expect(mockSettingsStore.watchSetting.mock.calls[0][0]).toEqual("feature_mjolnir");
|
||||
expect(mockSettingsStore.watchSetting.mock.calls[1][0]).toEqual("feature_new_device_manager");
|
||||
|
||||
// call the watch setting callback
|
||||
watchSettingCallbacks["feature_mjolnir"]("feature_mjolnir", '', SettingLevel.ACCOUNT, true, true);
|
||||
watchSettingCallbacks["feature_mjolnir"]("feature_mjolnir", "", SettingLevel.ACCOUNT, true, true);
|
||||
// tab is rendered now
|
||||
expect(queryByTestId(`settings-tab-${UserTab.Mjolnir}`)).toBeTruthy();
|
||||
|
||||
// call the watch setting callback
|
||||
watchSettingCallbacks["feature_new_device_manager"](
|
||||
"feature_new_device_manager", '', SettingLevel.ACCOUNT, true, true,
|
||||
"feature_new_device_manager",
|
||||
"",
|
||||
SettingLevel.ACCOUNT,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
// tab is rendered now
|
||||
expect(queryByTestId(`settings-tab-${UserTab.SessionManager}`)).toBeTruthy();
|
||||
|
@ -168,7 +172,7 @@ describe('<UserSettingsDialog />', () => {
|
|||
unmount();
|
||||
|
||||
// unwatches settings on unmount
|
||||
expect(mockSettingsStore.unwatchSetting).toHaveBeenCalledWith('mock-watcher-id-feature_mjolnir');
|
||||
expect(mockSettingsStore.unwatchSetting).toHaveBeenCalledWith('mock-watcher-id-feature_new_device_manager');
|
||||
expect(mockSettingsStore.unwatchSetting).toHaveBeenCalledWith("mock-watcher-id-feature_mjolnir");
|
||||
expect(mockSettingsStore.unwatchSetting).toHaveBeenCalledWith("mock-watcher-id-feature_new_device_manager");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -22,19 +22,21 @@ import { PublicRoomResultDetails } from "../../../../../src/components/views/dia
|
|||
|
||||
describe("PublicRoomResultDetails", () => {
|
||||
it("renders", () => {
|
||||
const { asFragment } = render(<PublicRoomResultDetails
|
||||
room={{
|
||||
room_id: "room-id",
|
||||
name: "hello?",
|
||||
canonical_alias: "canonical-alias",
|
||||
world_readable: true,
|
||||
guest_can_join: false,
|
||||
num_joined_members: 666,
|
||||
}}
|
||||
labelId="label-id"
|
||||
descriptionId="description-id"
|
||||
detailsId="details-id"
|
||||
/>);
|
||||
const { asFragment } = render(
|
||||
<PublicRoomResultDetails
|
||||
room={{
|
||||
room_id: "room-id",
|
||||
name: "hello?",
|
||||
canonical_alias: "canonical-alias",
|
||||
world_readable: true,
|
||||
guest_can_join: false,
|
||||
num_joined_members: 666,
|
||||
}}
|
||||
labelId="label-id"
|
||||
descriptionId="description-id"
|
||||
detailsId="details-id"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
@ -57,12 +59,14 @@ describe("PublicRoomResultDetails", () => {
|
|||
...partialPublicRoomChunk,
|
||||
};
|
||||
|
||||
const { asFragment } = render(<PublicRoomResultDetails
|
||||
room={roomChunk}
|
||||
labelId="label-id"
|
||||
descriptionId="description-id"
|
||||
detailsId="details-id"
|
||||
/>);
|
||||
const { asFragment } = render(
|
||||
<PublicRoomResultDetails
|
||||
room={roomChunk}
|
||||
labelId="label-id"
|
||||
descriptionId="description-id"
|
||||
detailsId="details-id"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -14,22 +14,21 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { mount } from "enzyme";
|
||||
import { act } from "react-dom/test-utils";
|
||||
|
||||
import AccessibleButton from '../../../../src/components/views/elements/AccessibleButton';
|
||||
import { Key } from '../../../../src/Keyboard';
|
||||
import { mockPlatformPeg, unmockPlatformPeg } from '../../../test-utils';
|
||||
import AccessibleButton from "../../../../src/components/views/elements/AccessibleButton";
|
||||
import { Key } from "../../../../src/Keyboard";
|
||||
import { mockPlatformPeg, unmockPlatformPeg } from "../../../test-utils";
|
||||
|
||||
describe('<AccessibleButton />', () => {
|
||||
describe("<AccessibleButton />", () => {
|
||||
const defaultProps = {
|
||||
onClick: jest.fn(),
|
||||
children: 'i am a button',
|
||||
children: "i am a button",
|
||||
};
|
||||
const getComponent = (props = {}) =>
|
||||
mount(<AccessibleButton {...defaultProps} {...props} />);
|
||||
const getComponent = (props = {}) => mount(<AccessibleButton {...defaultProps} {...props} />);
|
||||
|
||||
beforeEach(() => {
|
||||
mockPlatformPeg();
|
||||
|
@ -39,66 +38,67 @@ describe('<AccessibleButton />', () => {
|
|||
unmockPlatformPeg();
|
||||
});
|
||||
|
||||
const makeKeyboardEvent = (key: string) => ({
|
||||
key,
|
||||
stopPropagation: jest.fn(),
|
||||
preventDefault: jest.fn(),
|
||||
}) as unknown as KeyboardEvent;
|
||||
const makeKeyboardEvent = (key: string) =>
|
||||
({
|
||||
key,
|
||||
stopPropagation: jest.fn(),
|
||||
preventDefault: jest.fn(),
|
||||
} as unknown as KeyboardEvent);
|
||||
|
||||
it('renders div with role button by default', () => {
|
||||
it("renders div with role button by default", () => {
|
||||
const component = getComponent();
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders a button element', () => {
|
||||
const component = getComponent({ element: 'button' });
|
||||
it("renders a button element", () => {
|
||||
const component = getComponent({ element: "button" });
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders with correct classes when button has kind', () => {
|
||||
it("renders with correct classes when button has kind", () => {
|
||||
const component = getComponent({
|
||||
kind: 'primary',
|
||||
kind: "primary",
|
||||
});
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('disables button correctly', () => {
|
||||
it("disables button correctly", () => {
|
||||
const onClick = jest.fn();
|
||||
const component = getComponent({
|
||||
onClick,
|
||||
disabled: true,
|
||||
});
|
||||
expect(component.find('.mx_AccessibleButton').props().disabled).toBeTruthy();
|
||||
expect(component.find('.mx_AccessibleButton').props()['aria-disabled']).toBeTruthy();
|
||||
expect(component.find(".mx_AccessibleButton").props().disabled).toBeTruthy();
|
||||
expect(component.find(".mx_AccessibleButton").props()["aria-disabled"]).toBeTruthy();
|
||||
|
||||
act(() => {
|
||||
component.simulate('click');
|
||||
component.simulate("click");
|
||||
});
|
||||
|
||||
expect(onClick).not.toHaveBeenCalled();
|
||||
|
||||
act(() => {
|
||||
const keydownEvent = makeKeyboardEvent(Key.ENTER);
|
||||
component.simulate('keydown', keydownEvent);
|
||||
component.simulate("keydown", keydownEvent);
|
||||
});
|
||||
|
||||
expect(onClick).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls onClick handler on button click', () => {
|
||||
it("calls onClick handler on button click", () => {
|
||||
const onClick = jest.fn();
|
||||
const component = getComponent({
|
||||
onClick,
|
||||
});
|
||||
|
||||
act(() => {
|
||||
component.simulate('click');
|
||||
component.simulate("click");
|
||||
});
|
||||
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls onClick handler on button mousedown when triggerOnMousedown is passed', () => {
|
||||
it("calls onClick handler on button mousedown when triggerOnMousedown is passed", () => {
|
||||
const onClick = jest.fn();
|
||||
const component = getComponent({
|
||||
onClick,
|
||||
|
@ -106,14 +106,14 @@ describe('<AccessibleButton />', () => {
|
|||
});
|
||||
|
||||
act(() => {
|
||||
component.simulate('mousedown');
|
||||
component.simulate("mousedown");
|
||||
});
|
||||
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('handling keyboard events', () => {
|
||||
it('calls onClick handler on enter keydown', () => {
|
||||
describe("handling keyboard events", () => {
|
||||
it("calls onClick handler on enter keydown", () => {
|
||||
const onClick = jest.fn();
|
||||
const component = getComponent({
|
||||
onClick,
|
||||
|
@ -121,13 +121,13 @@ describe('<AccessibleButton />', () => {
|
|||
|
||||
const keyboardEvent = makeKeyboardEvent(Key.ENTER);
|
||||
act(() => {
|
||||
component.simulate('keydown', keyboardEvent);
|
||||
component.simulate("keydown", keyboardEvent);
|
||||
});
|
||||
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
|
||||
act(() => {
|
||||
component.simulate('keyup', keyboardEvent);
|
||||
component.simulate("keyup", keyboardEvent);
|
||||
});
|
||||
|
||||
// handler only called once on keydown
|
||||
|
@ -137,7 +137,7 @@ describe('<AccessibleButton />', () => {
|
|||
expect(keyboardEvent.preventDefault).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('calls onClick handler on space keyup', () => {
|
||||
it("calls onClick handler on space keyup", () => {
|
||||
const onClick = jest.fn();
|
||||
const component = getComponent({
|
||||
onClick,
|
||||
|
@ -145,13 +145,13 @@ describe('<AccessibleButton />', () => {
|
|||
|
||||
const keyboardEvent = makeKeyboardEvent(Key.SPACE);
|
||||
act(() => {
|
||||
component.simulate('keydown', keyboardEvent);
|
||||
component.simulate("keydown", keyboardEvent);
|
||||
});
|
||||
|
||||
expect(onClick).not.toHaveBeenCalled();
|
||||
|
||||
act(() => {
|
||||
component.simulate('keyup', keyboardEvent);
|
||||
component.simulate("keyup", keyboardEvent);
|
||||
});
|
||||
|
||||
// handler only called once on keyup
|
||||
|
@ -161,7 +161,7 @@ describe('<AccessibleButton />', () => {
|
|||
expect(keyboardEvent.preventDefault).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('calls onKeydown/onKeyUp handlers for keys other than space and enter', () => {
|
||||
it("calls onKeydown/onKeyUp handlers for keys other than space and enter", () => {
|
||||
const onClick = jest.fn();
|
||||
const onKeyDown = jest.fn();
|
||||
const onKeyUp = jest.fn();
|
||||
|
@ -173,8 +173,8 @@ describe('<AccessibleButton />', () => {
|
|||
|
||||
const keyboardEvent = makeKeyboardEvent(Key.K);
|
||||
act(() => {
|
||||
component.simulate('keydown', keyboardEvent);
|
||||
component.simulate('keyup', keyboardEvent);
|
||||
component.simulate("keydown", keyboardEvent);
|
||||
component.simulate("keyup", keyboardEvent);
|
||||
});
|
||||
|
||||
expect(onClick).not.toHaveBeenCalled();
|
||||
|
@ -184,7 +184,7 @@ describe('<AccessibleButton />', () => {
|
|||
expect(keyboardEvent.preventDefault).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does nothing on non space/enter key presses when no onKeydown/onKeyUp handlers provided', () => {
|
||||
it("does nothing on non space/enter key presses when no onKeydown/onKeyUp handlers provided", () => {
|
||||
const onClick = jest.fn();
|
||||
const component = getComponent({
|
||||
onClick,
|
||||
|
@ -192,8 +192,8 @@ describe('<AccessibleButton />', () => {
|
|||
|
||||
const keyboardEvent = makeKeyboardEvent(Key.K);
|
||||
act(() => {
|
||||
component.simulate('keydown', keyboardEvent);
|
||||
component.simulate('keyup', keyboardEvent);
|
||||
component.simulate("keydown", keyboardEvent);
|
||||
component.simulate("keyup", keyboardEvent);
|
||||
});
|
||||
|
||||
// no onClick call, no problems
|
||||
|
|
|
@ -52,17 +52,15 @@ describe("AppTile", () => {
|
|||
let app1: IApp;
|
||||
let app2: IApp;
|
||||
|
||||
const waitForRps = (roomId: string) => new Promise<void>(resolve => {
|
||||
const update = () => {
|
||||
if (
|
||||
RightPanelStore.instance.currentCardForRoom(roomId).phase !==
|
||||
RightPanelPhases.Widget
|
||||
) return;
|
||||
RightPanelStore.instance.off(UPDATE_EVENT, update);
|
||||
resolve();
|
||||
};
|
||||
RightPanelStore.instance.on(UPDATE_EVENT, update);
|
||||
});
|
||||
const waitForRps = (roomId: string) =>
|
||||
new Promise<void>((resolve) => {
|
||||
const update = () => {
|
||||
if (RightPanelStore.instance.currentCardForRoom(roomId).phase !== RightPanelPhases.Widget) return;
|
||||
RightPanelStore.instance.off(UPDATE_EVENT, update);
|
||||
resolve();
|
||||
};
|
||||
RightPanelStore.instance.on(UPDATE_EVENT, update);
|
||||
});
|
||||
|
||||
beforeAll(async () => {
|
||||
stubClient();
|
||||
|
@ -75,7 +73,7 @@ describe("AppTile", () => {
|
|||
r1 = new Room("r1", cli, "@name:example.com");
|
||||
r2 = new Room("r2", cli, "@name:example.com");
|
||||
|
||||
jest.spyOn(cli, "getRoom").mockImplementation(roomId => {
|
||||
jest.spyOn(cli, "getRoom").mockImplementation((roomId) => {
|
||||
if (roomId === "r1") return r1;
|
||||
if (roomId === "r2") return r2;
|
||||
return null;
|
||||
|
@ -105,7 +103,7 @@ describe("AppTile", () => {
|
|||
creatorUserId: cli.getUserId(),
|
||||
avatar_url: undefined,
|
||||
};
|
||||
jest.spyOn(WidgetStore.instance, "getApps").mockImplementation(roomId => {
|
||||
jest.spyOn(WidgetStore.instance, "getApps").mockImplementation((roomId) => {
|
||||
if (roomId === "r1") return [app1];
|
||||
if (roomId === "r2") return [app2];
|
||||
});
|
||||
|
@ -130,12 +128,14 @@ describe("AppTile", () => {
|
|||
if (name !== "RightPanel.phases") return realGetValue(name, roomId);
|
||||
if (roomId === "r1") {
|
||||
return {
|
||||
history: [{
|
||||
phase: RightPanelPhases.Widget,
|
||||
state: {
|
||||
widgetId: "1",
|
||||
history: [
|
||||
{
|
||||
phase: RightPanelPhases.Widget,
|
||||
state: {
|
||||
widgetId: "1",
|
||||
},
|
||||
},
|
||||
}],
|
||||
],
|
||||
isOpen: true,
|
||||
};
|
||||
}
|
||||
|
@ -143,12 +143,11 @@ describe("AppTile", () => {
|
|||
});
|
||||
|
||||
// Run initial render with room 1, and also running lifecycle methods
|
||||
const renderer = TestRenderer.create(<MatrixClientContext.Provider value={cli}>
|
||||
<RightPanel
|
||||
room={r1}
|
||||
resizeNotifier={resizeNotifier}
|
||||
/>
|
||||
</MatrixClientContext.Provider>);
|
||||
const renderer = TestRenderer.create(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<RightPanel room={r1} resizeNotifier={resizeNotifier} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
// Wait for RPS room 1 updates to fire
|
||||
const rpsUpdated = waitForRps("r1");
|
||||
dis.dispatch({
|
||||
|
@ -169,12 +168,11 @@ describe("AppTile", () => {
|
|||
action: Action.ViewRoom,
|
||||
room_id: "r2",
|
||||
});
|
||||
renderer.update(<MatrixClientContext.Provider value={cli}>
|
||||
<RightPanel
|
||||
room={r2}
|
||||
resizeNotifier={resizeNotifier}
|
||||
/>
|
||||
</MatrixClientContext.Provider>);
|
||||
renderer.update(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<RightPanel room={r2} resizeNotifier={resizeNotifier} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
|
||||
expect(endWidgetActions.mock.calls.length).toBe(1);
|
||||
expect(ActiveWidgetStore.instance.isLive("1", "r1")).toBe(false);
|
||||
|
@ -185,16 +183,18 @@ describe("AppTile", () => {
|
|||
it("distinguishes widgets with the same ID in different rooms", async () => {
|
||||
// Set up right panel state
|
||||
const realGetValue = SettingsStore.getValue;
|
||||
jest.spyOn(SettingsStore, 'getValue').mockImplementation((name, roomId) => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((name, roomId) => {
|
||||
if (name === "RightPanel.phases") {
|
||||
if (roomId === "r1") {
|
||||
return {
|
||||
history: [{
|
||||
phase: RightPanelPhases.Widget,
|
||||
state: {
|
||||
widgetId: "1",
|
||||
history: [
|
||||
{
|
||||
phase: RightPanelPhases.Widget,
|
||||
state: {
|
||||
widgetId: "1",
|
||||
},
|
||||
},
|
||||
}],
|
||||
],
|
||||
isOpen: true,
|
||||
};
|
||||
}
|
||||
|
@ -204,12 +204,11 @@ describe("AppTile", () => {
|
|||
});
|
||||
|
||||
// Run initial render with room 1, and also running lifecycle methods
|
||||
const renderer = TestRenderer.create(<MatrixClientContext.Provider value={cli}>
|
||||
<RightPanel
|
||||
room={r1}
|
||||
resizeNotifier={resizeNotifier}
|
||||
/>
|
||||
</MatrixClientContext.Provider>);
|
||||
const renderer = TestRenderer.create(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<RightPanel room={r1} resizeNotifier={resizeNotifier} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
// Wait for RPS room 1 updates to fire
|
||||
const rpsUpdated1 = waitForRps("r1");
|
||||
dis.dispatch({
|
||||
|
@ -225,12 +224,14 @@ describe("AppTile", () => {
|
|||
if (name === "RightPanel.phases") {
|
||||
if (roomId === "r2") {
|
||||
return {
|
||||
history: [{
|
||||
phase: RightPanelPhases.Widget,
|
||||
state: {
|
||||
widgetId: "1",
|
||||
history: [
|
||||
{
|
||||
phase: RightPanelPhases.Widget,
|
||||
state: {
|
||||
widgetId: "1",
|
||||
},
|
||||
},
|
||||
}],
|
||||
],
|
||||
isOpen: true,
|
||||
};
|
||||
}
|
||||
|
@ -245,12 +246,11 @@ describe("AppTile", () => {
|
|||
action: Action.ViewRoom,
|
||||
room_id: "r2",
|
||||
});
|
||||
renderer.update(<MatrixClientContext.Provider value={cli}>
|
||||
<RightPanel
|
||||
room={r2}
|
||||
resizeNotifier={resizeNotifier}
|
||||
/>
|
||||
</MatrixClientContext.Provider>);
|
||||
renderer.update(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<RightPanel room={r2} resizeNotifier={resizeNotifier} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await rpsUpdated2;
|
||||
|
||||
expect(ActiveWidgetStore.instance.isLive("1", "r1")).toBe(false);
|
||||
|
@ -279,13 +279,11 @@ describe("AppTile", () => {
|
|||
});
|
||||
|
||||
// Run initial render with room 1, and also running lifecycle methods
|
||||
const renderer = TestRenderer.create(<MatrixClientContext.Provider value={cli}>
|
||||
<AppsDrawer
|
||||
userId={cli.getUserId()}
|
||||
room={r1}
|
||||
resizeNotifier={resizeNotifier}
|
||||
/>
|
||||
</MatrixClientContext.Provider>);
|
||||
const renderer = TestRenderer.create(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<AppsDrawer userId={cli.getUserId()} room={r1} resizeNotifier={resizeNotifier} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
|
||||
expect(ActiveWidgetStore.instance.isLive("1", "r1")).toBe(true);
|
||||
|
||||
|
@ -319,38 +317,34 @@ describe("AppTile", () => {
|
|||
let moveToContainerSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = mount((
|
||||
wrapper = mount(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<AppTile
|
||||
key={app1.id}
|
||||
app={app1}
|
||||
room={r1}
|
||||
/>
|
||||
</MatrixClientContext.Provider>
|
||||
));
|
||||
<AppTile key={app1.id} app={app1} room={r1} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
|
||||
moveToContainerSpy = jest.spyOn(WidgetLayoutStore.instance, 'moveToContainer');
|
||||
moveToContainerSpy = jest.spyOn(WidgetLayoutStore.instance, "moveToContainer");
|
||||
});
|
||||
|
||||
it("requiresClient should be true", () => {
|
||||
expect(wrapper.state('requiresClient')).toBe(true);
|
||||
expect(wrapper.state("requiresClient")).toBe(true);
|
||||
});
|
||||
|
||||
it("clicking 'minimise' should send the widget to the right", () => {
|
||||
const minimiseButton = wrapper.find('.mx_AppTileMenuBar_iconButton_minimise');
|
||||
minimiseButton.first().simulate('click');
|
||||
const minimiseButton = wrapper.find(".mx_AppTileMenuBar_iconButton_minimise");
|
||||
minimiseButton.first().simulate("click");
|
||||
expect(moveToContainerSpy).toHaveBeenCalledWith(r1, app1, Container.Right);
|
||||
});
|
||||
|
||||
it("clicking 'maximise' should send the widget to the center", () => {
|
||||
const minimiseButton = wrapper.find('.mx_AppTileMenuBar_iconButton_maximise');
|
||||
minimiseButton.first().simulate('click');
|
||||
const minimiseButton = wrapper.find(".mx_AppTileMenuBar_iconButton_maximise");
|
||||
minimiseButton.first().simulate("click");
|
||||
expect(moveToContainerSpy).toHaveBeenCalledWith(r1, app1, Container.Center);
|
||||
});
|
||||
|
||||
describe("for a maximised (centered) widget", () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(WidgetLayoutStore.instance, 'isInContainer').mockImplementation(
|
||||
jest.spyOn(WidgetLayoutStore.instance, "isInContainer").mockImplementation(
|
||||
(room: Optional<Room>, widget: IApp, container: Container) => {
|
||||
return room === r1 && widget === app1 && container === Container.Center;
|
||||
},
|
||||
|
@ -358,8 +352,8 @@ describe("AppTile", () => {
|
|||
});
|
||||
|
||||
it("clicking 'un-maximise' should send the widget to the top", () => {
|
||||
const unMaximiseButton = wrapper.find('.mx_AppTileMenuBar_iconButton_collapse');
|
||||
unMaximiseButton.first().simulate('click');
|
||||
const unMaximiseButton = wrapper.find(".mx_AppTileMenuBar_iconButton_collapse");
|
||||
unMaximiseButton.first().simulate("click");
|
||||
expect(moveToContainerSpy).toHaveBeenCalledWith(r1, app1, Container.Top);
|
||||
});
|
||||
});
|
||||
|
@ -378,19 +372,15 @@ describe("AppTile", () => {
|
|||
const mockWidget = new ElementWidget(app1);
|
||||
WidgetMessagingStore.instance.storeMessaging(mockWidget, r1.roomId, api);
|
||||
|
||||
wrapper = mount((
|
||||
wrapper = mount(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<AppTile
|
||||
key={app1.id}
|
||||
app={app1}
|
||||
room={r1}
|
||||
/>
|
||||
</MatrixClientContext.Provider>
|
||||
));
|
||||
<AppTile key={app1.id} app={app1} room={r1} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
});
|
||||
|
||||
it("requiresClient should be false", () => {
|
||||
expect(wrapper.state('requiresClient')).toBe(false);
|
||||
expect(wrapper.state("requiresClient")).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,23 +14,23 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import { MatrixEvent, RoomMember } from 'matrix-js-sdk/src/matrix';
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { MatrixEvent, RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import {
|
||||
getMockClientWithEventEmitter,
|
||||
mkMembership,
|
||||
mockClientMethodsUser,
|
||||
unmockClientPeg,
|
||||
} from '../../../test-utils';
|
||||
} from "../../../test-utils";
|
||||
import EventListSummary from "../../../../src/components/views/elements/EventListSummary";
|
||||
import { Layout } from '../../../../src/settings/enums/Layout';
|
||||
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
||||
import { Layout } from "../../../../src/settings/enums/Layout";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
|
||||
describe('EventListSummary', function() {
|
||||
const roomId = '!room:server.org';
|
||||
describe("EventListSummary", function () {
|
||||
const roomId = "!room:server.org";
|
||||
// Generate dummy event tiles for use in simulating an expanded MELS
|
||||
const generateTiles = (events: MatrixEvent[]) => {
|
||||
return events.map((e) => {
|
||||
|
@ -64,13 +64,14 @@ describe('EventListSummary', function() {
|
|||
prevMembership?: string;
|
||||
}
|
||||
const generateMembershipEvent = (
|
||||
eventId: string, { senderId, userId, membership, prevMembership }: MembershipEventParams,
|
||||
eventId: string,
|
||||
{ senderId, userId, membership, prevMembership }: MembershipEventParams,
|
||||
): MatrixEvent => {
|
||||
const member = new RoomMember(roomId, userId);
|
||||
// Use localpart as display name;
|
||||
member.name = userId.match(/@([^:]*):/)[1];
|
||||
jest.spyOn(member, 'getAvatarUrl').mockReturnValue('avatar.jpeg');
|
||||
jest.spyOn(member, 'getMxcAvatarUrl').mockReturnValue('mxc://avatar.url/image.png');
|
||||
jest.spyOn(member, "getAvatarUrl").mockReturnValue("avatar.jpeg");
|
||||
jest.spyOn(member, "getMxcAvatarUrl").mockReturnValue("mxc://avatar.url/image.png");
|
||||
const e = mkMembership({
|
||||
event: true,
|
||||
room: roomId,
|
||||
|
@ -102,7 +103,7 @@ describe('EventListSummary', function() {
|
|||
let eventsForUsers = [];
|
||||
let userId = "";
|
||||
for (let i = 0; i < n; i++) {
|
||||
userId = userIdTemplate.replace('$', i);
|
||||
userId = userIdTemplate.replace("$", i);
|
||||
events.forEach((e) => {
|
||||
e.userId = userId;
|
||||
});
|
||||
|
@ -121,13 +122,14 @@ describe('EventListSummary', function() {
|
|||
children: [],
|
||||
};
|
||||
const renderComponent = (props = {}): ReactWrapper => {
|
||||
return mount(<MatrixClientContext.Provider value={mockClient}>
|
||||
<EventListSummary {...defaultProps} {...props} />
|
||||
</MatrixClientContext.Provider>,
|
||||
return mount(
|
||||
<MatrixClientContext.Provider value={mockClient}>
|
||||
<EventListSummary {...defaultProps} {...props} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
|
@ -135,10 +137,8 @@ describe('EventListSummary', function() {
|
|||
unmockClientPeg();
|
||||
});
|
||||
|
||||
it('renders expanded events if there are less than props.threshold', function() {
|
||||
const events = generateEvents([
|
||||
{ userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" },
|
||||
]);
|
||||
it("renders expanded events if there are less than props.threshold", function () {
|
||||
const events = generateEvents([{ userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }]);
|
||||
const props = {
|
||||
events: events,
|
||||
children: generateTiles(events),
|
||||
|
@ -149,12 +149,14 @@ describe('EventListSummary', function() {
|
|||
|
||||
const wrapper = renderComponent(props); // matrix cli context wrapper
|
||||
|
||||
expect(wrapper.find('GenericEventListSummary').props().children).toEqual([
|
||||
<div className="event_tile" key="event0">Expanded membership</div>,
|
||||
expect(wrapper.find("GenericEventListSummary").props().children).toEqual([
|
||||
<div className="event_tile" key="event0">
|
||||
Expanded membership
|
||||
</div>,
|
||||
]);
|
||||
});
|
||||
|
||||
it('renders expanded events if there are less than props.threshold', function() {
|
||||
it("renders expanded events if there are less than props.threshold", function () {
|
||||
const events = generateEvents([
|
||||
{ userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" },
|
||||
{ userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" },
|
||||
|
@ -169,13 +171,17 @@ describe('EventListSummary', function() {
|
|||
|
||||
const wrapper = renderComponent(props); // matrix cli context wrapper
|
||||
|
||||
expect(wrapper.find('GenericEventListSummary').props().children).toEqual([
|
||||
<div className="event_tile" key="event0">Expanded membership</div>,
|
||||
<div className="event_tile" key="event1">Expanded membership</div>,
|
||||
expect(wrapper.find("GenericEventListSummary").props().children).toEqual([
|
||||
<div className="event_tile" key="event0">
|
||||
Expanded membership
|
||||
</div>,
|
||||
<div className="event_tile" key="event1">
|
||||
Expanded membership
|
||||
</div>,
|
||||
]);
|
||||
});
|
||||
|
||||
it('renders collapsed events if events.length = props.threshold', function() {
|
||||
it("renders collapsed events if events.length = props.threshold", function () {
|
||||
const events = generateEvents([
|
||||
{ userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" },
|
||||
{ userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" },
|
||||
|
@ -196,7 +202,7 @@ describe('EventListSummary', function() {
|
|||
expect(summaryText).toBe("user_1 joined and left and joined");
|
||||
});
|
||||
|
||||
it('truncates long join,leave repetitions', function() {
|
||||
it("truncates long join,leave repetitions", function () {
|
||||
const events = generateEvents([
|
||||
{ userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" },
|
||||
{ userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" },
|
||||
|
@ -228,7 +234,7 @@ describe('EventListSummary', function() {
|
|||
expect(summaryText).toBe("user_1 joined and left 7 times");
|
||||
});
|
||||
|
||||
it('truncates long join,leave repetitions between other events', function() {
|
||||
it("truncates long join,leave repetitions between other events", function () {
|
||||
const events = generateEvents([
|
||||
{
|
||||
userId: "@user_1:some.domain",
|
||||
|
@ -269,12 +275,10 @@ describe('EventListSummary', function() {
|
|||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe(
|
||||
"user_1 was unbanned, joined and left 7 times and was invited",
|
||||
);
|
||||
expect(summaryText).toBe("user_1 was unbanned, joined and left 7 times and was invited");
|
||||
});
|
||||
|
||||
it('truncates multiple sequences of repetitions with other events between', function() {
|
||||
it("truncates multiple sequences of repetitions with other events between", function () {
|
||||
const events = generateEvents([
|
||||
{
|
||||
userId: "@user_1:some.domain",
|
||||
|
@ -318,12 +322,11 @@ describe('EventListSummary', function() {
|
|||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe(
|
||||
"user_1 was unbanned, joined and left 2 times, was banned, " +
|
||||
"joined and left 3 times and was invited",
|
||||
"user_1 was unbanned, joined and left 2 times, was banned, " + "joined and left 3 times and was invited",
|
||||
);
|
||||
});
|
||||
|
||||
it('handles multiple users following the same sequence of memberships', function() {
|
||||
it("handles multiple users following the same sequence of memberships", function () {
|
||||
const events = generateEvents([
|
||||
// user_1
|
||||
{
|
||||
|
@ -372,12 +375,10 @@ describe('EventListSummary', function() {
|
|||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe(
|
||||
"user_1 and one other were unbanned, joined and left 2 times and were banned",
|
||||
);
|
||||
expect(summaryText).toBe("user_1 and one other were unbanned, joined and left 2 times and were banned");
|
||||
});
|
||||
|
||||
it('handles many users following the same sequence of memberships', function() {
|
||||
it("handles many users following the same sequence of memberships", function () {
|
||||
const events = generateEventsForUsers("@user_$:some.domain", 20, [
|
||||
{
|
||||
prevMembership: "ban",
|
||||
|
@ -406,12 +407,10 @@ describe('EventListSummary', function() {
|
|||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe(
|
||||
"user_0 and 19 others were unbanned, joined and left 2 times and were banned",
|
||||
);
|
||||
expect(summaryText).toBe("user_0 and 19 others were unbanned, joined and left 2 times and were banned");
|
||||
});
|
||||
|
||||
it('correctly orders sequences of transitions by the order of their first event', function() {
|
||||
it("correctly orders sequences of transitions by the order of their first event", function () {
|
||||
const events = generateEvents([
|
||||
{
|
||||
userId: "@user_2:some.domain",
|
||||
|
@ -454,11 +453,11 @@ describe('EventListSummary', function() {
|
|||
|
||||
expect(summaryText).toBe(
|
||||
"user_2 was unbanned and joined and left 2 times, user_1 was unbanned, " +
|
||||
"joined and left 2 times and was banned",
|
||||
"joined and left 2 times and was banned",
|
||||
);
|
||||
});
|
||||
|
||||
it('correctly identifies transitions', function() {
|
||||
it("correctly identifies transitions", function () {
|
||||
const events = generateEvents([
|
||||
// invited
|
||||
{ userId: "@user_1:some.domain", membership: "invite" },
|
||||
|
@ -524,11 +523,11 @@ describe('EventListSummary', function() {
|
|||
|
||||
expect(summaryText).toBe(
|
||||
"user_1 was invited, was banned, joined, rejected their invitation, left, " +
|
||||
"had their invitation withdrawn, was unbanned, was removed, left and was removed",
|
||||
"had their invitation withdrawn, was unbanned, was removed, left and was removed",
|
||||
);
|
||||
});
|
||||
|
||||
it('handles invitation plurals correctly when there are multiple users', function() {
|
||||
it("handles invitation plurals correctly when there are multiple users", function () {
|
||||
const events = generateEvents([
|
||||
{
|
||||
userId: "@user_1:some.domain",
|
||||
|
@ -566,12 +565,11 @@ describe('EventListSummary', function() {
|
|||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe(
|
||||
"user_1 and one other rejected their invitations and " +
|
||||
"had their invitations withdrawn",
|
||||
"user_1 and one other rejected their invitations and " + "had their invitations withdrawn",
|
||||
);
|
||||
});
|
||||
|
||||
it('handles invitation plurals correctly when there are multiple invites', function() {
|
||||
it("handles invitation plurals correctly when there are multiple invites", function () {
|
||||
const events = generateEvents([
|
||||
{
|
||||
userId: "@user_1:some.domain",
|
||||
|
@ -596,12 +594,10 @@ describe('EventListSummary', function() {
|
|||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe(
|
||||
"user_1 rejected their invitation 2 times",
|
||||
);
|
||||
expect(summaryText).toBe("user_1 rejected their invitation 2 times");
|
||||
});
|
||||
|
||||
it('handles a summary length = 2, with no "others"', function() {
|
||||
it('handles a summary length = 2, with no "others"', function () {
|
||||
const events = generateEvents([
|
||||
{ userId: "@user_1:some.domain", membership: "join" },
|
||||
{ userId: "@user_1:some.domain", membership: "join" },
|
||||
|
@ -620,12 +616,10 @@ describe('EventListSummary', function() {
|
|||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe(
|
||||
"user_1 and user_2 joined 2 times",
|
||||
);
|
||||
expect(summaryText).toBe("user_1 and user_2 joined 2 times");
|
||||
});
|
||||
|
||||
it('handles a summary length = 2, with 1 "other"', function() {
|
||||
it('handles a summary length = 2, with 1 "other"', function () {
|
||||
const events = generateEvents([
|
||||
{ userId: "@user_1:some.domain", membership: "join" },
|
||||
{ userId: "@user_2:some.domain", membership: "join" },
|
||||
|
@ -643,15 +637,11 @@ describe('EventListSummary', function() {
|
|||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe(
|
||||
"user_1, user_2 and one other joined",
|
||||
);
|
||||
expect(summaryText).toBe("user_1, user_2 and one other joined");
|
||||
});
|
||||
|
||||
it('handles a summary length = 2, with many "others"', function() {
|
||||
const events = generateEventsForUsers("@user_$:some.domain", 20, [
|
||||
{ membership: "join" },
|
||||
]);
|
||||
it('handles a summary length = 2, with many "others"', function () {
|
||||
const events = generateEventsForUsers("@user_$:some.domain", 20, [{ membership: "join" }]);
|
||||
const props = {
|
||||
events: events,
|
||||
children: generateTiles(events),
|
||||
|
@ -664,8 +654,6 @@ describe('EventListSummary', function() {
|
|||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe(
|
||||
"user_0, user_1 and 18 others joined",
|
||||
);
|
||||
expect(summaryText).toBe("user_0, user_1 and 18 others joined");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,39 +12,45 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { renderIntoDocument } from 'react-dom/test-utils';
|
||||
import React from "react";
|
||||
import { renderIntoDocument } from "react-dom/test-utils";
|
||||
|
||||
import ExternalLink from '../../../../src/components/views/elements/ExternalLink';
|
||||
import ExternalLink from "../../../../src/components/views/elements/ExternalLink";
|
||||
|
||||
describe('<ExternalLink />', () => {
|
||||
describe("<ExternalLink />", () => {
|
||||
const defaultProps = {
|
||||
"href": 'test.com',
|
||||
"href": "test.com",
|
||||
"onClick": jest.fn(),
|
||||
"className": 'myCustomClass',
|
||||
'data-test-id': 'test',
|
||||
"className": "myCustomClass",
|
||||
"data-test-id": "test",
|
||||
};
|
||||
const getComponent = (props = {}) => {
|
||||
const wrapper = renderIntoDocument<HTMLDivElement>(
|
||||
<div><ExternalLink {...defaultProps} {...props} /></div>,
|
||||
<div>
|
||||
<ExternalLink {...defaultProps} {...props} />
|
||||
</div>,
|
||||
) as HTMLDivElement;
|
||||
return wrapper.children[0];
|
||||
};
|
||||
|
||||
it('renders link correctly', () => {
|
||||
const children = <span>react element <b>children</b></span>;
|
||||
expect(getComponent({ children, target: '_self', rel: 'noopener' })).toMatchSnapshot();
|
||||
it("renders link correctly", () => {
|
||||
const children = (
|
||||
<span>
|
||||
react element <b>children</b>
|
||||
</span>
|
||||
);
|
||||
expect(getComponent({ children, target: "_self", rel: "noopener" })).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('defaults target and rel', () => {
|
||||
const children = 'test';
|
||||
it("defaults target and rel", () => {
|
||||
const children = "test";
|
||||
const component = getComponent({ children });
|
||||
expect(component.getAttribute('rel')).toEqual('noreferrer noopener');
|
||||
expect(component.getAttribute('target')).toEqual('_blank');
|
||||
expect(component.getAttribute("rel")).toEqual("noreferrer noopener");
|
||||
expect(component.getAttribute("target")).toEqual("_blank");
|
||||
});
|
||||
|
||||
it('renders plain text link correctly', () => {
|
||||
const children = 'test';
|
||||
it("renders plain text link correctly", () => {
|
||||
const children = "test";
|
||||
expect(getComponent({ children })).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,55 +14,55 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { act, fireEvent, render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { act, fireEvent, render } from "@testing-library/react";
|
||||
import React from "react";
|
||||
|
||||
import { FilterDropdown } from '../../../../src/components/views/elements/FilterDropdown';
|
||||
import { flushPromises, mockPlatformPeg } from '../../../test-utils';
|
||||
import { FilterDropdown } from "../../../../src/components/views/elements/FilterDropdown";
|
||||
import { flushPromises, mockPlatformPeg } from "../../../test-utils";
|
||||
|
||||
mockPlatformPeg();
|
||||
|
||||
describe('<FilterDropdown />', () => {
|
||||
describe("<FilterDropdown />", () => {
|
||||
const options = [
|
||||
{ id: 'one', label: 'Option one' },
|
||||
{ id: 'two', label: 'Option two', description: 'with description' },
|
||||
{ id: "one", label: "Option one" },
|
||||
{ id: "two", label: "Option two", description: "with description" },
|
||||
];
|
||||
const defaultProps = {
|
||||
className: 'test',
|
||||
value: 'one',
|
||||
className: "test",
|
||||
value: "one",
|
||||
options,
|
||||
id: 'test',
|
||||
label: 'test label',
|
||||
id: "test",
|
||||
label: "test label",
|
||||
onOptionChange: jest.fn(),
|
||||
};
|
||||
const getComponent = (props = {}): JSX.Element =>
|
||||
(<FilterDropdown {...defaultProps} {...props} />);
|
||||
const getComponent = (props = {}): JSX.Element => <FilterDropdown {...defaultProps} {...props} />;
|
||||
|
||||
const openDropdown = async (container: HTMLElement): Promise<void> => await act(async () => {
|
||||
const button = container.querySelector('[role="button"]');
|
||||
expect(button).toBeTruthy();
|
||||
fireEvent.click(button as Element);
|
||||
await flushPromises();
|
||||
});
|
||||
const openDropdown = async (container: HTMLElement): Promise<void> =>
|
||||
await act(async () => {
|
||||
const button = container.querySelector('[role="button"]');
|
||||
expect(button).toBeTruthy();
|
||||
fireEvent.click(button as Element);
|
||||
await flushPromises();
|
||||
});
|
||||
|
||||
it('renders selected option', () => {
|
||||
it("renders selected option", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders when selected option is not in options', () => {
|
||||
const { container } = render(getComponent({ value: 'oops' }));
|
||||
it("renders when selected option is not in options", () => {
|
||||
const { container } = render(getComponent({ value: "oops" }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders selected option with selectedLabel', () => {
|
||||
const { container } = render(getComponent({ selectedLabel: 'Show' }));
|
||||
it("renders selected option with selectedLabel", () => {
|
||||
const { container } = render(getComponent({ selectedLabel: "Show" }));
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders dropdown options in menu', async () => {
|
||||
it("renders dropdown options in menu", async () => {
|
||||
const { container } = render(getComponent());
|
||||
await openDropdown(container);
|
||||
expect(container.querySelector('.mx_Dropdown_menu')).toMatchSnapshot();
|
||||
expect(container.querySelector(".mx_Dropdown_menu")).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,24 +14,21 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { mount } from "enzyme";
|
||||
import { act } from "react-dom/test-utils";
|
||||
|
||||
import LabelledCheckbox from "../../../../src/components/views/elements/LabelledCheckbox";
|
||||
|
||||
// Fake random strings to give a predictable snapshot for checkbox IDs
|
||||
jest.mock(
|
||||
'matrix-js-sdk/src/randomstring',
|
||||
() => {
|
||||
return {
|
||||
randomString: () => "abdefghi",
|
||||
};
|
||||
},
|
||||
);
|
||||
jest.mock("matrix-js-sdk/src/randomstring", () => {
|
||||
return {
|
||||
randomString: () => "abdefghi",
|
||||
};
|
||||
});
|
||||
|
||||
describe('<LabelledCheckbox />', () => {
|
||||
describe("<LabelledCheckbox />", () => {
|
||||
type CompProps = React.ComponentProps<typeof LabelledCheckbox>;
|
||||
const getComponent = (props: CompProps) => mount(<LabelledCheckbox {...props} />);
|
||||
type CompClass = ReturnType<typeof getComponent>;
|
||||
|
@ -42,29 +39,26 @@ describe('<LabelledCheckbox />', () => {
|
|||
|
||||
const isChecked = (checkbox: ReturnType<typeof getCheckbox>) => checkbox.is(`[checked=true]`);
|
||||
const isDisabled = (checkbox: ReturnType<typeof getCheckbox>) => checkbox.is(`[disabled=true]`);
|
||||
const getText = (span: ReturnType<typeof getLabel>) => span.length > 0 ? span.at(0).text() : null;
|
||||
const getText = (span: ReturnType<typeof getLabel>) => (span.length > 0 ? span.at(0).text() : null);
|
||||
|
||||
test.each([null, "this is a byline"])(
|
||||
"should render with byline of %p",
|
||||
(byline) => {
|
||||
const props: CompProps = {
|
||||
label: "Hello world",
|
||||
value: true,
|
||||
byline: byline,
|
||||
onChange: jest.fn(),
|
||||
};
|
||||
const component = getComponent(props);
|
||||
const checkbox = getCheckbox(component);
|
||||
test.each([null, "this is a byline"])("should render with byline of %p", (byline) => {
|
||||
const props: CompProps = {
|
||||
label: "Hello world",
|
||||
value: true,
|
||||
byline: byline,
|
||||
onChange: jest.fn(),
|
||||
};
|
||||
const component = getComponent(props);
|
||||
const checkbox = getCheckbox(component);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
expect(isChecked(checkbox)).toBe(true);
|
||||
expect(isDisabled(checkbox)).toBe(false);
|
||||
expect(getText(getLabel(component))).toBe(props.label);
|
||||
expect(getText(getByline(component))).toBe(byline);
|
||||
},
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
expect(isChecked(checkbox)).toBe(true);
|
||||
expect(isDisabled(checkbox)).toBe(false);
|
||||
expect(getText(getLabel(component))).toBe(props.label);
|
||||
expect(getText(getByline(component))).toBe(byline);
|
||||
});
|
||||
|
||||
it('should support unchecked by default', () => {
|
||||
it("should support unchecked by default", () => {
|
||||
const props: CompProps = {
|
||||
label: "Hello world",
|
||||
value: false,
|
||||
|
@ -75,7 +69,7 @@ describe('<LabelledCheckbox />', () => {
|
|||
expect(isChecked(getCheckbox(component))).toBe(false);
|
||||
});
|
||||
|
||||
it('should be possible to disable the checkbox', () => {
|
||||
it("should be possible to disable the checkbox", () => {
|
||||
const props: CompProps = {
|
||||
label: "Hello world",
|
||||
value: false,
|
||||
|
@ -87,7 +81,7 @@ describe('<LabelledCheckbox />', () => {
|
|||
expect(isDisabled(getCheckbox(component))).toBe(true);
|
||||
});
|
||||
|
||||
it('should emit onChange calls', () => {
|
||||
it("should emit onChange calls", () => {
|
||||
const props: CompProps = {
|
||||
label: "Hello world",
|
||||
value: false,
|
||||
|
@ -98,13 +92,13 @@ describe('<LabelledCheckbox />', () => {
|
|||
expect(props.onChange).not.toHaveBeenCalled();
|
||||
|
||||
act(() => {
|
||||
getCheckbox(component).simulate('change');
|
||||
getCheckbox(component).simulate("change");
|
||||
});
|
||||
|
||||
expect(props.onChange).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should react to value and disabled prop changes', () => {
|
||||
it("should react to value and disabled prop changes", () => {
|
||||
const props: CompProps = {
|
||||
label: "Hello world",
|
||||
value: false,
|
||||
|
|
|
@ -14,44 +14,41 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
import React from "react";
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
|
||||
import LearnMore from '../../../../src/components/views/elements/LearnMore';
|
||||
import Modal from '../../../../src/Modal';
|
||||
import InfoDialog from '../../../../src/components/views/dialogs/InfoDialog';
|
||||
import LearnMore from "../../../../src/components/views/elements/LearnMore";
|
||||
import Modal from "../../../../src/Modal";
|
||||
import InfoDialog from "../../../../src/components/views/dialogs/InfoDialog";
|
||||
|
||||
describe('<LearnMore />', () => {
|
||||
describe("<LearnMore />", () => {
|
||||
const defaultProps = {
|
||||
title: 'Test',
|
||||
description: 'test test test',
|
||||
['data-testid']: 'testid',
|
||||
title: "Test",
|
||||
description: "test test test",
|
||||
["data-testid"]: "testid",
|
||||
};
|
||||
const getComponent = (props = {}) =>
|
||||
(<LearnMore {...defaultProps} {...props} />);
|
||||
const getComponent = (props = {}) => <LearnMore {...defaultProps} {...props} />;
|
||||
|
||||
const modalSpy = jest.spyOn(Modal, 'createDialog').mockReturnValue(undefined);
|
||||
const modalSpy = jest.spyOn(Modal, "createDialog").mockReturnValue(undefined);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders button', () => {
|
||||
it("renders button", () => {
|
||||
const { container } = render(getComponent());
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('opens modal on click', async () => {
|
||||
it("opens modal on click", async () => {
|
||||
const { getByTestId } = render(getComponent());
|
||||
fireEvent.click(getByTestId('testid'));
|
||||
fireEvent.click(getByTestId("testid"));
|
||||
|
||||
expect(modalSpy).toHaveBeenCalledWith(
|
||||
InfoDialog,
|
||||
{
|
||||
button: 'Got it',
|
||||
description: defaultProps.description,
|
||||
hasCloseButton: true,
|
||||
title: defaultProps.title,
|
||||
});
|
||||
expect(modalSpy).toHaveBeenCalledWith(InfoDialog, {
|
||||
button: "Got it",
|
||||
description: defaultProps.description,
|
||||
hasCloseButton: true,
|
||||
title: defaultProps.title,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -19,34 +19,28 @@ import { Linkify } from "../../../../src/components/views/elements/Linkify";
|
|||
|
||||
describe("Linkify", () => {
|
||||
it("linkifies the context", () => {
|
||||
const { container } = render(<Linkify>
|
||||
https://perdu.com
|
||||
</Linkify>);
|
||||
const { container } = render(<Linkify>https://perdu.com</Linkify>);
|
||||
expect(container.innerHTML).toBe(
|
||||
"<div><a href=\"https://perdu.com\" class=\"linkified\" target=\"_blank\" rel=\"noreferrer noopener\">"+
|
||||
"https://perdu.com" +
|
||||
"</a></div>",
|
||||
'<div><a href="https://perdu.com" class="linkified" target="_blank" rel="noreferrer noopener">' +
|
||||
"https://perdu.com" +
|
||||
"</a></div>",
|
||||
);
|
||||
});
|
||||
|
||||
it("correctly linkifies a room alias", () => {
|
||||
const { container } = render(<Linkify>
|
||||
#element-web:matrix.org
|
||||
</Linkify>);
|
||||
const { container } = render(<Linkify>#element-web:matrix.org</Linkify>);
|
||||
expect(container.innerHTML).toBe(
|
||||
"<div>" +
|
||||
"<a href=\"https://matrix.to/#/#element-web:matrix.org\" class=\"linkified\" rel=\"noreferrer noopener\">" +
|
||||
"#element-web:matrix.org" +
|
||||
"</a></div>",
|
||||
'<a href="https://matrix.to/#/#element-web:matrix.org" class="linkified" rel="noreferrer noopener">' +
|
||||
"#element-web:matrix.org" +
|
||||
"</a></div>",
|
||||
);
|
||||
});
|
||||
|
||||
it("changes the root tag name", () => {
|
||||
const TAG_NAME = "p";
|
||||
|
||||
const { container } = render(<Linkify as={TAG_NAME}>
|
||||
Hello world!
|
||||
</Linkify>);
|
||||
const { container } = render(<Linkify as={TAG_NAME}>Hello world!</Linkify>);
|
||||
|
||||
expect(container.querySelectorAll("p")).toHaveLength(1);
|
||||
});
|
||||
|
@ -60,31 +54,29 @@ describe("Linkify", () => {
|
|||
|
||||
// upon clicking the element, change the content, and expect
|
||||
// linkify to update
|
||||
return <div onClick={onClick}>
|
||||
<Linkify>
|
||||
{ n % 2 === 0
|
||||
? "https://perdu.com"
|
||||
: "https://matrix.org" }
|
||||
</Linkify>
|
||||
</div>;
|
||||
return (
|
||||
<div onClick={onClick}>
|
||||
<Linkify>{n % 2 === 0 ? "https://perdu.com" : "https://matrix.org"}</Linkify>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const { container } = render(<DummyTest />);
|
||||
|
||||
expect(container.innerHTML).toBe(
|
||||
"<div><div>" +
|
||||
"<a href=\"https://perdu.com\" class=\"linkified\" target=\"_blank\" rel=\"noreferrer noopener\">" +
|
||||
"https://perdu.com" +
|
||||
"</a></div></div>",
|
||||
'<a href="https://perdu.com" class="linkified" target="_blank" rel="noreferrer noopener">' +
|
||||
"https://perdu.com" +
|
||||
"</a></div></div>",
|
||||
);
|
||||
|
||||
fireEvent.click(container.querySelector("div"));
|
||||
|
||||
expect(container.innerHTML).toBe(
|
||||
"<div><div>" +
|
||||
"<a href=\"https://matrix.org\" class=\"linkified\" target=\"_blank\" rel=\"noreferrer noopener\">" +
|
||||
"https://matrix.org" +
|
||||
"</a></div></div>",
|
||||
'<a href="https://matrix.org" class="linkified" target="_blank" rel="noreferrer noopener">' +
|
||||
"https://matrix.org" +
|
||||
"</a></div></div>",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -24,16 +24,13 @@ import {
|
|||
M_POLL_START,
|
||||
M_TEXT,
|
||||
PollStartEvent,
|
||||
} from 'matrix-events-sdk';
|
||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||
} from "matrix-events-sdk";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
|
||||
import {
|
||||
findById,
|
||||
getMockClientWithEventEmitter,
|
||||
} from '../../../test-utils';
|
||||
import { findById, getMockClientWithEventEmitter } from "../../../test-utils";
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import PollCreateDialog from "../../../../src/components/views/elements/PollCreateDialog";
|
||||
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
|
||||
// Fake date to give a predictable snapshot
|
||||
const realDateNow = Date.now;
|
||||
|
@ -50,7 +47,7 @@ afterAll(() => {
|
|||
|
||||
describe("PollCreateDialog", () => {
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
sendEvent: jest.fn().mockResolvedValue({ event_id: '1' }),
|
||||
sendEvent: jest.fn().mockResolvedValue({ event_id: "1" }),
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -58,48 +55,35 @@ describe("PollCreateDialog", () => {
|
|||
});
|
||||
|
||||
it("renders a blank poll", () => {
|
||||
const dialog = mount(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />,
|
||||
{
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: { value: mockClient },
|
||||
},
|
||||
);
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />, {
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: { value: mockClient },
|
||||
});
|
||||
expect(dialog.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("autofocuses the poll topic on mount", () => {
|
||||
const dialog = mount(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />,
|
||||
);
|
||||
expect(findById(dialog, 'poll-topic-input').at(0).props().autoFocus).toEqual(true);
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(findById(dialog, "poll-topic-input").at(0).props().autoFocus).toEqual(true);
|
||||
});
|
||||
|
||||
it("autofocuses the new poll option field after clicking add option button", () => {
|
||||
const dialog = mount(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />,
|
||||
);
|
||||
expect(findById(dialog, 'poll-topic-input').at(0).props().autoFocus).toEqual(true);
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(findById(dialog, "poll-topic-input").at(0).props().autoFocus).toEqual(true);
|
||||
|
||||
dialog.find("div.mx_PollCreateDialog_addOption").simulate("click");
|
||||
|
||||
expect(findById(dialog, 'poll-topic-input').at(0).props().autoFocus).toEqual(false);
|
||||
expect(findById(dialog, 'pollcreate_option_1').at(0).props().autoFocus).toEqual(false);
|
||||
expect(findById(dialog, 'pollcreate_option_2').at(0).props().autoFocus).toEqual(true);
|
||||
expect(findById(dialog, "poll-topic-input").at(0).props().autoFocus).toEqual(false);
|
||||
expect(findById(dialog, "pollcreate_option_1").at(0).props().autoFocus).toEqual(false);
|
||||
expect(findById(dialog, "pollcreate_option_2").at(0).props().autoFocus).toEqual(true);
|
||||
});
|
||||
|
||||
it("renders a question and some options", () => {
|
||||
const dialog = mount(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />,
|
||||
);
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(submitIsDisabled(dialog)).toBe(true);
|
||||
|
||||
// When I set some values in the boxes
|
||||
changeValue(
|
||||
dialog,
|
||||
"Question or topic",
|
||||
"How many turnips is the optimal number?",
|
||||
);
|
||||
changeValue(dialog, "Question or topic", "How many turnips is the optimal number?");
|
||||
changeValue(dialog, "Option 1", "As many as my neighbour");
|
||||
changeValue(dialog, "Option 2", "The question is meaningless");
|
||||
dialog.find("div.mx_PollCreateDialog_addOption").simulate("click");
|
||||
|
@ -109,19 +93,11 @@ describe("PollCreateDialog", () => {
|
|||
|
||||
it("renders info from a previous event", () => {
|
||||
const previousEvent: MatrixEvent = new MatrixEvent(
|
||||
PollStartEvent.from(
|
||||
"Poll Q",
|
||||
["Answer 1", "Answer 2"],
|
||||
M_POLL_KIND_DISCLOSED,
|
||||
).serialize(),
|
||||
PollStartEvent.from("Poll Q", ["Answer 1", "Answer 2"], M_POLL_KIND_DISCLOSED).serialize(),
|
||||
);
|
||||
|
||||
const dialog = mount(
|
||||
<PollCreateDialog
|
||||
room={createRoom()}
|
||||
onFinished={jest.fn()}
|
||||
editingMxEvent={previousEvent}
|
||||
/>,
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} editingMxEvent={previousEvent} />,
|
||||
);
|
||||
|
||||
expect(submitIsDisabled(dialog)).toBe(false);
|
||||
|
@ -129,17 +105,13 @@ describe("PollCreateDialog", () => {
|
|||
});
|
||||
|
||||
it("doesn't allow submitting until there are options", () => {
|
||||
const dialog = mount(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />,
|
||||
);
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(submitIsDisabled(dialog)).toBe(true);
|
||||
});
|
||||
|
||||
it("does allow submitting when there are options and a question", () => {
|
||||
// Given a dialog with no info in (which I am unable to submit)
|
||||
const dialog = mount(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />,
|
||||
);
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(submitIsDisabled(dialog)).toBe(true);
|
||||
|
||||
// When I set some values in the boxes
|
||||
|
@ -152,74 +124,42 @@ describe("PollCreateDialog", () => {
|
|||
});
|
||||
|
||||
it("shows the open poll description at first", () => {
|
||||
const dialog = mount(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />,
|
||||
);
|
||||
expect(
|
||||
dialog.find('select').prop("value"),
|
||||
).toEqual(M_POLL_KIND_DISCLOSED.name);
|
||||
expect(
|
||||
dialog.find('p').text(),
|
||||
).toEqual("Voters see results as soon as they have voted");
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(dialog.find("select").prop("value")).toEqual(M_POLL_KIND_DISCLOSED.name);
|
||||
expect(dialog.find("p").text()).toEqual("Voters see results as soon as they have voted");
|
||||
});
|
||||
|
||||
it("shows the closed poll description if we choose it", () => {
|
||||
const dialog = mount(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />,
|
||||
);
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
changeKind(dialog, M_POLL_KIND_UNDISCLOSED.name);
|
||||
expect(
|
||||
dialog.find('select').prop("value"),
|
||||
).toEqual(M_POLL_KIND_UNDISCLOSED.name);
|
||||
expect(
|
||||
dialog.find('p').text(),
|
||||
).toEqual("Results are only revealed when you end the poll");
|
||||
expect(dialog.find("select").prop("value")).toEqual(M_POLL_KIND_UNDISCLOSED.name);
|
||||
expect(dialog.find("p").text()).toEqual("Results are only revealed when you end the poll");
|
||||
});
|
||||
|
||||
it("shows the open poll description if we choose it", () => {
|
||||
const dialog = mount(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />,
|
||||
);
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
changeKind(dialog, M_POLL_KIND_UNDISCLOSED.name);
|
||||
changeKind(dialog, M_POLL_KIND_DISCLOSED.name);
|
||||
expect(
|
||||
dialog.find('select').prop("value"),
|
||||
).toEqual(M_POLL_KIND_DISCLOSED.name);
|
||||
expect(
|
||||
dialog.find('p').text(),
|
||||
).toEqual("Voters see results as soon as they have voted");
|
||||
expect(dialog.find("select").prop("value")).toEqual(M_POLL_KIND_DISCLOSED.name);
|
||||
expect(dialog.find("p").text()).toEqual("Voters see results as soon as they have voted");
|
||||
});
|
||||
|
||||
it("shows the closed poll description when editing a closed poll", () => {
|
||||
const previousEvent: MatrixEvent = new MatrixEvent(
|
||||
PollStartEvent.from(
|
||||
"Poll Q",
|
||||
["Answer 1", "Answer 2"],
|
||||
M_POLL_KIND_UNDISCLOSED,
|
||||
).serialize(),
|
||||
PollStartEvent.from("Poll Q", ["Answer 1", "Answer 2"], M_POLL_KIND_UNDISCLOSED).serialize(),
|
||||
);
|
||||
previousEvent.event.event_id = "$prevEventId";
|
||||
|
||||
const dialog = mount(
|
||||
<PollCreateDialog
|
||||
room={createRoom()}
|
||||
onFinished={jest.fn()}
|
||||
editingMxEvent={previousEvent}
|
||||
/>,
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} editingMxEvent={previousEvent} />,
|
||||
);
|
||||
|
||||
expect(
|
||||
dialog.find('select').prop("value"),
|
||||
).toEqual(M_POLL_KIND_UNDISCLOSED.name);
|
||||
expect(
|
||||
dialog.find('p').text(),
|
||||
).toEqual("Results are only revealed when you end the poll");
|
||||
expect(dialog.find("select").prop("value")).toEqual(M_POLL_KIND_UNDISCLOSED.name);
|
||||
expect(dialog.find("p").text()).toEqual("Results are only revealed when you end the poll");
|
||||
});
|
||||
|
||||
it("displays a spinner after submitting", () => {
|
||||
const dialog = mount(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />,
|
||||
);
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
changeValue(dialog, "Question or topic", "Q");
|
||||
changeValue(dialog, "Option 1", "A1");
|
||||
changeValue(dialog, "Option 2", "A2");
|
||||
|
@ -230,9 +170,7 @@ describe("PollCreateDialog", () => {
|
|||
});
|
||||
|
||||
it("sends a poll create event when submitted", () => {
|
||||
const dialog = mount(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />,
|
||||
);
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
changeValue(dialog, "Question or topic", "Q");
|
||||
changeValue(dialog, "Option 1", "A1");
|
||||
changeValue(dialog, "Option 2", "A2");
|
||||
|
@ -240,50 +178,40 @@ describe("PollCreateDialog", () => {
|
|||
dialog.find("button").simulate("click");
|
||||
const [, , eventType, sentEventContent] = mockClient.sendEvent.mock.calls[0];
|
||||
expect(M_POLL_START.matches(eventType)).toBeTruthy();
|
||||
expect(sentEventContent).toEqual(
|
||||
{
|
||||
[M_TEXT.name]: "Q\n1. A1\n2. A2",
|
||||
[M_POLL_START.name]: {
|
||||
"answers": [
|
||||
{
|
||||
"id": expect.any(String),
|
||||
[M_TEXT.name]: "A1",
|
||||
},
|
||||
{
|
||||
"id": expect.any(String),
|
||||
[M_TEXT.name]: "A2",
|
||||
},
|
||||
],
|
||||
"kind": M_POLL_KIND_DISCLOSED.name,
|
||||
"max_selections": 1,
|
||||
"question": {
|
||||
"body": "Q",
|
||||
"format": undefined,
|
||||
"formatted_body": undefined,
|
||||
"msgtype": "m.text",
|
||||
[M_TEXT.name]: "Q",
|
||||
expect(sentEventContent).toEqual({
|
||||
[M_TEXT.name]: "Q\n1. A1\n2. A2",
|
||||
[M_POLL_START.name]: {
|
||||
answers: [
|
||||
{
|
||||
id: expect.any(String),
|
||||
[M_TEXT.name]: "A1",
|
||||
},
|
||||
{
|
||||
id: expect.any(String),
|
||||
[M_TEXT.name]: "A2",
|
||||
},
|
||||
],
|
||||
kind: M_POLL_KIND_DISCLOSED.name,
|
||||
max_selections: 1,
|
||||
question: {
|
||||
body: "Q",
|
||||
format: undefined,
|
||||
formatted_body: undefined,
|
||||
msgtype: "m.text",
|
||||
[M_TEXT.name]: "Q",
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("sends a poll edit event when editing", () => {
|
||||
const previousEvent: MatrixEvent = new MatrixEvent(
|
||||
PollStartEvent.from(
|
||||
"Poll Q",
|
||||
["Answer 1", "Answer 2"],
|
||||
M_POLL_KIND_DISCLOSED,
|
||||
).serialize(),
|
||||
PollStartEvent.from("Poll Q", ["Answer 1", "Answer 2"], M_POLL_KIND_DISCLOSED).serialize(),
|
||||
);
|
||||
previousEvent.event.event_id = "$prevEventId";
|
||||
|
||||
const dialog = mount(
|
||||
<PollCreateDialog
|
||||
room={createRoom()}
|
||||
onFinished={jest.fn()}
|
||||
editingMxEvent={previousEvent}
|
||||
/>,
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} editingMxEvent={previousEvent} />,
|
||||
);
|
||||
|
||||
changeValue(dialog, "Question or topic", "Poll Q updated");
|
||||
|
@ -293,65 +221,51 @@ describe("PollCreateDialog", () => {
|
|||
|
||||
const [, , eventType, sentEventContent] = mockClient.sendEvent.mock.calls[0];
|
||||
expect(M_POLL_START.matches(eventType)).toBeTruthy();
|
||||
expect(sentEventContent).toEqual(
|
||||
{
|
||||
"m.new_content": {
|
||||
[M_TEXT.name]: "Poll Q updated\n1. Answer 1\n2. Answer 2 updated",
|
||||
[M_POLL_START.name]: {
|
||||
"answers": [
|
||||
{
|
||||
"id": expect.any(String),
|
||||
[M_TEXT.name]: "Answer 1",
|
||||
},
|
||||
{
|
||||
"id": expect.any(String),
|
||||
[M_TEXT.name]: "Answer 2 updated",
|
||||
},
|
||||
],
|
||||
"kind": M_POLL_KIND_UNDISCLOSED.name,
|
||||
"max_selections": 1,
|
||||
"question": {
|
||||
"body": "Poll Q updated",
|
||||
"format": undefined,
|
||||
"formatted_body": undefined,
|
||||
"msgtype": "m.text",
|
||||
[M_TEXT.name]: "Poll Q updated",
|
||||
expect(sentEventContent).toEqual({
|
||||
"m.new_content": {
|
||||
[M_TEXT.name]: "Poll Q updated\n1. Answer 1\n2. Answer 2 updated",
|
||||
[M_POLL_START.name]: {
|
||||
answers: [
|
||||
{
|
||||
id: expect.any(String),
|
||||
[M_TEXT.name]: "Answer 1",
|
||||
},
|
||||
{
|
||||
id: expect.any(String),
|
||||
[M_TEXT.name]: "Answer 2 updated",
|
||||
},
|
||||
],
|
||||
kind: M_POLL_KIND_UNDISCLOSED.name,
|
||||
max_selections: 1,
|
||||
question: {
|
||||
body: "Poll Q updated",
|
||||
format: undefined,
|
||||
formatted_body: undefined,
|
||||
msgtype: "m.text",
|
||||
[M_TEXT.name]: "Poll Q updated",
|
||||
},
|
||||
},
|
||||
"m.relates_to": {
|
||||
"event_id": previousEvent.getId(),
|
||||
"rel_type": "m.replace",
|
||||
},
|
||||
},
|
||||
);
|
||||
"m.relates_to": {
|
||||
event_id: previousEvent.getId(),
|
||||
rel_type: "m.replace",
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function createRoom(): Room {
|
||||
return new Room(
|
||||
"roomid",
|
||||
MatrixClientPeg.get(),
|
||||
"@name:example.com",
|
||||
{},
|
||||
);
|
||||
return new Room("roomid", MatrixClientPeg.get(), "@name:example.com", {});
|
||||
}
|
||||
|
||||
function changeValue(wrapper: ReactWrapper, labelText: string, value: string) {
|
||||
wrapper.find(`input[label="${labelText}"]`).simulate(
|
||||
"change",
|
||||
{ target: { value: value } },
|
||||
);
|
||||
wrapper.find(`input[label="${labelText}"]`).simulate("change", { target: { value: value } });
|
||||
}
|
||||
|
||||
function changeKind(wrapper: ReactWrapper, value: string) {
|
||||
wrapper.find("select").simulate(
|
||||
"change",
|
||||
{ target: { value: value } },
|
||||
);
|
||||
wrapper.find("select").simulate("change", { target: { value: value } });
|
||||
}
|
||||
|
||||
function submitIsDisabled(wrapper: ReactWrapper) {
|
||||
return wrapper.find('button[type="submit"]').prop("aria-disabled") === true;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,12 +14,12 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
|
||||
import PowerSelector from "../../../../src/components/views/elements/PowerSelector";
|
||||
|
||||
describe('<PowerSelector />', () => {
|
||||
describe("<PowerSelector />", () => {
|
||||
it("should reset back to custom value when custom input is blurred blank", async () => {
|
||||
const fn = jest.fn();
|
||||
render(<PowerSelector value={25} maxValue={100} usersDefault={0} onChange={fn} />);
|
||||
|
|
|
@ -28,7 +28,9 @@ describe("<ProgressBar/>", () => {
|
|||
expect(progress.value).toBe(0);
|
||||
|
||||
// Await the animation to conclude to our initial value of 50
|
||||
act(() => { jest.runAllTimers(); });
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect(progress.position).toBe(0.5);
|
||||
|
||||
// Move the needle to 80%
|
||||
|
@ -36,7 +38,9 @@ describe("<ProgressBar/>", () => {
|
|||
expect(progress.position).toBe(0.5);
|
||||
|
||||
// Let the animaiton run a tiny bit, assert it has moved from where it was to where it needs to go
|
||||
act(() => { jest.advanceTimersByTime(150); });
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(150);
|
||||
});
|
||||
expect(progress.position).toBeGreaterThan(0.5);
|
||||
expect(progress.position).toBeLessThan(0.8);
|
||||
});
|
||||
|
|
|
@ -24,13 +24,13 @@ describe("<QRCode />", () => {
|
|||
|
||||
it("renders a QR with defaults", async () => {
|
||||
const { container, getAllByAltText } = render(<QRCode data="asd" />);
|
||||
await waitFor(() => getAllByAltText('QR Code').length === 1);
|
||||
await waitFor(() => getAllByAltText("QR Code").length === 1);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders a QR with high error correction level", async () => {
|
||||
const { container, getAllByAltText } = render(<QRCode data="asd" errorCorrectionLevel="high" />);
|
||||
await waitFor(() => getAllByAltText('QR Code').length === 1);
|
||||
await waitFor(() => getAllByAltText("QR Code").length === 1);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,12 +14,12 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as testUtils from '../../../test-utils';
|
||||
import * as testUtils from "../../../test-utils";
|
||||
import { getParentEventId } from "../../../../src/utils/Reply";
|
||||
|
||||
describe("ReplyChain", () => {
|
||||
describe('getParentEventId', () => {
|
||||
it('retrieves relation reply from unedited event', () => {
|
||||
describe("getParentEventId", () => {
|
||||
it("retrieves relation reply from unedited event", () => {
|
||||
const originalEventWithRelation = testUtils.mkEvent({
|
||||
event: true,
|
||||
type: "m.room.message",
|
||||
|
@ -28,7 +28,7 @@ describe("ReplyChain", () => {
|
|||
"body": "> Reply to this message\n\n foo",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
"event_id": "$qkjmFBTEc0VvfVyzq1CJuh1QZi_xDIgNEFjZ4Pq34og",
|
||||
event_id: "$qkjmFBTEc0VvfVyzq1CJuh1QZi_xDIgNEFjZ4Pq34og",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -36,11 +36,12 @@ describe("ReplyChain", () => {
|
|||
room: "room_id",
|
||||
});
|
||||
|
||||
expect(getParentEventId(originalEventWithRelation))
|
||||
.toStrictEqual('$qkjmFBTEc0VvfVyzq1CJuh1QZi_xDIgNEFjZ4Pq34og');
|
||||
expect(getParentEventId(originalEventWithRelation)).toStrictEqual(
|
||||
"$qkjmFBTEc0VvfVyzq1CJuh1QZi_xDIgNEFjZ4Pq34og",
|
||||
);
|
||||
});
|
||||
|
||||
it('retrieves relation reply from original event when edited', () => {
|
||||
it("retrieves relation reply from original event when edited", () => {
|
||||
const originalEventWithRelation = testUtils.mkEvent({
|
||||
event: true,
|
||||
type: "m.room.message",
|
||||
|
@ -49,7 +50,7 @@ describe("ReplyChain", () => {
|
|||
"body": "> Reply to this message\n\n foo",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
"event_id": "$qkjmFBTEc0VvfVyzq1CJuh1QZi_xDIgNEFjZ4Pq34og",
|
||||
event_id: "$qkjmFBTEc0VvfVyzq1CJuh1QZi_xDIgNEFjZ4Pq34og",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -64,12 +65,12 @@ describe("ReplyChain", () => {
|
|||
"msgtype": "m.text",
|
||||
"body": "> Reply to this message\n\n * foo bar",
|
||||
"m.new_content": {
|
||||
"msgtype": "m.text",
|
||||
"body": "foo bar",
|
||||
msgtype: "m.text",
|
||||
body: "foo bar",
|
||||
},
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.replace",
|
||||
"event_id": originalEventWithRelation.getId(),
|
||||
rel_type: "m.replace",
|
||||
event_id: originalEventWithRelation.getId(),
|
||||
},
|
||||
},
|
||||
user: "some_other_user",
|
||||
|
@ -80,11 +81,12 @@ describe("ReplyChain", () => {
|
|||
originalEventWithRelation.makeReplaced(editEvent);
|
||||
|
||||
// The relation should be pulled from the original event
|
||||
expect(getParentEventId(originalEventWithRelation))
|
||||
.toStrictEqual('$qkjmFBTEc0VvfVyzq1CJuh1QZi_xDIgNEFjZ4Pq34og');
|
||||
expect(getParentEventId(originalEventWithRelation)).toStrictEqual(
|
||||
"$qkjmFBTEc0VvfVyzq1CJuh1QZi_xDIgNEFjZ4Pq34og",
|
||||
);
|
||||
});
|
||||
|
||||
it('retrieves relation reply from edit event when provided', () => {
|
||||
it("retrieves relation reply from edit event when provided", () => {
|
||||
const originalEvent = testUtils.mkEvent({
|
||||
event: true,
|
||||
type: "m.room.message",
|
||||
|
@ -107,13 +109,13 @@ describe("ReplyChain", () => {
|
|||
"body": "foo bar",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
"event_id": "$qkjmFBTEc0VvfVyzq1CJuh1QZi_xDIgNEFjZ4Pq34og",
|
||||
event_id: "$qkjmFBTEc0VvfVyzq1CJuh1QZi_xDIgNEFjZ4Pq34og",
|
||||
},
|
||||
},
|
||||
},
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.replace",
|
||||
"event_id": originalEvent.getId(),
|
||||
rel_type: "m.replace",
|
||||
event_id: originalEvent.getId(),
|
||||
},
|
||||
},
|
||||
user: "some_other_user",
|
||||
|
@ -124,11 +126,10 @@ describe("ReplyChain", () => {
|
|||
originalEvent.makeReplaced(editEvent);
|
||||
|
||||
// The relation should be pulled from the edit event
|
||||
expect(getParentEventId(originalEvent))
|
||||
.toStrictEqual('$qkjmFBTEc0VvfVyzq1CJuh1QZi_xDIgNEFjZ4Pq34og');
|
||||
expect(getParentEventId(originalEvent)).toStrictEqual("$qkjmFBTEc0VvfVyzq1CJuh1QZi_xDIgNEFjZ4Pq34og");
|
||||
});
|
||||
|
||||
it('prefers relation reply from edit event over original event', () => {
|
||||
it("prefers relation reply from edit event over original event", () => {
|
||||
const originalEventWithRelation = testUtils.mkEvent({
|
||||
event: true,
|
||||
type: "m.room.message",
|
||||
|
@ -137,7 +138,7 @@ describe("ReplyChain", () => {
|
|||
"body": "> Reply to this message\n\n foo",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
"event_id": "$111",
|
||||
event_id: "$111",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -156,13 +157,13 @@ describe("ReplyChain", () => {
|
|||
"body": "foo bar",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
"event_id": "$999",
|
||||
event_id: "$999",
|
||||
},
|
||||
},
|
||||
},
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.replace",
|
||||
"event_id": originalEventWithRelation.getId(),
|
||||
rel_type: "m.replace",
|
||||
event_id: originalEventWithRelation.getId(),
|
||||
},
|
||||
},
|
||||
user: "some_other_user",
|
||||
|
@ -173,10 +174,10 @@ describe("ReplyChain", () => {
|
|||
originalEventWithRelation.makeReplaced(editEvent);
|
||||
|
||||
// The relation should be pulled from the edit event
|
||||
expect(getParentEventId(originalEventWithRelation)).toStrictEqual('$999');
|
||||
expect(getParentEventId(originalEventWithRelation)).toStrictEqual("$999");
|
||||
});
|
||||
|
||||
it('able to clear relation reply from original event by providing empty relation field', () => {
|
||||
it("able to clear relation reply from original event by providing empty relation field", () => {
|
||||
const originalEventWithRelation = testUtils.mkEvent({
|
||||
event: true,
|
||||
type: "m.room.message",
|
||||
|
@ -185,7 +186,7 @@ describe("ReplyChain", () => {
|
|||
"body": "> Reply to this message\n\n foo",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
"event_id": "$111",
|
||||
event_id: "$111",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -206,8 +207,8 @@ describe("ReplyChain", () => {
|
|||
"m.relates_to": {},
|
||||
},
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.replace",
|
||||
"event_id": originalEventWithRelation.getId(),
|
||||
rel_type: "m.replace",
|
||||
event_id: originalEventWithRelation.getId(),
|
||||
},
|
||||
},
|
||||
user: "some_other_user",
|
||||
|
|
|
@ -14,47 +14,47 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
|
||||
import StyledRadioGroup from "../../../../src/components/views/elements/StyledRadioGroup";
|
||||
|
||||
describe('<StyledRadioGroup />', () => {
|
||||
describe("<StyledRadioGroup />", () => {
|
||||
const optionA = {
|
||||
value: 'Anteater',
|
||||
value: "Anteater",
|
||||
label: <span>Anteater label</span>,
|
||||
description: 'anteater description',
|
||||
className: 'a-class',
|
||||
description: "anteater description",
|
||||
className: "a-class",
|
||||
};
|
||||
const optionB = {
|
||||
value: 'Badger',
|
||||
value: "Badger",
|
||||
label: <span>Badger label</span>,
|
||||
};
|
||||
const optionC = {
|
||||
value: 'Canary',
|
||||
value: "Canary",
|
||||
label: <span>Canary label</span>,
|
||||
description: <span>Canary description</span>,
|
||||
};
|
||||
const defaultDefinitions = [optionA, optionB, optionC];
|
||||
const defaultProps = {
|
||||
name: 'test',
|
||||
className: 'test-class',
|
||||
name: "test",
|
||||
className: "test-class",
|
||||
definitions: defaultDefinitions,
|
||||
onChange: jest.fn(),
|
||||
};
|
||||
const getComponent = (props = {}) => render(<StyledRadioGroup {...defaultProps} {...props} />);
|
||||
|
||||
const getInputByValue = (component, value) => component.container.querySelector(`input[value="${value}"]`);
|
||||
const getCheckedInput = component => component.container.querySelector('input[checked]');
|
||||
const getCheckedInput = (component) => component.container.querySelector("input[checked]");
|
||||
|
||||
it('renders radios correctly when no value is provided', () => {
|
||||
it("renders radios correctly when no value is provided", () => {
|
||||
const component = getComponent();
|
||||
|
||||
expect(component.asFragment()).toMatchSnapshot();
|
||||
expect(getCheckedInput(component)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('selects correct button when value is provided', () => {
|
||||
it("selects correct button when value is provided", () => {
|
||||
const component = getComponent({
|
||||
value: optionC.value,
|
||||
});
|
||||
|
@ -62,14 +62,11 @@ describe('<StyledRadioGroup />', () => {
|
|||
expect(getCheckedInput(component).value).toEqual(optionC.value);
|
||||
});
|
||||
|
||||
it('selects correct buttons when definitions have checked prop', () => {
|
||||
const definitions = [
|
||||
{ ...optionA, checked: true },
|
||||
optionB,
|
||||
{ ...optionC, checked: false },
|
||||
];
|
||||
it("selects correct buttons when definitions have checked prop", () => {
|
||||
const definitions = [{ ...optionA, checked: true }, optionB, { ...optionC, checked: false }];
|
||||
const component = getComponent({
|
||||
value: optionC.value, definitions,
|
||||
value: optionC.value,
|
||||
definitions,
|
||||
});
|
||||
|
||||
expect(getInputByValue(component, optionA.value)).toBeChecked();
|
||||
|
@ -78,26 +75,22 @@ describe('<StyledRadioGroup />', () => {
|
|||
expect(getInputByValue(component, optionC.value)).not.toBeChecked();
|
||||
});
|
||||
|
||||
it('disables individual buttons based on definition.disabled', () => {
|
||||
const definitions = [
|
||||
optionA,
|
||||
{ ...optionB, disabled: true },
|
||||
{ ...optionC, disabled: true },
|
||||
];
|
||||
it("disables individual buttons based on definition.disabled", () => {
|
||||
const definitions = [optionA, { ...optionB, disabled: true }, { ...optionC, disabled: true }];
|
||||
const component = getComponent({ definitions });
|
||||
expect(getInputByValue(component, optionA.value)).not.toBeDisabled();
|
||||
expect(getInputByValue(component, optionB.value)).toBeDisabled();
|
||||
expect(getInputByValue(component, optionC.value)).toBeDisabled();
|
||||
});
|
||||
|
||||
it('disables all buttons with disabled prop', () => {
|
||||
it("disables all buttons with disabled prop", () => {
|
||||
const component = getComponent({ disabled: true });
|
||||
expect(getInputByValue(component, optionA.value)).toBeDisabled();
|
||||
expect(getInputByValue(component, optionB.value)).toBeDisabled();
|
||||
expect(getInputByValue(component, optionC.value)).toBeDisabled();
|
||||
});
|
||||
|
||||
it('calls onChange on click', () => {
|
||||
it("calls onChange on click", () => {
|
||||
const onChange = jest.fn();
|
||||
const component = getComponent({
|
||||
value: optionC.value,
|
||||
|
|
|
@ -15,29 +15,26 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React from "react";
|
||||
import {
|
||||
renderIntoDocument,
|
||||
Simulate,
|
||||
} from 'react-dom/test-utils';
|
||||
import { renderIntoDocument, Simulate } from "react-dom/test-utils";
|
||||
import { act } from "react-dom/test-utils";
|
||||
|
||||
import { Alignment } from '../../../../src/components/views/elements/Tooltip';
|
||||
import { Alignment } from "../../../../src/components/views/elements/Tooltip";
|
||||
import TooltipTarget from "../../../../src/components/views/elements/TooltipTarget";
|
||||
|
||||
describe('<TooltipTarget />', () => {
|
||||
describe("<TooltipTarget />", () => {
|
||||
const defaultProps = {
|
||||
"tooltipTargetClassName": 'test tooltipTargetClassName',
|
||||
"className": 'test className',
|
||||
"tooltipClassName": 'test tooltipClassName',
|
||||
"label": 'test label',
|
||||
"tooltipTargetClassName": "test tooltipTargetClassName",
|
||||
"className": "test className",
|
||||
"tooltipClassName": "test tooltipClassName",
|
||||
"label": "test label",
|
||||
"alignment": Alignment.Left,
|
||||
"id": 'test id',
|
||||
'data-test-id': 'test',
|
||||
"id": "test id",
|
||||
"data-test-id": "test",
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
// clean up renderer tooltips
|
||||
const wrapper = document.querySelector('.mx_Tooltip_wrapper');
|
||||
const wrapper = document.querySelector(".mx_Tooltip_wrapper");
|
||||
while (wrapper?.firstChild) {
|
||||
wrapper.removeChild(wrapper.lastChild);
|
||||
}
|
||||
|
@ -45,19 +42,19 @@ describe('<TooltipTarget />', () => {
|
|||
|
||||
const getComponent = (props = {}) => {
|
||||
const wrapper = renderIntoDocument<HTMLSpanElement>(
|
||||
// wrap in element so renderIntoDocument can render functional component
|
||||
// wrap in element so renderIntoDocument can render functional component
|
||||
<span>
|
||||
<TooltipTarget {...defaultProps} {...props}>
|
||||
<span>child</span>
|
||||
</TooltipTarget>
|
||||
</span>,
|
||||
) as HTMLSpanElement;
|
||||
return wrapper.querySelector('[data-test-id=test]');
|
||||
return wrapper.querySelector("[data-test-id=test]");
|
||||
};
|
||||
|
||||
const getVisibleTooltip = () => document.querySelector('.mx_Tooltip.mx_Tooltip_visible');
|
||||
const getVisibleTooltip = () => document.querySelector(".mx_Tooltip.mx_Tooltip_visible");
|
||||
|
||||
it('renders container', () => {
|
||||
it("renders container", () => {
|
||||
const component = getComponent();
|
||||
expect(component).toMatchSnapshot();
|
||||
expect(getVisibleTooltip()).toBeFalsy();
|
||||
|
@ -72,7 +69,7 @@ describe('<TooltipTarget />', () => {
|
|||
expect(getVisibleTooltip()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('hides tooltip on mouseleave', () => {
|
||||
it("hides tooltip on mouseleave", () => {
|
||||
const wrapper = getComponent();
|
||||
act(() => {
|
||||
Simulate.mouseOver(wrapper);
|
||||
|
@ -84,7 +81,7 @@ describe('<TooltipTarget />', () => {
|
|||
expect(getVisibleTooltip()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('displays tooltip on focus', () => {
|
||||
it("displays tooltip on focus", () => {
|
||||
const wrapper = getComponent();
|
||||
act(() => {
|
||||
Simulate.focus(wrapper);
|
||||
|
@ -92,7 +89,7 @@ describe('<TooltipTarget />', () => {
|
|||
expect(getVisibleTooltip()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('hides tooltip on blur', async () => {
|
||||
it("hides tooltip on blur", async () => {
|
||||
const wrapper = getComponent();
|
||||
act(() => {
|
||||
Simulate.focus(wrapper);
|
||||
|
|
|
@ -14,51 +14,52 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { mount } from "enzyme";
|
||||
import { act } from "react-dom/test-utils";
|
||||
|
||||
import LiveDurationDropdown, { DEFAULT_DURATION_MS }
|
||||
from '../../../../src/components/views/location/LiveDurationDropdown';
|
||||
import { findById, mockPlatformPeg } from '../../../test-utils';
|
||||
import LiveDurationDropdown, {
|
||||
DEFAULT_DURATION_MS,
|
||||
} from "../../../../src/components/views/location/LiveDurationDropdown";
|
||||
import { findById, mockPlatformPeg } from "../../../test-utils";
|
||||
|
||||
mockPlatformPeg({ overrideBrowserShortcuts: jest.fn().mockReturnValue(false) });
|
||||
|
||||
describe('<LiveDurationDropdown />', () => {
|
||||
describe("<LiveDurationDropdown />", () => {
|
||||
const defaultProps = {
|
||||
timeout: DEFAULT_DURATION_MS,
|
||||
onChange: jest.fn(),
|
||||
};
|
||||
const getComponent = (props = {}) =>
|
||||
mount(<LiveDurationDropdown {...defaultProps} {...props} />);
|
||||
const getComponent = (props = {}) => mount(<LiveDurationDropdown {...defaultProps} {...props} />);
|
||||
|
||||
const getOption = (wrapper, timeout) => findById(wrapper, `live-duration__${timeout}`).at(0);
|
||||
const getSelectedOption = (wrapper) => findById(wrapper, 'live-duration_value');
|
||||
const openDropdown = (wrapper) => act(() => {
|
||||
wrapper.find('[role="button"]').at(0).simulate('click');
|
||||
wrapper.setProps({});
|
||||
});
|
||||
const getSelectedOption = (wrapper) => findById(wrapper, "live-duration_value");
|
||||
const openDropdown = (wrapper) =>
|
||||
act(() => {
|
||||
wrapper.find('[role="button"]').at(0).simulate("click");
|
||||
wrapper.setProps({});
|
||||
});
|
||||
|
||||
it('renders timeout as selected option', () => {
|
||||
it("renders timeout as selected option", () => {
|
||||
const wrapper = getComponent();
|
||||
expect(getSelectedOption(wrapper).text()).toEqual('Share for 15m');
|
||||
expect(getSelectedOption(wrapper).text()).toEqual("Share for 15m");
|
||||
});
|
||||
|
||||
it('renders non-default timeout as selected option', () => {
|
||||
it("renders non-default timeout as selected option", () => {
|
||||
const timeout = 1234567;
|
||||
const wrapper = getComponent({ timeout });
|
||||
expect(getSelectedOption(wrapper).text()).toEqual(`Share for 21m`);
|
||||
});
|
||||
|
||||
it('renders a dropdown option for a non-default timeout value', () => {
|
||||
it("renders a dropdown option for a non-default timeout value", () => {
|
||||
const timeout = 1234567;
|
||||
const wrapper = getComponent({ timeout });
|
||||
openDropdown(wrapper);
|
||||
expect(getOption(wrapper, timeout).text()).toEqual(`Share for 21m`);
|
||||
});
|
||||
|
||||
it('updates value on option selection', () => {
|
||||
it("updates value on option selection", () => {
|
||||
const onChange = jest.fn();
|
||||
const wrapper = getComponent({ onChange });
|
||||
|
||||
|
@ -67,7 +68,7 @@ describe('<LiveDurationDropdown />', () => {
|
|||
openDropdown(wrapper);
|
||||
|
||||
act(() => {
|
||||
getOption(wrapper, ONE_HOUR).simulate('click');
|
||||
getOption(wrapper, ONE_HOUR).simulate("click");
|
||||
});
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith(ONE_HOUR);
|
||||
|
|
|
@ -14,34 +14,34 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import maplibregl from "maplibre-gl";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from "enzyme";
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||
import { mocked } from 'jest-mock';
|
||||
import { logger } from 'matrix-js-sdk/src/logger';
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { mocked } from "jest-mock";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import LocationPicker from "../../../../src/components/views/location/LocationPicker";
|
||||
import { LocationShareType } from "../../../../src/components/views/location/shareLocation";
|
||||
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
||||
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||
import { findById, findByTestId, mockPlatformPeg } from '../../../test-utils';
|
||||
import { findMapStyleUrl, LocationShareError } from '../../../../src/utils/location';
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import { findById, findByTestId, mockPlatformPeg } from "../../../test-utils";
|
||||
import { findMapStyleUrl, LocationShareError } from "../../../../src/utils/location";
|
||||
|
||||
jest.mock('../../../../src/utils/location/findMapStyleUrl', () => ({
|
||||
findMapStyleUrl: jest.fn().mockReturnValue('tileserver.com'),
|
||||
jest.mock("../../../../src/utils/location/findMapStyleUrl", () => ({
|
||||
findMapStyleUrl: jest.fn().mockReturnValue("tileserver.com"),
|
||||
}));
|
||||
|
||||
// dropdown uses this
|
||||
mockPlatformPeg({ overrideBrowserShortcuts: jest.fn().mockReturnValue(false) });
|
||||
|
||||
describe("LocationPicker", () => {
|
||||
describe('<LocationPicker />', () => {
|
||||
const roomId = '!room:server.org';
|
||||
const userId = '@user:server.org';
|
||||
describe("<LocationPicker />", () => {
|
||||
const roomId = "!room:server.org";
|
||||
const userId = "@user:server.org";
|
||||
const sender = new RoomMember(roomId, userId);
|
||||
const defaultProps = {
|
||||
sender,
|
||||
|
@ -56,10 +56,11 @@ describe("LocationPicker", () => {
|
|||
isGuest: jest.fn(),
|
||||
getClientWellKnown: jest.fn(),
|
||||
};
|
||||
const getComponent = (props = {}) => mount(<LocationPicker {...defaultProps} {...props} />, {
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: { value: mockClient },
|
||||
});
|
||||
const getComponent = (props = {}) =>
|
||||
mount(<LocationPicker {...defaultProps} {...props} />, {
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: { value: mockClient },
|
||||
});
|
||||
|
||||
const mockMap = new maplibregl.Map();
|
||||
const mockGeolocate = new maplibregl.GeolocateControl();
|
||||
|
@ -82,33 +83,33 @@ describe("LocationPicker", () => {
|
|||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(logger, 'error').mockRestore();
|
||||
jest.spyOn(MatrixClientPeg, 'get').mockReturnValue(mockClient as unknown as MatrixClient);
|
||||
jest.spyOn(logger, "error").mockRestore();
|
||||
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient as unknown as MatrixClient);
|
||||
jest.clearAllMocks();
|
||||
mocked(mockMap).addControl.mockReset();
|
||||
mocked(findMapStyleUrl).mockReturnValue('tileserver.com');
|
||||
mocked(findMapStyleUrl).mockReturnValue("tileserver.com");
|
||||
});
|
||||
|
||||
it('displays error when map emits an error', () => {
|
||||
it("displays error when map emits an error", () => {
|
||||
// suppress expected error log
|
||||
jest.spyOn(logger, 'error').mockImplementation(() => { });
|
||||
jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||
const wrapper = getComponent();
|
||||
|
||||
act(() => {
|
||||
// @ts-ignore
|
||||
mocked(mockMap).emit('error', { error: 'Something went wrong' });
|
||||
mocked(mockMap).emit("error", { error: "Something went wrong" });
|
||||
wrapper.setProps({});
|
||||
});
|
||||
|
||||
expect(findByTestId(wrapper, 'map-rendering-error').find('p').text()).toEqual(
|
||||
"This homeserver is not configured correctly to display maps, "
|
||||
+ "or the configured map server may be unreachable.",
|
||||
expect(findByTestId(wrapper, "map-rendering-error").find("p").text()).toEqual(
|
||||
"This homeserver is not configured correctly to display maps, " +
|
||||
"or the configured map server may be unreachable.",
|
||||
);
|
||||
});
|
||||
|
||||
it('displays error when map display is not configured properly', () => {
|
||||
it("displays error when map display is not configured properly", () => {
|
||||
// suppress expected error log
|
||||
jest.spyOn(logger, 'error').mockImplementation(() => { });
|
||||
jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||
mocked(findMapStyleUrl).mockImplementation(() => {
|
||||
throw new Error(LocationShareError.MapStyleUrlNotConfigured);
|
||||
});
|
||||
|
@ -116,111 +117,111 @@ describe("LocationPicker", () => {
|
|||
const wrapper = getComponent();
|
||||
wrapper.setProps({});
|
||||
|
||||
expect(findByTestId(wrapper, 'map-rendering-error').find('p').text()).toEqual(
|
||||
expect(findByTestId(wrapper, "map-rendering-error").find("p").text()).toEqual(
|
||||
"This homeserver is not configured to display maps.",
|
||||
);
|
||||
});
|
||||
|
||||
it('displays error when map setup throws', () => {
|
||||
it("displays error when map setup throws", () => {
|
||||
// suppress expected error log
|
||||
jest.spyOn(logger, 'error').mockImplementation(() => { });
|
||||
jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||
|
||||
// throw an error
|
||||
mocked(mockMap).addControl.mockImplementation(() => { throw new Error('oups'); });
|
||||
mocked(mockMap).addControl.mockImplementation(() => {
|
||||
throw new Error("oups");
|
||||
});
|
||||
|
||||
const wrapper = getComponent();
|
||||
wrapper.setProps({});
|
||||
|
||||
expect(findByTestId(wrapper, 'map-rendering-error').find('p').text()).toEqual(
|
||||
"This homeserver is not configured correctly to display maps, "
|
||||
+ "or the configured map server may be unreachable.",
|
||||
expect(findByTestId(wrapper, "map-rendering-error").find("p").text()).toEqual(
|
||||
"This homeserver is not configured correctly to display maps, " +
|
||||
"or the configured map server may be unreachable.",
|
||||
);
|
||||
});
|
||||
|
||||
it('initiates map with geolocation', () => {
|
||||
it("initiates map with geolocation", () => {
|
||||
getComponent();
|
||||
|
||||
expect(mockMap.addControl).toHaveBeenCalledWith(mockGeolocate);
|
||||
act(() => {
|
||||
// @ts-ignore
|
||||
mocked(mockMap).emit('load');
|
||||
mocked(mockMap).emit("load");
|
||||
});
|
||||
|
||||
expect(mockGeolocate.trigger).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
const testUserLocationShareTypes = (shareType: LocationShareType.Own | LocationShareType.Live) => {
|
||||
describe('user location behaviours', () => {
|
||||
it('closes and displays error when geolocation errors', () => {
|
||||
describe("user location behaviours", () => {
|
||||
it("closes and displays error when geolocation errors", () => {
|
||||
// suppress expected error log
|
||||
jest.spyOn(logger, 'error').mockImplementation(() => { });
|
||||
jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||
const onFinished = jest.fn();
|
||||
getComponent({ onFinished, shareType });
|
||||
|
||||
expect(mockMap.addControl).toHaveBeenCalledWith(mockGeolocate);
|
||||
act(() => {
|
||||
// @ts-ignore
|
||||
mockMap.emit('load');
|
||||
mockMap.emit("load");
|
||||
// @ts-ignore
|
||||
mockGeolocate.emit('error', {});
|
||||
mockGeolocate.emit("error", {});
|
||||
});
|
||||
|
||||
// dialog is closed on error
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('sets position on geolocate event', () => {
|
||||
it("sets position on geolocate event", () => {
|
||||
const wrapper = getComponent({ shareType });
|
||||
act(() => {
|
||||
// @ts-ignore
|
||||
mocked(mockGeolocate).emit('geolocate', mockGeolocationPosition);
|
||||
mocked(mockGeolocate).emit("geolocate", mockGeolocationPosition);
|
||||
wrapper.setProps({});
|
||||
});
|
||||
|
||||
// marker added
|
||||
expect(maplibregl.Marker).toHaveBeenCalled();
|
||||
expect(mockMarker.setLngLat).toHaveBeenCalledWith(new maplibregl.LngLat(
|
||||
12.4, 43.2,
|
||||
));
|
||||
expect(mockMarker.setLngLat).toHaveBeenCalledWith(new maplibregl.LngLat(12.4, 43.2));
|
||||
// submit button is enabled when position is truthy
|
||||
expect(findByTestId(wrapper, 'location-picker-submit-button').at(0).props().disabled).toBeFalsy();
|
||||
expect(wrapper.find('MemberAvatar').length).toBeTruthy();
|
||||
expect(findByTestId(wrapper, "location-picker-submit-button").at(0).props().disabled).toBeFalsy();
|
||||
expect(wrapper.find("MemberAvatar").length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('disables submit button until geolocation completes', () => {
|
||||
it("disables submit button until geolocation completes", () => {
|
||||
const onChoose = jest.fn();
|
||||
const wrapper = getComponent({ shareType, onChoose });
|
||||
|
||||
// submit button is enabled when position is truthy
|
||||
expect(findByTestId(wrapper, 'location-picker-submit-button').at(0).props().disabled).toBeTruthy();
|
||||
expect(findByTestId(wrapper, "location-picker-submit-button").at(0).props().disabled).toBeTruthy();
|
||||
act(() => {
|
||||
findByTestId(wrapper, 'location-picker-submit-button').at(0).simulate('click');
|
||||
findByTestId(wrapper, "location-picker-submit-button").at(0).simulate("click");
|
||||
});
|
||||
// nothing happens on button click
|
||||
expect(onChoose).not.toHaveBeenCalled();
|
||||
|
||||
act(() => {
|
||||
// @ts-ignore
|
||||
mocked(mockGeolocate).emit('geolocate', mockGeolocationPosition);
|
||||
mocked(mockGeolocate).emit("geolocate", mockGeolocationPosition);
|
||||
wrapper.setProps({});
|
||||
});
|
||||
|
||||
// submit button is enabled when position is truthy
|
||||
expect(findByTestId(wrapper, 'location-picker-submit-button').at(0).props().disabled).toBeFalsy();
|
||||
expect(findByTestId(wrapper, "location-picker-submit-button").at(0).props().disabled).toBeFalsy();
|
||||
});
|
||||
|
||||
it('submits location', () => {
|
||||
it("submits location", () => {
|
||||
const onChoose = jest.fn();
|
||||
const wrapper = getComponent({ onChoose, shareType });
|
||||
act(() => {
|
||||
// @ts-ignore
|
||||
mocked(mockGeolocate).emit('geolocate', mockGeolocationPosition);
|
||||
mocked(mockGeolocate).emit("geolocate", mockGeolocationPosition);
|
||||
// make sure button is enabled
|
||||
wrapper.setProps({});
|
||||
});
|
||||
|
||||
act(() => {
|
||||
findByTestId(wrapper, 'location-picker-submit-button').at(0).simulate('click');
|
||||
findByTestId(wrapper, "location-picker-submit-button").at(0).simulate("click");
|
||||
});
|
||||
|
||||
// content of this call is tested in LocationShareMenu-test
|
||||
|
@ -229,67 +230,68 @@ describe("LocationPicker", () => {
|
|||
});
|
||||
};
|
||||
|
||||
describe('for Own location share type', () => {
|
||||
describe("for Own location share type", () => {
|
||||
testUserLocationShareTypes(LocationShareType.Own);
|
||||
});
|
||||
|
||||
describe('for Live location share type', () => {
|
||||
describe("for Live location share type", () => {
|
||||
const shareType = LocationShareType.Live;
|
||||
testUserLocationShareTypes(shareType);
|
||||
|
||||
const getOption = (wrapper, timeout) => findById(wrapper, `live-duration__${timeout}`).at(0);
|
||||
const getDropdown = wrapper => findByTestId(wrapper, 'live-duration-dropdown');
|
||||
const getSelectedOption = (wrapper) => findById(wrapper, 'live-duration_value');
|
||||
const getDropdown = (wrapper) => findByTestId(wrapper, "live-duration-dropdown");
|
||||
const getSelectedOption = (wrapper) => findById(wrapper, "live-duration_value");
|
||||
|
||||
const openDropdown = (wrapper) => act(() => {
|
||||
const dropdown = getDropdown(wrapper);
|
||||
dropdown.find('[role="button"]').at(0).simulate('click');
|
||||
wrapper.setProps({});
|
||||
});
|
||||
const openDropdown = (wrapper) =>
|
||||
act(() => {
|
||||
const dropdown = getDropdown(wrapper);
|
||||
dropdown.find('[role="button"]').at(0).simulate("click");
|
||||
wrapper.setProps({});
|
||||
});
|
||||
|
||||
it('renders live duration dropdown with default option', () => {
|
||||
it("renders live duration dropdown with default option", () => {
|
||||
const wrapper = getComponent({ shareType });
|
||||
expect(getSelectedOption(getDropdown(wrapper)).text()).toEqual('Share for 15m');
|
||||
expect(getSelectedOption(getDropdown(wrapper)).text()).toEqual("Share for 15m");
|
||||
});
|
||||
|
||||
it('updates selected duration', () => {
|
||||
it("updates selected duration", () => {
|
||||
const wrapper = getComponent({ shareType });
|
||||
|
||||
openDropdown(wrapper);
|
||||
const dropdown = getDropdown(wrapper);
|
||||
act(() => {
|
||||
getOption(dropdown, 3600000).simulate('click');
|
||||
getOption(dropdown, 3600000).simulate("click");
|
||||
});
|
||||
|
||||
// value updated
|
||||
expect(getSelectedOption(getDropdown(wrapper)).text()).toEqual('Share for 1h');
|
||||
expect(getSelectedOption(getDropdown(wrapper)).text()).toEqual("Share for 1h");
|
||||
});
|
||||
});
|
||||
|
||||
describe('for Pin drop location share type', () => {
|
||||
describe("for Pin drop location share type", () => {
|
||||
const shareType = LocationShareType.Pin;
|
||||
it('initiates map with geolocation', () => {
|
||||
it("initiates map with geolocation", () => {
|
||||
getComponent({ shareType });
|
||||
|
||||
expect(mockMap.addControl).toHaveBeenCalledWith(mockGeolocate);
|
||||
act(() => {
|
||||
// @ts-ignore
|
||||
mocked(mockMap).emit('load');
|
||||
mocked(mockMap).emit("load");
|
||||
});
|
||||
|
||||
expect(mockGeolocate.trigger).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('removes geolocation control on geolocation error', () => {
|
||||
it("removes geolocation control on geolocation error", () => {
|
||||
// suppress expected error log
|
||||
jest.spyOn(logger, 'error').mockImplementation(() => { });
|
||||
jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||
const onFinished = jest.fn();
|
||||
getComponent({ onFinished, shareType });
|
||||
act(() => {
|
||||
// @ts-ignore
|
||||
mockMap.emit('load');
|
||||
mockMap.emit("load");
|
||||
// @ts-ignore
|
||||
mockGeolocate.emit('error', {});
|
||||
mockGeolocate.emit("error", {});
|
||||
});
|
||||
|
||||
expect(mockMap.removeControl).toHaveBeenCalledWith(mockGeolocate);
|
||||
|
@ -297,47 +299,45 @@ describe("LocationPicker", () => {
|
|||
expect(onFinished).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not set position on geolocate event', () => {
|
||||
it("does not set position on geolocate event", () => {
|
||||
mocked(maplibregl.Marker).mockClear();
|
||||
const wrapper = getComponent({ shareType });
|
||||
act(() => {
|
||||
// @ts-ignore
|
||||
mocked(mockGeolocate).emit('geolocate', mockGeolocationPosition);
|
||||
mocked(mockGeolocate).emit("geolocate", mockGeolocationPosition);
|
||||
});
|
||||
|
||||
// marker not added
|
||||
expect(wrapper.find('Marker').length).toBeFalsy();
|
||||
expect(wrapper.find("Marker").length).toBeFalsy();
|
||||
});
|
||||
|
||||
it('sets position on click event', () => {
|
||||
it("sets position on click event", () => {
|
||||
const wrapper = getComponent({ shareType });
|
||||
act(() => {
|
||||
// @ts-ignore
|
||||
mocked(mockMap).emit('click', mockClickEvent);
|
||||
mocked(mockMap).emit("click", mockClickEvent);
|
||||
wrapper.setProps({});
|
||||
});
|
||||
|
||||
// marker added
|
||||
expect(maplibregl.Marker).toHaveBeenCalled();
|
||||
expect(mockMarker.setLngLat).toHaveBeenCalledWith(new maplibregl.LngLat(
|
||||
12.4, 43.2,
|
||||
));
|
||||
expect(mockMarker.setLngLat).toHaveBeenCalledWith(new maplibregl.LngLat(12.4, 43.2));
|
||||
|
||||
// marker is set, icon not avatar
|
||||
expect(wrapper.find('.mx_Marker_icon').length).toBeTruthy();
|
||||
expect(wrapper.find(".mx_Marker_icon").length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('submits location', () => {
|
||||
it("submits location", () => {
|
||||
const onChoose = jest.fn();
|
||||
const wrapper = getComponent({ onChoose, shareType });
|
||||
act(() => {
|
||||
// @ts-ignore
|
||||
mocked(mockMap).emit('click', mockClickEvent);
|
||||
mocked(mockMap).emit("click", mockClickEvent);
|
||||
wrapper.setProps({});
|
||||
});
|
||||
|
||||
act(() => {
|
||||
findByTestId(wrapper, 'location-picker-submit-button').at(0).simulate('click');
|
||||
findByTestId(wrapper, "location-picker-submit-button").at(0).simulate("click");
|
||||
});
|
||||
|
||||
// content of this call is tested in LocationShareMenu-test
|
||||
|
|
|
@ -14,43 +14,43 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import { mocked } from 'jest-mock';
|
||||
import { RoomMember } from 'matrix-js-sdk/src/models/room-member';
|
||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||
import { RelationType } from 'matrix-js-sdk/src/matrix';
|
||||
import { logger } from 'matrix-js-sdk/src/logger';
|
||||
import { M_ASSET, LocationAssetType } from 'matrix-js-sdk/src/@types/location';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { mocked } from "jest-mock";
|
||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { RelationType } from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { M_ASSET, LocationAssetType } from "matrix-js-sdk/src/@types/location";
|
||||
import { act } from "react-dom/test-utils";
|
||||
|
||||
import LocationShareMenu from '../../../../src/components/views/location/LocationShareMenu';
|
||||
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
||||
import { ChevronFace } from '../../../../src/components/structures/ContextMenu';
|
||||
import SettingsStore from '../../../../src/settings/SettingsStore';
|
||||
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||
import { LocationShareType } from '../../../../src/components/views/location/shareLocation';
|
||||
import LocationShareMenu from "../../../../src/components/views/location/LocationShareMenu";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import { ChevronFace } from "../../../../src/components/structures/ContextMenu";
|
||||
import SettingsStore from "../../../../src/settings/SettingsStore";
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import { LocationShareType } from "../../../../src/components/views/location/shareLocation";
|
||||
import {
|
||||
findByTagAndTestId,
|
||||
findByTestId,
|
||||
flushPromisesWithFakeTimers,
|
||||
getMockClientWithEventEmitter,
|
||||
setupAsyncStoreWithClient,
|
||||
} from '../../../test-utils';
|
||||
import Modal from '../../../../src/Modal';
|
||||
import { DEFAULT_DURATION_MS } from '../../../../src/components/views/location/LiveDurationDropdown';
|
||||
import { OwnBeaconStore } from '../../../../src/stores/OwnBeaconStore';
|
||||
import { SettingLevel } from '../../../../src/settings/SettingLevel';
|
||||
import QuestionDialog from '../../../../src/components/views/dialogs/QuestionDialog';
|
||||
} from "../../../test-utils";
|
||||
import Modal from "../../../../src/Modal";
|
||||
import { DEFAULT_DURATION_MS } from "../../../../src/components/views/location/LiveDurationDropdown";
|
||||
import { OwnBeaconStore } from "../../../../src/stores/OwnBeaconStore";
|
||||
import { SettingLevel } from "../../../../src/settings/SettingLevel";
|
||||
import QuestionDialog from "../../../../src/components/views/dialogs/QuestionDialog";
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
jest.mock('../../../../src/utils/location/findMapStyleUrl', () => ({
|
||||
findMapStyleUrl: jest.fn().mockReturnValue('test'),
|
||||
jest.mock("../../../../src/utils/location/findMapStyleUrl", () => ({
|
||||
findMapStyleUrl: jest.fn().mockReturnValue("test"),
|
||||
}));
|
||||
|
||||
jest.mock('../../../../src/settings/SettingsStore', () => ({
|
||||
jest.mock("../../../../src/settings/SettingsStore", () => ({
|
||||
getValue: jest.fn(),
|
||||
setValue: jest.fn(),
|
||||
monitorSetting: jest.fn(),
|
||||
|
@ -58,44 +58,45 @@ jest.mock('../../../../src/settings/SettingsStore', () => ({
|
|||
unwatchSetting: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../../src/stores/OwnProfileStore', () => ({
|
||||
jest.mock("../../../../src/stores/OwnProfileStore", () => ({
|
||||
OwnProfileStore: {
|
||||
instance: {
|
||||
displayName: 'Ernie',
|
||||
getHttpAvatarUrl: jest.fn().mockReturnValue('image.com/img'),
|
||||
displayName: "Ernie",
|
||||
getHttpAvatarUrl: jest.fn().mockReturnValue("image.com/img"),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('../../../../src/Modal', () => ({
|
||||
jest.mock("../../../../src/Modal", () => ({
|
||||
createDialog: jest.fn(),
|
||||
on: jest.fn(),
|
||||
off: jest.fn(),
|
||||
ModalManagerEvent: { Opened: "opened" },
|
||||
}));
|
||||
|
||||
describe('<LocationShareMenu />', () => {
|
||||
const userId = '@ernie:server.org';
|
||||
describe("<LocationShareMenu />", () => {
|
||||
const userId = "@ernie:server.org";
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getUserId: jest.fn().mockReturnValue(userId),
|
||||
getClientWellKnown: jest.fn().mockResolvedValue({
|
||||
map_style_url: 'maps.com',
|
||||
map_style_url: "maps.com",
|
||||
}),
|
||||
sendMessage: jest.fn(),
|
||||
unstable_createLiveBeacon: jest.fn().mockResolvedValue({ event_id: '1' }),
|
||||
unstable_setLiveBeacon: jest.fn().mockResolvedValue({ event_id: '1' }),
|
||||
unstable_createLiveBeacon: jest.fn().mockResolvedValue({ event_id: "1" }),
|
||||
unstable_setLiveBeacon: jest.fn().mockResolvedValue({ event_id: "1" }),
|
||||
getVisibleRooms: jest.fn().mockReturnValue([]),
|
||||
});
|
||||
|
||||
const defaultProps = {
|
||||
menuPosition: {
|
||||
top: 1, left: 1,
|
||||
top: 1,
|
||||
left: 1,
|
||||
chevronFace: ChevronFace.Bottom,
|
||||
},
|
||||
onFinished: jest.fn(),
|
||||
openMenu: jest.fn(),
|
||||
roomId: '!room:server.org',
|
||||
sender: new RoomMember('!room:server.org', userId),
|
||||
roomId: "!room:server.org",
|
||||
sender: new RoomMember("!room:server.org", userId),
|
||||
};
|
||||
|
||||
const position = {
|
||||
|
@ -105,7 +106,7 @@ describe('<LocationShareMenu />', () => {
|
|||
accuracy: 10,
|
||||
},
|
||||
timestamp: 1646305006802,
|
||||
type: 'geolocate',
|
||||
type: "geolocate",
|
||||
};
|
||||
|
||||
const makeOwnBeaconStore = async () => {
|
||||
|
@ -122,11 +123,11 @@ describe('<LocationShareMenu />', () => {
|
|||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.spyOn(logger, 'error').mockRestore();
|
||||
jest.spyOn(logger, "error").mockRestore();
|
||||
mocked(SettingsStore).getValue.mockReturnValue(false);
|
||||
mockClient.sendMessage.mockClear();
|
||||
mockClient.unstable_createLiveBeacon.mockClear().mockResolvedValue({ event_id: '1' });
|
||||
jest.spyOn(MatrixClientPeg, 'get').mockReturnValue(mockClient as unknown as MatrixClient);
|
||||
mockClient.unstable_createLiveBeacon.mockClear().mockResolvedValue({ event_id: "1" });
|
||||
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient as unknown as MatrixClient);
|
||||
mocked(Modal).createDialog.mockClear();
|
||||
|
||||
jest.clearAllMocks();
|
||||
|
@ -135,20 +136,20 @@ describe('<LocationShareMenu />', () => {
|
|||
});
|
||||
|
||||
const getShareTypeOption = (component: ReactWrapper, shareType: LocationShareType) =>
|
||||
findByTagAndTestId(component, `share-location-option-${shareType}`, 'button');
|
||||
findByTagAndTestId(component, `share-location-option-${shareType}`, "button");
|
||||
|
||||
const getBackButton = (component: ReactWrapper) =>
|
||||
findByTagAndTestId(component, 'share-dialog-buttons-back', 'button');
|
||||
findByTagAndTestId(component, "share-dialog-buttons-back", "button");
|
||||
|
||||
const getCancelButton = (component: ReactWrapper) =>
|
||||
findByTagAndTestId(component, 'share-dialog-buttons-cancel', 'button');
|
||||
findByTagAndTestId(component, "share-dialog-buttons-cancel", "button");
|
||||
|
||||
const getSubmitButton = (component: ReactWrapper) =>
|
||||
findByTagAndTestId(component, 'location-picker-submit-button', 'button');
|
||||
findByTagAndTestId(component, "location-picker-submit-button", "button");
|
||||
|
||||
const setLocation = (component: ReactWrapper) => {
|
||||
// set the location
|
||||
const locationPickerInstance = component.find('LocationPicker').instance();
|
||||
const locationPickerInstance = component.find("LocationPicker").instance();
|
||||
act(() => {
|
||||
// @ts-ignore
|
||||
locationPickerInstance.onGeolocate(position);
|
||||
|
@ -159,38 +160,38 @@ describe('<LocationShareMenu />', () => {
|
|||
|
||||
const setShareType = (component: ReactWrapper, shareType: LocationShareType) =>
|
||||
act(() => {
|
||||
getShareTypeOption(component, shareType).at(0).simulate('click');
|
||||
getShareTypeOption(component, shareType).at(0).simulate("click");
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
describe('when only Own share type is enabled', () => {
|
||||
describe("when only Own share type is enabled", () => {
|
||||
beforeEach(() => enableSettings([]));
|
||||
|
||||
it('renders own and live location options', () => {
|
||||
it("renders own and live location options", () => {
|
||||
const component = getComponent();
|
||||
expect(getShareTypeOption(component, LocationShareType.Own).length).toBe(1);
|
||||
expect(getShareTypeOption(component, LocationShareType.Live).length).toBe(1);
|
||||
});
|
||||
|
||||
it('renders back button from location picker screen', () => {
|
||||
it("renders back button from location picker screen", () => {
|
||||
const component = getComponent();
|
||||
setShareType(component, LocationShareType.Own);
|
||||
|
||||
expect(getBackButton(component).length).toBe(1);
|
||||
});
|
||||
|
||||
it('clicking cancel button from location picker closes dialog', () => {
|
||||
it("clicking cancel button from location picker closes dialog", () => {
|
||||
const onFinished = jest.fn();
|
||||
const component = getComponent({ onFinished });
|
||||
|
||||
act(() => {
|
||||
getCancelButton(component).at(0).simulate('click');
|
||||
getCancelButton(component).at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('creates static own location share event on submission', () => {
|
||||
it("creates static own location share event on submission", () => {
|
||||
const onFinished = jest.fn();
|
||||
const component = getComponent({ onFinished });
|
||||
|
||||
|
@ -199,7 +200,7 @@ describe('<LocationShareMenu />', () => {
|
|||
setLocation(component);
|
||||
|
||||
act(() => {
|
||||
getSubmitButton(component).at(0).simulate('click');
|
||||
getSubmitButton(component).at(0).simulate("click");
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
|
@ -207,66 +208,68 @@ describe('<LocationShareMenu />', () => {
|
|||
const [messageRoomId, relation, messageBody] = mockClient.sendMessage.mock.calls[0];
|
||||
expect(messageRoomId).toEqual(defaultProps.roomId);
|
||||
expect(relation).toEqual(null);
|
||||
expect(messageBody).toEqual(expect.objectContaining({
|
||||
[M_ASSET.name]: {
|
||||
type: LocationAssetType.Self,
|
||||
},
|
||||
}));
|
||||
expect(messageBody).toEqual(
|
||||
expect.objectContaining({
|
||||
[M_ASSET.name]: {
|
||||
type: LocationAssetType.Self,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with pin drop share type enabled', () => {
|
||||
it('renders share type switch with own and pin drop options', () => {
|
||||
describe("with pin drop share type enabled", () => {
|
||||
it("renders share type switch with own and pin drop options", () => {
|
||||
const component = getComponent();
|
||||
expect(component.find('LocationPicker').length).toBe(0);
|
||||
expect(component.find("LocationPicker").length).toBe(0);
|
||||
|
||||
expect(getShareTypeOption(component, LocationShareType.Own).length).toBe(1);
|
||||
expect(getShareTypeOption(component, LocationShareType.Pin).length).toBe(1);
|
||||
});
|
||||
|
||||
it('does not render back button on share type screen', () => {
|
||||
it("does not render back button on share type screen", () => {
|
||||
const component = getComponent();
|
||||
expect(getBackButton(component).length).toBe(0);
|
||||
});
|
||||
|
||||
it('clicking cancel button from share type screen closes dialog', () => {
|
||||
it("clicking cancel button from share type screen closes dialog", () => {
|
||||
const onFinished = jest.fn();
|
||||
const component = getComponent({ onFinished });
|
||||
|
||||
act(() => {
|
||||
getCancelButton(component).at(0).simulate('click');
|
||||
getCancelButton(component).at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('selecting own location share type advances to location picker', () => {
|
||||
it("selecting own location share type advances to location picker", () => {
|
||||
const component = getComponent();
|
||||
|
||||
setShareType(component, LocationShareType.Own);
|
||||
|
||||
expect(component.find('LocationPicker').length).toBe(1);
|
||||
expect(component.find("LocationPicker").length).toBe(1);
|
||||
});
|
||||
|
||||
it('clicking back button from location picker screen goes back to share screen', () => {
|
||||
it("clicking back button from location picker screen goes back to share screen", () => {
|
||||
const onFinished = jest.fn();
|
||||
const component = getComponent({ onFinished });
|
||||
|
||||
// advance to location picker
|
||||
setShareType(component, LocationShareType.Own);
|
||||
|
||||
expect(component.find('LocationPicker').length).toBe(1);
|
||||
expect(component.find("LocationPicker").length).toBe(1);
|
||||
|
||||
act(() => {
|
||||
getBackButton(component).at(0).simulate('click');
|
||||
getBackButton(component).at(0).simulate("click");
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
// back to share type
|
||||
expect(component.find('ShareType').length).toBe(1);
|
||||
expect(component.find("ShareType").length).toBe(1);
|
||||
});
|
||||
|
||||
it('creates pin drop location share event on submission', () => {
|
||||
it("creates pin drop location share event on submission", () => {
|
||||
const onFinished = jest.fn();
|
||||
const component = getComponent({ onFinished });
|
||||
|
||||
|
@ -276,7 +279,7 @@ describe('<LocationShareMenu />', () => {
|
|||
setLocation(component);
|
||||
|
||||
act(() => {
|
||||
getSubmitButton(component).at(0).simulate('click');
|
||||
getSubmitButton(component).at(0).simulate("click");
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
|
@ -284,76 +287,81 @@ describe('<LocationShareMenu />', () => {
|
|||
const [messageRoomId, relation, messageBody] = mockClient.sendMessage.mock.calls[0];
|
||||
expect(messageRoomId).toEqual(defaultProps.roomId);
|
||||
expect(relation).toEqual(null);
|
||||
expect(messageBody).toEqual(expect.objectContaining({
|
||||
[M_ASSET.name]: {
|
||||
type: LocationAssetType.Pin,
|
||||
},
|
||||
}));
|
||||
expect(messageBody).toEqual(
|
||||
expect.objectContaining({
|
||||
[M_ASSET.name]: {
|
||||
type: LocationAssetType.Pin,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with live location disabled', () => {
|
||||
describe("with live location disabled", () => {
|
||||
beforeEach(() => enableSettings([]));
|
||||
|
||||
const getToggle = (component: ReactWrapper) =>
|
||||
findByTestId(component, 'enable-live-share-toggle').find('[role="switch"]').at(0);
|
||||
findByTestId(component, "enable-live-share-toggle").find('[role="switch"]').at(0);
|
||||
const getSubmitEnableButton = (component: ReactWrapper) =>
|
||||
findByTestId(component, 'enable-live-share-submit').at(0);
|
||||
findByTestId(component, "enable-live-share-submit").at(0);
|
||||
|
||||
it('goes to labs flag screen after live options is clicked', () => {
|
||||
it("goes to labs flag screen after live options is clicked", () => {
|
||||
const onFinished = jest.fn();
|
||||
const component = getComponent({ onFinished });
|
||||
|
||||
setShareType(component, LocationShareType.Live);
|
||||
|
||||
expect(findByTestId(component, 'location-picker-enable-live-share')).toMatchSnapshot();
|
||||
expect(findByTestId(component, "location-picker-enable-live-share")).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('disables OK button when labs flag is not enabled', () => {
|
||||
it("disables OK button when labs flag is not enabled", () => {
|
||||
const component = getComponent();
|
||||
|
||||
setShareType(component, LocationShareType.Live);
|
||||
|
||||
expect(getSubmitEnableButton(component).props()['disabled']).toBeTruthy();
|
||||
expect(getSubmitEnableButton(component).props()["disabled"]).toBeTruthy();
|
||||
});
|
||||
|
||||
it('enables OK button when labs flag is toggled to enabled', () => {
|
||||
it("enables OK button when labs flag is toggled to enabled", () => {
|
||||
const component = getComponent();
|
||||
|
||||
setShareType(component, LocationShareType.Live);
|
||||
|
||||
act(() => {
|
||||
getToggle(component).simulate('click');
|
||||
getToggle(component).simulate("click");
|
||||
component.setProps({});
|
||||
});
|
||||
expect(getSubmitEnableButton(component).props()['disabled']).toBeFalsy();
|
||||
expect(getSubmitEnableButton(component).props()["disabled"]).toBeFalsy();
|
||||
});
|
||||
|
||||
it('enables live share setting on ok button submit', () => {
|
||||
it("enables live share setting on ok button submit", () => {
|
||||
const component = getComponent();
|
||||
|
||||
setShareType(component, LocationShareType.Live);
|
||||
|
||||
act(() => {
|
||||
getToggle(component).simulate('click');
|
||||
getToggle(component).simulate("click");
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
act(() => {
|
||||
getSubmitEnableButton(component).simulate('click');
|
||||
getSubmitEnableButton(component).simulate("click");
|
||||
});
|
||||
|
||||
expect(SettingsStore.setValue).toHaveBeenCalledWith(
|
||||
'feature_location_share_live', undefined, SettingLevel.DEVICE, true,
|
||||
"feature_location_share_live",
|
||||
undefined,
|
||||
SettingLevel.DEVICE,
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
it('navigates to location picker when live share is enabled in settings store', () => {
|
||||
it("navigates to location picker when live share is enabled in settings store", () => {
|
||||
// @ts-ignore
|
||||
mocked(SettingsStore.watchSetting).mockImplementation((featureName, roomId, callback) => {
|
||||
callback(featureName, roomId, SettingLevel.DEVICE, '', '');
|
||||
callback(featureName, roomId, SettingLevel.DEVICE, "", "");
|
||||
window.setTimeout(() => {
|
||||
callback(featureName, roomId, SettingLevel.DEVICE, '', '');
|
||||
callback(featureName, roomId, SettingLevel.DEVICE, "", "");
|
||||
}, 1000);
|
||||
});
|
||||
mocked(SettingsStore.getValue).mockReturnValue(false);
|
||||
|
@ -362,7 +370,7 @@ describe('<LocationShareMenu />', () => {
|
|||
setShareType(component, LocationShareType.Live);
|
||||
|
||||
// we're on enable live share screen
|
||||
expect(findByTestId(component, 'location-picker-enable-live-share').length).toBeTruthy();
|
||||
expect(findByTestId(component, "location-picker-enable-live-share").length).toBeTruthy();
|
||||
|
||||
act(() => {
|
||||
mocked(SettingsStore.getValue).mockReturnValue(true);
|
||||
|
@ -373,24 +381,24 @@ describe('<LocationShareMenu />', () => {
|
|||
component.setProps({});
|
||||
|
||||
// advanced to location picker
|
||||
expect(component.find('LocationPicker').length).toBeTruthy();
|
||||
expect(component.find("LocationPicker").length).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Live location share', () => {
|
||||
describe("Live location share", () => {
|
||||
beforeEach(() => enableSettings(["feature_location_share_live"]));
|
||||
|
||||
it('does not display live location share option when composer has a relation', () => {
|
||||
it("does not display live location share option when composer has a relation", () => {
|
||||
const relation = {
|
||||
rel_type: RelationType.Thread,
|
||||
event_id: '12345',
|
||||
event_id: "12345",
|
||||
};
|
||||
const component = getComponent({ relation });
|
||||
|
||||
expect(getShareTypeOption(component, LocationShareType.Live).length).toBeFalsy();
|
||||
});
|
||||
|
||||
it('creates beacon info event on submission', async () => {
|
||||
it("creates beacon info event on submission", async () => {
|
||||
const onFinished = jest.fn();
|
||||
const component = getComponent({ onFinished });
|
||||
|
||||
|
@ -399,7 +407,7 @@ describe('<LocationShareMenu />', () => {
|
|||
setLocation(component);
|
||||
|
||||
act(() => {
|
||||
getSubmitButton(component).at(0).simulate('click');
|
||||
getSubmitButton(component).at(0).simulate("click");
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
|
@ -409,21 +417,23 @@ describe('<LocationShareMenu />', () => {
|
|||
expect(onFinished).toHaveBeenCalled();
|
||||
const [eventRoomId, eventContent] = mockClient.unstable_createLiveBeacon.mock.calls[0];
|
||||
expect(eventRoomId).toEqual(defaultProps.roomId);
|
||||
expect(eventContent).toEqual(expect.objectContaining({
|
||||
// default timeout
|
||||
timeout: DEFAULT_DURATION_MS,
|
||||
description: `Ernie's live location`,
|
||||
live: true,
|
||||
[M_ASSET.name]: {
|
||||
type: LocationAssetType.Self,
|
||||
},
|
||||
}));
|
||||
expect(eventContent).toEqual(
|
||||
expect.objectContaining({
|
||||
// default timeout
|
||||
timeout: DEFAULT_DURATION_MS,
|
||||
description: `Ernie's live location`,
|
||||
live: true,
|
||||
[M_ASSET.name]: {
|
||||
type: LocationAssetType.Self,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('opens error dialog when beacon creation fails', async () => {
|
||||
it("opens error dialog when beacon creation fails", async () => {
|
||||
// stub logger to keep console clean from expected error
|
||||
const logSpy = jest.spyOn(logger, 'error').mockReturnValue(undefined);
|
||||
const error = new Error('oh no');
|
||||
const logSpy = jest.spyOn(logger, "error").mockReturnValue(undefined);
|
||||
const error = new Error("oh no");
|
||||
mockClient.unstable_createLiveBeacon.mockRejectedValue(error);
|
||||
const component = getComponent();
|
||||
|
||||
|
@ -432,7 +442,7 @@ describe('<LocationShareMenu />', () => {
|
|||
setLocation(component);
|
||||
|
||||
act(() => {
|
||||
getSubmitButton(component).at(0).simulate('click');
|
||||
getSubmitButton(component).at(0).simulate("click");
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
|
@ -441,18 +451,21 @@ describe('<LocationShareMenu />', () => {
|
|||
await flushPromisesWithFakeTimers();
|
||||
|
||||
expect(logSpy).toHaveBeenCalledWith("We couldn't start sharing your live location", error);
|
||||
expect(mocked(Modal).createDialog).toHaveBeenCalledWith(QuestionDialog, expect.objectContaining({
|
||||
button: 'Try again',
|
||||
description: 'Element could not send your location. Please try again later.',
|
||||
title: `We couldn't send your location`,
|
||||
cancelButton: 'Cancel',
|
||||
}));
|
||||
expect(mocked(Modal).createDialog).toHaveBeenCalledWith(
|
||||
QuestionDialog,
|
||||
expect.objectContaining({
|
||||
button: "Try again",
|
||||
description: "Element could not send your location. Please try again later.",
|
||||
title: `We couldn't send your location`,
|
||||
cancelButton: "Cancel",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('opens error dialog when beacon creation fails with permission error', async () => {
|
||||
it("opens error dialog when beacon creation fails with permission error", async () => {
|
||||
// stub logger to keep console clean from expected error
|
||||
const logSpy = jest.spyOn(logger, 'error').mockReturnValue(undefined);
|
||||
const error = { errcode: 'M_FORBIDDEN' } as unknown as Error;
|
||||
const logSpy = jest.spyOn(logger, "error").mockReturnValue(undefined);
|
||||
const error = { errcode: "M_FORBIDDEN" } as unknown as Error;
|
||||
mockClient.unstable_createLiveBeacon.mockRejectedValue(error);
|
||||
const component = getComponent();
|
||||
|
||||
|
@ -461,7 +474,7 @@ describe('<LocationShareMenu />', () => {
|
|||
setLocation(component);
|
||||
|
||||
act(() => {
|
||||
getSubmitButton(component).at(0).simulate('click');
|
||||
getSubmitButton(component).at(0).simulate("click");
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
|
@ -470,12 +483,15 @@ describe('<LocationShareMenu />', () => {
|
|||
await flushPromisesWithFakeTimers();
|
||||
|
||||
expect(logSpy).toHaveBeenCalledWith("Insufficient permissions to start sharing your live location", error);
|
||||
expect(mocked(Modal).createDialog).toHaveBeenCalledWith(QuestionDialog, expect.objectContaining({
|
||||
button: 'OK',
|
||||
description: 'You need to have the right permissions in order to share locations in this room.',
|
||||
title: `You don't have permission to share locations`,
|
||||
hasCancelButton: false,
|
||||
}));
|
||||
expect(mocked(Modal).createDialog).toHaveBeenCalledWith(
|
||||
QuestionDialog,
|
||||
expect.objectContaining({
|
||||
button: "OK",
|
||||
description: "You need to have the right permissions in order to share locations in this room.",
|
||||
title: `You don't have permission to share locations`,
|
||||
hasCancelButton: false,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,23 +14,23 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { RoomMember } from 'matrix-js-sdk/src/matrix';
|
||||
import { LocationAssetType } from 'matrix-js-sdk/src/@types/location';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import { mount } from "enzyme";
|
||||
import { RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
import { LocationAssetType } from "matrix-js-sdk/src/@types/location";
|
||||
import maplibregl from "maplibre-gl";
|
||||
|
||||
import LocationViewDialog from '../../../../src/components/views/location/LocationViewDialog';
|
||||
import { TILE_SERVER_WK_KEY } from '../../../../src/utils/WellKnownUtils';
|
||||
import { getMockClientWithEventEmitter, makeLocationEvent } from '../../../test-utils';
|
||||
import LocationViewDialog from "../../../../src/components/views/location/LocationViewDialog";
|
||||
import { TILE_SERVER_WK_KEY } from "../../../../src/utils/WellKnownUtils";
|
||||
import { getMockClientWithEventEmitter, makeLocationEvent } from "../../../test-utils";
|
||||
|
||||
describe('<LocationViewDialog />', () => {
|
||||
const roomId = '!room:server';
|
||||
const userId = '@user:server';
|
||||
describe("<LocationViewDialog />", () => {
|
||||
const roomId = "!room:server";
|
||||
const userId = "@user:server";
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getClientWellKnown: jest.fn().mockReturnValue({
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: 'maps.com' },
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: "maps.com" },
|
||||
}),
|
||||
isGuest: jest.fn().mockReturnValue(false),
|
||||
});
|
||||
|
@ -40,24 +40,23 @@ describe('<LocationViewDialog />', () => {
|
|||
mxEvent: defaultEvent,
|
||||
onFinished: jest.fn(),
|
||||
};
|
||||
const getComponent = (props = {}) =>
|
||||
mount(<LocationViewDialog {...defaultProps} {...props} />);
|
||||
const getComponent = (props = {}) => mount(<LocationViewDialog {...defaultProps} {...props} />);
|
||||
|
||||
beforeAll(() => {
|
||||
maplibregl.AttributionControl = jest.fn();
|
||||
});
|
||||
|
||||
it('renders map correctly', () => {
|
||||
it("renders map correctly", () => {
|
||||
const component = getComponent();
|
||||
expect(component.find('Map')).toMatchSnapshot();
|
||||
expect(component.find("Map")).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders marker correctly for self share', () => {
|
||||
it("renders marker correctly for self share", () => {
|
||||
const selfShareEvent = makeLocationEvent("geo:51.5076,-0.1276", LocationAssetType.Self);
|
||||
const member = new RoomMember(roomId, userId);
|
||||
// @ts-ignore cheat assignment to property
|
||||
selfShareEvent.sender = member;
|
||||
const component = getComponent({ mxEvent: selfShareEvent });
|
||||
expect(component.find('SmartMarker').props()['roomMember']).toEqual(member);
|
||||
expect(component.find("SmartMarker").props()["roomMember"]).toEqual(member);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,29 +14,29 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import { ClientEvent } from 'matrix-js-sdk/src/matrix';
|
||||
import { logger } from 'matrix-js-sdk/src/logger';
|
||||
import { mount } from "enzyme";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import maplibregl from "maplibre-gl";
|
||||
import { ClientEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import Map from '../../../../src/components/views/location/Map';
|
||||
import { findByTestId, getMockClientWithEventEmitter } from '../../../test-utils';
|
||||
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
||||
import { TILE_SERVER_WK_KEY } from '../../../../src/utils/WellKnownUtils';
|
||||
import Map from "../../../../src/components/views/location/Map";
|
||||
import { findByTestId, getMockClientWithEventEmitter } from "../../../test-utils";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import { TILE_SERVER_WK_KEY } from "../../../../src/utils/WellKnownUtils";
|
||||
|
||||
describe('<Map />', () => {
|
||||
describe("<Map />", () => {
|
||||
const defaultProps = {
|
||||
centerGeoUri: 'geo:52,41',
|
||||
id: 'test-123',
|
||||
centerGeoUri: "geo:52,41",
|
||||
id: "test-123",
|
||||
onError: jest.fn(),
|
||||
onClick: jest.fn(),
|
||||
};
|
||||
const matrixClient = getMockClientWithEventEmitter({
|
||||
getClientWellKnown: jest.fn().mockReturnValue({
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: 'maps.com' },
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: "maps.com" },
|
||||
}),
|
||||
});
|
||||
const getComponent = (props = {}) =>
|
||||
|
@ -52,33 +52,33 @@ describe('<Map />', () => {
|
|||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
matrixClient.getClientWellKnown.mockReturnValue({
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: 'maps.com' },
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: "maps.com" },
|
||||
});
|
||||
|
||||
jest.spyOn(logger, 'error').mockRestore();
|
||||
jest.spyOn(logger, "error").mockRestore();
|
||||
});
|
||||
|
||||
const mockMap = new maplibregl.Map();
|
||||
|
||||
it('renders', () => {
|
||||
it("renders", () => {
|
||||
const component = getComponent();
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('onClientWellKnown emits', () => {
|
||||
it('updates map style when style url is truthy', () => {
|
||||
describe("onClientWellKnown emits", () => {
|
||||
it("updates map style when style url is truthy", () => {
|
||||
getComponent();
|
||||
|
||||
act(() => {
|
||||
matrixClient.emit(ClientEvent.ClientWellKnown, {
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: 'new.maps.com' },
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: "new.maps.com" },
|
||||
});
|
||||
});
|
||||
|
||||
expect(mockMap.setStyle).toHaveBeenCalledWith('new.maps.com');
|
||||
expect(mockMap.setStyle).toHaveBeenCalledWith("new.maps.com");
|
||||
});
|
||||
|
||||
it('does not update map style when style url is truthy', () => {
|
||||
it("does not update map style when style url is truthy", () => {
|
||||
getComponent();
|
||||
|
||||
act(() => {
|
||||
|
@ -91,58 +91,60 @@ describe('<Map />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('map centering', () => {
|
||||
it('does not try to center when no center uri provided', () => {
|
||||
describe("map centering", () => {
|
||||
it("does not try to center when no center uri provided", () => {
|
||||
getComponent({ centerGeoUri: null });
|
||||
expect(mockMap.setCenter).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('sets map center to centerGeoUri', () => {
|
||||
getComponent({ centerGeoUri: 'geo:51,42' });
|
||||
it("sets map center to centerGeoUri", () => {
|
||||
getComponent({ centerGeoUri: "geo:51,42" });
|
||||
expect(mockMap.setCenter).toHaveBeenCalledWith({ lat: 51, lon: 42 });
|
||||
});
|
||||
|
||||
it('handles invalid centerGeoUri', () => {
|
||||
const logSpy = jest.spyOn(logger, 'error').mockImplementation();
|
||||
getComponent({ centerGeoUri: '123 Sesame Street' });
|
||||
it("handles invalid centerGeoUri", () => {
|
||||
const logSpy = jest.spyOn(logger, "error").mockImplementation();
|
||||
getComponent({ centerGeoUri: "123 Sesame Street" });
|
||||
expect(mockMap.setCenter).not.toHaveBeenCalled();
|
||||
expect(logSpy).toHaveBeenCalledWith('Could not set map center');
|
||||
expect(logSpy).toHaveBeenCalledWith("Could not set map center");
|
||||
});
|
||||
|
||||
it('updates map center when centerGeoUri prop changes', () => {
|
||||
const component = getComponent({ centerGeoUri: 'geo:51,42' });
|
||||
it("updates map center when centerGeoUri prop changes", () => {
|
||||
const component = getComponent({ centerGeoUri: "geo:51,42" });
|
||||
|
||||
component.setProps({ centerGeoUri: 'geo:53,45' });
|
||||
component.setProps({ centerGeoUri: 'geo:56,47' });
|
||||
component.setProps({ centerGeoUri: "geo:53,45" });
|
||||
component.setProps({ centerGeoUri: "geo:56,47" });
|
||||
expect(mockMap.setCenter).toHaveBeenCalledWith({ lat: 51, lon: 42 });
|
||||
expect(mockMap.setCenter).toHaveBeenCalledWith({ lat: 53, lon: 45 });
|
||||
expect(mockMap.setCenter).toHaveBeenCalledWith({ lat: 56, lon: 47 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('map bounds', () => {
|
||||
it('does not try to fit map bounds when no bounds provided', () => {
|
||||
describe("map bounds", () => {
|
||||
it("does not try to fit map bounds when no bounds provided", () => {
|
||||
getComponent({ bounds: null });
|
||||
expect(mockMap.fitBounds).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('fits map to bounds', () => {
|
||||
it("fits map to bounds", () => {
|
||||
const bounds = { north: 51, south: 50, east: 42, west: 41 };
|
||||
getComponent({ bounds });
|
||||
expect(mockMap.fitBounds).toHaveBeenCalledWith(new maplibregl.LngLatBounds([bounds.west, bounds.south],
|
||||
[bounds.east, bounds.north]), { padding: 100, maxZoom: 15 });
|
||||
expect(mockMap.fitBounds).toHaveBeenCalledWith(
|
||||
new maplibregl.LngLatBounds([bounds.west, bounds.south], [bounds.east, bounds.north]),
|
||||
{ padding: 100, maxZoom: 15 },
|
||||
);
|
||||
});
|
||||
|
||||
it('handles invalid bounds', () => {
|
||||
const logSpy = jest.spyOn(logger, 'error').mockImplementation();
|
||||
const bounds = { north: 'a', south: 'b', east: 42, west: 41 };
|
||||
it("handles invalid bounds", () => {
|
||||
const logSpy = jest.spyOn(logger, "error").mockImplementation();
|
||||
const bounds = { north: "a", south: "b", east: 42, west: 41 };
|
||||
getComponent({ bounds });
|
||||
expect(mockMap.fitBounds).not.toHaveBeenCalled();
|
||||
expect(logSpy).toHaveBeenCalledWith('Invalid map bounds');
|
||||
expect(logSpy).toHaveBeenCalledWith("Invalid map bounds");
|
||||
});
|
||||
|
||||
it('updates map bounds when bounds prop changes', () => {
|
||||
const component = getComponent({ centerGeoUri: 'geo:51,42' });
|
||||
it("updates map bounds when bounds prop changes", () => {
|
||||
const component = getComponent({ centerGeoUri: "geo:51,42" });
|
||||
|
||||
const bounds = { north: 51, south: 50, east: 42, west: 41 };
|
||||
const bounds2 = { north: 53, south: 51, east: 45, west: 44 };
|
||||
|
@ -152,8 +154,8 @@ describe('<Map />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('children', () => {
|
||||
it('renders without children', () => {
|
||||
describe("children", () => {
|
||||
it("renders without children", () => {
|
||||
const component = getComponent({ children: null });
|
||||
|
||||
component.setProps({});
|
||||
|
@ -162,18 +164,22 @@ describe('<Map />', () => {
|
|||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders children with map renderProp', () => {
|
||||
const children = ({ map }) => <div data-test-id='test-child' data-map={map}>Hello, world</div>;
|
||||
it("renders children with map renderProp", () => {
|
||||
const children = ({ map }) => (
|
||||
<div data-test-id="test-child" data-map={map}>
|
||||
Hello, world
|
||||
</div>
|
||||
);
|
||||
|
||||
const component = getComponent({ children });
|
||||
|
||||
// renders child with map instance
|
||||
expect(findByTestId(component, 'test-child').props()['data-map']).toEqual(mockMap);
|
||||
expect(findByTestId(component, "test-child").props()["data-map"]).toEqual(mockMap);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onClick', () => {
|
||||
it('eats clicks to maplibre attribution button', () => {
|
||||
describe("onClick", () => {
|
||||
it("eats clicks to maplibre attribution button", () => {
|
||||
const onClick = jest.fn();
|
||||
const component = getComponent({ onClick });
|
||||
|
||||
|
@ -181,20 +187,20 @@ describe('<Map />', () => {
|
|||
// this is added to the dom by maplibregl
|
||||
// which is mocked
|
||||
// just fake the target
|
||||
const fakeEl = document.createElement('div');
|
||||
fakeEl.className = 'maplibregl-ctrl-attrib-button';
|
||||
component.simulate('click', { target: fakeEl });
|
||||
const fakeEl = document.createElement("div");
|
||||
fakeEl.className = "maplibregl-ctrl-attrib-button";
|
||||
component.simulate("click", { target: fakeEl });
|
||||
});
|
||||
|
||||
expect(onClick).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls onClick', () => {
|
||||
it("calls onClick", () => {
|
||||
const onClick = jest.fn();
|
||||
const component = getComponent({ onClick });
|
||||
|
||||
act(() => {
|
||||
component.simulate('click');
|
||||
component.simulate("click");
|
||||
});
|
||||
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
|
|
|
@ -14,43 +14,43 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render, RenderResult } from '@testing-library/react';
|
||||
import React from "react";
|
||||
import { render, RenderResult } from "@testing-library/react";
|
||||
|
||||
import { MapError, MapErrorProps } from '../../../../src/components/views/location/MapError';
|
||||
import { LocationShareError } from '../../../../src/utils/location';
|
||||
import { MapError, MapErrorProps } from "../../../../src/components/views/location/MapError";
|
||||
import { LocationShareError } from "../../../../src/utils/location";
|
||||
|
||||
describe('<MapError />', () => {
|
||||
describe("<MapError />", () => {
|
||||
const defaultProps = {
|
||||
onFinished: jest.fn(),
|
||||
error: LocationShareError.MapStyleUrlNotConfigured,
|
||||
className: 'test',
|
||||
className: "test",
|
||||
};
|
||||
const getComponent = (props: Partial<MapErrorProps> = {}): RenderResult =>
|
||||
render(<MapError {...defaultProps} {...props} />);
|
||||
|
||||
it('renders correctly for MapStyleUrlNotConfigured', () => {
|
||||
it("renders correctly for MapStyleUrlNotConfigured", () => {
|
||||
const { container } = getComponent();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders correctly for MapStyleUrlNotReachable', () => {
|
||||
it("renders correctly for MapStyleUrlNotReachable", () => {
|
||||
const { container } = getComponent({
|
||||
error: LocationShareError.MapStyleUrlNotReachable,
|
||||
});
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('does not render button when onFinished falsy', () => {
|
||||
it("does not render button when onFinished falsy", () => {
|
||||
const { queryByText } = getComponent({
|
||||
error: LocationShareError.MapStyleUrlNotReachable,
|
||||
onFinished: undefined,
|
||||
});
|
||||
// no button
|
||||
expect(queryByText('OK')).toBeFalsy();
|
||||
expect(queryByText("OK")).toBeFalsy();
|
||||
});
|
||||
|
||||
it('applies class when isMinimised is truthy', () => {
|
||||
it("applies class when isMinimised is truthy", () => {
|
||||
const { container } = getComponent({
|
||||
isMinimised: true,
|
||||
});
|
||||
|
|
|
@ -14,39 +14,38 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { RoomMember } from 'matrix-js-sdk/src/matrix';
|
||||
import { mount } from "enzyme";
|
||||
import { RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import Marker from '../../../../src/components/views/location/Marker';
|
||||
import Marker from "../../../../src/components/views/location/Marker";
|
||||
|
||||
describe('<Marker />', () => {
|
||||
describe("<Marker />", () => {
|
||||
const defaultProps = {
|
||||
id: 'abc123',
|
||||
id: "abc123",
|
||||
};
|
||||
const getComponent = (props = {}) =>
|
||||
mount(<Marker {...defaultProps} {...props} />);
|
||||
const getComponent = (props = {}) => mount(<Marker {...defaultProps} {...props} />);
|
||||
|
||||
it('renders with location icon when no room member', () => {
|
||||
it("renders with location icon when no room member", () => {
|
||||
const component = getComponent();
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('does not try to use member color without room member', () => {
|
||||
it("does not try to use member color without room member", () => {
|
||||
const component = getComponent({ useMemberColor: true });
|
||||
expect(component.find('div').at(0).props().className).toEqual('mx_Marker mx_Marker_defaultColor');
|
||||
expect(component.find("div").at(0).props().className).toEqual("mx_Marker mx_Marker_defaultColor");
|
||||
});
|
||||
|
||||
it('uses member color class', () => {
|
||||
const member = new RoomMember('!room:server', '@user:server');
|
||||
it("uses member color class", () => {
|
||||
const member = new RoomMember("!room:server", "@user:server");
|
||||
const component = getComponent({ useMemberColor: true, roomMember: member });
|
||||
expect(component.find('div').at(0).props().className).toEqual('mx_Marker mx_Username_color3');
|
||||
expect(component.find("div").at(0).props().className).toEqual("mx_Marker mx_Username_color3");
|
||||
});
|
||||
|
||||
it('renders member avatar when roomMember is truthy', () => {
|
||||
const member = new RoomMember('!room:server', '@user:server');
|
||||
it("renders member avatar when roomMember is truthy", () => {
|
||||
const member = new RoomMember("!room:server", "@user:server");
|
||||
const component = getComponent({ roomMember: member });
|
||||
expect(component.find('MemberAvatar').length).toBeTruthy();
|
||||
expect(component.find("MemberAvatar").length).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,34 +14,33 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { mocked } from 'jest-mock';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import { mount } from "enzyme";
|
||||
import { mocked } from "jest-mock";
|
||||
import maplibregl from "maplibre-gl";
|
||||
|
||||
import SmartMarker from '../../../../src/components/views/location/SmartMarker';
|
||||
import SmartMarker from "../../../../src/components/views/location/SmartMarker";
|
||||
|
||||
jest.mock('../../../../src/utils/location/findMapStyleUrl', () => ({
|
||||
findMapStyleUrl: jest.fn().mockReturnValue('tileserver.com'),
|
||||
jest.mock("../../../../src/utils/location/findMapStyleUrl", () => ({
|
||||
findMapStyleUrl: jest.fn().mockReturnValue("tileserver.com"),
|
||||
}));
|
||||
|
||||
describe('<SmartMarker />', () => {
|
||||
describe("<SmartMarker />", () => {
|
||||
const mockMap = new maplibregl.Map();
|
||||
const mockMarker = new maplibregl.Marker();
|
||||
|
||||
const defaultProps = {
|
||||
map: mockMap,
|
||||
geoUri: 'geo:43.2,54.6',
|
||||
geoUri: "geo:43.2,54.6",
|
||||
};
|
||||
const getComponent = (props = {}) =>
|
||||
mount(<SmartMarker {...defaultProps} {...props} />);
|
||||
const getComponent = (props = {}) => mount(<SmartMarker {...defaultProps} {...props} />);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('creates a marker on mount', () => {
|
||||
it("creates a marker on mount", () => {
|
||||
const component = getComponent();
|
||||
expect(component).toMatchSnapshot();
|
||||
|
||||
|
@ -55,11 +54,11 @@ describe('<SmartMarker />', () => {
|
|||
expect(mockMarker.addTo).toHaveBeenCalledWith(mockMap);
|
||||
});
|
||||
|
||||
it('updates marker position on change', () => {
|
||||
const component = getComponent({ geoUri: 'geo:40,50' });
|
||||
it("updates marker position on change", () => {
|
||||
const component = getComponent({ geoUri: "geo:40,50" });
|
||||
|
||||
component.setProps({ geoUri: 'geo:41,51' });
|
||||
component.setProps({ geoUri: 'geo:42,52' });
|
||||
component.setProps({ geoUri: "geo:41,51" });
|
||||
component.setProps({ geoUri: "geo:42,52" });
|
||||
|
||||
// marker added only once
|
||||
expect(maplibregl.Marker).toHaveBeenCalledTimes(1);
|
||||
|
@ -69,7 +68,7 @@ describe('<SmartMarker />', () => {
|
|||
expect(mocked(mockMarker.setLngLat)).toHaveBeenCalledWith({ lat: 42, lon: 52 });
|
||||
});
|
||||
|
||||
it('removes marker on unmount', () => {
|
||||
it("removes marker on unmount", () => {
|
||||
const component = getComponent();
|
||||
expect(component).toMatchSnapshot();
|
||||
|
||||
|
|
|
@ -14,48 +14,47 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { mount } from "enzyme";
|
||||
import maplibregl from "maplibre-gl";
|
||||
import { act } from "react-dom/test-utils";
|
||||
|
||||
import ZoomButtons from '../../../../src/components/views/location/ZoomButtons';
|
||||
import { findByTestId } from '../../../test-utils';
|
||||
import ZoomButtons from "../../../../src/components/views/location/ZoomButtons";
|
||||
import { findByTestId } from "../../../test-utils";
|
||||
|
||||
describe('<ZoomButtons />', () => {
|
||||
describe("<ZoomButtons />", () => {
|
||||
const mockMap = new maplibregl.Map();
|
||||
const defaultProps = {
|
||||
map: mockMap,
|
||||
};
|
||||
const getComponent = (props = {}) =>
|
||||
mount(<ZoomButtons {...defaultProps} {...props} />);
|
||||
const getComponent = (props = {}) => mount(<ZoomButtons {...defaultProps} {...props} />);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders buttons', () => {
|
||||
it("renders buttons", () => {
|
||||
const component = getComponent();
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('calls map zoom in on zoom in click', () => {
|
||||
it("calls map zoom in on zoom in click", () => {
|
||||
const component = getComponent();
|
||||
|
||||
act(() => {
|
||||
findByTestId(component, 'map-zoom-in-button').at(0).simulate('click');
|
||||
findByTestId(component, "map-zoom-in-button").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(mockMap.zoomIn).toHaveBeenCalled();
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('calls map zoom out on zoom out click', () => {
|
||||
it("calls map zoom out on zoom out click", () => {
|
||||
const component = getComponent();
|
||||
|
||||
act(() => {
|
||||
findByTestId(component, 'map-zoom-out-button').at(0).simulate('click');
|
||||
findByTestId(component, "map-zoom-out-button").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(mockMap.zoomOut).toHaveBeenCalled();
|
||||
|
|
|
@ -47,13 +47,11 @@ describe("shareLocation", () => {
|
|||
} as unknown as MatrixClient;
|
||||
|
||||
mocked(makeLocationContent).mockReturnValue(content);
|
||||
mocked(doMaybeLocalRoomAction).mockImplementation(<T>(
|
||||
roomId: string,
|
||||
fn: (actualRoomId: string) => Promise<T>,
|
||||
client?: MatrixClient,
|
||||
) => {
|
||||
return fn(roomId);
|
||||
});
|
||||
mocked(doMaybeLocalRoomAction).mockImplementation(
|
||||
<T>(roomId: string, fn: (actualRoomId: string) => Promise<T>, client?: MatrixClient) => {
|
||||
return fn(roomId);
|
||||
},
|
||||
);
|
||||
|
||||
shareLocationFn = shareLocation(client, roomId, shareType, null, () => {});
|
||||
});
|
||||
|
|
|
@ -68,16 +68,18 @@ describe("CallEvent", () => {
|
|||
alice = mkRoomMember(room.roomId, "@alice:example.org");
|
||||
bob = mkRoomMember(room.roomId, "@bob:example.org");
|
||||
jest.spyOn(room, "getMember").mockImplementation(
|
||||
userId => [alice, bob].find(member => member.userId === userId) ?? null,
|
||||
(userId) => [alice, bob].find((member) => member.userId === userId) ?? null,
|
||||
);
|
||||
|
||||
client.getRoom.mockImplementation(roomId => roomId === room.roomId ? room : null);
|
||||
client.getRoom.mockImplementation((roomId) => (roomId === room.roomId ? room : null));
|
||||
client.getRooms.mockReturnValue([room]);
|
||||
client.reEmitter.reEmit(room, [RoomStateEvent.Events]);
|
||||
|
||||
await Promise.all([CallStore.instance, WidgetMessagingStore.instance].map(
|
||||
store => setupAsyncStoreWithClient(store, client),
|
||||
));
|
||||
await Promise.all(
|
||||
[CallStore.instance, WidgetMessagingStore.instance].map((store) =>
|
||||
setupAsyncStoreWithClient(store, client),
|
||||
),
|
||||
);
|
||||
|
||||
MockedCall.create(room, "1");
|
||||
const maybeCall = CallStore.instance.getCall(room.roomId);
|
||||
|
@ -99,7 +101,9 @@ describe("CallEvent", () => {
|
|||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
const renderEvent = () => { render(<CallEvent mxEvent={call.event} />); };
|
||||
const renderEvent = () => {
|
||||
render(<CallEvent mxEvent={call.event} />);
|
||||
};
|
||||
|
||||
it("shows a message and duration if the call was ended", () => {
|
||||
jest.advanceTimersByTime(90000);
|
||||
|
@ -121,7 +125,10 @@ describe("CallEvent", () => {
|
|||
|
||||
it("shows call details and connection controls if the call is loaded", async () => {
|
||||
jest.advanceTimersByTime(90000);
|
||||
call.participants = new Map([[alice, new Set(["a"])], [bob, new Set(["b"])]]);
|
||||
call.participants = new Map([
|
||||
[alice, new Set(["a"])],
|
||||
[bob, new Set(["b"])],
|
||||
]);
|
||||
renderEvent();
|
||||
|
||||
screen.getByText("@alice:example.org started a video call");
|
||||
|
@ -132,11 +139,13 @@ describe("CallEvent", () => {
|
|||
const dispatcherSpy = jest.fn();
|
||||
const dispatcherRef = defaultDispatcher.register(dispatcherSpy);
|
||||
fireEvent.click(screen.getByRole("button", { name: "Join" }));
|
||||
await waitFor(() => expect(dispatcherSpy).toHaveBeenCalledWith({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
view_call: true,
|
||||
}));
|
||||
await waitFor(() =>
|
||||
expect(dispatcherSpy).toHaveBeenCalledWith({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
view_call: true,
|
||||
}),
|
||||
);
|
||||
defaultDispatcher.unregister(dispatcherRef);
|
||||
await act(() => call.connect());
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ describe("DateSeparator", () => {
|
|||
const HOUR_MS = 3600000;
|
||||
const DAY_MS = HOUR_MS * 24;
|
||||
// Friday Dec 17 2021, 9:09am
|
||||
const now = '2021-12-17T08:09:00.000Z';
|
||||
const now = "2021-12-17T08:09:00.000Z";
|
||||
const nowMs = 1639728540000;
|
||||
const defaultProps = {
|
||||
ts: nowMs,
|
||||
|
@ -47,23 +47,23 @@ describe("DateSeparator", () => {
|
|||
|
||||
const mockClient = getMockClientWithEventEmitter({});
|
||||
const getComponent = (props = {}) =>
|
||||
render((
|
||||
render(
|
||||
<MatrixClientContext.Provider value={mockClient}>
|
||||
<DateSeparator {...defaultProps} {...props} />
|
||||
</MatrixClientContext.Provider>
|
||||
));
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
|
||||
type TestCase = [string, number, string];
|
||||
const testCases: TestCase[] = [
|
||||
['the exact same moment', nowMs, 'Today'],
|
||||
['same day as current day', nowMs - HOUR_MS, 'Today'],
|
||||
['day before the current day', nowMs - (HOUR_MS * 12), 'Yesterday'],
|
||||
['2 days ago', nowMs - DAY_MS * 2, 'Wednesday'],
|
||||
['144 hours ago', nowMs - HOUR_MS * 144, 'Sat, Dec 11 2021'],
|
||||
["the exact same moment", nowMs, "Today"],
|
||||
["same day as current day", nowMs - HOUR_MS, "Today"],
|
||||
["day before the current day", nowMs - HOUR_MS * 12, "Yesterday"],
|
||||
["2 days ago", nowMs - DAY_MS * 2, "Wednesday"],
|
||||
["144 hours ago", nowMs - HOUR_MS * 144, "Sat, Dec 11 2021"],
|
||||
[
|
||||
'6 days ago, but less than 144h',
|
||||
new Date('Saturday Dec 11 2021 23:59:00 GMT+0100 (Central European Standard Time)').getTime(),
|
||||
'Saturday',
|
||||
"6 days ago, but less than 144h",
|
||||
new Date("Saturday Dec 11 2021 23:59:00 GMT+0100 (Central European Standard Time)").getTime(),
|
||||
"Saturday",
|
||||
],
|
||||
];
|
||||
|
||||
|
@ -80,24 +80,25 @@ describe("DateSeparator", () => {
|
|||
global.Date = RealDate;
|
||||
});
|
||||
|
||||
it('renders the date separator correctly', () => {
|
||||
it("renders the date separator correctly", () => {
|
||||
const { asFragment } = getComponent();
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
expect(SettingsStore.getValue).toHaveBeenCalledWith(UIFeature.TimelineEnableRelativeDates);
|
||||
});
|
||||
|
||||
it.each(testCases)('formats date correctly when current time is %s', (_d, ts, result) => {
|
||||
it.each(testCases)("formats date correctly when current time is %s", (_d, ts, result) => {
|
||||
expect(getComponent({ ts, forExport: false }).container.textContent).toEqual(result);
|
||||
});
|
||||
|
||||
describe('when forExport is true', () => {
|
||||
it.each(testCases)('formats date in full when current time is %s', (_d, ts) => {
|
||||
expect(getComponent({ ts, forExport: true }).container.textContent)
|
||||
.toEqual(formatFullDateNoTime(new Date(ts)));
|
||||
describe("when forExport is true", () => {
|
||||
it.each(testCases)("formats date in full when current time is %s", (_d, ts) => {
|
||||
expect(getComponent({ ts, forExport: true }).container.textContent).toEqual(
|
||||
formatFullDateNoTime(new Date(ts)),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when Settings.TimelineEnableRelativeDates is falsy', () => {
|
||||
describe("when Settings.TimelineEnableRelativeDates is falsy", () => {
|
||||
beforeEach(() => {
|
||||
(SettingsStore.getValue as jest.Mock) = jest.fn((arg) => {
|
||||
if (arg === UIFeature.TimelineEnableRelativeDates) {
|
||||
|
@ -105,13 +106,14 @@ describe("DateSeparator", () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
it.each(testCases)('formats date in full when current time is %s', (_d, ts) => {
|
||||
expect(getComponent({ ts, forExport: false }).container.textContent)
|
||||
.toEqual(formatFullDateNoTime(new Date(ts)));
|
||||
it.each(testCases)("formats date in full when current time is %s", (_d, ts) => {
|
||||
expect(getComponent({ ts, forExport: false }).container.textContent).toEqual(
|
||||
formatFullDateNoTime(new Date(ts)),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when feature_jump_to_date is enabled', () => {
|
||||
describe("when feature_jump_to_date is enabled", () => {
|
||||
beforeEach(() => {
|
||||
mocked(SettingsStore).getValue.mockImplementation((arg): any => {
|
||||
if (arg === "feature_jump_to_date") {
|
||||
|
@ -119,7 +121,7 @@ describe("DateSeparator", () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
it('renders the date separator correctly', () => {
|
||||
it("renders the date separator correctly", () => {
|
||||
const { asFragment } = getComponent();
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -14,22 +14,24 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import { mocked } from "jest-mock";
|
||||
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render, screen } from "@testing-library/react";
|
||||
|
||||
import EncryptionEvent from "../../../../src/components/views/messages/EncryptionEvent";
|
||||
import { createTestClient, mkMessage } from "../../../test-utils";
|
||||
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||
import { LocalRoom } from '../../../../src/models/LocalRoom';
|
||||
import DMRoomMap from '../../../../src/utils/DMRoomMap';
|
||||
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import { LocalRoom } from "../../../../src/models/LocalRoom";
|
||||
import DMRoomMap from "../../../../src/utils/DMRoomMap";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
|
||||
const renderEncryptionEvent = (client: MatrixClient, event: MatrixEvent) => {
|
||||
render(<MatrixClientContext.Provider value={client}>
|
||||
<EncryptionEvent mxEvent={event} />
|
||||
</MatrixClientContext.Provider>);
|
||||
render(
|
||||
<MatrixClientContext.Provider value={client}>
|
||||
<EncryptionEvent mxEvent={event} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
};
|
||||
|
||||
const checkTexts = (title: string, subTitle: string) => {
|
||||
|
@ -69,8 +71,8 @@ describe("EncryptionEvent", () => {
|
|||
renderEncryptionEvent(client, event);
|
||||
checkTexts(
|
||||
"Encryption enabled",
|
||||
"Messages in this room are end-to-end encrypted. "
|
||||
+ "When people join, you can verify them in their profile, just tap on their avatar.",
|
||||
"Messages in this room are end-to-end encrypted. " +
|
||||
"When people join, you can verify them in their profile, just tap on their avatar.",
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -83,10 +85,7 @@ describe("EncryptionEvent", () => {
|
|||
|
||||
it("should show the expected texts", () => {
|
||||
renderEncryptionEvent(client, event);
|
||||
checkTexts(
|
||||
"Encryption enabled",
|
||||
"Some encryption parameters have been changed.",
|
||||
);
|
||||
checkTexts("Encryption enabled", "Some encryption parameters have been changed.");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -14,68 +14,58 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import {
|
||||
BeaconEvent,
|
||||
getBeaconInfoIdentifier,
|
||||
RelationType,
|
||||
MatrixEvent,
|
||||
EventType,
|
||||
} from 'matrix-js-sdk/src/matrix';
|
||||
import { Relations } from 'matrix-js-sdk/src/models/relations';
|
||||
import { M_BEACON } from 'matrix-js-sdk/src/@types/beacon';
|
||||
import { mount } from "enzyme";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import maplibregl from "maplibre-gl";
|
||||
import { BeaconEvent, getBeaconInfoIdentifier, RelationType, MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
|
||||
import { Relations } from "matrix-js-sdk/src/models/relations";
|
||||
import { M_BEACON } from "matrix-js-sdk/src/@types/beacon";
|
||||
|
||||
import MBeaconBody from '../../../../src/components/views/messages/MBeaconBody';
|
||||
import MBeaconBody from "../../../../src/components/views/messages/MBeaconBody";
|
||||
import {
|
||||
getMockClientWithEventEmitter,
|
||||
makeBeaconEvent,
|
||||
makeBeaconInfoEvent,
|
||||
makeRoomWithBeacons,
|
||||
makeRoomWithStateEvents,
|
||||
} from '../../../test-utils';
|
||||
import { RoomPermalinkCreator } from '../../../../src/utils/permalinks/Permalinks';
|
||||
import { MediaEventHelper } from '../../../../src/utils/MediaEventHelper';
|
||||
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
||||
import Modal from '../../../../src/Modal';
|
||||
import { TILE_SERVER_WK_KEY } from '../../../../src/utils/WellKnownUtils';
|
||||
import { MapError } from '../../../../src/components/views/location/MapError';
|
||||
import * as mapUtilHooks from '../../../../src/utils/location/useMap';
|
||||
import { LocationShareError } from '../../../../src/utils/location';
|
||||
} from "../../../test-utils";
|
||||
import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks";
|
||||
import { MediaEventHelper } from "../../../../src/utils/MediaEventHelper";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import Modal from "../../../../src/Modal";
|
||||
import { TILE_SERVER_WK_KEY } from "../../../../src/utils/WellKnownUtils";
|
||||
import { MapError } from "../../../../src/components/views/location/MapError";
|
||||
import * as mapUtilHooks from "../../../../src/utils/location/useMap";
|
||||
import { LocationShareError } from "../../../../src/utils/location";
|
||||
|
||||
describe('<MBeaconBody />', () => {
|
||||
describe("<MBeaconBody />", () => {
|
||||
// 14.03.2022 16:15
|
||||
const now = 1647270879403;
|
||||
// stable date for snapshots
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(now);
|
||||
const roomId = '!room:server';
|
||||
const aliceId = '@alice:server';
|
||||
jest.spyOn(global.Date, "now").mockReturnValue(now);
|
||||
const roomId = "!room:server";
|
||||
const aliceId = "@alice:server";
|
||||
|
||||
const mockMap = new maplibregl.Map();
|
||||
const mockMarker = new maplibregl.Marker();
|
||||
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getClientWellKnown: jest.fn().mockReturnValue({
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: 'maps.com' },
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: "maps.com" },
|
||||
}),
|
||||
getUserId: jest.fn().mockReturnValue(aliceId),
|
||||
getRoom: jest.fn(),
|
||||
redactEvent: jest.fn(),
|
||||
});
|
||||
|
||||
const defaultEvent = makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ isLive: true },
|
||||
'$alice-room1-1',
|
||||
);
|
||||
const defaultEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: true }, "$alice-room1-1");
|
||||
|
||||
const defaultProps = {
|
||||
mxEvent: defaultEvent,
|
||||
highlights: [],
|
||||
highlightLink: '',
|
||||
highlightLink: "",
|
||||
onHeightChanged: jest.fn(),
|
||||
onMessageAllowed: jest.fn(),
|
||||
// we dont use these and they pollute the snapshots
|
||||
|
@ -89,7 +79,7 @@ describe('<MBeaconBody />', () => {
|
|||
wrappingComponentProps: { value: mockClient },
|
||||
});
|
||||
|
||||
const modalSpy = jest.spyOn(Modal, 'createDialog').mockReturnValue(undefined);
|
||||
const modalSpy = jest.spyOn(Modal, "createDialog").mockReturnValue(undefined);
|
||||
|
||||
beforeAll(() => {
|
||||
maplibregl.AttributionControl = jest.fn();
|
||||
|
@ -100,73 +90,66 @@ describe('<MBeaconBody />', () => {
|
|||
});
|
||||
|
||||
const testBeaconStatuses = () => {
|
||||
it('renders stopped beacon UI for an explicitly stopped beacon', () => {
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ isLive: false },
|
||||
'$alice-room1-1',
|
||||
);
|
||||
it("renders stopped beacon UI for an explicitly stopped beacon", () => {
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: false }, "$alice-room1-1");
|
||||
makeRoomWithStateEvents([beaconInfoEvent], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: beaconInfoEvent });
|
||||
expect(component.text()).toEqual("Live location ended");
|
||||
});
|
||||
|
||||
it('renders stopped beacon UI for an expired beacon', () => {
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(aliceId,
|
||||
it("renders stopped beacon UI for an expired beacon", () => {
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
roomId,
|
||||
// puts this beacons live period in the past
|
||||
{ isLive: true, timestamp: now - 600000, timeout: 500 },
|
||||
'$alice-room1-1',
|
||||
"$alice-room1-1",
|
||||
);
|
||||
makeRoomWithStateEvents([beaconInfoEvent], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: beaconInfoEvent });
|
||||
expect(component.text()).toEqual("Live location ended");
|
||||
});
|
||||
|
||||
it('renders loading beacon UI for a beacon that has not started yet', () => {
|
||||
it("renders loading beacon UI for a beacon that has not started yet", () => {
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
roomId,
|
||||
// puts this beacons start timestamp in the future
|
||||
{ isLive: true, timestamp: now + 60000, timeout: 500 },
|
||||
'$alice-room1-1',
|
||||
"$alice-room1-1",
|
||||
);
|
||||
makeRoomWithStateEvents([beaconInfoEvent], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: beaconInfoEvent });
|
||||
expect(component.text()).toEqual("Loading live location...");
|
||||
});
|
||||
|
||||
it('does not open maximised map when on click when beacon is stopped', () => {
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(aliceId,
|
||||
it("does not open maximised map when on click when beacon is stopped", () => {
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
roomId,
|
||||
// puts this beacons live period in the past
|
||||
{ isLive: true, timestamp: now - 600000, timeout: 500 },
|
||||
'$alice-room1-1',
|
||||
"$alice-room1-1",
|
||||
);
|
||||
makeRoomWithStateEvents([beaconInfoEvent], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: beaconInfoEvent });
|
||||
act(() => {
|
||||
component.find('.mx_MBeaconBody_map').at(0).simulate('click');
|
||||
component.find(".mx_MBeaconBody_map").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(modalSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('renders stopped UI when a beacon event is not the latest beacon for a user', () => {
|
||||
it("renders stopped UI when a beacon event is not the latest beacon for a user", () => {
|
||||
const aliceBeaconInfo1 = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
roomId,
|
||||
// this one is a little older
|
||||
{ isLive: true, timestamp: now - 500 },
|
||||
'$alice-room1-1',
|
||||
"$alice-room1-1",
|
||||
);
|
||||
aliceBeaconInfo1.event.origin_server_ts = now - 500;
|
||||
const aliceBeaconInfo2 = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
roomId,
|
||||
{ isLive: true },
|
||||
'$alice-room1-2',
|
||||
);
|
||||
const aliceBeaconInfo2 = makeBeaconInfoEvent(aliceId, roomId, { isLive: true }, "$alice-room1-2");
|
||||
|
||||
makeRoomWithStateEvents([aliceBeaconInfo1, aliceBeaconInfo2], { roomId, mockClient });
|
||||
|
||||
|
@ -175,21 +158,16 @@ describe('<MBeaconBody />', () => {
|
|||
expect(component.text()).toEqual("Live location ended");
|
||||
});
|
||||
|
||||
it('renders stopped UI when a beacon event is replaced', () => {
|
||||
it("renders stopped UI when a beacon event is replaced", () => {
|
||||
const aliceBeaconInfo1 = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
roomId,
|
||||
// this one is a little older
|
||||
{ isLive: true, timestamp: now - 500 },
|
||||
'$alice-room1-1',
|
||||
"$alice-room1-1",
|
||||
);
|
||||
aliceBeaconInfo1.event.origin_server_ts = now - 500;
|
||||
const aliceBeaconInfo2 = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
roomId,
|
||||
{ isLive: true },
|
||||
'$alice-room1-2',
|
||||
);
|
||||
const aliceBeaconInfo2 = makeBeaconInfoEvent(aliceId, roomId, { isLive: true }, "$alice-room1-2");
|
||||
|
||||
const room = makeRoomWithStateEvents([aliceBeaconInfo1], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo1 });
|
||||
|
@ -210,14 +188,9 @@ describe('<MBeaconBody />', () => {
|
|||
|
||||
testBeaconStatuses();
|
||||
|
||||
describe('on liveness change', () => {
|
||||
it('renders stopped UI when a beacon stops being live', () => {
|
||||
const aliceBeaconInfo = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
roomId,
|
||||
{ isLive: true },
|
||||
'$alice-room1-1',
|
||||
);
|
||||
describe("on liveness change", () => {
|
||||
it("renders stopped UI when a beacon stops being live", () => {
|
||||
const aliceBeaconInfo = makeBeaconInfoEvent(aliceId, roomId, { isLive: true }, "$alice-room1-1");
|
||||
|
||||
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo));
|
||||
|
@ -236,97 +209,96 @@ describe('<MBeaconBody />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('latestLocationState', () => {
|
||||
const aliceBeaconInfo = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
roomId,
|
||||
{ isLive: true },
|
||||
'$alice-room1-1',
|
||||
);
|
||||
describe("latestLocationState", () => {
|
||||
const aliceBeaconInfo = makeBeaconInfoEvent(aliceId, roomId, { isLive: true }, "$alice-room1-1");
|
||||
|
||||
const location1 = makeBeaconEvent(
|
||||
aliceId, { beaconInfoId: aliceBeaconInfo.getId(), geoUri: 'geo:51,41', timestamp: now + 1 },
|
||||
);
|
||||
const location2 = makeBeaconEvent(
|
||||
aliceId, { beaconInfoId: aliceBeaconInfo.getId(), geoUri: 'geo:52,42', timestamp: now + 10000 },
|
||||
);
|
||||
const location1 = makeBeaconEvent(aliceId, {
|
||||
beaconInfoId: aliceBeaconInfo.getId(),
|
||||
geoUri: "geo:51,41",
|
||||
timestamp: now + 1,
|
||||
});
|
||||
const location2 = makeBeaconEvent(aliceId, {
|
||||
beaconInfoId: aliceBeaconInfo.getId(),
|
||||
geoUri: "geo:52,42",
|
||||
timestamp: now + 10000,
|
||||
});
|
||||
|
||||
it('renders a live beacon without a location correctly', () => {
|
||||
it("renders a live beacon without a location correctly", () => {
|
||||
makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
expect(component.text()).toEqual("Loading live location...");
|
||||
});
|
||||
|
||||
it('does nothing on click when a beacon has no location', () => {
|
||||
it("does nothing on click when a beacon has no location", () => {
|
||||
makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
act(() => {
|
||||
component.find('.mx_MBeaconBody_map').at(0).simulate('click');
|
||||
component.find(".mx_MBeaconBody_map").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(modalSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('renders a live beacon with a location correctly', () => {
|
||||
it("renders a live beacon with a location correctly", () => {
|
||||
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo));
|
||||
beaconInstance.addLocations([location1]);
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
expect(component.find('Map').length).toBeTruthy;
|
||||
expect(component.find("Map").length).toBeTruthy;
|
||||
});
|
||||
|
||||
it('opens maximised map view on click when beacon has a live location', () => {
|
||||
it("opens maximised map view on click when beacon has a live location", () => {
|
||||
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo));
|
||||
beaconInstance.addLocations([location1]);
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
act(() => {
|
||||
component.find('Map').simulate('click');
|
||||
component.find("Map").simulate("click");
|
||||
});
|
||||
|
||||
// opens modal
|
||||
expect(modalSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does nothing on click when a beacon has no location', () => {
|
||||
it("does nothing on click when a beacon has no location", () => {
|
||||
makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
act(() => {
|
||||
component.find('.mx_MBeaconBody_map').at(0).simulate('click');
|
||||
component.find(".mx_MBeaconBody_map").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(modalSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('renders a live beacon with a location correctly', () => {
|
||||
it("renders a live beacon with a location correctly", () => {
|
||||
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo));
|
||||
beaconInstance.addLocations([location1]);
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
expect(component.find('Map').length).toBeTruthy;
|
||||
expect(component.find("Map").length).toBeTruthy;
|
||||
});
|
||||
|
||||
it('opens maximised map view on click when beacon has a live location', () => {
|
||||
it("opens maximised map view on click when beacon has a live location", () => {
|
||||
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo));
|
||||
beaconInstance.addLocations([location1]);
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
act(() => {
|
||||
component.find('Map').simulate('click');
|
||||
component.find("Map").simulate("click");
|
||||
});
|
||||
|
||||
// opens modal
|
||||
expect(modalSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('updates latest location', () => {
|
||||
it("updates latest location", () => {
|
||||
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
|
@ -349,33 +321,30 @@ describe('<MBeaconBody />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('redaction', () => {
|
||||
describe("redaction", () => {
|
||||
const makeEvents = (): {
|
||||
beaconInfoEvent: MatrixEvent;
|
||||
location1: MatrixEvent;
|
||||
location2: MatrixEvent;
|
||||
} => {
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
roomId,
|
||||
{ isLive: true },
|
||||
'$alice-room1-1',
|
||||
);
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: true }, "$alice-room1-1");
|
||||
|
||||
const location1 = makeBeaconEvent(
|
||||
aliceId, { beaconInfoId: beaconInfoEvent.getId(), geoUri: 'geo:51,41', timestamp: now + 1 },
|
||||
aliceId,
|
||||
{ beaconInfoId: beaconInfoEvent.getId(), geoUri: "geo:51,41", timestamp: now + 1 },
|
||||
roomId,
|
||||
);
|
||||
location1.event.event_id = '1';
|
||||
location1.event.event_id = "1";
|
||||
const location2 = makeBeaconEvent(
|
||||
aliceId, { beaconInfoId: beaconInfoEvent.getId(), geoUri: 'geo:52,42', timestamp: now + 10000 },
|
||||
aliceId,
|
||||
{ beaconInfoId: beaconInfoEvent.getId(), geoUri: "geo:52,42", timestamp: now + 10000 },
|
||||
roomId,
|
||||
);
|
||||
location2.event.event_id = '2';
|
||||
location2.event.event_id = "2";
|
||||
return { beaconInfoEvent, location1, location2 };
|
||||
};
|
||||
|
||||
const redactionEvent = new MatrixEvent({ type: EventType.RoomRedaction, content: { reason: 'test reason' } });
|
||||
const redactionEvent = new MatrixEvent({ type: EventType.RoomRedaction, content: { reason: "test reason" } });
|
||||
|
||||
const setupRoomWithBeacon = (beaconInfoEvent, locationEvents: MatrixEvent[] = []) => {
|
||||
const room = makeRoomWithStateEvents([beaconInfoEvent], { roomId, mockClient });
|
||||
|
@ -384,14 +353,14 @@ describe('<MBeaconBody />', () => {
|
|||
};
|
||||
const mockGetRelationsForEvent = (locationEvents: MatrixEvent[] = []) => {
|
||||
const relations = new Relations(RelationType.Reference, M_BEACON.name, mockClient);
|
||||
jest.spyOn(relations, 'getRelations').mockReturnValue(locationEvents);
|
||||
jest.spyOn(relations, "getRelations").mockReturnValue(locationEvents);
|
||||
|
||||
const getRelationsForEvent = jest.fn().mockReturnValue(relations);
|
||||
|
||||
return getRelationsForEvent;
|
||||
};
|
||||
|
||||
it('does nothing when getRelationsForEvent is falsy', () => {
|
||||
it("does nothing when getRelationsForEvent is falsy", () => {
|
||||
const { beaconInfoEvent, location1, location2 } = makeEvents();
|
||||
setupRoomWithBeacon(beaconInfoEvent, [location1, location2]);
|
||||
|
||||
|
@ -405,10 +374,10 @@ describe('<MBeaconBody />', () => {
|
|||
expect(mockClient.redactEvent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('cleans up redaction listener on unmount', () => {
|
||||
it("cleans up redaction listener on unmount", () => {
|
||||
const { beaconInfoEvent, location1, location2 } = makeEvents();
|
||||
setupRoomWithBeacon(beaconInfoEvent, [location1, location2]);
|
||||
const removeListenerSpy = jest.spyOn(beaconInfoEvent, 'removeListener');
|
||||
const removeListenerSpy = jest.spyOn(beaconInfoEvent, "removeListener");
|
||||
|
||||
const component = getComponent({ mxEvent: beaconInfoEvent });
|
||||
|
||||
|
@ -419,7 +388,7 @@ describe('<MBeaconBody />', () => {
|
|||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does nothing when beacon has no related locations', async () => {
|
||||
it("does nothing when beacon has no related locations", async () => {
|
||||
const { beaconInfoEvent } = makeEvents();
|
||||
// no locations
|
||||
setupRoomWithBeacon(beaconInfoEvent, []);
|
||||
|
@ -432,12 +401,14 @@ describe('<MBeaconBody />', () => {
|
|||
});
|
||||
|
||||
expect(getRelationsForEvent).toHaveBeenCalledWith(
|
||||
beaconInfoEvent.getId(), RelationType.Reference, M_BEACON.name,
|
||||
beaconInfoEvent.getId(),
|
||||
RelationType.Reference,
|
||||
M_BEACON.name,
|
||||
);
|
||||
expect(mockClient.redactEvent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('redacts related locations on beacon redaction', async () => {
|
||||
it("redacts related locations on beacon redaction", async () => {
|
||||
const { beaconInfoEvent, location1, location2 } = makeEvents();
|
||||
setupRoomWithBeacon(beaconInfoEvent, [location1, location2]);
|
||||
|
||||
|
@ -450,43 +421,36 @@ describe('<MBeaconBody />', () => {
|
|||
});
|
||||
|
||||
expect(getRelationsForEvent).toHaveBeenCalledWith(
|
||||
beaconInfoEvent.getId(), RelationType.Reference, M_BEACON.name,
|
||||
beaconInfoEvent.getId(),
|
||||
RelationType.Reference,
|
||||
M_BEACON.name,
|
||||
);
|
||||
expect(mockClient.redactEvent).toHaveBeenCalledTimes(2);
|
||||
expect(mockClient.redactEvent).toHaveBeenCalledWith(
|
||||
roomId,
|
||||
location1.getId(),
|
||||
undefined,
|
||||
{ reason: 'test reason' },
|
||||
);
|
||||
expect(mockClient.redactEvent).toHaveBeenCalledWith(
|
||||
roomId,
|
||||
location2.getId(),
|
||||
undefined,
|
||||
{ reason: 'test reason' },
|
||||
);
|
||||
expect(mockClient.redactEvent).toHaveBeenCalledWith(roomId, location1.getId(), undefined, {
|
||||
reason: "test reason",
|
||||
});
|
||||
expect(mockClient.redactEvent).toHaveBeenCalledWith(roomId, location2.getId(), undefined, {
|
||||
reason: "test reason",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when map display is not configured', () => {
|
||||
describe("when map display is not configured", () => {
|
||||
beforeEach(() => {
|
||||
// mock map utils to raise MapStyleUrlNotConfigured error
|
||||
jest.spyOn(mapUtilHooks, 'useMap').mockImplementation(
|
||||
({ onError }) => {
|
||||
onError(new Error(LocationShareError.MapStyleUrlNotConfigured));
|
||||
return mockMap;
|
||||
});
|
||||
jest.spyOn(mapUtilHooks, "useMap").mockImplementation(({ onError }) => {
|
||||
onError(new Error(LocationShareError.MapStyleUrlNotConfigured));
|
||||
return mockMap;
|
||||
});
|
||||
});
|
||||
|
||||
it('renders maps unavailable error for a live beacon with location', () => {
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ isLive: true },
|
||||
'$alice-room1-1',
|
||||
);
|
||||
const location1 = makeBeaconEvent(
|
||||
aliceId, { beaconInfoId: beaconInfoEvent.getId(), geoUri: 'geo:51,41', timestamp: now + 1 },
|
||||
);
|
||||
it("renders maps unavailable error for a live beacon with location", () => {
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: true }, "$alice-room1-1");
|
||||
const location1 = makeBeaconEvent(aliceId, {
|
||||
beaconInfoId: beaconInfoEvent.getId(),
|
||||
geoUri: "geo:51,41",
|
||||
timestamp: now + 1,
|
||||
});
|
||||
|
||||
makeRoomWithBeacons(roomId, mockClient, [beaconInfoEvent], [location1]);
|
||||
|
||||
|
|
|
@ -48,8 +48,8 @@ describe("<MImageBody/>", () => {
|
|||
getIgnoredUsers: jest.fn(),
|
||||
getVersions: jest.fn().mockResolvedValue({
|
||||
unstable_features: {
|
||||
'org.matrix.msc3882': true,
|
||||
'org.matrix.msc3886': true,
|
||||
"org.matrix.msc3882": true,
|
||||
"org.matrix.msc3886": true,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
@ -75,11 +75,13 @@ describe("<MImageBody/>", () => {
|
|||
it("should show error when encrypted media cannot be downloaded", async () => {
|
||||
fetchMock.getOnce(url, { status: 500 });
|
||||
|
||||
render(<MImageBody
|
||||
{...props}
|
||||
mxEvent={encryptedMediaEvent}
|
||||
mediaEventHelper={new MediaEventHelper(encryptedMediaEvent)}
|
||||
/>);
|
||||
render(
|
||||
<MImageBody
|
||||
{...props}
|
||||
mxEvent={encryptedMediaEvent}
|
||||
mediaEventHelper={new MediaEventHelper(encryptedMediaEvent)}
|
||||
/>,
|
||||
);
|
||||
|
||||
await screen.findByText("Error downloading image");
|
||||
});
|
||||
|
@ -88,11 +90,13 @@ describe("<MImageBody/>", () => {
|
|||
fetchMock.getOnce(url, "thisistotallyanencryptedpng");
|
||||
mocked(encrypt.decryptAttachment).mockRejectedValue(new Error("Failed to decrypt"));
|
||||
|
||||
render(<MImageBody
|
||||
{...props}
|
||||
mxEvent={encryptedMediaEvent}
|
||||
mediaEventHelper={new MediaEventHelper(encryptedMediaEvent)}
|
||||
/>);
|
||||
render(
|
||||
<MImageBody
|
||||
{...props}
|
||||
mxEvent={encryptedMediaEvent}
|
||||
mediaEventHelper={new MediaEventHelper(encryptedMediaEvent)}
|
||||
/>,
|
||||
);
|
||||
|
||||
await screen.findByText("Error decrypting image");
|
||||
});
|
||||
|
|
|
@ -14,33 +14,40 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import TestRenderer from 'react-test-renderer';
|
||||
import { EventEmitter } from 'events';
|
||||
import { MatrixEvent, EventType } from 'matrix-js-sdk/src/matrix';
|
||||
import { CryptoEvent } from 'matrix-js-sdk/src/crypto';
|
||||
import { UserTrustLevel } from 'matrix-js-sdk/src/crypto/CrossSigning';
|
||||
import { VerificationRequest } from 'matrix-js-sdk/src/crypto/verification/request/VerificationRequest';
|
||||
import React from "react";
|
||||
import TestRenderer from "react-test-renderer";
|
||||
import { EventEmitter } from "events";
|
||||
import { MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
|
||||
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
|
||||
import { UserTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
|
||||
import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||
|
||||
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||
import MKeyVerificationConclusion from '../../../../src/components/views/messages/MKeyVerificationConclusion';
|
||||
import { getMockClientWithEventEmitter } from '../../../test-utils';
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import MKeyVerificationConclusion from "../../../../src/components/views/messages/MKeyVerificationConclusion";
|
||||
import { getMockClientWithEventEmitter } from "../../../test-utils";
|
||||
|
||||
const trustworthy = ({ isCrossSigningVerified: () => true }) as unknown as UserTrustLevel;
|
||||
const untrustworthy = ({ isCrossSigningVerified: () => false }) as unknown as UserTrustLevel;
|
||||
const trustworthy = { isCrossSigningVerified: () => true } as unknown as UserTrustLevel;
|
||||
const untrustworthy = { isCrossSigningVerified: () => false } as unknown as UserTrustLevel;
|
||||
|
||||
describe("MKeyVerificationConclusion", () => {
|
||||
const userId = '@user:server';
|
||||
const userId = "@user:server";
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getRoom: jest.fn(),
|
||||
getUserId: jest.fn().mockReturnValue(userId),
|
||||
checkUserTrust: jest.fn(),
|
||||
});
|
||||
|
||||
const getMockVerificationRequest = (
|
||||
{ pending, cancelled, done, otherUserId }:
|
||||
{ pending?: boolean, cancelled?: boolean, done?: boolean, otherUserId?: string },
|
||||
) => {
|
||||
const getMockVerificationRequest = ({
|
||||
pending,
|
||||
cancelled,
|
||||
done,
|
||||
otherUserId,
|
||||
}: {
|
||||
pending?: boolean;
|
||||
cancelled?: boolean;
|
||||
done?: boolean;
|
||||
otherUserId?: string;
|
||||
}) => {
|
||||
class MockVerificationRequest extends EventEmitter {
|
||||
constructor(
|
||||
public readonly pending: boolean,
|
||||
|
@ -60,41 +67,33 @@ describe("MKeyVerificationConclusion", () => {
|
|||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(MatrixClientPeg, 'get').mockRestore();
|
||||
jest.spyOn(MatrixClientPeg, "get").mockRestore();
|
||||
});
|
||||
|
||||
it("shouldn't render if there's no verificationRequest", () => {
|
||||
const event = new MatrixEvent({});
|
||||
const renderer = TestRenderer.create(
|
||||
<MKeyVerificationConclusion mxEvent={event} />,
|
||||
);
|
||||
const renderer = TestRenderer.create(<MKeyVerificationConclusion mxEvent={event} />);
|
||||
expect(renderer.toJSON()).toBeNull();
|
||||
});
|
||||
|
||||
it("shouldn't render if the verificationRequest is pending", () => {
|
||||
const event = new MatrixEvent({});
|
||||
event.verificationRequest = getMockVerificationRequest({ pending: true });
|
||||
const renderer = TestRenderer.create(
|
||||
<MKeyVerificationConclusion mxEvent={event} />,
|
||||
);
|
||||
const renderer = TestRenderer.create(<MKeyVerificationConclusion mxEvent={event} />);
|
||||
expect(renderer.toJSON()).toBeNull();
|
||||
});
|
||||
|
||||
it("shouldn't render if the event type is cancel but the request type isn't", () => {
|
||||
const event = new MatrixEvent({ type: EventType.KeyVerificationCancel });
|
||||
event.verificationRequest = getMockVerificationRequest({ cancelled: false });
|
||||
const renderer = TestRenderer.create(
|
||||
<MKeyVerificationConclusion mxEvent={event} />,
|
||||
);
|
||||
const renderer = TestRenderer.create(<MKeyVerificationConclusion mxEvent={event} />);
|
||||
expect(renderer.toJSON()).toBeNull();
|
||||
});
|
||||
|
||||
it("shouldn't render if the event type is done but the request type isn't", () => {
|
||||
const event = new MatrixEvent({ type: "m.key.verification.done" });
|
||||
event.verificationRequest = getMockVerificationRequest({ done: false });
|
||||
const renderer = TestRenderer.create(
|
||||
<MKeyVerificationConclusion mxEvent={event} />,
|
||||
);
|
||||
const renderer = TestRenderer.create(<MKeyVerificationConclusion mxEvent={event} />);
|
||||
expect(renderer.toJSON()).toBeNull();
|
||||
});
|
||||
|
||||
|
@ -103,9 +102,7 @@ describe("MKeyVerificationConclusion", () => {
|
|||
|
||||
const event = new MatrixEvent({ type: "m.key.verification.done" });
|
||||
event.verificationRequest = getMockVerificationRequest({ done: true });
|
||||
const renderer = TestRenderer.create(
|
||||
<MKeyVerificationConclusion mxEvent={event} />,
|
||||
);
|
||||
const renderer = TestRenderer.create(<MKeyVerificationConclusion mxEvent={event} />);
|
||||
expect(renderer.toJSON()).toBeNull();
|
||||
});
|
||||
|
||||
|
@ -114,9 +111,7 @@ describe("MKeyVerificationConclusion", () => {
|
|||
|
||||
const event = new MatrixEvent({ type: "m.key.verification.done" });
|
||||
event.verificationRequest = getMockVerificationRequest({ done: true, otherUserId: "@someuser:domain" });
|
||||
const renderer = TestRenderer.create(
|
||||
<MKeyVerificationConclusion mxEvent={event} />,
|
||||
);
|
||||
const renderer = TestRenderer.create(<MKeyVerificationConclusion mxEvent={event} />);
|
||||
expect(renderer.toJSON()).toBeNull();
|
||||
|
||||
mockClient.checkUserTrust.mockReturnValue(trustworthy);
|
||||
|
|
|
@ -14,33 +14,33 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from "enzyme";
|
||||
import { LocationAssetType } from "matrix-js-sdk/src/@types/location";
|
||||
import { ClientEvent, RoomMember } from 'matrix-js-sdk/src/matrix';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
import { logger } from 'matrix-js-sdk/src/logger';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { SyncState } from 'matrix-js-sdk/src/sync';
|
||||
import { ClientEvent, RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
import maplibregl from "maplibre-gl";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { SyncState } from "matrix-js-sdk/src/sync";
|
||||
|
||||
import MLocationBody from "../../../../src/components/views/messages/MLocationBody";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks";
|
||||
import { MediaEventHelper } from "../../../../src/utils/MediaEventHelper";
|
||||
import Modal from '../../../../src/Modal';
|
||||
import Modal from "../../../../src/Modal";
|
||||
import SdkConfig from "../../../../src/SdkConfig";
|
||||
import { TILE_SERVER_WK_KEY } from '../../../../src/utils/WellKnownUtils';
|
||||
import { TILE_SERVER_WK_KEY } from "../../../../src/utils/WellKnownUtils";
|
||||
import { makeLocationEvent } from "../../../test-utils/location";
|
||||
import { getMockClientWithEventEmitter } from '../../../test-utils';
|
||||
import { getMockClientWithEventEmitter } from "../../../test-utils";
|
||||
|
||||
describe("MLocationBody", () => {
|
||||
describe('<MLocationBody>', () => {
|
||||
const roomId = '!room:server';
|
||||
const userId = '@user:server';
|
||||
describe("<MLocationBody>", () => {
|
||||
const roomId = "!room:server";
|
||||
const userId = "@user:server";
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getClientWellKnown: jest.fn().mockReturnValue({
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: 'maps.com' },
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: "maps.com" },
|
||||
}),
|
||||
isGuest: jest.fn().mockReturnValue(false),
|
||||
});
|
||||
|
@ -48,26 +48,27 @@ describe("MLocationBody", () => {
|
|||
const defaultProps = {
|
||||
mxEvent: defaultEvent,
|
||||
highlights: [],
|
||||
highlightLink: '',
|
||||
highlightLink: "",
|
||||
onHeightChanged: jest.fn(),
|
||||
onMessageAllowed: jest.fn(),
|
||||
permalinkCreator: {} as RoomPermalinkCreator,
|
||||
mediaEventHelper: {} as MediaEventHelper,
|
||||
};
|
||||
const getComponent = (props = {}) => mount(<MLocationBody {...defaultProps} {...props} />, {
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: { value: mockClient },
|
||||
});
|
||||
const getComponent = (props = {}) =>
|
||||
mount(<MLocationBody {...defaultProps} {...props} />, {
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: { value: mockClient },
|
||||
});
|
||||
const getMapErrorComponent = () => {
|
||||
const mockMap = new maplibregl.Map();
|
||||
mockClient.getClientWellKnown.mockReturnValue({
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: 'bad-tile-server.com' },
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: "bad-tile-server.com" },
|
||||
});
|
||||
const component = getComponent();
|
||||
|
||||
// simulate error initialising map in maplibregl
|
||||
// @ts-ignore
|
||||
mockMap.emit('error', { status: 404 });
|
||||
mockMap.emit("error", { status: 404 });
|
||||
|
||||
return component;
|
||||
};
|
||||
|
@ -80,33 +81,33 @@ describe("MLocationBody", () => {
|
|||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('with error', () => {
|
||||
describe("with error", () => {
|
||||
let sdkConfigSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
// eat expected errors to keep console clean
|
||||
jest.spyOn(logger, 'error').mockImplementation(() => { });
|
||||
jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||
mockClient.getClientWellKnown.mockReturnValue({});
|
||||
sdkConfigSpy = jest.spyOn(SdkConfig, 'get').mockReturnValue({});
|
||||
sdkConfigSpy = jest.spyOn(SdkConfig, "get").mockReturnValue({});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
sdkConfigSpy.mockRestore();
|
||||
jest.spyOn(logger, 'error').mockRestore();
|
||||
jest.spyOn(logger, "error").mockRestore();
|
||||
});
|
||||
|
||||
it('displays correct fallback content without error style when map_style_url is not configured', () => {
|
||||
it("displays correct fallback content without error style when map_style_url is not configured", () => {
|
||||
const component = getComponent();
|
||||
expect(component.find(".mx_EventTile_body")).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('displays correct fallback content when map_style_url is misconfigured', () => {
|
||||
it("displays correct fallback content when map_style_url is misconfigured", () => {
|
||||
const component = getMapErrorComponent();
|
||||
component.setProps({});
|
||||
expect(component.find(".mx_EventTile_body")).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should clear the error on reconnect', () => {
|
||||
it("should clear the error on reconnect", () => {
|
||||
const component = getMapErrorComponent();
|
||||
expect((component.state() as React.ComponentState).error).toBeDefined();
|
||||
mockClient.emit(ClientEvent.Sync, SyncState.Reconnecting, SyncState.Error);
|
||||
|
@ -114,57 +115,58 @@ describe("MLocationBody", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('without error', () => {
|
||||
describe("without error", () => {
|
||||
beforeEach(() => {
|
||||
mockClient.getClientWellKnown.mockReturnValue({
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: 'maps.com' },
|
||||
[TILE_SERVER_WK_KEY.name]: { map_style_url: "maps.com" },
|
||||
});
|
||||
|
||||
// MLocationBody uses random number for map id
|
||||
// stabilise for test
|
||||
jest.spyOn(global.Math, 'random').mockReturnValue(0.123456);
|
||||
jest.spyOn(global.Math, "random").mockReturnValue(0.123456);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(global.Math, 'random').mockRestore();
|
||||
jest.spyOn(global.Math, "random").mockRestore();
|
||||
});
|
||||
|
||||
it('renders map correctly', () => {
|
||||
it("renders map correctly", () => {
|
||||
const mockMap = new maplibregl.Map();
|
||||
const component = getComponent();
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
// map was centered
|
||||
expect(mockMap.setCenter).toHaveBeenCalledWith({
|
||||
lat: 51.5076, lon: -0.1276,
|
||||
lat: 51.5076,
|
||||
lon: -0.1276,
|
||||
});
|
||||
});
|
||||
|
||||
it('opens map dialog on click', () => {
|
||||
const modalSpy = jest.spyOn(Modal, 'createDialog').mockReturnValue(undefined);
|
||||
it("opens map dialog on click", () => {
|
||||
const modalSpy = jest.spyOn(Modal, "createDialog").mockReturnValue(undefined);
|
||||
const component = getComponent();
|
||||
|
||||
act(() => {
|
||||
component.find('Map').at(0).simulate('click');
|
||||
component.find("Map").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(modalSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('renders marker correctly for a non-self share', () => {
|
||||
it("renders marker correctly for a non-self share", () => {
|
||||
const mockMap = new maplibregl.Map();
|
||||
const component = getComponent();
|
||||
|
||||
expect(component.find('SmartMarker').at(0).props()).toEqual(
|
||||
expect(component.find("SmartMarker").at(0).props()).toEqual(
|
||||
expect.objectContaining({
|
||||
map: mockMap,
|
||||
geoUri: 'geo:51.5076,-0.1276',
|
||||
geoUri: "geo:51.5076,-0.1276",
|
||||
roomMember: undefined,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('renders marker correctly for a self share', () => {
|
||||
it("renders marker correctly for a self share", () => {
|
||||
const selfShareEvent = makeLocationEvent("geo:51.5076,-0.1276", LocationAssetType.Self);
|
||||
const member = new RoomMember(roomId, userId);
|
||||
// @ts-ignore cheat assignment to property
|
||||
|
@ -172,9 +174,7 @@ describe("MLocationBody", () => {
|
|||
const component = getComponent({ mxEvent: selfShareEvent });
|
||||
|
||||
// render self locations with user avatars
|
||||
expect(component.find('SmartMarker').at(0).props()['roomMember']).toEqual(
|
||||
member,
|
||||
);
|
||||
expect(component.find("SmartMarker").at(0).props()["roomMember"]).toEqual(member);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -49,7 +49,7 @@ const CHECKED = "mx_MPollBody_option_checked";
|
|||
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getUserId: jest.fn().mockReturnValue("@me:example.com"),
|
||||
sendEvent: jest.fn().mockReturnValue(Promise.resolve({ "event_id": "fake_send_id" })),
|
||||
sendEvent: jest.fn().mockReturnValue(Promise.resolve({ event_id: "fake_send_id" })),
|
||||
getRoom: jest.fn(),
|
||||
});
|
||||
|
||||
|
@ -76,9 +76,7 @@ describe("MPollBody", () => {
|
|||
const ev2 = responseEvent();
|
||||
const badEvent = badResponseEvent();
|
||||
|
||||
const voteRelations = new RelatedRelations([
|
||||
newVoteRelations([ev1, badEvent, ev2]),
|
||||
]);
|
||||
const voteRelations = new RelatedRelations([newVoteRelations([ev1, badEvent, ev2])]);
|
||||
expect(
|
||||
allVotes(
|
||||
{ getRoomId: () => "$room" } as MatrixEvent,
|
||||
|
@ -87,21 +85,13 @@ describe("MPollBody", () => {
|
|||
new RelatedRelations([newEndRelations([])]),
|
||||
),
|
||||
).toEqual([
|
||||
new UserVote(
|
||||
ev1.getTs(),
|
||||
ev1.getSender(),
|
||||
ev1.getContent()[M_POLL_RESPONSE.name].answers,
|
||||
),
|
||||
new UserVote(ev1.getTs(), ev1.getSender(), ev1.getContent()[M_POLL_RESPONSE.name].answers),
|
||||
new UserVote(
|
||||
badEvent.getTs(),
|
||||
badEvent.getSender(),
|
||||
[], // should be spoiled
|
||||
),
|
||||
new UserVote(
|
||||
ev2.getTs(),
|
||||
ev2.getSender(),
|
||||
ev2.getContent()[M_POLL_RESPONSE.name].answers,
|
||||
),
|
||||
new UserVote(ev2.getTs(), ev2.getSender(), ev2.getContent()[M_POLL_RESPONSE.name].answers),
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -117,13 +107,7 @@ describe("MPollBody", () => {
|
|||
|
||||
setRedactionAllowedForMeOnly(mockClient);
|
||||
|
||||
expect(
|
||||
pollEndTs(
|
||||
{ getRoomId: () => "$room" } as MatrixEvent,
|
||||
mockClient,
|
||||
endRelations,
|
||||
),
|
||||
).toBe(12);
|
||||
expect(pollEndTs({ getRoomId: () => "$room" } as MatrixEvent, mockClient, endRelations)).toBe(12);
|
||||
});
|
||||
|
||||
it("ignores unauthorised end poll event when finding end ts", () => {
|
||||
|
@ -138,13 +122,7 @@ describe("MPollBody", () => {
|
|||
|
||||
setRedactionAllowedForMeOnly(mockClient);
|
||||
|
||||
expect(
|
||||
pollEndTs(
|
||||
{ getRoomId: () => "$room" } as MatrixEvent,
|
||||
mockClient,
|
||||
endRelations,
|
||||
),
|
||||
).toBe(13);
|
||||
expect(pollEndTs({ getRoomId: () => "$room" } as MatrixEvent, mockClient, endRelations)).toBe(13);
|
||||
});
|
||||
|
||||
it("counts only votes before the end poll event", () => {
|
||||
|
@ -157,18 +135,9 @@ describe("MPollBody", () => {
|
|||
responseEvent("ps@matrix.org", "wings", 19),
|
||||
]),
|
||||
]);
|
||||
const endRelations = new RelatedRelations([
|
||||
newEndRelations([
|
||||
endEvent("@me:example.com", 25),
|
||||
]),
|
||||
]);
|
||||
const endRelations = new RelatedRelations([newEndRelations([endEvent("@me:example.com", 25)])]);
|
||||
expect(
|
||||
allVotes(
|
||||
{ getRoomId: () => "$room" } as MatrixEvent,
|
||||
MatrixClientPeg.get(),
|
||||
voteRelations,
|
||||
endRelations,
|
||||
),
|
||||
allVotes({ getRoomId: () => "$room" } as MatrixEvent, MatrixClientPeg.get(), voteRelations, endRelations),
|
||||
).toEqual([
|
||||
new UserVote(13, "sf@matrix.org", ["wings"]),
|
||||
new UserVote(13, "id@matrix.org", ["wings"]),
|
||||
|
@ -184,8 +153,7 @@ describe("MPollBody", () => {
|
|||
expect(votesCount(body, "italian")).toBe("");
|
||||
expect(votesCount(body, "wings")).toBe("");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("No votes cast");
|
||||
expect(body.find('h2').html())
|
||||
.toEqual("<h2>What should we order for the party?</h2>");
|
||||
expect(body.find("h2").html()).toEqual("<h2>What should we order for the party?</h2>");
|
||||
});
|
||||
|
||||
it("finds votes from multiple people", () => {
|
||||
|
@ -210,9 +178,7 @@ describe("MPollBody", () => {
|
|||
responseEvent("@catrd:example.com", "poutine"),
|
||||
responseEvent("@dune2:example.com", "wings"),
|
||||
];
|
||||
const ends = [
|
||||
endEvent("@notallowed:example.com", 12),
|
||||
];
|
||||
const ends = [endEvent("@notallowed:example.com", 12)];
|
||||
const body = newMPollBody(votes, ends);
|
||||
|
||||
// Even though an end event was sent, we render the poll as unfinished
|
||||
|
@ -236,27 +202,23 @@ describe("MPollBody", () => {
|
|||
expect(votesCount(body, "poutine")).toBe("");
|
||||
expect(votesCount(body, "italian")).toBe("");
|
||||
expect(votesCount(body, "wings")).toBe("");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe(
|
||||
"4 votes cast. Vote to see the results");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("4 votes cast. Vote to see the results");
|
||||
});
|
||||
|
||||
it("hides a single vote if I have not voted", () => {
|
||||
const votes = [
|
||||
responseEvent("@alice:example.com", "pizza"),
|
||||
];
|
||||
const votes = [responseEvent("@alice:example.com", "pizza")];
|
||||
const body = newMPollBody(votes);
|
||||
expect(votesCount(body, "pizza")).toBe("");
|
||||
expect(votesCount(body, "poutine")).toBe("");
|
||||
expect(votesCount(body, "italian")).toBe("");
|
||||
expect(votesCount(body, "wings")).toBe("");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe(
|
||||
"1 vote cast. Vote to see the results");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("1 vote cast. Vote to see the results");
|
||||
});
|
||||
|
||||
it("takes someone's most recent vote if they voted several times", () => {
|
||||
const votes = [
|
||||
responseEvent("@me:example.com", "pizza", 12),
|
||||
responseEvent("@me:example.com", "wings", 20), // latest me
|
||||
responseEvent("@me:example.com", "wings", 20), // latest me
|
||||
responseEvent("@qbert:example.com", "pizza", 14),
|
||||
responseEvent("@qbert:example.com", "poutine", 16), // latest qbert
|
||||
responseEvent("@qbert:example.com", "wings", 15),
|
||||
|
@ -321,8 +283,7 @@ describe("MPollBody", () => {
|
|||
const votes = [responseEvent("@me:example.com", "pizza", 100)];
|
||||
const body = newMPollBody(votes);
|
||||
const props: IBodyProps = body.instance().props as IBodyProps;
|
||||
const voteRelations = props!.getRelationsForEvent!(
|
||||
"$mypoll", "m.reference", M_POLL_RESPONSE.name);
|
||||
const voteRelations = props!.getRelationsForEvent!("$mypoll", "m.reference", M_POLL_RESPONSE.name);
|
||||
expect(voteRelations).toBeDefined();
|
||||
clickRadio(body, "pizza");
|
||||
|
||||
|
@ -343,8 +304,7 @@ describe("MPollBody", () => {
|
|||
const votes = [responseEvent("@me:example.com", "pizza")];
|
||||
const body = newMPollBody(votes);
|
||||
const props: IBodyProps = body.instance().props as IBodyProps;
|
||||
const voteRelations = props!.getRelationsForEvent!(
|
||||
"$mypoll", "m.reference", M_POLL_RESPONSE.name);
|
||||
const voteRelations = props!.getRelationsForEvent!("$mypoll", "m.reference", M_POLL_RESPONSE.name);
|
||||
expect(voteRelations).toBeDefined();
|
||||
clickRadio(body, "pizza");
|
||||
|
||||
|
@ -369,10 +329,7 @@ describe("MPollBody", () => {
|
|||
|
||||
it("highlights my vote even if I did it on another device", () => {
|
||||
// Given I voted italian
|
||||
const votes = [
|
||||
responseEvent("@me:example.com", "italian"),
|
||||
responseEvent("@nf:example.com", "wings"),
|
||||
];
|
||||
const votes = [responseEvent("@me:example.com", "italian"), responseEvent("@nf:example.com", "wings")];
|
||||
const body = newMPollBody(votes);
|
||||
|
||||
// But I didn't click anything locally
|
||||
|
@ -384,10 +341,7 @@ describe("MPollBody", () => {
|
|||
|
||||
it("ignores extra answers", () => {
|
||||
// When cb votes for 2 things, we consider the first only
|
||||
const votes = [
|
||||
responseEvent("@cb:example.com", ["pizza", "wings"]),
|
||||
responseEvent("@me:example.com", "wings"),
|
||||
];
|
||||
const votes = [responseEvent("@cb:example.com", ["pizza", "wings"]), responseEvent("@me:example.com", "wings")];
|
||||
const body = newMPollBody(votes);
|
||||
expect(votesCount(body, "pizza")).toBe("1 vote");
|
||||
expect(votesCount(body, "poutine")).toBe("0 votes");
|
||||
|
@ -470,14 +424,12 @@ describe("MPollBody", () => {
|
|||
|
||||
it("renders the first 20 answers if 21 were given", () => {
|
||||
const answers = Array.from(Array(21).keys()).map((i) => {
|
||||
return { "id": `id${i}`, [M_TEXT.name]: `Name ${i}` };
|
||||
return { id: `id${i}`, [M_TEXT.name]: `Name ${i}` };
|
||||
});
|
||||
const votes = [];
|
||||
const ends = [];
|
||||
const body = newMPollBody(votes, ends, answers);
|
||||
expect(
|
||||
body.find('.mx_MPollBody_option').length,
|
||||
).toBe(20);
|
||||
expect(body.find(".mx_MPollBody_option").length).toBe(20);
|
||||
});
|
||||
|
||||
it("hides scores if I voted but the poll is undisclosed", () => {
|
||||
|
@ -493,8 +445,7 @@ describe("MPollBody", () => {
|
|||
expect(votesCount(body, "poutine")).toBe("");
|
||||
expect(votesCount(body, "italian")).toBe("");
|
||||
expect(votesCount(body, "wings")).toBe("");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe(
|
||||
"Results will be visible when the poll is ended");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Results will be visible when the poll is ended");
|
||||
});
|
||||
|
||||
it("highlights my vote if the poll is undisclosed", () => {
|
||||
|
@ -522,16 +473,13 @@ describe("MPollBody", () => {
|
|||
responseEvent("@catrd:example.com", "poutine"),
|
||||
responseEvent("@dune2:example.com", "wings"),
|
||||
];
|
||||
const ends = [
|
||||
endEvent("@me:example.com", 12),
|
||||
];
|
||||
const ends = [endEvent("@me:example.com", 12)];
|
||||
const body = newMPollBody(votes, ends, null, false);
|
||||
expect(endedVotesCount(body, "pizza")).toBe("3 votes");
|
||||
expect(endedVotesCount(body, "poutine")).toBe("1 vote");
|
||||
expect(endedVotesCount(body, "italian")).toBe("0 votes");
|
||||
expect(endedVotesCount(body, "wings")).toBe("1 vote");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe(
|
||||
"Final result based on 5 votes");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Final result based on 5 votes");
|
||||
});
|
||||
|
||||
it("sends a vote event when I choose an option", () => {
|
||||
|
@ -548,9 +496,7 @@ describe("MPollBody", () => {
|
|||
clickRadio(body, "wings");
|
||||
clickRadio(body, "wings");
|
||||
clickRadio(body, "wings");
|
||||
expect(mockClient.sendEvent).toHaveBeenCalledWith(
|
||||
...expectedResponseEventCall("wings"),
|
||||
);
|
||||
expect(mockClient.sendEvent).toHaveBeenCalledWith(...expectedResponseEventCall("wings"));
|
||||
});
|
||||
|
||||
it("sends no vote event when I click what I already chose", () => {
|
||||
|
@ -576,13 +522,8 @@ describe("MPollBody", () => {
|
|||
});
|
||||
|
||||
it("sends no events when I click in an ended poll", () => {
|
||||
const ends = [
|
||||
endEvent("@me:example.com", 25),
|
||||
];
|
||||
const votes = [
|
||||
responseEvent("@uy:example.com", "wings", 15),
|
||||
responseEvent("@uy:example.com", "poutine", 15),
|
||||
];
|
||||
const ends = [endEvent("@me:example.com", 25)];
|
||||
const votes = [responseEvent("@uy:example.com", "wings", 15), responseEvent("@uy:example.com", "poutine", 15)];
|
||||
const body = newMPollBody(votes, ends);
|
||||
clickEndedOption(body, "wings");
|
||||
clickEndedOption(body, "italian");
|
||||
|
@ -622,9 +563,7 @@ describe("MPollBody", () => {
|
|||
responseEvent("@fa:example.com", "poutine", 18),
|
||||
responseEvent("@of:example.com", "poutine", 31), // Late
|
||||
];
|
||||
const ends = [
|
||||
endEvent("@me:example.com", 25),
|
||||
];
|
||||
const ends = [endEvent("@me:example.com", 25)];
|
||||
expect(runFindTopAnswer(votes, ends)).toEqual("Italian, Pizza and Poutine");
|
||||
});
|
||||
|
||||
|
@ -646,7 +585,7 @@ describe("MPollBody", () => {
|
|||
it("counts votes as normal if the poll is ended", () => {
|
||||
const votes = [
|
||||
responseEvent("@me:example.com", "pizza", 12),
|
||||
responseEvent("@me:example.com", "wings", 20), // latest me
|
||||
responseEvent("@me:example.com", "wings", 20), // latest me
|
||||
responseEvent("@qbert:example.com", "pizza", 14),
|
||||
responseEvent("@qbert:example.com", "poutine", 16), // latest qbert
|
||||
responseEvent("@qbert:example.com", "wings", 15),
|
||||
|
@ -657,9 +596,7 @@ describe("MPollBody", () => {
|
|||
expect(endedVotesCount(body, "poutine")).toBe("1 vote");
|
||||
expect(endedVotesCount(body, "italian")).toBe("0 votes");
|
||||
expect(endedVotesCount(body, "wings")).toBe("1 vote");
|
||||
expect(
|
||||
body.find(".mx_MPollBody_totalVotes").text(),
|
||||
).toBe("Final result based on 2 votes");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Final result based on 2 votes");
|
||||
});
|
||||
|
||||
it("counts a single vote as normal if the poll is ended", () => {
|
||||
|
@ -670,9 +607,7 @@ describe("MPollBody", () => {
|
|||
expect(endedVotesCount(body, "poutine")).toBe("1 vote");
|
||||
expect(endedVotesCount(body, "italian")).toBe("0 votes");
|
||||
expect(endedVotesCount(body, "wings")).toBe("0 votes");
|
||||
expect(
|
||||
body.find(".mx_MPollBody_totalVotes").text(),
|
||||
).toBe("Final result based on 1 vote");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Final result based on 1 vote");
|
||||
});
|
||||
|
||||
it("shows ended vote counts of different numbers", () => {
|
||||
|
@ -692,18 +627,16 @@ describe("MPollBody", () => {
|
|||
expect(endedVotesCount(body, "poutine")).toBe("0 votes");
|
||||
expect(endedVotesCount(body, "italian")).toBe("0 votes");
|
||||
expect(endedVotesCount(body, "wings")).toBe("3 votes");
|
||||
expect(
|
||||
body.find(".mx_MPollBody_totalVotes").text(),
|
||||
).toBe("Final result based on 5 votes");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Final result based on 5 votes");
|
||||
});
|
||||
|
||||
it("ignores votes that arrived after poll ended", () => {
|
||||
const votes = [
|
||||
responseEvent("@sd:example.com", "wings", 30), // Late
|
||||
responseEvent("@sd:example.com", "wings", 30), // Late
|
||||
responseEvent("@ff:example.com", "wings", 20),
|
||||
responseEvent("@ut:example.com", "wings", 14),
|
||||
responseEvent("@iu:example.com", "wings", 15),
|
||||
responseEvent("@jf:example.com", "wings", 35), // Late
|
||||
responseEvent("@jf:example.com", "wings", 35), // Late
|
||||
responseEvent("@wf:example.com", "pizza", 15),
|
||||
responseEvent("@ld:example.com", "pizza", 15),
|
||||
];
|
||||
|
@ -714,23 +647,21 @@ describe("MPollBody", () => {
|
|||
expect(endedVotesCount(body, "poutine")).toBe("0 votes");
|
||||
expect(endedVotesCount(body, "italian")).toBe("0 votes");
|
||||
expect(endedVotesCount(body, "wings")).toBe("3 votes");
|
||||
expect(
|
||||
body.find(".mx_MPollBody_totalVotes").text(),
|
||||
).toBe("Final result based on 5 votes");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Final result based on 5 votes");
|
||||
});
|
||||
|
||||
it("counts votes that arrived after an unauthorised poll end event", () => {
|
||||
const votes = [
|
||||
responseEvent("@sd:example.com", "wings", 30), // Late
|
||||
responseEvent("@sd:example.com", "wings", 30), // Late
|
||||
responseEvent("@ff:example.com", "wings", 20),
|
||||
responseEvent("@ut:example.com", "wings", 14),
|
||||
responseEvent("@iu:example.com", "wings", 15),
|
||||
responseEvent("@jf:example.com", "wings", 35), // Late
|
||||
responseEvent("@jf:example.com", "wings", 35), // Late
|
||||
responseEvent("@wf:example.com", "pizza", 15),
|
||||
responseEvent("@ld:example.com", "pizza", 15),
|
||||
];
|
||||
const ends = [
|
||||
endEvent("@unauthorised:example.com", 5), // Should be ignored
|
||||
endEvent("@unauthorised:example.com", 5), // Should be ignored
|
||||
endEvent("@me:example.com", 25),
|
||||
];
|
||||
const body = newMPollBody(votes, ends);
|
||||
|
@ -739,9 +670,7 @@ describe("MPollBody", () => {
|
|||
expect(endedVotesCount(body, "poutine")).toBe("0 votes");
|
||||
expect(endedVotesCount(body, "italian")).toBe("0 votes");
|
||||
expect(endedVotesCount(body, "wings")).toBe("3 votes");
|
||||
expect(
|
||||
body.find(".mx_MPollBody_totalVotes").text(),
|
||||
).toBe("Final result based on 5 votes");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Final result based on 5 votes");
|
||||
});
|
||||
|
||||
it("ignores votes that arrived after the first end poll event", () => {
|
||||
|
@ -749,11 +678,11 @@ describe("MPollBody", () => {
|
|||
// "Votes sent on or before the end event's timestamp are valid votes"
|
||||
|
||||
const votes = [
|
||||
responseEvent("@sd:example.com", "wings", 30), // Late
|
||||
responseEvent("@sd:example.com", "wings", 30), // Late
|
||||
responseEvent("@ff:example.com", "wings", 20),
|
||||
responseEvent("@ut:example.com", "wings", 14),
|
||||
responseEvent("@iu:example.com", "wings", 25), // Just on time
|
||||
responseEvent("@jf:example.com", "wings", 35), // Late
|
||||
responseEvent("@iu:example.com", "wings", 25), // Just on time
|
||||
responseEvent("@jf:example.com", "wings", 35), // Late
|
||||
responseEvent("@wf:example.com", "pizza", 15),
|
||||
responseEvent("@ld:example.com", "pizza", 15),
|
||||
];
|
||||
|
@ -768,9 +697,7 @@ describe("MPollBody", () => {
|
|||
expect(endedVotesCount(body, "poutine")).toBe("0 votes");
|
||||
expect(endedVotesCount(body, "italian")).toBe("0 votes");
|
||||
expect(endedVotesCount(body, "wings")).toBe("3 votes");
|
||||
expect(
|
||||
body.find(".mx_MPollBody_totalVotes").text(),
|
||||
).toBe("Final result based on 5 votes");
|
||||
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Final result based on 5 votes");
|
||||
});
|
||||
|
||||
it("highlights the winning vote in an ended poll", () => {
|
||||
|
@ -788,12 +715,8 @@ describe("MPollBody", () => {
|
|||
expect(endedVoteChecked(body, "pizza")).toBe(false);
|
||||
|
||||
// Double-check by looking for the endedOptionWinner class
|
||||
expect(
|
||||
endedVoteDiv(body, "wings").hasClass("mx_MPollBody_endedOptionWinner"),
|
||||
).toBe(true);
|
||||
expect(
|
||||
endedVoteDiv(body, "pizza").hasClass("mx_MPollBody_endedOptionWinner"),
|
||||
).toBe(false);
|
||||
expect(endedVoteDiv(body, "wings").hasClass("mx_MPollBody_endedOptionWinner")).toBe(true);
|
||||
expect(endedVoteDiv(body, "pizza").hasClass("mx_MPollBody_endedOptionWinner")).toBe(false);
|
||||
});
|
||||
|
||||
it("highlights multiple winning votes", () => {
|
||||
|
@ -836,9 +759,9 @@ describe("MPollBody", () => {
|
|||
|
||||
it("says poll is not ended if asking for relations returns undefined", () => {
|
||||
const pollEvent = new MatrixEvent({
|
||||
"event_id": "$mypoll",
|
||||
"room_id": "#myroom:example.com",
|
||||
"content": newPollStart([]),
|
||||
event_id: "$mypoll",
|
||||
room_id: "#myroom:example.com",
|
||||
content: newPollStart([]),
|
||||
});
|
||||
mockClient.getRoom.mockImplementation((_roomId) => {
|
||||
return {
|
||||
|
@ -849,45 +772,38 @@ describe("MPollBody", () => {
|
|||
},
|
||||
} as unknown as Room;
|
||||
});
|
||||
const getRelationsForEvent =
|
||||
(eventId: string, relationType: string, eventType: string) => {
|
||||
expect(eventId).toBe("$mypoll");
|
||||
expect(relationType).toBe("m.reference");
|
||||
expect(M_POLL_END.matches(eventType)).toBe(true);
|
||||
return undefined;
|
||||
};
|
||||
expect(
|
||||
isPollEnded(
|
||||
pollEvent,
|
||||
MatrixClientPeg.get(),
|
||||
getRelationsForEvent,
|
||||
),
|
||||
).toBe(false);
|
||||
const getRelationsForEvent = (eventId: string, relationType: string, eventType: string) => {
|
||||
expect(eventId).toBe("$mypoll");
|
||||
expect(relationType).toBe("m.reference");
|
||||
expect(M_POLL_END.matches(eventType)).toBe(true);
|
||||
return undefined;
|
||||
};
|
||||
expect(isPollEnded(pollEvent, MatrixClientPeg.get(), getRelationsForEvent)).toBe(false);
|
||||
});
|
||||
|
||||
it("Displays edited content and new answer IDs if the poll has been edited", () => {
|
||||
const pollEvent = new MatrixEvent({
|
||||
"type": M_POLL_START.name,
|
||||
"event_id": "$mypoll",
|
||||
"room_id": "#myroom:example.com",
|
||||
"content": newPollStart(
|
||||
type: M_POLL_START.name,
|
||||
event_id: "$mypoll",
|
||||
room_id: "#myroom:example.com",
|
||||
content: newPollStart(
|
||||
[
|
||||
{ "id": "o1", [M_TEXT.name]: "old answer 1" },
|
||||
{ "id": "o2", [M_TEXT.name]: "old answer 2" },
|
||||
{ id: "o1", [M_TEXT.name]: "old answer 1" },
|
||||
{ id: "o2", [M_TEXT.name]: "old answer 2" },
|
||||
],
|
||||
"old question",
|
||||
),
|
||||
});
|
||||
const replacingEvent = new MatrixEvent({
|
||||
"type": M_POLL_START.name,
|
||||
"event_id": "$mypollreplacement",
|
||||
"room_id": "#myroom:example.com",
|
||||
"content": {
|
||||
type: M_POLL_START.name,
|
||||
event_id: "$mypollreplacement",
|
||||
room_id: "#myroom:example.com",
|
||||
content: {
|
||||
"m.new_content": newPollStart(
|
||||
[
|
||||
{ "id": "n1", [M_TEXT.name]: "new answer 1" },
|
||||
{ "id": "n2", [M_TEXT.name]: "new answer 2" },
|
||||
{ "id": "n3", [M_TEXT.name]: "new answer 3" },
|
||||
{ id: "n1", [M_TEXT.name]: "new answer 1" },
|
||||
{ id: "n2", [M_TEXT.name]: "new answer 2" },
|
||||
{ id: "n3", [M_TEXT.name]: "new answer 3" },
|
||||
],
|
||||
"new question",
|
||||
),
|
||||
|
@ -895,18 +811,15 @@ describe("MPollBody", () => {
|
|||
});
|
||||
pollEvent.makeReplaced(replacingEvent);
|
||||
const body = newMPollBodyFromEvent(pollEvent, []);
|
||||
expect(body.find('h2').html())
|
||||
.toEqual(
|
||||
"<h2>new question"
|
||||
+ "<span class=\"mx_MPollBody_edited\"> (edited)</span>"
|
||||
+ "</h2>",
|
||||
);
|
||||
expect(body.find("h2").html()).toEqual(
|
||||
"<h2>new question" + '<span class="mx_MPollBody_edited"> (edited)</span>' + "</h2>",
|
||||
);
|
||||
const inputs = body.find('input[type="radio"]');
|
||||
expect(inputs).toHaveLength(3);
|
||||
expect(inputs.at(0).prop("value")).toEqual("n1");
|
||||
expect(inputs.at(1).prop("value")).toEqual("n2");
|
||||
expect(inputs.at(2).prop("value")).toEqual("n3");
|
||||
const options = body.find('.mx_MPollBody_optionText');
|
||||
const options = body.find(".mx_MPollBody_optionText");
|
||||
expect(options).toHaveLength(3);
|
||||
expect(options.at(0).text()).toEqual("new answer 1");
|
||||
expect(options.at(1).text()).toEqual("new answer 2");
|
||||
|
@ -1027,10 +940,7 @@ function newEndRelations(relationEvents: Array<MatrixEvent>): Relations {
|
|||
return newRelations(relationEvents, M_POLL_END.name);
|
||||
}
|
||||
|
||||
function newRelations(
|
||||
relationEvents: Array<MatrixEvent>,
|
||||
eventType: string,
|
||||
): Relations {
|
||||
function newRelations(relationEvents: Array<MatrixEvent>, eventType: string): Relations {
|
||||
const voteRelations = new Relations("m.reference", eventType, null);
|
||||
for (const ev of relationEvents) {
|
||||
voteRelations.addEvent(ev);
|
||||
|
@ -1045,10 +955,10 @@ function newMPollBody(
|
|||
disclosed = true,
|
||||
): ReactWrapper {
|
||||
const mxEvent = new MatrixEvent({
|
||||
"type": M_POLL_START.name,
|
||||
"event_id": "$mypoll",
|
||||
"room_id": "#myroom:example.com",
|
||||
"content": newPollStart(answers, null, disclosed),
|
||||
type: M_POLL_START.name,
|
||||
event_id: "$mypoll",
|
||||
room_id: "#myroom:example.com",
|
||||
content: newPollStart(answers, null, disclosed),
|
||||
});
|
||||
return newMPollBodyFromEvent(mxEvent, relationEvents, endEvents);
|
||||
}
|
||||
|
@ -1060,10 +970,10 @@ function newMPollBodyFromEvent(
|
|||
): ReactWrapper {
|
||||
const voteRelations = newVoteRelations(relationEvents);
|
||||
const endRelations = newEndRelations(endEvents);
|
||||
return mount(<MPollBody
|
||||
mxEvent={mxEvent}
|
||||
getRelationsForEvent={
|
||||
(eventId: string, relationType: string, eventType: string) => {
|
||||
return mount(
|
||||
<MPollBody
|
||||
mxEvent={mxEvent}
|
||||
getRelationsForEvent={(eventId: string, relationType: string, eventType: string) => {
|
||||
expect(eventId).toBe("$mypoll");
|
||||
expect(relationType).toBe("m.reference");
|
||||
if (M_POLL_RESPONSE.matches(eventType)) {
|
||||
|
@ -1073,22 +983,22 @@ function newMPollBodyFromEvent(
|
|||
} else {
|
||||
fail("Unexpected eventType: " + eventType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We don't use any of these props, but they're required.
|
||||
highlightLink="unused"
|
||||
highlights={[]}
|
||||
mediaEventHelper={null}
|
||||
onHeightChanged={() => {}}
|
||||
onMessageAllowed={() => {}}
|
||||
permalinkCreator={null}
|
||||
/>, {
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: {
|
||||
value: mockClient,
|
||||
}}
|
||||
// We don't use any of these props, but they're required.
|
||||
highlightLink="unused"
|
||||
highlights={[]}
|
||||
mediaEventHelper={null}
|
||||
onHeightChanged={() => {}}
|
||||
onMessageAllowed={() => {}}
|
||||
permalinkCreator={null}
|
||||
/>,
|
||||
{
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: {
|
||||
value: mockClient,
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
function clickRadio(wrapper: ReactWrapper, value: string) {
|
||||
|
@ -1104,21 +1014,15 @@ function clickEndedOption(wrapper: ReactWrapper, value: string) {
|
|||
}
|
||||
|
||||
function voteButton(wrapper: ReactWrapper, value: string): ReactWrapper {
|
||||
return wrapper.find(
|
||||
`div.mx_MPollBody_option`,
|
||||
).findWhere(w => w.key() === value);
|
||||
return wrapper.find(`div.mx_MPollBody_option`).findWhere((w) => w.key() === value);
|
||||
}
|
||||
|
||||
function votesCount(wrapper: ReactWrapper, value: string): string {
|
||||
return wrapper.find(
|
||||
`StyledRadioButton[value="${value}"] .mx_MPollBody_optionVoteCount`,
|
||||
).text();
|
||||
return wrapper.find(`StyledRadioButton[value="${value}"] .mx_MPollBody_optionVoteCount`).text();
|
||||
}
|
||||
|
||||
function endedVoteChecked(wrapper: ReactWrapper, value: string): boolean {
|
||||
return endedVoteDiv(wrapper, value)
|
||||
.closest(".mx_MPollBody_option")
|
||||
.hasClass("mx_MPollBody_option_checked");
|
||||
return endedVoteDiv(wrapper, value).closest(".mx_MPollBody_option").hasClass("mx_MPollBody_option_checked");
|
||||
}
|
||||
|
||||
function endedVoteDiv(wrapper: ReactWrapper, value: string): ReactWrapper {
|
||||
|
@ -1126,22 +1030,16 @@ function endedVoteDiv(wrapper: ReactWrapper, value: string): ReactWrapper {
|
|||
}
|
||||
|
||||
function endedVotesCount(wrapper: ReactWrapper, value: string): string {
|
||||
return wrapper.find(
|
||||
`div[data-value="${value}"] .mx_MPollBody_optionVoteCount`,
|
||||
).text();
|
||||
return wrapper.find(`div[data-value="${value}"] .mx_MPollBody_optionVoteCount`).text();
|
||||
}
|
||||
|
||||
function newPollStart(
|
||||
answers?: POLL_ANSWER[],
|
||||
question?: string,
|
||||
disclosed = true,
|
||||
): M_POLL_START_EVENT_CONTENT {
|
||||
function newPollStart(answers?: POLL_ANSWER[], question?: string, disclosed = true): M_POLL_START_EVENT_CONTENT {
|
||||
if (!answers) {
|
||||
answers = [
|
||||
{ "id": "pizza", [M_TEXT.name]: "Pizza" },
|
||||
{ "id": "poutine", [M_TEXT.name]: "Poutine" },
|
||||
{ "id": "italian", [M_TEXT.name]: "Italian" },
|
||||
{ "id": "wings", [M_TEXT.name]: "Wings" },
|
||||
{ id: "pizza", [M_TEXT.name]: "Pizza" },
|
||||
{ id: "poutine", [M_TEXT.name]: "Poutine" },
|
||||
{ id: "italian", [M_TEXT.name]: "Italian" },
|
||||
{ id: "wings", [M_TEXT.name]: "Wings" },
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -1149,43 +1047,35 @@ function newPollStart(
|
|||
question = "What should we order for the party?";
|
||||
}
|
||||
|
||||
const answersFallback = answers
|
||||
.map((a, i) => `${i + 1}. ${a[M_TEXT.name]}`)
|
||||
.join("\n");
|
||||
const answersFallback = answers.map((a, i) => `${i + 1}. ${a[M_TEXT.name]}`).join("\n");
|
||||
|
||||
const fallback = `${question}\n${answersFallback}`;
|
||||
|
||||
return {
|
||||
[M_POLL_START.name]: {
|
||||
"question": {
|
||||
question: {
|
||||
[M_TEXT.name]: question,
|
||||
},
|
||||
"kind": (
|
||||
disclosed
|
||||
? M_POLL_KIND_DISCLOSED.name
|
||||
: M_POLL_KIND_UNDISCLOSED.name
|
||||
),
|
||||
"answers": answers,
|
||||
kind: disclosed ? M_POLL_KIND_DISCLOSED.name : M_POLL_KIND_UNDISCLOSED.name,
|
||||
answers: answers,
|
||||
},
|
||||
[M_TEXT.name]: fallback,
|
||||
};
|
||||
}
|
||||
|
||||
function badResponseEvent(): MatrixEvent {
|
||||
return new MatrixEvent(
|
||||
{
|
||||
"event_id": nextId(),
|
||||
"type": M_POLL_RESPONSE.name,
|
||||
"sender": "@malicious:example.com",
|
||||
"content": {
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.reference",
|
||||
"event_id": "$mypoll",
|
||||
},
|
||||
// Does not actually contain a response
|
||||
return new MatrixEvent({
|
||||
event_id: nextId(),
|
||||
type: M_POLL_RESPONSE.name,
|
||||
sender: "@malicious:example.com",
|
||||
content: {
|
||||
"m.relates_to": {
|
||||
rel_type: "m.reference",
|
||||
event_id: "$mypoll",
|
||||
},
|
||||
// Does not actually contain a response
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function responseEvent(
|
||||
|
@ -1194,116 +1084,103 @@ function responseEvent(
|
|||
ts = 0,
|
||||
): MatrixEvent {
|
||||
const ans = typeof answers === "string" ? [answers] : answers;
|
||||
return new MatrixEvent(
|
||||
{
|
||||
"event_id": nextId(),
|
||||
"room_id": "#myroom:example.com",
|
||||
"origin_server_ts": ts,
|
||||
"type": M_POLL_RESPONSE.name,
|
||||
"sender": sender,
|
||||
"content": {
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.reference",
|
||||
"event_id": "$mypoll",
|
||||
},
|
||||
[M_POLL_RESPONSE.name]: {
|
||||
"answers": ans,
|
||||
},
|
||||
return new MatrixEvent({
|
||||
event_id: nextId(),
|
||||
room_id: "#myroom:example.com",
|
||||
origin_server_ts: ts,
|
||||
type: M_POLL_RESPONSE.name,
|
||||
sender: sender,
|
||||
content: {
|
||||
"m.relates_to": {
|
||||
rel_type: "m.reference",
|
||||
event_id: "$mypoll",
|
||||
},
|
||||
[M_POLL_RESPONSE.name]: {
|
||||
answers: ans,
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function expectedResponseEvent(answer: string) {
|
||||
return {
|
||||
"content": {
|
||||
content: {
|
||||
[M_POLL_RESPONSE.name]: {
|
||||
"answers": [answer],
|
||||
answers: [answer],
|
||||
},
|
||||
"m.relates_to": {
|
||||
"event_id": "$mypoll",
|
||||
"rel_type": "m.reference",
|
||||
event_id: "$mypoll",
|
||||
rel_type: "m.reference",
|
||||
},
|
||||
},
|
||||
"roomId": "#myroom:example.com",
|
||||
"eventType": M_POLL_RESPONSE.name,
|
||||
"txnId": undefined,
|
||||
"callback": undefined,
|
||||
roomId: "#myroom:example.com",
|
||||
eventType: M_POLL_RESPONSE.name,
|
||||
txnId: undefined,
|
||||
callback: undefined,
|
||||
};
|
||||
}
|
||||
function expectedResponseEventCall(answer: string) {
|
||||
const {
|
||||
content, roomId, eventType,
|
||||
} = expectedResponseEvent(answer);
|
||||
return [
|
||||
roomId, eventType, content,
|
||||
];
|
||||
const { content, roomId, eventType } = expectedResponseEvent(answer);
|
||||
return [roomId, eventType, content];
|
||||
}
|
||||
|
||||
function endEvent(
|
||||
sender = "@me:example.com",
|
||||
ts = 0,
|
||||
): MatrixEvent {
|
||||
return new MatrixEvent(
|
||||
{
|
||||
"event_id": nextId(),
|
||||
"room_id": "#myroom:example.com",
|
||||
"origin_server_ts": ts,
|
||||
"type": M_POLL_END.name,
|
||||
"sender": sender,
|
||||
"content": {
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.reference",
|
||||
"event_id": "$mypoll",
|
||||
},
|
||||
[M_POLL_END.name]: {},
|
||||
[M_TEXT.name]: "The poll has ended. Something.",
|
||||
function endEvent(sender = "@me:example.com", ts = 0): MatrixEvent {
|
||||
return new MatrixEvent({
|
||||
event_id: nextId(),
|
||||
room_id: "#myroom:example.com",
|
||||
origin_server_ts: ts,
|
||||
type: M_POLL_END.name,
|
||||
sender: sender,
|
||||
content: {
|
||||
"m.relates_to": {
|
||||
rel_type: "m.reference",
|
||||
event_id: "$mypoll",
|
||||
},
|
||||
[M_POLL_END.name]: {},
|
||||
[M_TEXT.name]: "The poll has ended. Something.",
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function runIsPollEnded(ends: MatrixEvent[]) {
|
||||
const pollEvent = new MatrixEvent({
|
||||
"event_id": "$mypoll",
|
||||
"room_id": "#myroom:example.com",
|
||||
"type": M_POLL_START.name,
|
||||
"content": newPollStart(),
|
||||
event_id: "$mypoll",
|
||||
room_id: "#myroom:example.com",
|
||||
type: M_POLL_START.name,
|
||||
content: newPollStart(),
|
||||
});
|
||||
|
||||
setRedactionAllowedForMeOnly(mockClient);
|
||||
|
||||
const getRelationsForEvent =
|
||||
(eventId: string, relationType: string, eventType: string) => {
|
||||
expect(eventId).toBe("$mypoll");
|
||||
expect(relationType).toBe("m.reference");
|
||||
expect(M_POLL_END.matches(eventType)).toBe(true);
|
||||
return newEndRelations(ends);
|
||||
};
|
||||
const getRelationsForEvent = (eventId: string, relationType: string, eventType: string) => {
|
||||
expect(eventId).toBe("$mypoll");
|
||||
expect(relationType).toBe("m.reference");
|
||||
expect(M_POLL_END.matches(eventType)).toBe(true);
|
||||
return newEndRelations(ends);
|
||||
};
|
||||
|
||||
return isPollEnded(pollEvent, mockClient, getRelationsForEvent);
|
||||
}
|
||||
|
||||
function runFindTopAnswer(votes: MatrixEvent[], ends: MatrixEvent[]) {
|
||||
const pollEvent = new MatrixEvent({
|
||||
"event_id": "$mypoll",
|
||||
"room_id": "#myroom:example.com",
|
||||
"type": M_POLL_START.name,
|
||||
"content": newPollStart(),
|
||||
event_id: "$mypoll",
|
||||
room_id: "#myroom:example.com",
|
||||
type: M_POLL_START.name,
|
||||
content: newPollStart(),
|
||||
});
|
||||
|
||||
const getRelationsForEvent =
|
||||
(eventId: string, relationType: string, eventType: string) => {
|
||||
expect(eventId).toBe("$mypoll");
|
||||
expect(relationType).toBe("m.reference");
|
||||
if (M_POLL_RESPONSE.matches(eventType)) {
|
||||
return newVoteRelations(votes);
|
||||
} else if (M_POLL_END.matches(eventType)) {
|
||||
return newEndRelations(ends);
|
||||
} else {
|
||||
fail(`eventType should be end or vote but was ${eventType}`);
|
||||
}
|
||||
};
|
||||
const getRelationsForEvent = (eventId: string, relationType: string, eventType: string) => {
|
||||
expect(eventId).toBe("$mypoll");
|
||||
expect(relationType).toBe("m.reference");
|
||||
if (M_POLL_RESPONSE.matches(eventType)) {
|
||||
return newVoteRelations(votes);
|
||||
} else if (M_POLL_END.matches(eventType)) {
|
||||
return newEndRelations(ends);
|
||||
} else {
|
||||
fail(`eventType should be end or vote but was ${eventType}`);
|
||||
}
|
||||
};
|
||||
|
||||
return findTopAnswer(pollEvent, MatrixClientPeg.get(), getRelationsForEvent);
|
||||
}
|
||||
|
|
|
@ -14,25 +14,26 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { MatrixEvent } from 'matrix-js-sdk/src/matrix';
|
||||
import { render, RenderResult } from '@testing-library/react';
|
||||
import React from "react";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { render, RenderResult } from "@testing-library/react";
|
||||
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks";
|
||||
import { MediaEventHelper } from "../../../../src/utils/MediaEventHelper";
|
||||
import { getMockClientWithEventEmitter } from '../../../test-utils';
|
||||
import MVideoBody from '../../../../src/components/views/messages/MVideoBody';
|
||||
import { getMockClientWithEventEmitter } from "../../../test-utils";
|
||||
import MVideoBody from "../../../../src/components/views/messages/MVideoBody";
|
||||
|
||||
jest.mock(
|
||||
"../../../../src/customisations/Media",
|
||||
() => {
|
||||
return { mediaFromContent: () => { return { isEncrypted: false }; } };
|
||||
},
|
||||
);
|
||||
jest.mock("../../../../src/customisations/Media", () => {
|
||||
return {
|
||||
mediaFromContent: () => {
|
||||
return { isEncrypted: false };
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
describe("MVideoBody", () => {
|
||||
it('does not crash when given a portrait image', () => {
|
||||
it("does not crash when given a portrait image", () => {
|
||||
// Check for an unreliable crash caused by a fractional-sized
|
||||
// image dimension being used for a CanvasImageData.
|
||||
const { asFragment } = makeMVideoBody(720, 1280);
|
||||
|
@ -68,7 +69,7 @@ function makeMVideoBody(w: number, h: number): RenderResult {
|
|||
const defaultProps = {
|
||||
mxEvent: event,
|
||||
highlights: [],
|
||||
highlightLink: '',
|
||||
highlightLink: "",
|
||||
onHeightChanged: jest.fn(),
|
||||
onMessageAllowed: jest.fn(),
|
||||
permalinkCreator: {} as RoomPermalinkCreator,
|
||||
|
|
|
@ -14,57 +14,50 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import { act } from 'react-test-renderer';
|
||||
import {
|
||||
EventType,
|
||||
EventStatus,
|
||||
MatrixEvent,
|
||||
MatrixEventEvent,
|
||||
MsgType,
|
||||
Room,
|
||||
} from 'matrix-js-sdk/src/matrix';
|
||||
import { FeatureSupport, Thread } from 'matrix-js-sdk/src/models/thread';
|
||||
import React from "react";
|
||||
import { render, fireEvent } from "@testing-library/react";
|
||||
import { act } from "react-test-renderer";
|
||||
import { EventType, EventStatus, MatrixEvent, MatrixEventEvent, MsgType, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { FeatureSupport, Thread } from "matrix-js-sdk/src/models/thread";
|
||||
|
||||
import MessageActionBar from '../../../../src/components/views/messages/MessageActionBar';
|
||||
import MessageActionBar from "../../../../src/components/views/messages/MessageActionBar";
|
||||
import {
|
||||
getMockClientWithEventEmitter,
|
||||
mockClientMethodsUser,
|
||||
mockClientMethodsEvents,
|
||||
makeBeaconInfoEvent,
|
||||
} from '../../../test-utils';
|
||||
import { RoomPermalinkCreator } from '../../../../src/utils/permalinks/Permalinks';
|
||||
import RoomContext, { TimelineRenderingType } from '../../../../src/contexts/RoomContext';
|
||||
import { IRoomState } from '../../../../src/components/structures/RoomView';
|
||||
import dispatcher from '../../../../src/dispatcher/dispatcher';
|
||||
import SettingsStore from '../../../../src/settings/SettingsStore';
|
||||
import { Action } from '../../../../src/dispatcher/actions';
|
||||
import { UserTab } from '../../../../src/components/views/dialogs/UserTab';
|
||||
} from "../../../test-utils";
|
||||
import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks";
|
||||
import RoomContext, { TimelineRenderingType } from "../../../../src/contexts/RoomContext";
|
||||
import { IRoomState } from "../../../../src/components/structures/RoomView";
|
||||
import dispatcher from "../../../../src/dispatcher/dispatcher";
|
||||
import SettingsStore from "../../../../src/settings/SettingsStore";
|
||||
import { Action } from "../../../../src/dispatcher/actions";
|
||||
import { UserTab } from "../../../../src/components/views/dialogs/UserTab";
|
||||
|
||||
jest.mock('../../../../src/dispatcher/dispatcher');
|
||||
jest.mock("../../../../src/dispatcher/dispatcher");
|
||||
|
||||
describe('<MessageActionBar />', () => {
|
||||
const userId = '@alice:server.org';
|
||||
const roomId = '!room:server.org';
|
||||
describe("<MessageActionBar />", () => {
|
||||
const userId = "@alice:server.org";
|
||||
const roomId = "!room:server.org";
|
||||
const alicesMessageEvent = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
sender: userId,
|
||||
room_id: roomId,
|
||||
content: {
|
||||
msgtype: MsgType.Text,
|
||||
body: 'Hello',
|
||||
body: "Hello",
|
||||
},
|
||||
event_id: "$alices_message",
|
||||
});
|
||||
|
||||
const bobsMessageEvent = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
sender: '@bob:server.org',
|
||||
sender: "@bob:server.org",
|
||||
room_id: roomId,
|
||||
content: {
|
||||
msgtype: MsgType.Text,
|
||||
body: 'I am bob',
|
||||
body: "I am bob",
|
||||
},
|
||||
event_id: "$bobs_message",
|
||||
});
|
||||
|
@ -84,7 +77,7 @@ describe('<MessageActionBar />', () => {
|
|||
const localStorageMock = (() => {
|
||||
let store = {};
|
||||
return {
|
||||
getItem: jest.fn().mockImplementation(key => store[key] ?? null),
|
||||
getItem: jest.fn().mockImplementation((key) => store[key] ?? null),
|
||||
setItem: jest.fn().mockImplementation((key, value) => {
|
||||
store[key] = value;
|
||||
}),
|
||||
|
@ -94,13 +87,13 @@ describe('<MessageActionBar />', () => {
|
|||
removeItem: jest.fn().mockImplementation((key) => delete store[key]),
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(window, 'localStorage', {
|
||||
Object.defineProperty(window, "localStorage", {
|
||||
value: localStorageMock,
|
||||
writable: true,
|
||||
});
|
||||
|
||||
const room = new Room(roomId, client, userId);
|
||||
jest.spyOn(room, 'getPendingEvents').mockReturnValue([]);
|
||||
jest.spyOn(room, "getPendingEvents").mockReturnValue([]);
|
||||
|
||||
client.getRoom.mockReturnValue(room);
|
||||
|
||||
|
@ -121,22 +114,23 @@ describe('<MessageActionBar />', () => {
|
|||
render(
|
||||
<RoomContext.Provider value={{ ...defaultRoomContext, ...roomContext }}>
|
||||
<MessageActionBar {...defaultProps} {...props} />
|
||||
</RoomContext.Provider>);
|
||||
</RoomContext.Provider>,
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
alicesMessageEvent.setStatus(EventStatus.SENT);
|
||||
jest.spyOn(SettingsStore, 'getValue').mockReturnValue(false);
|
||||
jest.spyOn(SettingsStore, 'setValue').mockResolvedValue(undefined);
|
||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
|
||||
jest.spyOn(SettingsStore, "setValue").mockResolvedValue(undefined);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(SettingsStore, 'getValue').mockRestore();
|
||||
jest.spyOn(SettingsStore, 'setValue').mockRestore();
|
||||
jest.spyOn(SettingsStore, "getValue").mockRestore();
|
||||
jest.spyOn(SettingsStore, "setValue").mockRestore();
|
||||
});
|
||||
|
||||
it('kills event listeners on unmount', () => {
|
||||
const offSpy = jest.spyOn(alicesMessageEvent, 'off').mockClear();
|
||||
it("kills event listeners on unmount", () => {
|
||||
const offSpy = jest.spyOn(alicesMessageEvent, "off").mockClear();
|
||||
const wrapper = getComponent({ mxEvent: alicesMessageEvent });
|
||||
|
||||
act(() => {
|
||||
|
@ -150,24 +144,24 @@ describe('<MessageActionBar />', () => {
|
|||
expect(client.decryptEventIfNeeded).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('decryption', () => {
|
||||
it('decrypts event if needed', () => {
|
||||
describe("decryption", () => {
|
||||
it("decrypts event if needed", () => {
|
||||
getComponent({ mxEvent: alicesMessageEvent });
|
||||
expect(client.decryptEventIfNeeded).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('updates component on decrypted event', () => {
|
||||
it("updates component on decrypted event", () => {
|
||||
const decryptingEvent = new MatrixEvent({
|
||||
type: EventType.RoomMessageEncrypted,
|
||||
sender: userId,
|
||||
room_id: roomId,
|
||||
content: {},
|
||||
});
|
||||
jest.spyOn(decryptingEvent, 'isBeingDecrypted').mockReturnValue(true);
|
||||
jest.spyOn(decryptingEvent, "isBeingDecrypted").mockReturnValue(true);
|
||||
const { queryByLabelText } = getComponent({ mxEvent: decryptingEvent });
|
||||
|
||||
// still encrypted event is not actionable => no reply button
|
||||
expect(queryByLabelText('Reply')).toBeFalsy();
|
||||
expect(queryByLabelText("Reply")).toBeFalsy();
|
||||
|
||||
act(() => {
|
||||
// ''decrypt'' the event
|
||||
|
@ -177,46 +171,46 @@ describe('<MessageActionBar />', () => {
|
|||
});
|
||||
|
||||
// new available actions after decryption
|
||||
expect(queryByLabelText('Reply')).toBeTruthy();
|
||||
expect(queryByLabelText("Reply")).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('status', () => {
|
||||
it('updates component when event status changes', () => {
|
||||
describe("status", () => {
|
||||
it("updates component when event status changes", () => {
|
||||
alicesMessageEvent.setStatus(EventStatus.QUEUED);
|
||||
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
|
||||
// pending event status, cancel action available
|
||||
expect(queryByLabelText('Delete')).toBeTruthy();
|
||||
expect(queryByLabelText("Delete")).toBeTruthy();
|
||||
|
||||
act(() => {
|
||||
alicesMessageEvent.setStatus(EventStatus.SENT);
|
||||
});
|
||||
|
||||
// event is sent, no longer cancelable
|
||||
expect(queryByLabelText('Delete')).toBeFalsy();
|
||||
expect(queryByLabelText("Delete")).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('redaction', () => {
|
||||
describe("redaction", () => {
|
||||
// this doesn't do what it's supposed to
|
||||
// because beforeRedaction event is fired... before redaction
|
||||
// event is unchanged at point when this component updates
|
||||
// TODO file bug
|
||||
xit('updates component on before redaction event', () => {
|
||||
xit("updates component on before redaction event", () => {
|
||||
const event = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
sender: userId,
|
||||
room_id: roomId,
|
||||
content: {
|
||||
msgtype: MsgType.Text,
|
||||
body: 'Hello',
|
||||
body: "Hello",
|
||||
},
|
||||
});
|
||||
const { queryByLabelText } = getComponent({ mxEvent: event });
|
||||
|
||||
// no pending redaction => no delete button
|
||||
expect(queryByLabelText('Delete')).toBeFalsy();
|
||||
expect(queryByLabelText("Delete")).toBeFalsy();
|
||||
|
||||
act(() => {
|
||||
const redactionEvent = new MatrixEvent({
|
||||
|
@ -229,110 +223,110 @@ describe('<MessageActionBar />', () => {
|
|||
});
|
||||
|
||||
// updated with local redaction event, delete now available
|
||||
expect(queryByLabelText('Delete')).toBeTruthy();
|
||||
expect(queryByLabelText("Delete")).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('options button', () => {
|
||||
it('renders options menu', () => {
|
||||
describe("options button", () => {
|
||||
it("renders options menu", () => {
|
||||
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
expect(queryByLabelText('Options')).toBeTruthy();
|
||||
expect(queryByLabelText("Options")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('opens message context menu on click', () => {
|
||||
it("opens message context menu on click", () => {
|
||||
const { getByTestId, queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
act(() => {
|
||||
fireEvent.click(queryByLabelText('Options'));
|
||||
fireEvent.click(queryByLabelText("Options"));
|
||||
});
|
||||
expect(getByTestId('mx_MessageContextMenu')).toBeTruthy();
|
||||
expect(getByTestId("mx_MessageContextMenu")).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('reply button', () => {
|
||||
it('renders reply button on own actionable event', () => {
|
||||
describe("reply button", () => {
|
||||
it("renders reply button on own actionable event", () => {
|
||||
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
expect(queryByLabelText('Reply')).toBeTruthy();
|
||||
expect(queryByLabelText("Reply")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders reply button on others actionable event', () => {
|
||||
it("renders reply button on others actionable event", () => {
|
||||
const { queryByLabelText } = getComponent({ mxEvent: bobsMessageEvent }, { canSendMessages: true });
|
||||
expect(queryByLabelText('Reply')).toBeTruthy();
|
||||
expect(queryByLabelText("Reply")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('does not render reply button on non-actionable event', () => {
|
||||
it("does not render reply button on non-actionable event", () => {
|
||||
// redacted event is not actionable
|
||||
const { queryByLabelText } = getComponent({ mxEvent: redactedEvent });
|
||||
expect(queryByLabelText('Reply')).toBeFalsy();
|
||||
expect(queryByLabelText("Reply")).toBeFalsy();
|
||||
});
|
||||
|
||||
it('does not render reply button when user cannot send messaged', () => {
|
||||
it("does not render reply button when user cannot send messaged", () => {
|
||||
// redacted event is not actionable
|
||||
const { queryByLabelText } = getComponent({ mxEvent: redactedEvent }, { canSendMessages: false });
|
||||
expect(queryByLabelText('Reply')).toBeFalsy();
|
||||
expect(queryByLabelText("Reply")).toBeFalsy();
|
||||
});
|
||||
|
||||
it('dispatches reply event on click', () => {
|
||||
it("dispatches reply event on click", () => {
|
||||
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(queryByLabelText('Reply'));
|
||||
fireEvent.click(queryByLabelText("Reply"));
|
||||
});
|
||||
|
||||
expect(dispatcher.dispatch).toHaveBeenCalledWith({
|
||||
action: 'reply_to_event',
|
||||
action: "reply_to_event",
|
||||
event: alicesMessageEvent,
|
||||
context: TimelineRenderingType.Room,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('react button', () => {
|
||||
it('renders react button on own actionable event', () => {
|
||||
describe("react button", () => {
|
||||
it("renders react button on own actionable event", () => {
|
||||
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
expect(queryByLabelText('React')).toBeTruthy();
|
||||
expect(queryByLabelText("React")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders react button on others actionable event', () => {
|
||||
it("renders react button on others actionable event", () => {
|
||||
const { queryByLabelText } = getComponent({ mxEvent: bobsMessageEvent });
|
||||
expect(queryByLabelText('React')).toBeTruthy();
|
||||
expect(queryByLabelText("React")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('does not render react button on non-actionable event', () => {
|
||||
it("does not render react button on non-actionable event", () => {
|
||||
// redacted event is not actionable
|
||||
const { queryByLabelText } = getComponent({ mxEvent: redactedEvent });
|
||||
expect(queryByLabelText('React')).toBeFalsy();
|
||||
expect(queryByLabelText("React")).toBeFalsy();
|
||||
});
|
||||
|
||||
it('does not render react button when user cannot react', () => {
|
||||
it("does not render react button when user cannot react", () => {
|
||||
// redacted event is not actionable
|
||||
const { queryByLabelText } = getComponent({ mxEvent: redactedEvent }, { canReact: false });
|
||||
expect(queryByLabelText('React')).toBeFalsy();
|
||||
expect(queryByLabelText("React")).toBeFalsy();
|
||||
});
|
||||
|
||||
it('opens reaction picker on click', () => {
|
||||
it("opens reaction picker on click", () => {
|
||||
const { queryByLabelText, getByTestId } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
act(() => {
|
||||
fireEvent.click(queryByLabelText('React'));
|
||||
fireEvent.click(queryByLabelText("React"));
|
||||
});
|
||||
expect(getByTestId('mx_EmojiPicker')).toBeTruthy();
|
||||
expect(getByTestId("mx_EmojiPicker")).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('cancel button', () => {
|
||||
it('renders cancel button for an event with a cancelable status', () => {
|
||||
describe("cancel button", () => {
|
||||
it("renders cancel button for an event with a cancelable status", () => {
|
||||
alicesMessageEvent.setStatus(EventStatus.QUEUED);
|
||||
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
expect(queryByLabelText('Delete')).toBeTruthy();
|
||||
expect(queryByLabelText("Delete")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders cancel button for an event with a pending edit', () => {
|
||||
it("renders cancel button for an event with a pending edit", () => {
|
||||
const event = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
sender: userId,
|
||||
room_id: roomId,
|
||||
content: {
|
||||
msgtype: MsgType.Text,
|
||||
body: 'Hello',
|
||||
body: "Hello",
|
||||
},
|
||||
});
|
||||
event.setStatus(EventStatus.SENT);
|
||||
|
@ -342,23 +336,23 @@ describe('<MessageActionBar />', () => {
|
|||
room_id: roomId,
|
||||
content: {
|
||||
msgtype: MsgType.Text,
|
||||
body: 'replacing event body',
|
||||
body: "replacing event body",
|
||||
},
|
||||
});
|
||||
replacingEvent.setStatus(EventStatus.QUEUED);
|
||||
event.makeReplaced(replacingEvent);
|
||||
const { queryByLabelText } = getComponent({ mxEvent: event });
|
||||
expect(queryByLabelText('Delete')).toBeTruthy();
|
||||
expect(queryByLabelText("Delete")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders cancel button for an event with a pending redaction', () => {
|
||||
it("renders cancel button for an event with a pending redaction", () => {
|
||||
const event = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
sender: userId,
|
||||
room_id: roomId,
|
||||
content: {
|
||||
msgtype: MsgType.Text,
|
||||
body: 'Hello',
|
||||
body: "Hello",
|
||||
},
|
||||
});
|
||||
event.setStatus(EventStatus.SENT);
|
||||
|
@ -372,45 +366,45 @@ describe('<MessageActionBar />', () => {
|
|||
|
||||
event.markLocallyRedacted(redactionEvent);
|
||||
const { queryByLabelText } = getComponent({ mxEvent: event });
|
||||
expect(queryByLabelText('Delete')).toBeTruthy();
|
||||
expect(queryByLabelText("Delete")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders cancel and retry button for an event with NOT_SENT status', () => {
|
||||
it("renders cancel and retry button for an event with NOT_SENT status", () => {
|
||||
alicesMessageEvent.setStatus(EventStatus.NOT_SENT);
|
||||
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
expect(queryByLabelText('Retry')).toBeTruthy();
|
||||
expect(queryByLabelText('Delete')).toBeTruthy();
|
||||
expect(queryByLabelText("Retry")).toBeTruthy();
|
||||
expect(queryByLabelText("Delete")).toBeTruthy();
|
||||
});
|
||||
|
||||
it.todo('unsends event on cancel click');
|
||||
it.todo('retrys event on retry click');
|
||||
it.todo("unsends event on cancel click");
|
||||
it.todo("retrys event on retry click");
|
||||
});
|
||||
|
||||
describe('thread button', () => {
|
||||
describe("thread button", () => {
|
||||
beforeEach(() => {
|
||||
Thread.setServerSideSupport(FeatureSupport.Stable);
|
||||
});
|
||||
|
||||
describe('when threads feature is not enabled', () => {
|
||||
it('does not render thread button when threads does not have server support', () => {
|
||||
jest.spyOn(SettingsStore, 'getValue').mockReturnValue(false);
|
||||
describe("when threads feature is not enabled", () => {
|
||||
it("does not render thread button when threads does not have server support", () => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
|
||||
Thread.setServerSideSupport(FeatureSupport.None);
|
||||
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
expect(queryByLabelText('Reply in thread')).toBeFalsy();
|
||||
expect(queryByLabelText("Reply in thread")).toBeFalsy();
|
||||
});
|
||||
|
||||
it('renders thread button when threads has server support', () => {
|
||||
jest.spyOn(SettingsStore, 'getValue').mockReturnValue(false);
|
||||
it("renders thread button when threads has server support", () => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
|
||||
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
expect(queryByLabelText('Reply in thread')).toBeTruthy();
|
||||
expect(queryByLabelText("Reply in thread")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('opens user settings on click', () => {
|
||||
jest.spyOn(SettingsStore, 'getValue').mockReturnValue(false);
|
||||
it("opens user settings on click", () => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
|
||||
const { getByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByLabelText('Reply in thread'));
|
||||
fireEvent.click(getByLabelText("Reply in thread"));
|
||||
});
|
||||
|
||||
expect(dispatcher.dispatch).toHaveBeenCalledWith({
|
||||
|
@ -420,27 +414,27 @@ describe('<MessageActionBar />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('when threads feature is enabled', () => {
|
||||
describe("when threads feature is enabled", () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(SettingsStore, 'getValue').mockImplementation(setting => setting === 'feature_thread');
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => setting === "feature_thread");
|
||||
});
|
||||
|
||||
it('renders thread button on own actionable event', () => {
|
||||
it("renders thread button on own actionable event", () => {
|
||||
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
expect(queryByLabelText('Reply in thread')).toBeTruthy();
|
||||
expect(queryByLabelText("Reply in thread")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('does not render thread button for a beacon_info event', () => {
|
||||
it("does not render thread button for a beacon_info event", () => {
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(userId, roomId);
|
||||
const { queryByLabelText } = getComponent({ mxEvent: beaconInfoEvent });
|
||||
expect(queryByLabelText('Reply in thread')).toBeFalsy();
|
||||
expect(queryByLabelText("Reply in thread")).toBeFalsy();
|
||||
});
|
||||
|
||||
it('opens thread on click', () => {
|
||||
it("opens thread on click", () => {
|
||||
const { getByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByLabelText('Reply in thread'));
|
||||
fireEvent.click(getByLabelText("Reply in thread"));
|
||||
});
|
||||
|
||||
expect(dispatcher.dispatch).toHaveBeenCalledWith({
|
||||
|
@ -450,26 +444,26 @@ describe('<MessageActionBar />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('opens parent thread for a thread reply message', () => {
|
||||
it("opens parent thread for a thread reply message", () => {
|
||||
const threadReplyEvent = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
sender: userId,
|
||||
room_id: roomId,
|
||||
content: {
|
||||
msgtype: MsgType.Text,
|
||||
body: 'this is a thread reply',
|
||||
body: "this is a thread reply",
|
||||
},
|
||||
});
|
||||
// mock the thread stuff
|
||||
jest.spyOn(threadReplyEvent, 'isThreadRoot', 'get').mockReturnValue(false);
|
||||
jest.spyOn(threadReplyEvent, "isThreadRoot", "get").mockReturnValue(false);
|
||||
// set alicesMessageEvent as the root event
|
||||
jest.spyOn(threadReplyEvent, 'getThread').mockReturnValue(
|
||||
{ rootEvent: alicesMessageEvent } as unknown as Thread,
|
||||
);
|
||||
jest.spyOn(threadReplyEvent, "getThread").mockReturnValue({
|
||||
rootEvent: alicesMessageEvent,
|
||||
} as unknown as Thread);
|
||||
const { getByLabelText } = getComponent({ mxEvent: threadReplyEvent });
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByLabelText('Reply in thread'));
|
||||
fireEvent.click(getByLabelText("Reply in thread"));
|
||||
});
|
||||
|
||||
expect(dispatcher.dispatch).toHaveBeenCalledWith({
|
||||
|
@ -484,113 +478,115 @@ describe('<MessageActionBar />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('favourite button', () => {
|
||||
describe("favourite button", () => {
|
||||
//for multiple event usecase
|
||||
const favButton = (evt: MatrixEvent) => {
|
||||
return getComponent({ mxEvent: evt }).getByTestId(evt.getId());
|
||||
};
|
||||
|
||||
describe('when favourite_messages feature is enabled', () => {
|
||||
describe("when favourite_messages feature is enabled", () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(SettingsStore, 'getValue')
|
||||
.mockImplementation(setting => setting === 'feature_favourite_messages');
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation(
|
||||
(setting) => setting === "feature_favourite_messages",
|
||||
);
|
||||
localStorageMock.clear();
|
||||
});
|
||||
|
||||
it('renders favourite button on own actionable event', () => {
|
||||
it("renders favourite button on own actionable event", () => {
|
||||
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
expect(queryByLabelText('Favourite')).toBeTruthy();
|
||||
expect(queryByLabelText("Favourite")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders favourite button on other actionable events', () => {
|
||||
it("renders favourite button on other actionable events", () => {
|
||||
const { queryByLabelText } = getComponent({ mxEvent: bobsMessageEvent });
|
||||
expect(queryByLabelText('Favourite')).toBeTruthy();
|
||||
expect(queryByLabelText("Favourite")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('does not render Favourite button on non-actionable event', () => {
|
||||
it("does not render Favourite button on non-actionable event", () => {
|
||||
//redacted event is not actionable
|
||||
const { queryByLabelText } = getComponent({ mxEvent: redactedEvent });
|
||||
expect(queryByLabelText('Favourite')).toBeFalsy();
|
||||
expect(queryByLabelText("Favourite")).toBeFalsy();
|
||||
});
|
||||
|
||||
it('remembers favourited state of multiple events, and handles the localStorage of the events accordingly',
|
||||
() => {
|
||||
const alicesAction = favButton(alicesMessageEvent);
|
||||
const bobsAction = favButton(bobsMessageEvent);
|
||||
it("remembers favourited state of multiple events, and handles the localStorage of the events accordingly", () => {
|
||||
const alicesAction = favButton(alicesMessageEvent);
|
||||
const bobsAction = favButton(bobsMessageEvent);
|
||||
|
||||
//default state before being clicked
|
||||
expect(alicesAction.classList).not.toContain('mx_MessageActionBar_favouriteButton_fillstar');
|
||||
expect(bobsAction.classList).not.toContain('mx_MessageActionBar_favouriteButton_fillstar');
|
||||
expect(localStorageMock.getItem('io_element_favouriteMessages')).toBeNull();
|
||||
//default state before being clicked
|
||||
expect(alicesAction.classList).not.toContain("mx_MessageActionBar_favouriteButton_fillstar");
|
||||
expect(bobsAction.classList).not.toContain("mx_MessageActionBar_favouriteButton_fillstar");
|
||||
expect(localStorageMock.getItem("io_element_favouriteMessages")).toBeNull();
|
||||
|
||||
//if only alice's event is fired
|
||||
act(() => {
|
||||
fireEvent.click(alicesAction);
|
||||
});
|
||||
|
||||
expect(alicesAction.classList).toContain('mx_MessageActionBar_favouriteButton_fillstar');
|
||||
expect(bobsAction.classList).not.toContain('mx_MessageActionBar_favouriteButton_fillstar');
|
||||
expect(localStorageMock.setItem)
|
||||
.toHaveBeenCalledWith('io_element_favouriteMessages', '["$alices_message"]');
|
||||
|
||||
//when bob's event is fired,both should be styled and stored in localStorage
|
||||
act(() => {
|
||||
fireEvent.click(bobsAction);
|
||||
});
|
||||
|
||||
expect(alicesAction.classList).toContain('mx_MessageActionBar_favouriteButton_fillstar');
|
||||
expect(bobsAction.classList).toContain('mx_MessageActionBar_favouriteButton_fillstar');
|
||||
expect(localStorageMock.setItem)
|
||||
.toHaveBeenCalledWith('io_element_favouriteMessages', '["$alices_message","$bobs_message"]');
|
||||
|
||||
//finally, at this point the localStorage should contain the two eventids
|
||||
expect(localStorageMock.getItem('io_element_favouriteMessages'))
|
||||
.toEqual('["$alices_message","$bobs_message"]');
|
||||
|
||||
//if decided to unfavourite bob's event by clicking again
|
||||
act(() => {
|
||||
fireEvent.click(bobsAction);
|
||||
});
|
||||
expect(bobsAction.classList).not.toContain('mx_MessageActionBar_favouriteButton_fillstar');
|
||||
expect(alicesAction.classList).toContain('mx_MessageActionBar_favouriteButton_fillstar');
|
||||
expect(localStorageMock.getItem('io_element_favouriteMessages')).toEqual('["$alices_message"]');
|
||||
//if only alice's event is fired
|
||||
act(() => {
|
||||
fireEvent.click(alicesAction);
|
||||
});
|
||||
|
||||
expect(alicesAction.classList).toContain("mx_MessageActionBar_favouriteButton_fillstar");
|
||||
expect(bobsAction.classList).not.toContain("mx_MessageActionBar_favouriteButton_fillstar");
|
||||
expect(localStorageMock.setItem).toHaveBeenCalledWith(
|
||||
"io_element_favouriteMessages",
|
||||
'["$alices_message"]',
|
||||
);
|
||||
|
||||
//when bob's event is fired,both should be styled and stored in localStorage
|
||||
act(() => {
|
||||
fireEvent.click(bobsAction);
|
||||
});
|
||||
|
||||
expect(alicesAction.classList).toContain("mx_MessageActionBar_favouriteButton_fillstar");
|
||||
expect(bobsAction.classList).toContain("mx_MessageActionBar_favouriteButton_fillstar");
|
||||
expect(localStorageMock.setItem).toHaveBeenCalledWith(
|
||||
"io_element_favouriteMessages",
|
||||
'["$alices_message","$bobs_message"]',
|
||||
);
|
||||
|
||||
//finally, at this point the localStorage should contain the two eventids
|
||||
expect(localStorageMock.getItem("io_element_favouriteMessages")).toEqual(
|
||||
'["$alices_message","$bobs_message"]',
|
||||
);
|
||||
|
||||
//if decided to unfavourite bob's event by clicking again
|
||||
act(() => {
|
||||
fireEvent.click(bobsAction);
|
||||
});
|
||||
expect(bobsAction.classList).not.toContain("mx_MessageActionBar_favouriteButton_fillstar");
|
||||
expect(alicesAction.classList).toContain("mx_MessageActionBar_favouriteButton_fillstar");
|
||||
expect(localStorageMock.getItem("io_element_favouriteMessages")).toEqual('["$alices_message"]');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when favourite_messages feature is disabled', () => {
|
||||
it('does not render', () => {
|
||||
jest.spyOn(SettingsStore, 'getValue').mockReturnValue(false);
|
||||
describe("when favourite_messages feature is disabled", () => {
|
||||
it("does not render", () => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
|
||||
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
expect(queryByLabelText('Favourite')).toBeFalsy();
|
||||
expect(queryByLabelText("Favourite")).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
["React"],
|
||||
["Reply"],
|
||||
["Reply in thread"],
|
||||
["Favourite"],
|
||||
["Edit"],
|
||||
])("does not show context menu when right-clicking", (buttonLabel: string) => {
|
||||
// For favourite button
|
||||
jest.spyOn(SettingsStore, 'getValue').mockReturnValue(true);
|
||||
it.each([["React"], ["Reply"], ["Reply in thread"], ["Favourite"], ["Edit"]])(
|
||||
"does not show context menu when right-clicking",
|
||||
(buttonLabel: string) => {
|
||||
// For favourite button
|
||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(true);
|
||||
|
||||
const event = new MouseEvent("contextmenu", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
event.stopPropagation = jest.fn();
|
||||
event.preventDefault = jest.fn();
|
||||
const event = new MouseEvent("contextmenu", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
event.stopPropagation = jest.fn();
|
||||
event.preventDefault = jest.fn();
|
||||
|
||||
const { queryByTestId, queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
act(() => {
|
||||
fireEvent(queryByLabelText(buttonLabel), event);
|
||||
});
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
expect(queryByTestId("mx_MessageContextMenu")).toBeFalsy();
|
||||
});
|
||||
const { queryByTestId, queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
act(() => {
|
||||
fireEvent(queryByLabelText(buttonLabel), event);
|
||||
});
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
expect(queryByTestId("mx_MessageContextMenu")).toBeFalsy();
|
||||
},
|
||||
);
|
||||
|
||||
it("does shows context menu when right-clicking options", () => {
|
||||
const { queryByTestId, queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
|
||||
|
|
|
@ -26,11 +26,11 @@ import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalink
|
|||
|
||||
jest.mock("../../../../src/components/views/messages/UnknownBody", () => ({
|
||||
__esModule: true,
|
||||
default: () => (<div data-testid="unknown-body" />),
|
||||
default: () => <div data-testid="unknown-body" />,
|
||||
}));
|
||||
|
||||
jest.mock("../../../../src/voice-broadcast/components/VoiceBroadcastBody", () => ({
|
||||
VoiceBroadcastBody: () => (<div data-testid="voice-broadcast-body" />),
|
||||
VoiceBroadcastBody: () => <div data-testid="voice-broadcast-body" />,
|
||||
}));
|
||||
|
||||
describe("MessageEvent", () => {
|
||||
|
@ -39,11 +39,13 @@ describe("MessageEvent", () => {
|
|||
let event: MatrixEvent;
|
||||
|
||||
const renderMessageEvent = (): RenderResult => {
|
||||
return render(<MessageEvent
|
||||
mxEvent={event}
|
||||
onHeightChanged={jest.fn()}
|
||||
permalinkCreator={new RoomPermalinkCreator(room)}
|
||||
/>);
|
||||
return render(
|
||||
<MessageEvent
|
||||
mxEvent={event}
|
||||
onHeightChanged={jest.fn()}
|
||||
permalinkCreator={new RoomPermalinkCreator(room)}
|
||||
/>,
|
||||
);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -31,7 +31,7 @@ import { MediaEventHelper } from "../../../../src/utils/MediaEventHelper";
|
|||
|
||||
describe("<TextualBody />", () => {
|
||||
afterEach(() => {
|
||||
jest.spyOn(MatrixClientPeg, 'get').mockRestore();
|
||||
jest.spyOn(MatrixClientPeg, "get").mockRestore();
|
||||
});
|
||||
|
||||
const defaultRoom = mkStubRoom("room_id", "test room", undefined);
|
||||
|
@ -58,7 +58,7 @@ describe("<TextualBody />", () => {
|
|||
const defaultProps = {
|
||||
mxEvent: defaultEvent,
|
||||
highlights: [],
|
||||
highlightLink: '',
|
||||
highlightLink: "",
|
||||
onMessageAllowed: jest.fn(),
|
||||
onHeightChanged: jest.fn(),
|
||||
permalinkCreator: new RoomPermalinkCreator(defaultRoom),
|
||||
|
@ -107,7 +107,7 @@ describe("<TextualBody />", () => {
|
|||
const wrapper = getComponent({ mxEvent: ev });
|
||||
expect(wrapper.text()).toBe(ev.getContent().body);
|
||||
const content = wrapper.find(".mx_EventTile_body");
|
||||
expect(content.html()).toBe(`<span class="mx_EventTile_body" dir="auto">${ ev.getContent().body }</span>`);
|
||||
expect(content.html()).toBe(`<span class="mx_EventTile_body" dir="auto">${ev.getContent().body}</span>`);
|
||||
});
|
||||
|
||||
describe("renders plain-text m.text correctly", () => {
|
||||
|
@ -130,7 +130,7 @@ describe("<TextualBody />", () => {
|
|||
const wrapper = getComponent({ mxEvent: ev });
|
||||
expect(wrapper.text()).toBe(ev.getContent().body);
|
||||
const content = wrapper.find(".mx_EventTile_body");
|
||||
expect(content.html()).toBe(`<span class="mx_EventTile_body" dir="auto">${ ev.getContent().body }</span>`);
|
||||
expect(content.html()).toBe(`<span class="mx_EventTile_body" dir="auto">${ev.getContent().body}</span>`);
|
||||
});
|
||||
|
||||
// If pills were rendered within a Portal/same shadow DOM then it'd be easier to test
|
||||
|
@ -149,9 +149,11 @@ describe("<TextualBody />", () => {
|
|||
const wrapper = getComponent({ mxEvent: ev });
|
||||
expect(wrapper.text()).toBe(ev.getContent().body);
|
||||
const content = wrapper.find(".mx_EventTile_body");
|
||||
expect(content.html()).toBe('<span class="mx_EventTile_body" dir="auto">' +
|
||||
'Visit <a href="https://matrix.org/" class="linkified" target="_blank" rel="noreferrer noopener">' +
|
||||
'https://matrix.org/</a></span>');
|
||||
expect(content.html()).toBe(
|
||||
'<span class="mx_EventTile_body" dir="auto">' +
|
||||
'Visit <a href="https://matrix.org/" class="linkified" target="_blank" rel="noreferrer noopener">' +
|
||||
"https://matrix.org/</a></span>",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -188,8 +190,11 @@ describe("<TextualBody />", () => {
|
|||
const wrapper = getComponent({ mxEvent: ev }, matrixClient);
|
||||
expect(wrapper.text()).toBe("foo baz bar del u");
|
||||
const content = wrapper.find(".mx_EventTile_body");
|
||||
expect(content.html()).toBe('<span class="mx_EventTile_body markdown-body" dir="auto">' +
|
||||
ev.getContent().formatted_body + '</span>');
|
||||
expect(content.html()).toBe(
|
||||
'<span class="mx_EventTile_body markdown-body" dir="auto">' +
|
||||
ev.getContent().formatted_body +
|
||||
"</span>",
|
||||
);
|
||||
});
|
||||
|
||||
it("spoilers get injected properly into the DOM", () => {
|
||||
|
@ -201,7 +206,7 @@ describe("<TextualBody />", () => {
|
|||
body: "Hey [Spoiler for movie](mxc://someserver/somefile)",
|
||||
msgtype: "m.text",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: "Hey <span data-mx-spoiler=\"movie\">the movie was awesome</span>",
|
||||
formatted_body: 'Hey <span data-mx-spoiler="movie">the movie was awesome</span>',
|
||||
},
|
||||
event: true,
|
||||
});
|
||||
|
@ -209,12 +214,14 @@ describe("<TextualBody />", () => {
|
|||
const wrapper = getComponent({ mxEvent: ev }, matrixClient);
|
||||
expect(wrapper.text()).toBe("Hey (movie) the movie was awesome");
|
||||
const content = wrapper.find(".mx_EventTile_body");
|
||||
expect(content.html()).toBe('<span class="mx_EventTile_body markdown-body" dir="auto">' +
|
||||
'Hey <span>' +
|
||||
'<span class="mx_EventTile_spoiler">' +
|
||||
'<span class="mx_EventTile_spoiler_reason">(movie)</span> ' +
|
||||
'<span class="mx_EventTile_spoiler_content"><span>the movie was awesome</span></span>' +
|
||||
'</span></span></span>');
|
||||
expect(content.html()).toBe(
|
||||
'<span class="mx_EventTile_body markdown-body" dir="auto">' +
|
||||
"Hey <span>" +
|
||||
'<span class="mx_EventTile_spoiler">' +
|
||||
'<span class="mx_EventTile_spoiler_reason">(movie)</span> ' +
|
||||
'<span class="mx_EventTile_spoiler_content"><span>the movie was awesome</span></span>' +
|
||||
"</span></span></span>",
|
||||
);
|
||||
});
|
||||
|
||||
it("linkification is not applied to code blocks", () => {
|
||||
|
@ -247,7 +254,7 @@ describe("<TextualBody />", () => {
|
|||
body: "Hey User",
|
||||
msgtype: "m.text",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: "Hey <a href=\"https://matrix.to/#/@user:server\">Member</a>",
|
||||
formatted_body: 'Hey <a href="https://matrix.to/#/@user:server">Member</a>',
|
||||
},
|
||||
event: true,
|
||||
});
|
||||
|
@ -290,8 +297,8 @@ describe("<TextualBody />", () => {
|
|||
msgtype: "m.text",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body:
|
||||
"An <a href=\"https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com/" +
|
||||
"$16085560162aNpaH:example.com?via=example.com\">event link</a> with text",
|
||||
'An <a href="https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com/' +
|
||||
'$16085560162aNpaH:example.com?via=example.com">event link</a> with text',
|
||||
},
|
||||
event: true,
|
||||
});
|
||||
|
@ -301,9 +308,9 @@ describe("<TextualBody />", () => {
|
|||
const content = wrapper.find(".mx_EventTile_body");
|
||||
expect(content.html()).toBe(
|
||||
'<span class="mx_EventTile_body markdown-body" dir="auto">' +
|
||||
'An <a href="https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com/' +
|
||||
'$16085560162aNpaH:example.com?via=example.com" ' +
|
||||
'rel="noreferrer noopener">event link</a> with text</span>',
|
||||
'An <a href="https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com/' +
|
||||
'$16085560162aNpaH:example.com?via=example.com" ' +
|
||||
'rel="noreferrer noopener">event link</a> with text</span>',
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -319,8 +326,8 @@ describe("<TextualBody />", () => {
|
|||
msgtype: "m.text",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body:
|
||||
"A <a href=\"https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com" +
|
||||
"?via=example.com&via=bob.com\">room link</a> with vias",
|
||||
'A <a href="https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com' +
|
||||
'?via=example.com&via=bob.com">room link</a> with vias',
|
||||
},
|
||||
event: true,
|
||||
});
|
||||
|
@ -330,17 +337,17 @@ describe("<TextualBody />", () => {
|
|||
const content = wrapper.find(".mx_EventTile_body");
|
||||
expect(content.html()).toBe(
|
||||
'<span class="mx_EventTile_body markdown-body" dir="auto">' +
|
||||
'A <span><bdi><a class="mx_Pill mx_RoomPill" ' +
|
||||
'href="https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com' +
|
||||
'?via=example.com&via=bob.com"' +
|
||||
'><img class="mx_BaseAvatar mx_BaseAvatar_image" ' +
|
||||
'src="mxc://avatar.url/room.png" ' +
|
||||
'style="width: 16px; height: 16px;" alt="" data-testid="avatar-img" aria-hidden="true">' +
|
||||
'<span class="mx_Pill_linkText">room name</span></a></bdi></span> with vias</span>',
|
||||
'A <span><bdi><a class="mx_Pill mx_RoomPill" ' +
|
||||
'href="https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com' +
|
||||
'?via=example.com&via=bob.com"' +
|
||||
'><img class="mx_BaseAvatar mx_BaseAvatar_image" ' +
|
||||
'src="mxc://avatar.url/room.png" ' +
|
||||
'style="width: 16px; height: 16px;" alt="" data-testid="avatar-img" aria-hidden="true">' +
|
||||
'<span class="mx_Pill_linkText">room name</span></a></bdi></span> with vias</span>',
|
||||
);
|
||||
});
|
||||
|
||||
it('renders formatted body without html corretly', () => {
|
||||
it("renders formatted body without html corretly", () => {
|
||||
const ev = mkEvent({
|
||||
type: "m.room.message",
|
||||
room: "room_id",
|
||||
|
@ -358,15 +365,13 @@ describe("<TextualBody />", () => {
|
|||
|
||||
const content = wrapper.find(".mx_EventTile_body");
|
||||
expect(content.html()).toBe(
|
||||
'<span class="mx_EventTile_body" dir="auto">' +
|
||||
'escaped *markdown*' +
|
||||
'</span>',
|
||||
'<span class="mx_EventTile_body" dir="auto">' + "escaped *markdown*" + "</span>",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("renders url previews correctly", () => {
|
||||
languageHandler.setMissingEntryGenerator(key => key.split('|', 2)[1]);
|
||||
languageHandler.setMissingEntryGenerator((key) => key.split("|", 2)[1]);
|
||||
|
||||
const matrixClient = getMockClientWithEventEmitter({
|
||||
getRoom: () => mkStubRoom("room_id", "room name", undefined),
|
||||
|
@ -408,21 +413,24 @@ describe("<TextualBody />", () => {
|
|||
},
|
||||
event: true,
|
||||
});
|
||||
jest.spyOn(ev, 'replacingEventDate').mockReturnValue(new Date(1993, 7, 3));
|
||||
jest.spyOn(ev, "replacingEventDate").mockReturnValue(new Date(1993, 7, 3));
|
||||
ev.makeReplaced(ev2);
|
||||
|
||||
wrapper.setProps({
|
||||
mxEvent: ev,
|
||||
replacingEventId: ev.getId(),
|
||||
}, () => {
|
||||
expect(wrapper.text()).toBe(ev2.getContent()["m.new_content"].body + "(edited)");
|
||||
wrapper.setProps(
|
||||
{
|
||||
mxEvent: ev,
|
||||
replacingEventId: ev.getId(),
|
||||
},
|
||||
() => {
|
||||
expect(wrapper.text()).toBe(ev2.getContent()["m.new_content"].body + "(edited)");
|
||||
|
||||
// XXX: this is to give TextualBody enough time for state to settle
|
||||
wrapper.setState({}, () => {
|
||||
widgets = wrapper.find("LinkPreviewGroup");
|
||||
// at this point we should have exactly two links (not the matrix.org one anymore)
|
||||
expect(widgets.at(0).prop("links")).toEqual(["https://vector.im/", "https://riot.im/"]);
|
||||
});
|
||||
});
|
||||
// XXX: this is to give TextualBody enough time for state to settle
|
||||
wrapper.setState({}, () => {
|
||||
widgets = wrapper.find("LinkPreviewGroup");
|
||||
// at this point we should have exactly two links (not the matrix.org one anymore)
|
||||
expect(widgets.at(0).prop("links")).toEqual(["https://vector.im/", "https://riot.im/"]);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,20 +14,19 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import React from "react";
|
||||
import { render } from "@testing-library/react";
|
||||
|
||||
import MediaProcessingError from '../../../../../src/components/views/messages/shared/MediaProcessingError';
|
||||
import MediaProcessingError from "../../../../../src/components/views/messages/shared/MediaProcessingError";
|
||||
|
||||
describe('<MediaProcessingError />', () => {
|
||||
describe("<MediaProcessingError />", () => {
|
||||
const defaultProps = {
|
||||
className: 'test-classname',
|
||||
children: 'Something went wrong',
|
||||
className: "test-classname",
|
||||
children: "Something went wrong",
|
||||
};
|
||||
const getComponent = (props = {}) =>
|
||||
render(<MediaProcessingError {...defaultProps} {...props} />);
|
||||
const getComponent = (props = {}) => render(<MediaProcessingError {...defaultProps} {...props} />);
|
||||
|
||||
it('renders', () => {
|
||||
it("renders", () => {
|
||||
const { container } = getComponent();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -32,12 +32,7 @@ import {
|
|||
PollEndEvent,
|
||||
} from "matrix-events-sdk";
|
||||
|
||||
import {
|
||||
stubClient,
|
||||
mkStubRoom,
|
||||
mkEvent,
|
||||
mkMessage,
|
||||
} from "../../../test-utils";
|
||||
import { stubClient, mkStubRoom, mkEvent, mkMessage } from "../../../test-utils";
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import PinnedMessagesCard from "../../../../src/components/views/right_panel/PinnedMessagesCard";
|
||||
import PinnedEventTile from "../../../../src/components/views/rooms/PinnedEventTile";
|
||||
|
@ -53,31 +48,34 @@ describe("<PinnedMessagesCard />", () => {
|
|||
cli.relations.mockResolvedValue({ originalEvent: {} as unknown as MatrixEvent, events: [] });
|
||||
|
||||
const mkRoom = (localPins: MatrixEvent[], nonLocalPins: MatrixEvent[]): Room => {
|
||||
const room = mkStubRoom("!room:example.org", 'room', cli);
|
||||
const room = mkStubRoom("!room:example.org", "room", cli);
|
||||
// Deferred since we may be adding or removing pins later
|
||||
const pins = () => [...localPins, ...nonLocalPins];
|
||||
|
||||
// Insert pin IDs into room state
|
||||
mocked(room.currentState).getStateEvents.mockImplementation((): any => mkEvent({
|
||||
event: true,
|
||||
type: EventType.RoomPinnedEvents,
|
||||
content: {
|
||||
pinned: pins().map(e => e.getId()),
|
||||
},
|
||||
user: '@user:example.org',
|
||||
room: '!room:example.org',
|
||||
}));
|
||||
mocked(room.currentState).getStateEvents.mockImplementation((): any =>
|
||||
mkEvent({
|
||||
event: true,
|
||||
type: EventType.RoomPinnedEvents,
|
||||
content: {
|
||||
pinned: pins().map((e) => e.getId()),
|
||||
},
|
||||
user: "@user:example.org",
|
||||
room: "!room:example.org",
|
||||
}),
|
||||
);
|
||||
|
||||
// Insert local pins into local timeline set
|
||||
room.getUnfilteredTimelineSet = () => ({
|
||||
getTimelineForEvent: () => ({
|
||||
getEvents: () => localPins,
|
||||
}),
|
||||
} as unknown as EventTimelineSet);
|
||||
room.getUnfilteredTimelineSet = () =>
|
||||
({
|
||||
getTimelineForEvent: () => ({
|
||||
getEvents: () => localPins,
|
||||
}),
|
||||
} as unknown as EventTimelineSet);
|
||||
|
||||
// Return all pins over fetchRoomEvent
|
||||
cli.fetchRoomEvent.mockImplementation((roomId, eventId) => {
|
||||
const event = pins().find(e => e.getId() === eventId)?.event;
|
||||
const event = pins().find((e) => e.getId() === eventId)?.event;
|
||||
return Promise.resolve(event as IMinimalEvent);
|
||||
});
|
||||
|
||||
|
@ -87,16 +85,19 @@ describe("<PinnedMessagesCard />", () => {
|
|||
const mountPins = async (room: Room): Promise<ReactWrapper<ComponentProps<typeof PinnedMessagesCard>>> => {
|
||||
let pins;
|
||||
await act(async () => {
|
||||
pins = mount(<PinnedMessagesCard
|
||||
room={room}
|
||||
onClose={jest.fn()}
|
||||
permalinkCreator={new RoomPermalinkCreator(room, room.roomId)}
|
||||
/>, {
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: { value: cli },
|
||||
});
|
||||
pins = mount(
|
||||
<PinnedMessagesCard
|
||||
room={room}
|
||||
onClose={jest.fn()}
|
||||
permalinkCreator={new RoomPermalinkCreator(room, room.roomId)}
|
||||
/>,
|
||||
{
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: { value: cli },
|
||||
},
|
||||
);
|
||||
// Wait a tick for state updates
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
});
|
||||
pins.update();
|
||||
|
||||
|
@ -105,15 +106,16 @@ describe("<PinnedMessagesCard />", () => {
|
|||
|
||||
const emitPinUpdates = async (pins: ReactWrapper<ComponentProps<typeof PinnedMessagesCard>>) => {
|
||||
const room = pins.props().room;
|
||||
const pinListener = mocked(room.currentState).on.mock.calls
|
||||
.find(([eventName, listener]) => eventName === RoomStateEvent.Events)[1];
|
||||
const pinListener = mocked(room.currentState).on.mock.calls.find(
|
||||
([eventName, listener]) => eventName === RoomStateEvent.Events,
|
||||
)[1];
|
||||
|
||||
await act(async () => {
|
||||
// Emit the update
|
||||
// @ts-ignore what is going on here?
|
||||
pinListener(room.currentState.getStateEvents());
|
||||
// Wait a tick for state updates
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
});
|
||||
pins.update();
|
||||
};
|
||||
|
@ -240,12 +242,14 @@ describe("<PinnedMessagesCard />", () => {
|
|||
["@alice:example.org", 0],
|
||||
["@bob:example.org", 0],
|
||||
["@eve:example.org", 1],
|
||||
].map(([user, option], i) => mkEvent({
|
||||
...PollResponseEvent.from([answers[option].id], poll.getId()).serialize(),
|
||||
event: true,
|
||||
room: "!room:example.org",
|
||||
user: user as string,
|
||||
}));
|
||||
].map(([user, option], i) =>
|
||||
mkEvent({
|
||||
...PollResponseEvent.from([answers[option].id], poll.getId()).serialize(),
|
||||
event: true,
|
||||
room: "!room:example.org",
|
||||
user: user as string,
|
||||
}),
|
||||
);
|
||||
const end = mkEvent({
|
||||
...PollEndEvent.from(poll.getId(), "Closing the poll").serialize(),
|
||||
event: true,
|
||||
|
@ -259,9 +263,9 @@ describe("<PinnedMessagesCard />", () => {
|
|||
switch (eventType) {
|
||||
case M_POLL_RESPONSE.name:
|
||||
// Paginate the results, for added challenge
|
||||
return (from === "page2") ?
|
||||
{ originalEvent: poll, events: responses.slice(2) } :
|
||||
{ originalEvent: poll, events: responses.slice(0, 2), nextBatch: "page2" };
|
||||
return from === "page2"
|
||||
? { originalEvent: poll, events: responses.slice(2) }
|
||||
: { originalEvent: poll, events: responses.slice(0, 2), nextBatch: "page2" };
|
||||
case M_POLL_END.name:
|
||||
return { originalEvent: null, events: [end] };
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
|||
import SettingsStore from "../../../../src/settings/SettingsStore";
|
||||
import { stubClient } from "../../../test-utils";
|
||||
|
||||
describe("RoomHeaderButtons-test.tsx", function() {
|
||||
describe("RoomHeaderButtons-test.tsx", function () {
|
||||
const ROOM_ID = "!roomId:example.org";
|
||||
let room: Room;
|
||||
let client: MatrixClient;
|
||||
|
@ -45,10 +45,7 @@ describe("RoomHeaderButtons-test.tsx", function() {
|
|||
});
|
||||
|
||||
function getComponent(room?: Room) {
|
||||
return render(<RoomHeaderButtons
|
||||
room={room}
|
||||
excludedRightPanelPhaseButtons={[]}
|
||||
/>);
|
||||
return render(<RoomHeaderButtons room={room} excludedRightPanelPhaseButtons={[]} />);
|
||||
}
|
||||
|
||||
function getThreadButton(container) {
|
||||
|
@ -56,9 +53,7 @@ describe("RoomHeaderButtons-test.tsx", function() {
|
|||
}
|
||||
|
||||
function isIndicatorOfType(container, type: "red" | "gray") {
|
||||
return container.querySelector(".mx_RightPanel_threadsButton .mx_Indicator")
|
||||
.className
|
||||
.includes(type);
|
||||
return container.querySelector(".mx_RightPanel_threadsButton .mx_Indicator").className.includes(type);
|
||||
}
|
||||
|
||||
it("shows the thread button", () => {
|
||||
|
|
|
@ -14,24 +14,24 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from 'enzyme';
|
||||
import { mocked } from 'jest-mock';
|
||||
import { mount } from "enzyme";
|
||||
import { mocked } from "jest-mock";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { Room, User, MatrixClient } from 'matrix-js-sdk/src/matrix';
|
||||
import { Phase, VerificationRequest } from 'matrix-js-sdk/src/crypto/verification/request/VerificationRequest';
|
||||
import { Room, User, MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { Phase, VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||
|
||||
import UserInfo from '../../../../src/components/views/right_panel/UserInfo';
|
||||
import { RightPanelPhases } from '../../../../src/stores/right-panel/RightPanelStorePhases';
|
||||
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
||||
import VerificationPanel from '../../../../src/components/views/right_panel/VerificationPanel';
|
||||
import EncryptionInfo from '../../../../src/components/views/right_panel/EncryptionInfo';
|
||||
import UserInfo from "../../../../src/components/views/right_panel/UserInfo";
|
||||
import { RightPanelPhases } from "../../../../src/stores/right-panel/RightPanelStorePhases";
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import VerificationPanel from "../../../../src/components/views/right_panel/VerificationPanel";
|
||||
import EncryptionInfo from "../../../../src/components/views/right_panel/EncryptionInfo";
|
||||
|
||||
const findByTestId = (component, id) => component.find(`[data-test-id="${id}"]`);
|
||||
|
||||
jest.mock('../../../../src/utils/DMRoomMap', () => {
|
||||
jest.mock("../../../../src/utils/DMRoomMap", () => {
|
||||
const mock = {
|
||||
getUserIdForRoomId: jest.fn(),
|
||||
getDMRoomsForUserId: jest.fn(),
|
||||
|
@ -43,8 +43,8 @@ jest.mock('../../../../src/utils/DMRoomMap', () => {
|
|||
};
|
||||
});
|
||||
|
||||
describe('<UserInfo />', () => {
|
||||
const defaultUserId = '@test:test';
|
||||
describe("<UserInfo />", () => {
|
||||
const defaultUserId = "@test:test";
|
||||
const defaultUser = new User(defaultUserId);
|
||||
|
||||
const mockClient = mocked({
|
||||
|
@ -57,7 +57,7 @@ describe('<UserInfo />', () => {
|
|||
isSynapseAdministrator: jest.fn().mockResolvedValue(false),
|
||||
isRoomEncrypted: jest.fn().mockReturnValue(false),
|
||||
doesServerSupportUnstableFeature: jest.fn().mockReturnValue(false),
|
||||
mxcUrlToHttp: jest.fn().mockReturnValue('mock-mxcUrlToHttp'),
|
||||
mxcUrlToHttp: jest.fn().mockReturnValue("mock-mxcUrlToHttp"),
|
||||
removeListener: jest.fn(),
|
||||
currentState: {
|
||||
on: jest.fn(),
|
||||
|
@ -65,7 +65,9 @@ describe('<UserInfo />', () => {
|
|||
} as unknown as MatrixClient);
|
||||
|
||||
const verificationRequest = {
|
||||
pending: true, on: jest.fn(), phase: Phase.Ready,
|
||||
pending: true,
|
||||
on: jest.fn(),
|
||||
phase: Phase.Ready,
|
||||
channel: { transactionId: 1 },
|
||||
otherPartySupportsMethod: jest.fn(),
|
||||
} as unknown as VerificationRequest;
|
||||
|
@ -77,51 +79,49 @@ describe('<UserInfo />', () => {
|
|||
onClose: jest.fn(),
|
||||
};
|
||||
|
||||
const getComponent = (props = {}) => mount(
|
||||
<UserInfo {...defaultProps} {...props} />,
|
||||
{
|
||||
const getComponent = (props = {}) =>
|
||||
mount(<UserInfo {...defaultProps} {...props} />, {
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: { value: mockClient },
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
jest.spyOn(MatrixClientPeg, 'get').mockReturnValue(mockClient);
|
||||
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mockClient.getUser.mockClear().mockReturnValue({} as unknown as User);
|
||||
});
|
||||
|
||||
it('closes on close button click', () => {
|
||||
it("closes on close button click", () => {
|
||||
const onClose = jest.fn();
|
||||
const component = getComponent({ onClose });
|
||||
act(() => {
|
||||
findByTestId(component, 'base-card-close-button').at(0).simulate('click');
|
||||
findByTestId(component, "base-card-close-button").at(0).simulate("click");
|
||||
});
|
||||
|
||||
expect(onClose).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('without a room', () => {
|
||||
it('does not render space header', () => {
|
||||
describe("without a room", () => {
|
||||
it("does not render space header", () => {
|
||||
const component = getComponent();
|
||||
expect(findByTestId(component, 'space-header').length).toBeFalsy();
|
||||
expect(findByTestId(component, "space-header").length).toBeFalsy();
|
||||
});
|
||||
|
||||
it('renders user info', () => {
|
||||
it("renders user info", () => {
|
||||
const component = getComponent();
|
||||
expect(component.find("BasicUserInfo").length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders encryption info panel without pending verification', () => {
|
||||
it("renders encryption info panel without pending verification", () => {
|
||||
const phase = RightPanelPhases.EncryptionPanel;
|
||||
const component = getComponent({ phase });
|
||||
|
||||
expect(component.find(EncryptionInfo).length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders encryption verification panel with pending verification', () => {
|
||||
it("renders encryption verification panel with pending verification", () => {
|
||||
const phase = RightPanelPhases.EncryptionPanel;
|
||||
const component = getComponent({ phase, verificationRequest });
|
||||
|
||||
|
@ -129,22 +129,22 @@ describe('<UserInfo />', () => {
|
|||
expect(component.find(VerificationPanel).length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders close button correctly when encryption panel with a pending verification request', () => {
|
||||
it("renders close button correctly when encryption panel with a pending verification request", () => {
|
||||
const phase = RightPanelPhases.EncryptionPanel;
|
||||
const component = getComponent({ phase, verificationRequest });
|
||||
|
||||
expect(findByTestId(component, 'base-card-close-button').at(0).props().title).toEqual('Cancel');
|
||||
expect(findByTestId(component, "base-card-close-button").at(0).props().title).toEqual("Cancel");
|
||||
});
|
||||
});
|
||||
|
||||
describe('with a room', () => {
|
||||
describe("with a room", () => {
|
||||
const room = {
|
||||
roomId: '!fkfk',
|
||||
roomId: "!fkfk",
|
||||
getType: jest.fn().mockReturnValue(undefined),
|
||||
isSpaceRoom: jest.fn().mockReturnValue(false),
|
||||
getMember: jest.fn().mockReturnValue(undefined),
|
||||
getMxcAvatarUrl: jest.fn().mockReturnValue('mock-avatar-url'),
|
||||
name: 'test room',
|
||||
getMxcAvatarUrl: jest.fn().mockReturnValue("mock-avatar-url"),
|
||||
name: "test room",
|
||||
on: jest.fn(),
|
||||
currentState: {
|
||||
getStateEvents: jest.fn(),
|
||||
|
@ -152,32 +152,33 @@ describe('<UserInfo />', () => {
|
|||
},
|
||||
} as unknown as Room;
|
||||
|
||||
it('renders user info', () => {
|
||||
it("renders user info", () => {
|
||||
const component = getComponent();
|
||||
expect(component.find("BasicUserInfo").length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('does not render space header when room is not a space room', () => {
|
||||
it("does not render space header when room is not a space room", () => {
|
||||
const component = getComponent({ room });
|
||||
expect(findByTestId(component, 'space-header').length).toBeFalsy();
|
||||
expect(findByTestId(component, "space-header").length).toBeFalsy();
|
||||
});
|
||||
|
||||
it('renders space header when room is a space room', () => {
|
||||
it("renders space header when room is a space room", () => {
|
||||
const spaceRoom = {
|
||||
...room, isSpaceRoom: jest.fn().mockReturnValue(true),
|
||||
...room,
|
||||
isSpaceRoom: jest.fn().mockReturnValue(true),
|
||||
};
|
||||
const component = getComponent({ room: spaceRoom });
|
||||
expect(findByTestId(component, 'space-header').length).toBeTruthy();
|
||||
expect(findByTestId(component, "space-header").length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders encryption info panel without pending verification', () => {
|
||||
it("renders encryption info panel without pending verification", () => {
|
||||
const phase = RightPanelPhases.EncryptionPanel;
|
||||
const component = getComponent({ phase, room });
|
||||
|
||||
expect(component.find(EncryptionInfo).length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders encryption verification panel with pending verification', () => {
|
||||
it("renders encryption verification panel with pending verification", () => {
|
||||
const phase = RightPanelPhases.EncryptionPanel;
|
||||
const component = getComponent({ phase, verificationRequest, room });
|
||||
|
||||
|
|
|
@ -14,12 +14,12 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import { MatrixClient, Room } from 'matrix-js-sdk/src/matrix';
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { MatrixClient, Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import BasicMessageComposer from '../../../../src/components/views/rooms/BasicMessageComposer';
|
||||
import BasicMessageComposer from "../../../../src/components/views/rooms/BasicMessageComposer";
|
||||
import * as TestUtils from "../../../test-utils";
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import EditorModel from "../../../../src/editor/model";
|
||||
|
@ -40,7 +40,7 @@ describe("BasicMessageComposer", () => {
|
|||
|
||||
wrapper.find(".mx_BasicMessageComposer_input").simulate("paste", {
|
||||
clipboardData: {
|
||||
getData: type => {
|
||||
getData: (type) => {
|
||||
if (type === "text/plain") {
|
||||
return "https://element.io";
|
||||
}
|
||||
|
@ -56,11 +56,9 @@ describe("BasicMessageComposer", () => {
|
|||
function render(model: EditorModel): ReactWrapper {
|
||||
const client: MatrixClient = MatrixClientPeg.get();
|
||||
|
||||
const roomId = '!1234567890:domain';
|
||||
const roomId = "!1234567890:domain";
|
||||
const userId = client.getUserId();
|
||||
const room = new Room(roomId, client, userId);
|
||||
|
||||
return mount((
|
||||
<BasicMessageComposer model={model} room={room} />
|
||||
));
|
||||
return mount(<BasicMessageComposer model={model} room={room} />);
|
||||
}
|
||||
|
|
|
@ -41,10 +41,7 @@ describe("EventTile", () => {
|
|||
// Give a way for a test to update the event prop.
|
||||
// changeEvent = setEvent;
|
||||
|
||||
return <EventTile
|
||||
mxEvent={mxEvent}
|
||||
{...props}
|
||||
/>;
|
||||
return <EventTile mxEvent={mxEvent} {...props} />;
|
||||
}
|
||||
|
||||
function getComponent(
|
||||
|
@ -58,7 +55,8 @@ describe("EventTile", () => {
|
|||
<MatrixClientContext.Provider value={client}>
|
||||
<RoomContext.Provider value={context}>
|
||||
<TestEventTile {...overrides} />
|
||||
</RoomContext.Provider>,
|
||||
</RoomContext.Provider>
|
||||
,
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
}
|
||||
|
@ -75,7 +73,7 @@ describe("EventTile", () => {
|
|||
|
||||
jest.spyOn(client, "getRoom").mockReturnValue(room);
|
||||
jest.spyOn(client, "decryptEventIfNeeded").mockResolvedValue();
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation(name => name === "feature_thread");
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((name) => name === "feature_thread");
|
||||
|
||||
mxEvent = mkMessage({
|
||||
room: room.roomId,
|
||||
|
@ -91,16 +89,22 @@ describe("EventTile", () => {
|
|||
});
|
||||
|
||||
it("removes the thread summary when thread is deleted", async () => {
|
||||
const { rootEvent, events: [, reply] } = mkThread({
|
||||
const {
|
||||
rootEvent,
|
||||
events: [, reply],
|
||||
} = mkThread({
|
||||
room,
|
||||
client,
|
||||
authorId: "@alice:example.org",
|
||||
participantUserIds: ["@alice:example.org"],
|
||||
length: 2, // root + 1 answer
|
||||
});
|
||||
getComponent({
|
||||
mxEvent: rootEvent,
|
||||
}, TimelineRenderingType.Room);
|
||||
getComponent(
|
||||
{
|
||||
mxEvent: rootEvent,
|
||||
},
|
||||
TimelineRenderingType.Room,
|
||||
);
|
||||
|
||||
await waitFor(() => expect(screen.queryByTestId("thread-summary")).not.toBeNull());
|
||||
|
||||
|
|
|
@ -15,26 +15,26 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactTestUtils from 'react-dom/test-utils';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||
import { RoomMember } from 'matrix-js-sdk/src/models/room-member';
|
||||
import React from "react";
|
||||
import ReactTestUtils from "react-dom/test-utils";
|
||||
import ReactDOM from "react-dom";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||
import { User } from "matrix-js-sdk/src/models/user";
|
||||
import { compare } from "matrix-js-sdk/src/utils";
|
||||
|
||||
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||
import * as TestUtils from '../../../test-utils';
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import * as TestUtils from "../../../test-utils";
|
||||
import MemberList from "../../../../src/components/views/rooms/MemberList";
|
||||
import MemberTile from '../../../../src/components/views/rooms/MemberTile';
|
||||
import { SDKContext } from '../../../../src/contexts/SDKContext';
|
||||
import { TestSdkContext } from '../../../TestSdkContext';
|
||||
import MemberTile from "../../../../src/components/views/rooms/MemberTile";
|
||||
import { SDKContext } from "../../../../src/contexts/SDKContext";
|
||||
import { TestSdkContext } from "../../../TestSdkContext";
|
||||
|
||||
function generateRoomId() {
|
||||
return '!' + Math.random().toString().slice(2, 10) + ':domain';
|
||||
return "!" + Math.random().toString().slice(2, 10) + ":domain";
|
||||
}
|
||||
|
||||
describe('MemberList', () => {
|
||||
describe("MemberList", () => {
|
||||
function createRoom(opts = {}) {
|
||||
const room = new Room(generateRoomId(), null, client.getUserId());
|
||||
if (opts) {
|
||||
|
@ -53,12 +53,12 @@ describe('MemberList', () => {
|
|||
let moderatorUsers = [];
|
||||
let defaultUsers = [];
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
TestUtils.stubClient();
|
||||
client = MatrixClientPeg.get();
|
||||
client.hasLazyLoadMembersEnabled = () => false;
|
||||
|
||||
parentDiv = document.createElement('div');
|
||||
parentDiv = document.createElement("div");
|
||||
document.body.appendChild(parentDiv);
|
||||
|
||||
// Make room
|
||||
|
@ -76,7 +76,7 @@ describe('MemberList', () => {
|
|||
adminUser.powerLevel = 100;
|
||||
adminUser.user = new User(adminUser.userId);
|
||||
adminUser.user.currentlyActive = true;
|
||||
adminUser.user.presence = 'online';
|
||||
adminUser.user.presence = "online";
|
||||
adminUser.user.lastPresenceTs = 1000;
|
||||
adminUser.user.lastActiveAgo = 10;
|
||||
adminUsers.push(adminUser);
|
||||
|
@ -86,7 +86,7 @@ describe('MemberList', () => {
|
|||
moderatorUser.powerLevel = 50;
|
||||
moderatorUser.user = new User(moderatorUser.userId);
|
||||
moderatorUser.user.currentlyActive = true;
|
||||
moderatorUser.user.presence = 'online';
|
||||
moderatorUser.user.presence = "online";
|
||||
moderatorUser.user.lastPresenceTs = 1000;
|
||||
moderatorUser.user.lastActiveAgo = 10;
|
||||
moderatorUsers.push(moderatorUser);
|
||||
|
@ -96,7 +96,7 @@ describe('MemberList', () => {
|
|||
defaultUser.powerLevel = 0;
|
||||
defaultUser.user = new User(defaultUser.userId);
|
||||
defaultUser.user.currentlyActive = true;
|
||||
defaultUser.user.presence = 'online';
|
||||
defaultUser.user.presence = "online";
|
||||
defaultUser.user.lastPresenceTs = 1000;
|
||||
defaultUser.user.lastActiveAgo = 10;
|
||||
defaultUsers.push(defaultUser);
|
||||
|
@ -109,7 +109,7 @@ describe('MemberList', () => {
|
|||
memberListRoom.currentState = {
|
||||
members: {},
|
||||
getMember: jest.fn(),
|
||||
getStateEvents: (eventType, stateKey) => stateKey === undefined ? [] : null, // ignore 3pid invites
|
||||
getStateEvents: (eventType, stateKey) => (stateKey === undefined ? [] : null), // ignore 3pid invites
|
||||
};
|
||||
for (const member of [...adminUsers, ...moderatorUsers, ...defaultUsers]) {
|
||||
memberListRoom.currentState.members[member.userId] = member;
|
||||
|
@ -121,17 +121,15 @@ describe('MemberList', () => {
|
|||
const context = new TestSdkContext();
|
||||
context.client = client;
|
||||
root = ReactDOM.render(
|
||||
(
|
||||
<SDKContext.Provider value={context}>
|
||||
<MemberList
|
||||
searchQuery=""
|
||||
onClose={jest.fn()}
|
||||
onSearchQueryChanged={jest.fn()}
|
||||
roomId={memberListRoom.roomId}
|
||||
ref={gatherWrappedRef}
|
||||
/>
|
||||
</SDKContext.Provider>
|
||||
),
|
||||
<SDKContext.Provider value={context}>
|
||||
<MemberList
|
||||
searchQuery=""
|
||||
onClose={jest.fn()}
|
||||
onSearchQueryChanged={jest.fn()}
|
||||
roomId={memberListRoom.roomId}
|
||||
ref={gatherWrappedRef}
|
||||
/>
|
||||
</SDKContext.Provider>,
|
||||
parentDiv,
|
||||
);
|
||||
});
|
||||
|
@ -166,15 +164,15 @@ describe('MemberList', () => {
|
|||
let groupChange = false;
|
||||
|
||||
if (isPresenceEnabled) {
|
||||
const convertPresence = (p) => p === 'unavailable' ? 'online' : p;
|
||||
const presenceIndex = p => {
|
||||
const order = ['active', 'online', 'offline'];
|
||||
const convertPresence = (p) => (p === "unavailable" ? "online" : p);
|
||||
const presenceIndex = (p) => {
|
||||
const order = ["active", "online", "offline"];
|
||||
const idx = order.indexOf(convertPresence(p));
|
||||
return idx === -1 ? order.length : idx; // unknown states at the end
|
||||
};
|
||||
|
||||
const idxA = presenceIndex(userA.currentlyActive ? 'active' : userA.presence);
|
||||
const idxB = presenceIndex(userB.currentlyActive ? 'active' : userB.presence);
|
||||
const idxA = presenceIndex(userA.currentlyActive ? "active" : userA.presence);
|
||||
const idxB = presenceIndex(userB.currentlyActive ? "active" : userB.presence);
|
||||
console.log("Comparing presence groups...");
|
||||
expect(idxB).toBeGreaterThanOrEqual(idxA);
|
||||
groupChange = idxA !== idxB;
|
||||
|
@ -203,8 +201,8 @@ describe('MemberList', () => {
|
|||
}
|
||||
|
||||
if (!groupChange) {
|
||||
const nameA = memberA.name[0] === '@' ? memberA.name.slice(1) : memberA.name;
|
||||
const nameB = memberB.name[0] === '@' ? memberB.name.slice(1) : memberB.name;
|
||||
const nameA = memberA.name[0] === "@" ? memberA.name.slice(1) : memberA.name;
|
||||
const nameB = memberB.name[0] === "@" ? memberB.name.slice(1) : memberB.name;
|
||||
const nameCompare = compare(nameB, nameA);
|
||||
console.log("Comparing name");
|
||||
expect(nameCompare).toBeGreaterThanOrEqual(0);
|
||||
|
@ -215,7 +213,7 @@ describe('MemberList', () => {
|
|||
}
|
||||
|
||||
function itDoesOrderMembersCorrectly(enablePresence) {
|
||||
describe('does order members correctly', () => {
|
||||
describe("does order members correctly", () => {
|
||||
// Note: even if presence is disabled, we still expect that the presence
|
||||
// tests will pass. All expectOrderedByPresenceAndPowerLevel does is ensure
|
||||
// the order is perceived correctly, regardless of what we did to the members.
|
||||
|
@ -223,22 +221,22 @@ describe('MemberList', () => {
|
|||
// Each of the 4 tests here is done to prove that the member list can meet
|
||||
// all 4 criteria independently. Together, they should work.
|
||||
|
||||
it('by presence state', () => {
|
||||
it("by presence state", () => {
|
||||
// Intentionally pick users that will confuse the power level sorting
|
||||
const activeUsers = [defaultUsers[0]];
|
||||
const onlineUsers = [adminUsers[0]];
|
||||
const offlineUsers = [...moderatorUsers, ...adminUsers.slice(1), ...defaultUsers.slice(1)];
|
||||
activeUsers.forEach((u) => {
|
||||
u.user.currentlyActive = true;
|
||||
u.user.presence = 'online';
|
||||
u.user.presence = "online";
|
||||
});
|
||||
onlineUsers.forEach((u) => {
|
||||
u.user.currentlyActive = false;
|
||||
u.user.presence = 'online';
|
||||
u.user.presence = "online";
|
||||
});
|
||||
offlineUsers.forEach((u) => {
|
||||
u.user.currentlyActive = false;
|
||||
u.user.presence = 'offline';
|
||||
u.user.presence = "offline";
|
||||
});
|
||||
|
||||
// Bypass all the event listeners and skip to the good part
|
||||
|
@ -249,7 +247,7 @@ describe('MemberList', () => {
|
|||
expectOrderedByPresenceAndPowerLevel(tiles, enablePresence);
|
||||
});
|
||||
|
||||
it('by power level', () => {
|
||||
it("by power level", () => {
|
||||
// We already have admin, moderator, and default users so leave them alone
|
||||
|
||||
// Bypass all the event listeners and skip to the good part
|
||||
|
@ -260,7 +258,7 @@ describe('MemberList', () => {
|
|||
expectOrderedByPresenceAndPowerLevel(tiles, enablePresence);
|
||||
});
|
||||
|
||||
it('by last active timestamp', () => {
|
||||
it("by last active timestamp", () => {
|
||||
// Intentionally pick users that will confuse the power level sorting
|
||||
// lastActiveAgoTs == lastPresenceTs - lastActiveAgo
|
||||
const activeUsers = [defaultUsers[0]];
|
||||
|
@ -290,7 +288,7 @@ describe('MemberList', () => {
|
|||
expectOrderedByPresenceAndPowerLevel(tiles, enablePresence);
|
||||
});
|
||||
|
||||
it('by name', () => {
|
||||
it("by name", () => {
|
||||
// Intentionally put everyone on the same level to force a name comparison
|
||||
const allUsers = [...adminUsers, ...moderatorUsers, ...defaultUsers];
|
||||
allUsers.forEach((u) => {
|
||||
|
@ -311,12 +309,11 @@ describe('MemberList', () => {
|
|||
});
|
||||
}
|
||||
|
||||
describe('when presence is enabled', () => {
|
||||
describe("when presence is enabled", () => {
|
||||
itDoesOrderMembersCorrectly(true);
|
||||
});
|
||||
|
||||
describe('when presence is not enabled', () => {
|
||||
describe("when presence is not enabled", () => {
|
||||
itDoesOrderMembersCorrectly(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -21,8 +21,9 @@ import { MatrixEvent, MsgType, RoomMember } from "matrix-js-sdk/src/matrix";
|
|||
import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread";
|
||||
|
||||
import { createTestClient, mkEvent, mkStubRoom, stubClient } from "../../../test-utils";
|
||||
import MessageComposer, { MessageComposer as MessageComposerClass }
|
||||
from "../../../../src/components/views/rooms/MessageComposer";
|
||||
import MessageComposer, {
|
||||
MessageComposer as MessageComposerClass,
|
||||
} from "../../../../src/components/views/rooms/MessageComposer";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import RoomContext from "../../../../src/contexts/RoomContext";
|
||||
|
@ -65,15 +66,20 @@ describe("MessageComposer", () => {
|
|||
});
|
||||
|
||||
it("Does not render a SendMessageComposer or MessageComposerButtons when room is tombstoned", () => {
|
||||
const wrapper = wrapAndRender({ room }, true, false, mkEvent({
|
||||
event: true,
|
||||
type: "m.room.tombstone",
|
||||
room: room.roomId,
|
||||
user: "@user1:server",
|
||||
skey: "",
|
||||
content: {},
|
||||
ts: Date.now(),
|
||||
}));
|
||||
const wrapper = wrapAndRender(
|
||||
{ room },
|
||||
true,
|
||||
false,
|
||||
mkEvent({
|
||||
event: true,
|
||||
type: "m.room.tombstone",
|
||||
room: room.roomId,
|
||||
user: "@user1:server",
|
||||
skey: "",
|
||||
content: {},
|
||||
ts: Date.now(),
|
||||
}),
|
||||
);
|
||||
|
||||
expect(wrapper.find("SendMessageComposer")).toHaveLength(0);
|
||||
expect(wrapper.find("MessageComposerButtons")).toHaveLength(0);
|
||||
|
@ -150,11 +156,14 @@ describe("MessageComposer", () => {
|
|||
beforeEach(async () => {
|
||||
// simulate settings update
|
||||
await SettingsStore.setValue(setting, null, SettingLevel.DEVICE, !value);
|
||||
dis.dispatch({
|
||||
action: Action.SettingUpdated,
|
||||
settingName: setting,
|
||||
newValue: !value,
|
||||
}, true);
|
||||
dis.dispatch(
|
||||
{
|
||||
action: Action.SettingUpdated,
|
||||
settingName: setting,
|
||||
newValue: !value,
|
||||
},
|
||||
true,
|
||||
);
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
|
@ -339,7 +348,7 @@ describe("MessageComposer", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('should render SendWysiwygComposer', () => {
|
||||
it("should render SendWysiwygComposer", () => {
|
||||
const room = mkStubRoom("!roomId:server", "Room 1", cli);
|
||||
|
||||
SettingsStore.setValue("feature_wysiwyg_composer", null, SettingLevel.DEVICE, true);
|
||||
|
@ -362,7 +371,7 @@ function wrapAndRender(
|
|||
currentState: undefined,
|
||||
roomId,
|
||||
client: mockClient,
|
||||
getMember: function(userId: string): RoomMember {
|
||||
getMember: function (userId: string): RoomMember {
|
||||
return new RoomMember(roomId, userId);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -53,11 +53,7 @@ describe("MessageComposerButtons", () => {
|
|||
false,
|
||||
);
|
||||
|
||||
expect(buttonLabels(buttons)).toEqual([
|
||||
"Emoji",
|
||||
"Attachment",
|
||||
"More options",
|
||||
]);
|
||||
expect(buttonLabels(buttons)).toEqual(["Emoji", "Attachment", "More options"]);
|
||||
});
|
||||
|
||||
it("Renders other buttons in menu in wide mode", () => {
|
||||
|
@ -76,12 +72,7 @@ describe("MessageComposerButtons", () => {
|
|||
"Emoji",
|
||||
"Attachment",
|
||||
"More options",
|
||||
[
|
||||
"Sticker",
|
||||
"Voice Message",
|
||||
"Poll",
|
||||
"Location",
|
||||
],
|
||||
["Sticker", "Voice Message", "Poll", "Location"],
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -97,10 +88,7 @@ describe("MessageComposerButtons", () => {
|
|||
true,
|
||||
);
|
||||
|
||||
expect(buttonLabels(buttons)).toEqual([
|
||||
"Emoji",
|
||||
"More options",
|
||||
]);
|
||||
expect(buttonLabels(buttons)).toEqual(["Emoji", "More options"]);
|
||||
});
|
||||
|
||||
it("Renders other buttons in menu (except voice messages) in narrow mode", () => {
|
||||
|
@ -115,20 +103,11 @@ describe("MessageComposerButtons", () => {
|
|||
true,
|
||||
);
|
||||
|
||||
expect(buttonLabels(buttons)).toEqual([
|
||||
"Emoji",
|
||||
"More options",
|
||||
[
|
||||
"Attachment",
|
||||
"Sticker",
|
||||
"Poll",
|
||||
"Location",
|
||||
],
|
||||
]);
|
||||
expect(buttonLabels(buttons)).toEqual(["Emoji", "More options", ["Attachment", "Sticker", "Poll", "Location"]]);
|
||||
});
|
||||
|
||||
describe('polls button', () => {
|
||||
it('should render when asked to', () => {
|
||||
describe("polls button", () => {
|
||||
it("should render when asked to", () => {
|
||||
const buttons = wrapAndRender(
|
||||
<MessageComposerButtons
|
||||
{...mockProps}
|
||||
|
@ -143,16 +122,11 @@ describe("MessageComposerButtons", () => {
|
|||
expect(buttonLabels(buttons)).toEqual([
|
||||
"Emoji",
|
||||
"More options",
|
||||
[
|
||||
"Attachment",
|
||||
"Sticker",
|
||||
"Poll",
|
||||
"Location",
|
||||
],
|
||||
["Attachment", "Sticker", "Poll", "Location"],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not render when asked not to', () => {
|
||||
it("should not render when asked not to", () => {
|
||||
const buttons = wrapAndRender(
|
||||
<MessageComposerButtons
|
||||
{...mockProps}
|
||||
|
@ -195,13 +169,7 @@ describe("MessageComposerButtons", () => {
|
|||
"Emoji",
|
||||
"Attachment",
|
||||
"More options",
|
||||
[
|
||||
"Sticker",
|
||||
"Voice Message",
|
||||
"Voice broadcast",
|
||||
"Poll",
|
||||
"Location",
|
||||
],
|
||||
["Sticker", "Voice Message", "Voice broadcast", "Poll", "Location"],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@ -209,13 +177,13 @@ describe("MessageComposerButtons", () => {
|
|||
|
||||
function wrapAndRender(component: React.ReactElement, narrow: boolean): ReactWrapper {
|
||||
const mockClient = createTestClient();
|
||||
jest.spyOn(MatrixClientPeg, 'get').mockReturnValue(mockClient);
|
||||
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient);
|
||||
const roomId = "myroomid";
|
||||
const mockRoom: any = {
|
||||
currentState: undefined,
|
||||
roomId,
|
||||
client: mockClient,
|
||||
getMember: function(userId: string): RoomMember {
|
||||
getMember: function (userId: string): RoomMember {
|
||||
return new RoomMember(roomId, userId);
|
||||
},
|
||||
};
|
||||
|
@ -223,9 +191,7 @@ function wrapAndRender(component: React.ReactElement, narrow: boolean): ReactWra
|
|||
|
||||
return mount(
|
||||
<MatrixClientContext.Provider value={mockClient}>
|
||||
<RoomContext.Provider value={roomState}>
|
||||
{ component }
|
||||
</RoomContext.Provider>
|
||||
<RoomContext.Provider value={roomState}>{component}</RoomContext.Provider>
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
}
|
||||
|
@ -274,23 +240,17 @@ function createRoomState(room: Room, narrow: boolean): IRoomState {
|
|||
function buttonLabels(buttons: ReactWrapper): any[] {
|
||||
// Note: Depends on the fact that the mini buttons use aria-label
|
||||
// and the labels under More options use textContent
|
||||
const mainButtons = (
|
||||
buttons
|
||||
.find('div.mx_MessageComposer_button[aria-label]')
|
||||
.map((button: ReactWrapper) => button.prop("aria-label") as string)
|
||||
.filter(x => x)
|
||||
);
|
||||
const mainButtons = buttons
|
||||
.find("div.mx_MessageComposer_button[aria-label]")
|
||||
.map((button: ReactWrapper) => button.prop("aria-label") as string)
|
||||
.filter((x) => x);
|
||||
|
||||
const extraButtons = (
|
||||
buttons
|
||||
.find('.mx_MessageComposer_Menu div.mx_AccessibleButton[role="menuitem"]')
|
||||
.map((button: ReactWrapper) => button.text())
|
||||
.filter(x => x)
|
||||
);
|
||||
const extraButtons = buttons
|
||||
.find('.mx_MessageComposer_Menu div.mx_AccessibleButton[role="menuitem"]')
|
||||
.map((button: ReactWrapper) => button.text())
|
||||
.filter((x) => x);
|
||||
|
||||
const list: any[] = [
|
||||
...mainButtons,
|
||||
];
|
||||
const list: any[] = [...mainButtons];
|
||||
|
||||
if (extraButtons.length > 0) {
|
||||
list.push(extraButtons);
|
||||
|
|
|
@ -29,7 +29,7 @@ import DMRoomMap from "../../../../src/utils/DMRoomMap";
|
|||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import { DirectoryMember } from "../../../../src/utils/direct-messages";
|
||||
|
||||
const renderNewRoomIntro = (client: MatrixClient, room: Room|LocalRoom) => {
|
||||
const renderNewRoomIntro = (client: MatrixClient, room: Room | LocalRoom) => {
|
||||
render(
|
||||
<MatrixClientContext.Provider value={client}>
|
||||
<RoomContext.Provider value={{ room, roomId: room.roomId } as unknown as IRoomState}>
|
||||
|
|
|
@ -17,9 +17,7 @@ limitations under the License.
|
|||
import { fireEvent, render } from "@testing-library/react";
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
StatelessNotificationBadge,
|
||||
} from "../../../../../src/components/views/rooms/NotificationBadge/StatelessNotificationBadge";
|
||||
import { StatelessNotificationBadge } from "../../../../../src/components/views/rooms/NotificationBadge/StatelessNotificationBadge";
|
||||
import SettingsStore from "../../../../../src/settings/SettingsStore";
|
||||
import { NotificationColor } from "../../../../../src/stores/notifications/NotificationColor";
|
||||
|
||||
|
@ -28,14 +26,16 @@ describe("NotificationBadge", () => {
|
|||
it("lets you click it", () => {
|
||||
const cb = jest.fn();
|
||||
|
||||
const { container } = render(<StatelessNotificationBadge
|
||||
symbol=""
|
||||
color={NotificationColor.Red}
|
||||
count={5}
|
||||
onClick={cb}
|
||||
onMouseOver={cb}
|
||||
onMouseLeave={cb}
|
||||
/>);
|
||||
const { container } = render(
|
||||
<StatelessNotificationBadge
|
||||
symbol=""
|
||||
color={NotificationColor.Red}
|
||||
count={5}
|
||||
onClick={cb}
|
||||
onMouseOver={cb}
|
||||
onMouseLeave={cb}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.click(container.firstChild);
|
||||
expect(cb).toHaveBeenCalledTimes(1);
|
||||
|
@ -52,11 +52,9 @@ describe("NotificationBadge", () => {
|
|||
return name === "feature_hidebold";
|
||||
});
|
||||
|
||||
const { container } = render(<StatelessNotificationBadge
|
||||
symbol=""
|
||||
color={NotificationColor.Bold}
|
||||
count={1}
|
||||
/>);
|
||||
const { container } = render(
|
||||
<StatelessNotificationBadge symbol="" color={NotificationColor.Bold} count={1} />,
|
||||
);
|
||||
|
||||
expect(container.firstChild).toBeNull();
|
||||
});
|
||||
|
|
|
@ -17,22 +17,14 @@ limitations under the License.
|
|||
import React from "react";
|
||||
import { render } from "@testing-library/react";
|
||||
|
||||
import {
|
||||
StatelessNotificationBadge,
|
||||
} from "../../../../../src/components/views/rooms/NotificationBadge/StatelessNotificationBadge";
|
||||
import { StatelessNotificationBadge } from "../../../../../src/components/views/rooms/NotificationBadge/StatelessNotificationBadge";
|
||||
import { NotificationColor } from "../../../../../src/stores/notifications/NotificationColor";
|
||||
|
||||
describe("StatelessNotificationBadge", () => {
|
||||
it("is highlighted when unsent", () => {
|
||||
const { container } = render(
|
||||
<StatelessNotificationBadge
|
||||
symbol="!"
|
||||
count={0}
|
||||
color={NotificationColor.Unsent}
|
||||
/>,
|
||||
<StatelessNotificationBadge symbol="!" count={0} color={NotificationColor.Unsent} />,
|
||||
);
|
||||
expect(
|
||||
container.querySelector(".mx_NotificationBadge_highlighted"),
|
||||
).not.toBe(null);
|
||||
expect(container.querySelector(".mx_NotificationBadge_highlighted")).not.toBe(null);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -22,16 +22,14 @@ import { NotificationCountType, Room } from "matrix-js-sdk/src/models/room";
|
|||
import { mocked } from "jest-mock";
|
||||
import { EventStatus } from "matrix-js-sdk/src/models/event-status";
|
||||
|
||||
import {
|
||||
UnreadNotificationBadge,
|
||||
} from "../../../../../src/components/views/rooms/NotificationBadge/UnreadNotificationBadge";
|
||||
import { UnreadNotificationBadge } from "../../../../../src/components/views/rooms/NotificationBadge/UnreadNotificationBadge";
|
||||
import { mkMessage, stubClient } from "../../../../test-utils/test-utils";
|
||||
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
|
||||
import * as RoomNotifs from "../../../../../src/RoomNotifs";
|
||||
|
||||
jest.mock("../../../../../src/RoomNotifs");
|
||||
jest.mock('../../../../../src/RoomNotifs', () => ({
|
||||
...(jest.requireActual('../../../../../src/RoomNotifs') as Object),
|
||||
jest.mock("../../../../../src/RoomNotifs", () => ({
|
||||
...(jest.requireActual("../../../../../src/RoomNotifs") as Object),
|
||||
getRoomNotifsState: jest.fn(),
|
||||
}));
|
||||
|
||||
|
@ -122,9 +120,7 @@ describe("UnreadNotificationBadge", () => {
|
|||
});
|
||||
|
||||
it("hides counter for muted rooms", () => {
|
||||
jest.spyOn(RoomNotifs, "getRoomNotifsState")
|
||||
.mockReset()
|
||||
.mockReturnValue(RoomNotifs.RoomNotifState.Mute);
|
||||
jest.spyOn(RoomNotifs, "getRoomNotifsState").mockReset().mockReturnValue(RoomNotifs.RoomNotifState.Mute);
|
||||
|
||||
const { container } = render(getComponent());
|
||||
expect(container.querySelector(".mx_NotificationBadge")).toBeNull();
|
||||
|
|
|
@ -19,32 +19,28 @@ import { determineAvatarPosition, readReceiptTooltip } from "../../../../src/com
|
|||
describe("ReadReceiptGroup", () => {
|
||||
describe("TooltipText", () => {
|
||||
it("returns '...and more' with hasMore", () => {
|
||||
expect(readReceiptTooltip(["Alice", "Bob", "Charlie", "Dan", "Eve"], true))
|
||||
.toEqual("Alice, Bob, Charlie, Dan, Eve and more");
|
||||
expect(readReceiptTooltip(["Alice", "Bob", "Charlie", "Dan"], true))
|
||||
.toEqual("Alice, Bob, Charlie, Dan and more");
|
||||
expect(readReceiptTooltip(["Alice", "Bob", "Charlie"], true))
|
||||
.toEqual("Alice, Bob, Charlie and more");
|
||||
expect(readReceiptTooltip(["Alice", "Bob"], true))
|
||||
.toEqual("Alice, Bob and more");
|
||||
expect(readReceiptTooltip(["Alice"], true))
|
||||
.toEqual("Alice and more");
|
||||
expect(readReceiptTooltip([], false))
|
||||
.toEqual(null);
|
||||
expect(readReceiptTooltip(["Alice", "Bob", "Charlie", "Dan", "Eve"], true)).toEqual(
|
||||
"Alice, Bob, Charlie, Dan, Eve and more",
|
||||
);
|
||||
expect(readReceiptTooltip(["Alice", "Bob", "Charlie", "Dan"], true)).toEqual(
|
||||
"Alice, Bob, Charlie, Dan and more",
|
||||
);
|
||||
expect(readReceiptTooltip(["Alice", "Bob", "Charlie"], true)).toEqual("Alice, Bob, Charlie and more");
|
||||
expect(readReceiptTooltip(["Alice", "Bob"], true)).toEqual("Alice, Bob and more");
|
||||
expect(readReceiptTooltip(["Alice"], true)).toEqual("Alice and more");
|
||||
expect(readReceiptTooltip([], false)).toEqual(null);
|
||||
});
|
||||
it("returns a pretty list without hasMore", () => {
|
||||
expect(readReceiptTooltip(["Alice", "Bob", "Charlie", "Dan", "Eve"], false))
|
||||
.toEqual("Alice, Bob, Charlie, Dan and Eve");
|
||||
expect(readReceiptTooltip(["Alice", "Bob", "Charlie", "Dan"], false))
|
||||
.toEqual("Alice, Bob, Charlie and Dan");
|
||||
expect(readReceiptTooltip(["Alice", "Bob", "Charlie"], false))
|
||||
.toEqual("Alice, Bob and Charlie");
|
||||
expect(readReceiptTooltip(["Alice", "Bob"], false))
|
||||
.toEqual("Alice and Bob");
|
||||
expect(readReceiptTooltip(["Alice"], false))
|
||||
.toEqual("Alice");
|
||||
expect(readReceiptTooltip([], false))
|
||||
.toEqual(null);
|
||||
expect(readReceiptTooltip(["Alice", "Bob", "Charlie", "Dan", "Eve"], false)).toEqual(
|
||||
"Alice, Bob, Charlie, Dan and Eve",
|
||||
);
|
||||
expect(readReceiptTooltip(["Alice", "Bob", "Charlie", "Dan"], false)).toEqual(
|
||||
"Alice, Bob, Charlie and Dan",
|
||||
);
|
||||
expect(readReceiptTooltip(["Alice", "Bob", "Charlie"], false)).toEqual("Alice, Bob and Charlie");
|
||||
expect(readReceiptTooltip(["Alice", "Bob"], false)).toEqual("Alice and Bob");
|
||||
expect(readReceiptTooltip(["Alice"], false)).toEqual("Alice");
|
||||
expect(readReceiptTooltip([], false)).toEqual(null);
|
||||
});
|
||||
});
|
||||
describe("AvatarPosition", () => {
|
||||
|
@ -53,44 +49,28 @@ describe("ReadReceiptGroup", () => {
|
|||
// We want to fill slots so the first avatar is in the right-most slot without leaving any slots at the left
|
||||
// unoccupied.
|
||||
it("to handle the non-overflowing case correctly", () => {
|
||||
expect(determineAvatarPosition(0, 4))
|
||||
.toEqual({ hidden: false, position: 0 });
|
||||
expect(determineAvatarPosition(0, 4)).toEqual({ hidden: false, position: 0 });
|
||||
|
||||
expect(determineAvatarPosition(0, 4))
|
||||
.toEqual({ hidden: false, position: 0 });
|
||||
expect(determineAvatarPosition(1, 4))
|
||||
.toEqual({ hidden: false, position: 1 });
|
||||
expect(determineAvatarPosition(0, 4)).toEqual({ hidden: false, position: 0 });
|
||||
expect(determineAvatarPosition(1, 4)).toEqual({ hidden: false, position: 1 });
|
||||
|
||||
expect(determineAvatarPosition(0, 4))
|
||||
.toEqual({ hidden: false, position: 0 });
|
||||
expect(determineAvatarPosition(1, 4))
|
||||
.toEqual({ hidden: false, position: 1 });
|
||||
expect(determineAvatarPosition(2, 4))
|
||||
.toEqual({ hidden: false, position: 2 });
|
||||
expect(determineAvatarPosition(0, 4)).toEqual({ hidden: false, position: 0 });
|
||||
expect(determineAvatarPosition(1, 4)).toEqual({ hidden: false, position: 1 });
|
||||
expect(determineAvatarPosition(2, 4)).toEqual({ hidden: false, position: 2 });
|
||||
|
||||
expect(determineAvatarPosition(0, 4))
|
||||
.toEqual({ hidden: false, position: 0 });
|
||||
expect(determineAvatarPosition(1, 4))
|
||||
.toEqual({ hidden: false, position: 1 });
|
||||
expect(determineAvatarPosition(2, 4))
|
||||
.toEqual({ hidden: false, position: 2 });
|
||||
expect(determineAvatarPosition(3, 4))
|
||||
.toEqual({ hidden: false, position: 3 });
|
||||
expect(determineAvatarPosition(0, 4)).toEqual({ hidden: false, position: 0 });
|
||||
expect(determineAvatarPosition(1, 4)).toEqual({ hidden: false, position: 1 });
|
||||
expect(determineAvatarPosition(2, 4)).toEqual({ hidden: false, position: 2 });
|
||||
expect(determineAvatarPosition(3, 4)).toEqual({ hidden: false, position: 3 });
|
||||
});
|
||||
|
||||
it("to handle the overflowing case correctly", () => {
|
||||
expect(determineAvatarPosition(0, 4))
|
||||
.toEqual({ hidden: false, position: 0 });
|
||||
expect(determineAvatarPosition(1, 4))
|
||||
.toEqual({ hidden: false, position: 1 });
|
||||
expect(determineAvatarPosition(2, 4))
|
||||
.toEqual({ hidden: false, position: 2 });
|
||||
expect(determineAvatarPosition(3, 4))
|
||||
.toEqual({ hidden: false, position: 3 });
|
||||
expect(determineAvatarPosition(4, 4))
|
||||
.toEqual({ hidden: true, position: 0 });
|
||||
expect(determineAvatarPosition(5, 4))
|
||||
.toEqual({ hidden: true, position: 0 });
|
||||
expect(determineAvatarPosition(0, 4)).toEqual({ hidden: false, position: 0 });
|
||||
expect(determineAvatarPosition(1, 4)).toEqual({ hidden: false, position: 1 });
|
||||
expect(determineAvatarPosition(2, 4)).toEqual({ hidden: false, position: 2 });
|
||||
expect(determineAvatarPosition(3, 4)).toEqual({ hidden: false, position: 3 });
|
||||
expect(determineAvatarPosition(4, 4)).toEqual({ hidden: true, position: 0 });
|
||||
expect(determineAvatarPosition(5, 4)).toEqual({ hidden: true, position: 0 });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,9 +14,9 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { render, screen, act, fireEvent, waitFor, getByRole } from "@testing-library/react";
|
||||
import { mocked, Mocked } from "jest-mock";
|
||||
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
|
||||
|
@ -26,7 +26,7 @@ import { PendingEventOrdering } from "matrix-js-sdk/src/client";
|
|||
import { CallType } from "matrix-js-sdk/src/webrtc/call";
|
||||
import { ClientWidgetApi, Widget } from "matrix-widget-api";
|
||||
import EventEmitter from "events";
|
||||
import { ISearchResults } from 'matrix-js-sdk/src/@types/search';
|
||||
import { ISearchResults } from "matrix-js-sdk/src/@types/search";
|
||||
|
||||
import type { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import type { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
|
@ -39,14 +39,14 @@ import {
|
|||
resetAsyncStoreWithClient,
|
||||
mockPlatformPeg,
|
||||
} from "../../../test-utils";
|
||||
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||
import DMRoomMap from '../../../../src/utils/DMRoomMap';
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import DMRoomMap from "../../../../src/utils/DMRoomMap";
|
||||
import RoomHeader, { IProps as RoomHeaderProps } from "../../../../src/components/views/rooms/RoomHeader";
|
||||
import { SearchScope } from '../../../../src/components/views/rooms/SearchBar';
|
||||
import { E2EStatus } from '../../../../src/utils/ShieldUtils';
|
||||
import { mkEvent } from '../../../test-utils';
|
||||
import { SearchScope } from "../../../../src/components/views/rooms/SearchBar";
|
||||
import { E2EStatus } from "../../../../src/utils/ShieldUtils";
|
||||
import { mkEvent } from "../../../test-utils";
|
||||
import { IRoomState } from "../../../../src/components/structures/RoomView";
|
||||
import RoomContext from '../../../../src/contexts/RoomContext';
|
||||
import RoomContext from "../../../../src/contexts/RoomContext";
|
||||
import SdkConfig from "../../../../src/SdkConfig";
|
||||
import SettingsStore from "../../../../src/settings/SettingsStore";
|
||||
import { ElementCall, JitsiCall } from "../../../../src/models/Call";
|
||||
|
@ -60,8 +60,8 @@ import WidgetUtils from "../../../../src/utils/WidgetUtils";
|
|||
import { ElementWidgetActions } from "../../../../src/stores/widgets/ElementWidgetActions";
|
||||
import MediaDeviceHandler, { MediaDeviceKindEnum } from "../../../../src/MediaDeviceHandler";
|
||||
|
||||
describe('RoomHeader (Enzyme)', () => {
|
||||
it('shows the room avatar in a room with only ourselves', () => {
|
||||
describe("RoomHeader (Enzyme)", () => {
|
||||
it("shows the room avatar in a room with only ourselves", () => {
|
||||
// When we render a non-DM room with 1 person in it
|
||||
const room = createRoom({ name: "X Room", isDm: false, userIds: [] });
|
||||
const rendered = mountHeader(room);
|
||||
|
@ -75,10 +75,9 @@ describe('RoomHeader (Enzyme)', () => {
|
|||
expect(image.prop("src")).toEqual("data:image/png;base64,00");
|
||||
});
|
||||
|
||||
it('shows the room avatar in a room with 2 people', () => {
|
||||
it("shows the room avatar in a room with 2 people", () => {
|
||||
// When we render a non-DM room with 2 people in it
|
||||
const room = createRoom(
|
||||
{ name: "Y Room", isDm: false, userIds: ["other"] });
|
||||
const room = createRoom({ name: "Y Room", isDm: false, userIds: ["other"] });
|
||||
const rendered = mountHeader(room);
|
||||
|
||||
// Then the room's avatar is the initial of its name
|
||||
|
@ -90,7 +89,7 @@ describe('RoomHeader (Enzyme)', () => {
|
|||
expect(image.prop("src")).toEqual("data:image/png;base64,00");
|
||||
});
|
||||
|
||||
it('shows the room avatar in a room with >2 people', () => {
|
||||
it("shows the room avatar in a room with >2 people", () => {
|
||||
// When we render a non-DM room with 3 people in it
|
||||
const room = createRoom({ name: "Z Room", isDm: false, userIds: ["other1", "other2"] });
|
||||
const rendered = mountHeader(room);
|
||||
|
@ -104,7 +103,7 @@ describe('RoomHeader (Enzyme)', () => {
|
|||
expect(image.prop("src")).toEqual("data:image/png;base64,00");
|
||||
});
|
||||
|
||||
it('shows the room avatar in a DM with only ourselves', () => {
|
||||
it("shows the room avatar in a DM with only ourselves", () => {
|
||||
// When we render a non-DM room with 1 person in it
|
||||
const room = createRoom({ name: "Z Room", isDm: true, userIds: [] });
|
||||
const rendered = mountHeader(room);
|
||||
|
@ -118,7 +117,7 @@ describe('RoomHeader (Enzyme)', () => {
|
|||
expect(image.prop("src")).toEqual("data:image/png;base64,00");
|
||||
});
|
||||
|
||||
it('shows the user avatar in a DM with 2 people', () => {
|
||||
it("shows the user avatar in a DM with 2 people", () => {
|
||||
// Note: this is the interesting case - this is the ONLY
|
||||
// time we should use the user's avatar.
|
||||
|
||||
|
@ -134,10 +133,12 @@ describe('RoomHeader (Enzyme)', () => {
|
|||
expect(rendered.find(".mx_BaseAvatar_initial")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('shows the room avatar in a DM with >2 people', () => {
|
||||
it("shows the room avatar in a DM with >2 people", () => {
|
||||
// When we render a DM room with 3 people in it
|
||||
const room = createRoom({
|
||||
name: "Z Room", isDm: true, userIds: ["other1", "other2"],
|
||||
name: "Z Room",
|
||||
isDm: true,
|
||||
userIds: ["other1", "other2"],
|
||||
});
|
||||
const rendered = mountHeader(room);
|
||||
|
||||
|
@ -160,17 +161,21 @@ describe('RoomHeader (Enzyme)', () => {
|
|||
|
||||
it("hides call buttons when the room is tombstoned", () => {
|
||||
const room = createRoom({ name: "Room", isDm: false, userIds: [] });
|
||||
const wrapper = mountHeader(room, {}, {
|
||||
tombstone: mkEvent({
|
||||
event: true,
|
||||
type: "m.room.tombstone",
|
||||
room: room.roomId,
|
||||
user: "@user1:server",
|
||||
skey: "",
|
||||
content: {},
|
||||
ts: Date.now(),
|
||||
}),
|
||||
});
|
||||
const wrapper = mountHeader(
|
||||
room,
|
||||
{},
|
||||
{
|
||||
tombstone: mkEvent({
|
||||
event: true,
|
||||
type: "m.room.tombstone",
|
||||
room: room.roomId,
|
||||
user: "@user1:server",
|
||||
skey: "",
|
||||
content: {},
|
||||
ts: Date.now(),
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
expect(wrapper.find('[aria-label="Voice call"]').hostNodes()).toHaveLength(0);
|
||||
expect(wrapper.find('[aria-label="Video call"]').hostNodes()).toHaveLength(0);
|
||||
|
@ -211,7 +216,7 @@ function createRoom(info: IRoomCreationInfo) {
|
|||
stubClient();
|
||||
const client: MatrixClient = MatrixClientPeg.get();
|
||||
|
||||
const roomId = '!1234567890:domain';
|
||||
const roomId = "!1234567890:domain";
|
||||
const userId = client.getUserId();
|
||||
if (info.isDm) {
|
||||
client.getAccountData = (eventType) => {
|
||||
|
@ -246,11 +251,11 @@ function mountHeader(room: Room, propsOverride = {}, roomContext?: Partial<IRoom
|
|||
const props = {
|
||||
room,
|
||||
inRoom: true,
|
||||
onSearchClick: () => { },
|
||||
onSearchClick: () => {},
|
||||
onInviteClick: null,
|
||||
onForgetClick: () => { },
|
||||
onCallPlaced: (_type) => { },
|
||||
onAppsClick: () => { },
|
||||
onForgetClick: () => {},
|
||||
onCallPlaced: (_type) => {},
|
||||
onAppsClick: () => {},
|
||||
e2eStatus: E2EStatus.Normal,
|
||||
appsShown: true,
|
||||
searchInfo: {
|
||||
|
@ -265,11 +270,11 @@ function mountHeader(room: Room, propsOverride = {}, roomContext?: Partial<IRoom
|
|||
...propsOverride,
|
||||
};
|
||||
|
||||
return mount((
|
||||
return mount(
|
||||
<RoomContext.Provider value={{ ...roomContext, room } as IRoomState}>
|
||||
<RoomHeader {...props} />
|
||||
</RoomContext.Provider>
|
||||
));
|
||||
</RoomContext.Provider>,
|
||||
);
|
||||
}
|
||||
|
||||
function mkCreationEvent(roomId: string, userId: string): MatrixEvent {
|
||||
|
@ -289,9 +294,7 @@ function mkCreationEvent(roomId: string, userId: string): MatrixEvent {
|
|||
});
|
||||
}
|
||||
|
||||
function mkNameEvent(
|
||||
roomId: string, userId: string, name: string,
|
||||
): MatrixEvent {
|
||||
function mkNameEvent(roomId: string, userId: string, name: string): MatrixEvent {
|
||||
return mkEvent({
|
||||
event: true,
|
||||
type: "m.room.name",
|
||||
|
@ -308,17 +311,15 @@ function mkJoinEvent(roomId: string, userId: string) {
|
|||
room: roomId,
|
||||
user: userId,
|
||||
content: {
|
||||
"membership": "join",
|
||||
"avatar_url": "mxc://example.org/" + userId,
|
||||
membership: "join",
|
||||
avatar_url: "mxc://example.org/" + userId,
|
||||
},
|
||||
});
|
||||
ret.event.state_key = userId;
|
||||
return ret;
|
||||
}
|
||||
|
||||
function mkDirectEvent(
|
||||
roomId: string, userId: string, otherUsers: string[],
|
||||
): MatrixEvent {
|
||||
function mkDirectEvent(roomId: string, userId: string, otherUsers: string[]): MatrixEvent {
|
||||
const content = {};
|
||||
for (const otherUserId of otherUsers) {
|
||||
content[otherUserId] = [roomId];
|
||||
|
@ -363,7 +364,7 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
});
|
||||
room.currentState.setStateEvents([mkCreationEvent(room.roomId, "@alice:example.org")]);
|
||||
|
||||
client.getRoom.mockImplementation(roomId => roomId === room.roomId ? room : null);
|
||||
client.getRoom.mockImplementation((roomId) => (roomId === room.roomId ? room : null));
|
||||
client.getRooms.mockReturnValue([room]);
|
||||
client.reEmitter.reEmit(room, [RoomStateEvent.Events]);
|
||||
client.sendStateEvent.mockImplementation(async (roomId, eventType, content, stateKey = "") => {
|
||||
|
@ -384,13 +385,13 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
bob = mkRoomMember(room.roomId, "@bob:example.org");
|
||||
carol = mkRoomMember(room.roomId, "@carol:example.org");
|
||||
|
||||
client.getRoom.mockImplementation(roomId => roomId === room.roomId ? room : null);
|
||||
client.getRoom.mockImplementation((roomId) => (roomId === room.roomId ? room : null));
|
||||
client.getRooms.mockReturnValue([room]);
|
||||
client.reEmitter.reEmit(room, [RoomStateEvent.Events]);
|
||||
|
||||
await Promise.all([CallStore.instance, WidgetStore.instance].map(
|
||||
store => setupAsyncStoreWithClient(store, client),
|
||||
));
|
||||
await Promise.all(
|
||||
[CallStore.instance, WidgetStore.instance].map((store) => setupAsyncStoreWithClient(store, client)),
|
||||
);
|
||||
|
||||
jest.spyOn(MediaDeviceHandler, "getDevices").mockResolvedValue({
|
||||
[MediaDeviceKindEnum.AudioInput]: [],
|
||||
|
@ -412,13 +413,11 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
const mockRoomMembers = (members: RoomMember[]) => {
|
||||
jest.spyOn(room, "getJoinedMembers").mockReturnValue(members);
|
||||
jest.spyOn(room, "getMember").mockImplementation(
|
||||
userId => members.find(member => member.userId === userId) ?? null,
|
||||
(userId) => members.find((member) => member.userId === userId) ?? null,
|
||||
);
|
||||
};
|
||||
const mockEnabledSettings = (settings: string[]) => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation(
|
||||
settingName => settings.includes(settingName),
|
||||
);
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName) => settings.includes(settingName));
|
||||
};
|
||||
const mockEventPowerLevels = (events: { [eventType: string]: number }) => {
|
||||
room.currentState.setStateEvents([
|
||||
|
@ -435,7 +434,7 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
const mockLegacyCall = () => {
|
||||
jest.spyOn(LegacyCallHandler.instance, "getCallForRoom").mockReturnValue({} as unknown as MatrixCall);
|
||||
};
|
||||
const withCall = async (fn: (call: ElementCall) => (void | Promise<void>)): Promise<void> => {
|
||||
const withCall = async (fn: (call: ElementCall) => void | Promise<void>): Promise<void> => {
|
||||
await ElementCall.create(room);
|
||||
const call = CallStore.instance.getCall(room.roomId);
|
||||
if (!(call instanceof ElementCall)) throw new Error("Failed to create call");
|
||||
|
@ -468,10 +467,10 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
<RoomHeader
|
||||
room={room}
|
||||
inRoom={true}
|
||||
onSearchClick={() => { }}
|
||||
onSearchClick={() => {}}
|
||||
onInviteClick={null}
|
||||
onForgetClick={() => { }}
|
||||
onAppsClick={() => { }}
|
||||
onForgetClick={() => {}}
|
||||
onAppsClick={() => {}}
|
||||
e2eStatus={E2EStatus.Normal}
|
||||
appsShown={true}
|
||||
searchInfo={{
|
||||
|
@ -505,13 +504,13 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
});
|
||||
|
||||
it(
|
||||
"hides the voice call button and disables the video call button if configured to use Element Call exclusively "
|
||||
+ "and there's an ongoing call",
|
||||
"hides the voice call button and disables the video call button if configured to use Element Call exclusively " +
|
||||
"and there's an ongoing call",
|
||||
async () => {
|
||||
mockEnabledSettings(["showCallButtonsInComposer", "feature_group_calls"]);
|
||||
SdkConfig.put(
|
||||
{ element_call: { url: "https://call.element.io", use_exclusively: true, brand: "Element Call" } },
|
||||
);
|
||||
SdkConfig.put({
|
||||
element_call: { url: "https://call.element.io", use_exclusively: true, brand: "Element Call" },
|
||||
});
|
||||
await ElementCall.create(room);
|
||||
|
||||
renderHeader();
|
||||
|
@ -521,13 +520,13 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
);
|
||||
|
||||
it(
|
||||
"hides the voice call button and starts an Element call when the video call button is pressed if configured to "
|
||||
+ "use Element Call exclusively",
|
||||
"hides the voice call button and starts an Element call when the video call button is pressed if configured to " +
|
||||
"use Element Call exclusively",
|
||||
async () => {
|
||||
mockEnabledSettings(["showCallButtonsInComposer", "feature_group_calls"]);
|
||||
SdkConfig.put(
|
||||
{ element_call: { url: "https://call.element.io", use_exclusively: true, brand: "Element Call" } },
|
||||
);
|
||||
SdkConfig.put({
|
||||
element_call: { url: "https://call.element.io", use_exclusively: true, brand: "Element Call" },
|
||||
});
|
||||
|
||||
renderHeader();
|
||||
expect(screen.queryByRole("button", { name: "Voice call" })).toBeNull();
|
||||
|
@ -535,23 +534,25 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
const dispatcherSpy = jest.fn();
|
||||
const dispatcherRef = defaultDispatcher.register(dispatcherSpy);
|
||||
fireEvent.click(screen.getByRole("button", { name: "Video call" }));
|
||||
await waitFor(() => expect(dispatcherSpy).toHaveBeenCalledWith({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
view_call: true,
|
||||
}));
|
||||
await waitFor(() =>
|
||||
expect(dispatcherSpy).toHaveBeenCalledWith({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
view_call: true,
|
||||
}),
|
||||
);
|
||||
defaultDispatcher.unregister(dispatcherRef);
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
"hides the voice call button and disables the video call button if configured to use Element Call exclusively "
|
||||
+ "and the user lacks permission",
|
||||
"hides the voice call button and disables the video call button if configured to use Element Call exclusively " +
|
||||
"and the user lacks permission",
|
||||
() => {
|
||||
mockEnabledSettings(["showCallButtonsInComposer", "feature_group_calls"]);
|
||||
SdkConfig.put(
|
||||
{ element_call: { url: "https://call.element.io", use_exclusively: true, brand: "Element Call" } },
|
||||
);
|
||||
SdkConfig.put({
|
||||
element_call: { url: "https://call.element.io", use_exclusively: true, brand: "Element Call" },
|
||||
});
|
||||
mockEventPowerLevels({ [ElementCall.CALL_EVENT_TYPE.name]: 100 });
|
||||
|
||||
renderHeader();
|
||||
|
@ -596,8 +597,8 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
});
|
||||
|
||||
it(
|
||||
"starts a legacy 1:1 call when call buttons are pressed in the new group call experience if there's 1 other "
|
||||
+ "member",
|
||||
"starts a legacy 1:1 call when call buttons are pressed in the new group call experience if there's 1 other " +
|
||||
"member",
|
||||
async () => {
|
||||
mockEnabledSettings(["showCallButtonsInComposer", "feature_group_calls"]);
|
||||
mockRoomMembers([alice, bob]);
|
||||
|
@ -617,8 +618,8 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
);
|
||||
|
||||
it(
|
||||
"creates a Jitsi widget when call buttons are pressed in the new group call experience if the user lacks "
|
||||
+ "permission to start Element calls",
|
||||
"creates a Jitsi widget when call buttons are pressed in the new group call experience if the user lacks " +
|
||||
"permission to start Element calls",
|
||||
async () => {
|
||||
mockEnabledSettings(["showCallButtonsInComposer", "feature_group_calls"]);
|
||||
mockRoomMembers([alice, bob, carol]);
|
||||
|
@ -639,8 +640,8 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
);
|
||||
|
||||
it(
|
||||
"creates a Jitsi widget when the voice call button is pressed and shows a menu when the video call button is "
|
||||
+ "pressed in the new group call experience",
|
||||
"creates a Jitsi widget when the voice call button is pressed and shows a menu when the video call button is " +
|
||||
"pressed in the new group call experience",
|
||||
async () => {
|
||||
mockEnabledSettings(["showCallButtonsInComposer", "feature_group_calls"]);
|
||||
mockRoomMembers([alice, bob, carol]);
|
||||
|
@ -664,18 +665,20 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
const dispatcherRef = defaultDispatcher.register(dispatcherSpy);
|
||||
fireEvent.click(screen.getByRole("button", { name: "Video call" }));
|
||||
fireEvent.click(getByRole(screen.getByRole("menu"), "menuitem", { name: /element/i }));
|
||||
await waitFor(() => expect(dispatcherSpy).toHaveBeenCalledWith({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
view_call: true,
|
||||
}));
|
||||
await waitFor(() =>
|
||||
expect(dispatcherSpy).toHaveBeenCalledWith({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
view_call: true,
|
||||
}),
|
||||
);
|
||||
defaultDispatcher.unregister(dispatcherRef);
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
"disables the voice call button and starts an Element call when the video call button is pressed in the new "
|
||||
+ "group call experience if the user lacks permission to edit widgets",
|
||||
"disables the voice call button and starts an Element call when the video call button is pressed in the new " +
|
||||
"group call experience if the user lacks permission to edit widgets",
|
||||
async () => {
|
||||
mockEnabledSettings(["showCallButtonsInComposer", "feature_group_calls"]);
|
||||
mockRoomMembers([alice, bob, carol]);
|
||||
|
@ -687,11 +690,13 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
const dispatcherSpy = jest.fn();
|
||||
const dispatcherRef = defaultDispatcher.register(dispatcherSpy);
|
||||
fireEvent.click(screen.getByRole("button", { name: "Video call" }));
|
||||
await waitFor(() => expect(dispatcherSpy).toHaveBeenCalledWith({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
view_call: true,
|
||||
}));
|
||||
await waitFor(() =>
|
||||
expect(dispatcherSpy).toHaveBeenCalledWith({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
view_call: true,
|
||||
}),
|
||||
);
|
||||
defaultDispatcher.unregister(dispatcherRef);
|
||||
},
|
||||
);
|
||||
|
@ -785,28 +790,32 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
const dispatcherSpy = jest.fn();
|
||||
const dispatcherRef = defaultDispatcher.register(dispatcherSpy);
|
||||
fireEvent.click(screen.getByRole("button", { name: /close/i }));
|
||||
await waitFor(() => expect(dispatcherSpy).toHaveBeenCalledWith({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
view_call: false,
|
||||
}));
|
||||
await waitFor(() =>
|
||||
expect(dispatcherSpy).toHaveBeenCalledWith({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
view_call: false,
|
||||
}),
|
||||
);
|
||||
defaultDispatcher.unregister(dispatcherRef);
|
||||
});
|
||||
|
||||
it("shows a reduce button when viewing a call that returns to the timeline when pressed", async () => {
|
||||
mockEnabledSettings(["feature_group_calls"]);
|
||||
|
||||
await withCall(async call => {
|
||||
await withCall(async (call) => {
|
||||
renderHeader({ viewingCall: true, activeCall: call });
|
||||
|
||||
const dispatcherSpy = jest.fn();
|
||||
const dispatcherRef = defaultDispatcher.register(dispatcherSpy);
|
||||
fireEvent.click(screen.getByRole("button", { name: /timeline/i }));
|
||||
await waitFor(() => expect(dispatcherSpy).toHaveBeenCalledWith({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
view_call: false,
|
||||
}));
|
||||
await waitFor(() =>
|
||||
expect(dispatcherSpy).toHaveBeenCalledWith({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
view_call: false,
|
||||
}),
|
||||
);
|
||||
defaultDispatcher.unregister(dispatcherRef);
|
||||
});
|
||||
});
|
||||
|
@ -814,7 +823,7 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
it("shows a layout button when viewing a call that shows a menu when pressed", async () => {
|
||||
mockEnabledSettings(["feature_group_calls"]);
|
||||
|
||||
await withCall(async call => {
|
||||
await withCall(async (call) => {
|
||||
await call.connect();
|
||||
const messaging = WidgetMessagingStore.instance.getMessagingForUid(WidgetUtils.getWidgetUid(call.widget));
|
||||
renderHeader({ viewingCall: true, activeCall: call });
|
||||
|
|
|
@ -14,33 +14,29 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactTestUtils from 'react-dom/test-utils';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {
|
||||
PendingEventOrdering,
|
||||
Room,
|
||||
RoomMember,
|
||||
} from 'matrix-js-sdk/src/matrix';
|
||||
import React from "react";
|
||||
import ReactTestUtils from "react-dom/test-utils";
|
||||
import ReactDOM from "react-dom";
|
||||
import { PendingEventOrdering, Room, RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import * as TestUtils from '../../../test-utils';
|
||||
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||
import dis from '../../../../src/dispatcher/dispatcher';
|
||||
import DMRoomMap from '../../../../src/utils/DMRoomMap';
|
||||
import * as TestUtils from "../../../test-utils";
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import dis from "../../../../src/dispatcher/dispatcher";
|
||||
import DMRoomMap from "../../../../src/utils/DMRoomMap";
|
||||
import { DefaultTagID } from "../../../../src/stores/room-list/models";
|
||||
import RoomListStore, { RoomListStoreClass } from "../../../../src/stores/room-list/RoomListStore";
|
||||
import RoomListLayoutStore from "../../../../src/stores/room-list/RoomListLayoutStore";
|
||||
import RoomList from "../../../../src/components/views/rooms/RoomList";
|
||||
import RoomSublist from "../../../../src/components/views/rooms/RoomSublist";
|
||||
import { RoomTile } from "../../../../src/components/views/rooms/RoomTile";
|
||||
import { getMockClientWithEventEmitter, mockClientMethodsUser } from '../../../test-utils';
|
||||
import ResizeNotifier from '../../../../src/utils/ResizeNotifier';
|
||||
import { getMockClientWithEventEmitter, mockClientMethodsUser } from "../../../test-utils";
|
||||
import ResizeNotifier from "../../../../src/utils/ResizeNotifier";
|
||||
|
||||
function generateRoomId() {
|
||||
return '!' + Math.random().toString().slice(2, 10) + ':domain';
|
||||
return "!" + Math.random().toString().slice(2, 10) + ":domain";
|
||||
}
|
||||
|
||||
describe('RoomList', () => {
|
||||
describe("RoomList", () => {
|
||||
function createRoom(opts) {
|
||||
const room = new Room(generateRoomId(), MatrixClientPeg.get(), client.getUserId(), {
|
||||
// The room list now uses getPendingEvents(), so we need a detached ordering.
|
||||
|
@ -54,9 +50,9 @@ describe('RoomList', () => {
|
|||
|
||||
let parentDiv = null;
|
||||
let root = null;
|
||||
const myUserId = '@me:domain';
|
||||
const myUserId = "@me:domain";
|
||||
|
||||
const movingRoomId = '!someroomid';
|
||||
const movingRoomId = "!someroomid";
|
||||
let movingRoom: Room | undefined;
|
||||
let otherRoom: Room | undefined;
|
||||
|
||||
|
@ -77,10 +73,10 @@ describe('RoomList', () => {
|
|||
onResize: jest.fn(),
|
||||
resizeNotifier: {} as unknown as ResizeNotifier,
|
||||
isMinimized: false,
|
||||
activeSpace: '',
|
||||
activeSpace: "",
|
||||
};
|
||||
|
||||
beforeEach(async function(done) {
|
||||
beforeEach(async function (done) {
|
||||
RoomListStoreClass.TEST_MODE = true;
|
||||
jest.clearAllMocks();
|
||||
|
||||
|
@ -88,43 +84,42 @@ describe('RoomList', () => {
|
|||
|
||||
DMRoomMap.makeShared();
|
||||
|
||||
parentDiv = document.createElement('div');
|
||||
parentDiv = document.createElement("div");
|
||||
document.body.appendChild(parentDiv);
|
||||
|
||||
const WrappedRoomList = TestUtils.wrapInMatrixClientContext(RoomList);
|
||||
root = ReactDOM.render(
|
||||
<WrappedRoomList {...defaultProps} />,
|
||||
parentDiv,
|
||||
);
|
||||
root = ReactDOM.render(<WrappedRoomList {...defaultProps} />, parentDiv);
|
||||
ReactTestUtils.findRenderedComponentWithType(root, RoomList);
|
||||
|
||||
movingRoom = createRoom({ name: 'Moving room' });
|
||||
movingRoom = createRoom({ name: "Moving room" });
|
||||
expect(movingRoom.roomId).not.toBe(null);
|
||||
|
||||
// Mock joined member
|
||||
myMember = new RoomMember(movingRoomId, myUserId);
|
||||
myMember.membership = 'join';
|
||||
movingRoom.updateMyMembership('join');
|
||||
movingRoom.getMember = (userId) => ({
|
||||
[client.credentials.userId]: myMember,
|
||||
}[userId]);
|
||||
myMember.membership = "join";
|
||||
movingRoom.updateMyMembership("join");
|
||||
movingRoom.getMember = (userId) =>
|
||||
({
|
||||
[client.credentials.userId]: myMember,
|
||||
}[userId]);
|
||||
|
||||
otherRoom = createRoom({ name: 'Other room' });
|
||||
otherRoom = createRoom({ name: "Other room" });
|
||||
myOtherMember = new RoomMember(otherRoom.roomId, myUserId);
|
||||
myOtherMember.membership = 'join';
|
||||
otherRoom.updateMyMembership('join');
|
||||
otherRoom.getMember = (userId) => ({
|
||||
[client.credentials.userId]: myOtherMember,
|
||||
}[userId]);
|
||||
myOtherMember.membership = "join";
|
||||
otherRoom.updateMyMembership("join");
|
||||
otherRoom.getMember = (userId) =>
|
||||
({
|
||||
[client.credentials.userId]: myOtherMember,
|
||||
}[userId]);
|
||||
|
||||
// Mock the matrix client
|
||||
const mockRooms = [
|
||||
movingRoom,
|
||||
otherRoom,
|
||||
createRoom({ tags: { 'm.favourite': { order: 0.1 } }, name: 'Some other room' }),
|
||||
createRoom({ tags: { 'm.favourite': { order: 0.2 } }, name: 'Some other room 2' }),
|
||||
createRoom({ tags: { 'm.lowpriority': {} }, name: 'Some unimportant room' }),
|
||||
createRoom({ tags: { 'custom.tag': {} }, name: 'Some room customly tagged' }),
|
||||
createRoom({ tags: { "m.favourite": { order: 0.1 } }, name: "Some other room" }),
|
||||
createRoom({ tags: { "m.favourite": { order: 0.2 } }, name: "Some other room 2" }),
|
||||
createRoom({ tags: { "m.lowpriority": {} }, name: "Some unimportant room" }),
|
||||
createRoom({ tags: { "custom.tag": {} }, name: "Some room customly tagged" }),
|
||||
];
|
||||
client.getRooms.mockReturnValue(mockRooms);
|
||||
client.getVisibleRooms.mockReturnValue(mockRooms);
|
||||
|
@ -166,9 +161,14 @@ describe('RoomList', () => {
|
|||
expectedRoomTile = roomTiles.find((tile) => tile.props.room === room);
|
||||
} catch (err) {
|
||||
// truncate the error message because it's spammy
|
||||
err.message = 'Error finding RoomTile for ' + room.roomId + ' in ' +
|
||||
subListTest + ': ' +
|
||||
err.message.split('componentType')[0] + '...';
|
||||
err.message =
|
||||
"Error finding RoomTile for " +
|
||||
room.roomId +
|
||||
" in " +
|
||||
subListTest +
|
||||
": " +
|
||||
err.message.split("componentType")[0] +
|
||||
"...";
|
||||
throw err;
|
||||
}
|
||||
|
||||
|
@ -193,77 +193,81 @@ describe('RoomList', () => {
|
|||
// Mock inverse m.direct
|
||||
// @ts-ignore forcing private property
|
||||
DMRoomMap.shared().roomToUser = {
|
||||
[movingRoom.roomId]: '@someotheruser:domain',
|
||||
[movingRoom.roomId]: "@someotheruser:domain",
|
||||
};
|
||||
}
|
||||
|
||||
dis.dispatch({ action: 'MatrixActions.sync', prevState: null, state: 'PREPARED', matrixClient: client });
|
||||
dis.dispatch({ action: "MatrixActions.sync", prevState: null, state: "PREPARED", matrixClient: client });
|
||||
|
||||
expectRoomInSubList(movingRoom, srcSubListTest);
|
||||
|
||||
dis.dispatch({ action: 'RoomListActions.tagRoom.pending', request: {
|
||||
oldTagId, newTagId, room: movingRoom,
|
||||
} });
|
||||
dis.dispatch({
|
||||
action: "RoomListActions.tagRoom.pending",
|
||||
request: {
|
||||
oldTagId,
|
||||
newTagId,
|
||||
room: movingRoom,
|
||||
},
|
||||
});
|
||||
|
||||
expectRoomInSubList(movingRoom, destSubListTest);
|
||||
}
|
||||
|
||||
function itDoesCorrectOptimisticUpdatesForDraggedRoomTiles() {
|
||||
// TODO: Re-enable dragging tests when we support dragging again.
|
||||
describe.skip('does correct optimistic update when dragging from', () => {
|
||||
it('rooms to people', () => {
|
||||
describe.skip("does correct optimistic update when dragging from", () => {
|
||||
it("rooms to people", () => {
|
||||
expectCorrectMove(undefined, DefaultTagID.DM);
|
||||
});
|
||||
|
||||
it('rooms to favourites', () => {
|
||||
expectCorrectMove(undefined, 'm.favourite');
|
||||
it("rooms to favourites", () => {
|
||||
expectCorrectMove(undefined, "m.favourite");
|
||||
});
|
||||
|
||||
it('rooms to low priority', () => {
|
||||
expectCorrectMove(undefined, 'm.lowpriority');
|
||||
it("rooms to low priority", () => {
|
||||
expectCorrectMove(undefined, "m.lowpriority");
|
||||
});
|
||||
|
||||
// XXX: Known to fail - the view does not update immediately to reflect the change.
|
||||
// Whe running the app live, it updates when some other event occurs (likely the
|
||||
// m.direct arriving) that these tests do not fire.
|
||||
xit('people to rooms', () => {
|
||||
xit("people to rooms", () => {
|
||||
expectCorrectMove(DefaultTagID.DM, undefined);
|
||||
});
|
||||
|
||||
it('people to favourites', () => {
|
||||
expectCorrectMove(DefaultTagID.DM, 'm.favourite');
|
||||
it("people to favourites", () => {
|
||||
expectCorrectMove(DefaultTagID.DM, "m.favourite");
|
||||
});
|
||||
|
||||
it('people to lowpriority', () => {
|
||||
expectCorrectMove(DefaultTagID.DM, 'm.lowpriority');
|
||||
it("people to lowpriority", () => {
|
||||
expectCorrectMove(DefaultTagID.DM, "m.lowpriority");
|
||||
});
|
||||
|
||||
it('low priority to rooms', () => {
|
||||
expectCorrectMove('m.lowpriority', undefined);
|
||||
it("low priority to rooms", () => {
|
||||
expectCorrectMove("m.lowpriority", undefined);
|
||||
});
|
||||
|
||||
it('low priority to people', () => {
|
||||
expectCorrectMove('m.lowpriority', DefaultTagID.DM);
|
||||
it("low priority to people", () => {
|
||||
expectCorrectMove("m.lowpriority", DefaultTagID.DM);
|
||||
});
|
||||
|
||||
it('low priority to low priority', () => {
|
||||
expectCorrectMove('m.lowpriority', 'm.lowpriority');
|
||||
it("low priority to low priority", () => {
|
||||
expectCorrectMove("m.lowpriority", "m.lowpriority");
|
||||
});
|
||||
|
||||
it('favourites to rooms', () => {
|
||||
expectCorrectMove('m.favourite', undefined);
|
||||
it("favourites to rooms", () => {
|
||||
expectCorrectMove("m.favourite", undefined);
|
||||
});
|
||||
|
||||
it('favourites to people', () => {
|
||||
expectCorrectMove('m.favourite', DefaultTagID.DM);
|
||||
it("favourites to people", () => {
|
||||
expectCorrectMove("m.favourite", DefaultTagID.DM);
|
||||
});
|
||||
|
||||
it('favourites to low priority', () => {
|
||||
expectCorrectMove('m.favourite', 'm.lowpriority');
|
||||
it("favourites to low priority", () => {
|
||||
expectCorrectMove("m.favourite", "m.lowpriority");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
itDoesCorrectOptimisticUpdatesForDraggedRoomTiles();
|
||||
});
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue