diff --git a/test/components/views/right_panel/PinnedMessagesCard-test.tsx b/test/components/views/right_panel/PinnedMessagesCard-test.tsx index 4ea5d8d351..dce93be59f 100644 --- a/test/components/views/right_panel/PinnedMessagesCard-test.tsx +++ b/test/components/views/right_panel/PinnedMessagesCard-test.tsx @@ -14,12 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from "react"; -import { mount } from "enzyme"; +import React, { ComponentProps } from "react"; +import { mount, ReactWrapper } from "enzyme"; +import { mocked } from "jest-mock"; import { act } from "react-dom/test-utils"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { EventType, RelationType, MsgType } from "matrix-js-sdk/src/@types/event"; import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; +import { IEvent, Room, EventTimelineSet, IMinimalEvent } from "matrix-js-sdk/src/matrix"; import { M_POLL_RESPONSE, M_POLL_END, @@ -32,37 +34,37 @@ import { import "../../../skinned-sdk"; import { stubClient, - wrapInMatrixClientContext, mkStubRoom, mkEvent, mkMessage, } from "../../../test-utils"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; -import _PinnedMessagesCard from "../../../../src/components/views/right_panel/PinnedMessagesCard"; +import PinnedMessagesCard from "../../../../src/components/views/right_panel/PinnedMessagesCard"; import PinnedEventTile from "../../../../src/components/views/rooms/PinnedEventTile"; -import MPollBody from "../../../../src/components/views/messages/MPollBody.tsx"; - -const PinnedMessagesCard = wrapInMatrixClientContext(_PinnedMessagesCard); +import MPollBody from "../../../../src/components/views/messages/MPollBody"; +import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; describe("", () => { stubClient(); - const cli = MatrixClientPeg.get(); + const cli = mocked(MatrixClientPeg.get()); cli.getUserId.mockReturnValue("@alice:example.org"); - cli.setRoomAccountData = () => {}; - cli.relations = jest.fn().mockResolvedValue({ events: [] }); + cli.setRoomAccountData.mockReturnValue(undefined); + cli.relations.mockResolvedValue({ originalEvent: {} as unknown as MatrixEvent, events: [] }); const mkRoom = (localPins: MatrixEvent[], nonLocalPins: MatrixEvent[]): Room => { - const room = mkStubRoom("!room:example.org"); + 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 - room.currentState.getStateEvents.mockImplementation(() => mkEvent({ + mocked(room.currentState).getStateEvents.mockImplementation(() => 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 @@ -70,18 +72,24 @@ describe("", () => { getTimelineForEvent: () => ({ getEvents: () => localPins, }), - }); + } as unknown as EventTimelineSet); // Return all pins over fetchRoomEvent - cli.fetchRoomEvent = (roomId, eventId) => pins().find(e => e.getId() === eventId)?.event; + cli.fetchRoomEvent.mockImplementation((roomId, eventId) => { + const event = pins().find(e => e.getId() === eventId)?.event; + return Promise.resolve(event as IMinimalEvent); + }); return room; }; - const mountPins = async (room: Room): ReactWrapper => { + const mountPins = async (room: Room): Promise>> => { let pins; await act(async () => { - pins = mount( {}} />); + pins = mount(, { + wrappingComponent: MatrixClientContext.Provider, + wrappingComponentProps: { value: cli }, + }); // Wait a tick for state updates await new Promise(resolve => setImmediate(resolve)); }); @@ -90,13 +98,14 @@ describe("", () => { return pins; }; - const emitPinUpdates = async (pins: ReactWrapper) => { + const emitPinUpdates = async (pins: ReactWrapper>) => { const room = pins.props().room; - const pinListener = room.currentState.on.mock.calls + 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)); @@ -159,7 +168,9 @@ describe("", () => { event: true, type: EventType.RoomMessage, content: {}, - unsigned: { redacted_because: {} }, + unsigned: { redacted_because: {} as unknown as IEvent }, + room: "!room:example.org", + user: "@alice:example.org", }); const pins = await mountPins(mkRoom([pin], [])); @@ -172,7 +183,9 @@ describe("", () => { event: true, type: EventType.RoomMessage, content: {}, - unsigned: { redacted_because: {} }, + unsigned: { redacted_because: {} as unknown as IEvent }, + room: "!room:example.org", + user: "@alice:example.org", }); const pins = await mountPins(mkRoom([], [pin])); @@ -180,25 +193,27 @@ describe("", () => { }); it("accounts for edits", async () => { - cli.relations.mockResolvedValue({ - events: [mkEvent({ - event: true, - type: EventType.RoomMessage, - room: "!room:example.org", - user: "@alice:example.org", - content: { - "msgtype": MsgType.Text, - "body": " * First pinned message, edited", - "m.new_content": { - msgtype: MsgType.Text, - body: "First pinned message, edited", - }, - "m.relates_to": { - rel_type: RelationType.Replace, - event_id: pin1.getId(), - }, + const messageEvent = mkEvent({ + event: true, + type: EventType.RoomMessage, + room: "!room:example.org", + user: "@alice:example.org", + content: { + "msgtype": MsgType.Text, + "body": " * First pinned message, edited", + "m.new_content": { + msgtype: MsgType.Text, + body: "First pinned message, edited", }, - })], + "m.relates_to": { + rel_type: RelationType.Replace, + event_id: pin1.getId(), + }, + }, + }); + cli.relations.mockResolvedValue({ + originalEvent: pin1, + events: [messageEvent], }); const pins = await mountPins(mkRoom([], [pin1])); @@ -224,7 +239,7 @@ describe("", () => { ...PollResponseEvent.from([answers[option].id], poll.getId()).serialize(), event: true, room: "!room:example.org", - user, + user: user as string, })); const end = mkEvent({ ...PollEndEvent.from(poll.getId(), "Closing the poll").serialize(), @@ -234,19 +249,22 @@ describe("", () => { }); // Make the responses available - cli.relations.mockImplementation((roomId, eventId, relationType, eventType, { from }) => { + cli.relations.mockImplementation(async (roomId, eventId, relationType, eventType, { from }) => { if (eventId === poll.getId() && relationType === RelationType.Reference) { switch (eventType) { case M_POLL_RESPONSE.name: // Paginate the results, for added challenge return (from === "page2") ? - { events: responses.slice(2) } : - { events: responses.slice(0, 2), nextBatch: "page2" }; + { originalEvent: poll, events: responses.slice(2) } : + { originalEvent: poll, events: responses.slice(0, 2), nextBatch: "page2" }; case M_POLL_END.name: - return { events: [end] }; + return { originalEvent: null, events: [end] }; } } - return { events: [] }; + // type does not allow originalEvent to be falsy + // but code seems to + // so still test that + return { originalEvent: undefined as unknown as MatrixEvent, events: [] }; }); const pins = await mountPins(mkRoom([], [poll])); diff --git a/test/components/views/right_panel/UserInfo-test.tsx b/test/components/views/right_panel/UserInfo-test.tsx index 84587bee5c..c834f77db4 100644 --- a/test/components/views/right_panel/UserInfo-test.tsx +++ b/test/components/views/right_panel/UserInfo-test.tsx @@ -16,8 +16,9 @@ limitations under the License. import React from 'react'; import { mount } from 'enzyme'; +import { mocked } from 'jest-mock'; import { act } from "react-dom/test-utils"; -import { Room, User } from 'matrix-js-sdk/src/matrix'; +import { Room, User, MatrixClient } from 'matrix-js-sdk/src/matrix'; import { Phase, VerificationRequest } from 'matrix-js-sdk/src/crypto/verification/request/VerificationRequest'; import "../../../skinned-sdk"; @@ -46,13 +47,7 @@ describe('', () => { const defaultUserId = '@test:test'; const defaultUser = new User(defaultUserId); - const defaultProps = { - user: defaultUser, - phase: RightPanelPhases.RoomMemberInfo, - onClose: jest.fn(), - }; - - const mockClient = { + const mockClient = mocked({ getUser: jest.fn(), isGuest: jest.fn().mockReturnValue(false), isUserIgnored: jest.fn(), @@ -67,7 +62,7 @@ describe('', () => { currentState: { on: jest.fn(), }, - }; + } as unknown as MatrixClient); const verificationRequest = { pending: true, on: jest.fn(), phase: Phase.Ready, @@ -75,17 +70,27 @@ describe('', () => { otherPartySupportsMethod: jest.fn(), } as unknown as VerificationRequest; - const getComponent = (props = {}) => mount(, { - wrappingComponent: MatrixClientContext.Provider, - wrappingComponentProps: { value: mockClient }, - }); + const defaultProps = { + user: defaultUser, + // idk what is wrong with this type + phase: RightPanelPhases.RoomMemberInfo as RightPanelPhases.RoomMemberInfo, + onClose: jest.fn(), + }; + + const getComponent = (props = {}) => mount( + , + { + wrappingComponent: MatrixClientContext.Provider, + wrappingComponentProps: { value: mockClient }, + }, + ); beforeAll(() => { jest.spyOn(MatrixClientPeg, 'get').mockReturnValue(mockClient); }); beforeEach(() => { - mockClient.getUser.mockClear().mockResolvedValue(undefined); + mockClient.getUser.mockClear().mockReturnValue({} as unknown as User); }); it('closes on close button click', () => { diff --git a/test/components/views/rooms/MemberList-test.tsx b/test/components/views/rooms/MemberList-test.tsx index 7a1e73f0e9..b65ef052ff 100644 --- a/test/components/views/rooms/MemberList-test.tsx +++ b/test/components/views/rooms/MemberList-test.tsx @@ -28,13 +28,14 @@ import * as TestUtils from '../../../test-utils'; import { compare } from "../../../../src/utils/strings"; import MemberList from "../../../../src/components/views/rooms/MemberList"; import MemberTile from '../../../../src/components/views/rooms/MemberTile'; +import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; function generateRoomId() { return '!' + Math.random().toString().slice(2, 10) + ':domain'; } describe('MemberList', () => { - function createRoom(opts) { + function createRoom(opts = {}) { const room = new Room(generateRoomId(), null, client.getUserId()); if (opts) { Object.assign(room, opts); @@ -114,16 +115,20 @@ describe('MemberList', () => { memberListRoom.currentState.members[member.userId] = member; } - const WrappedMemberList = TestUtils.wrapInMatrixClientContext(MemberList); const gatherWrappedRef = (r) => { memberList = r; }; root = ReactDOM.render( ( - + + + ), parentDiv, ); diff --git a/test/components/views/rooms/MessageComposer-test.tsx b/test/components/views/rooms/MessageComposer-test.tsx index 7b4b0f0b78..af7c67fe2b 100644 --- a/test/components/views/rooms/MessageComposer-test.tsx +++ b/test/components/views/rooms/MessageComposer-test.tsx @@ -25,6 +25,9 @@ import MessageComposer from "../../../../src/components/views/rooms/MessageCompo import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import RoomContext from "../../../../src/contexts/RoomContext"; +import { IRoomState } from "../../../../src/components/structures/RoomView"; +import ResizeNotifier from "../../../../src/utils/ResizeNotifier"; +import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks"; describe("MessageComposer", () => { stubClient(); @@ -32,18 +35,14 @@ describe("MessageComposer", () => { const room = mkStubRoom("!roomId:server", "Room 1", cli); it("Renders a SendMessageComposer and MessageComposerButtons by default", () => { - const wrapper = wrapAndRender(( - - )); + const wrapper = wrapAndRender({ room }); expect(wrapper.find("SendMessageComposer")).toHaveLength(1); expect(wrapper.find("MessageComposerButtons")).toHaveLength(1); }); it("Does not render a SendMessageComposer or MessageComposerButtons when user has no permission", () => { - const wrapper = wrapAndRender(( - - ), false); + const wrapper = wrapAndRender({ room }, false); expect(wrapper.find("SendMessageComposer")).toHaveLength(0); expect(wrapper.find("MessageComposerButtons")).toHaveLength(0); @@ -51,9 +50,7 @@ describe("MessageComposer", () => { }); it("Does not render a SendMessageComposer or MessageComposerButtons when room is tombstoned", () => { - const wrapper = wrapAndRender(( - - ), true, mkEvent({ + const wrapper = wrapAndRender({ room }, true, mkEvent({ event: true, type: "m.room.tombstone", room: room.roomId, @@ -69,7 +66,7 @@ describe("MessageComposer", () => { }); }); -function wrapAndRender(component: React.ReactElement, canSendMessages = true, tombstone?: MatrixEvent): ReactWrapper { +function wrapAndRender(props = {}, canSendMessages = true, tombstone?: MatrixEvent): ReactWrapper { const mockClient = MatrixClientPeg.get(); const roomId = "myroomid"; const room: any = { @@ -80,10 +77,21 @@ function wrapAndRender(component: React.ReactElement, canSendMessages = true, to return new RoomMember(roomId, userId); }, }; + + const roomState = { + room, canSendMessages, tombstone, + } as unknown as IRoomState; + + const defaultProps = { + room, + resizeNotifier: new ResizeNotifier(), + permalinkCreator: new RoomPermalinkCreator(room), + }; + return mount( - - { component } + + , ); diff --git a/test/components/views/rooms/MessageComposerButtons-test.tsx b/test/components/views/rooms/MessageComposerButtons-test.tsx index d89d0141a4..65e9abb1e7 100644 --- a/test/components/views/rooms/MessageComposerButtons-test.tsx +++ b/test/components/views/rooms/MessageComposerButtons-test.tsx @@ -19,7 +19,6 @@ import { mount, ReactWrapper } from "enzyme"; import { Room } from "matrix-js-sdk/src/models/room"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; -import * as TestUtils from "../../../test-utils"; import sdk from "../../../skinned-sdk"; import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; import { Layout } from "../../../../src/settings/enums/Layout"; @@ -28,10 +27,7 @@ import { createTestClient } from "../../../test-utils"; import { IRoomState } from "../../../../src/components/structures/RoomView"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; -const _MessageComposerButtons = sdk.getComponent("views.rooms.MessageComposerButtons"); -const MessageComposerButtons = TestUtils.wrapInMatrixClientContext( - _MessageComposerButtons, -); +const MessageComposerButtons = sdk.getComponent("views.rooms.MessageComposerButtons"); describe("MessageComposerButtons", () => { it("Renders emoji and upload buttons in wide mode", () => { @@ -172,7 +168,8 @@ describe("MessageComposerButtons", () => { }); function wrapAndRender(component: React.ReactElement, narrow: boolean): ReactWrapper { - const mockClient = MatrixClientPeg.matrixClient = createTestClient(); + const mockClient = createTestClient(); + jest.spyOn(MatrixClientPeg, 'get').mockReturnValue(mockClient); const roomId = "myroomid"; const mockRoom: any = { currentState: undefined, @@ -202,7 +199,6 @@ function createRoomState(room: Room, narrow: boolean): IRoomState { shouldPeek: true, membersLoaded: false, numUnreadMessages: 0, - searching: false, guestsCanJoin: false, canPeek: false, showApps: false, diff --git a/test/components/views/rooms/RoomHeader-test.tsx b/test/components/views/rooms/RoomHeader-test.tsx index 9cff224f48..889dcc255c 100644 --- a/test/components/views/rooms/RoomHeader-test.tsx +++ b/test/components/views/rooms/RoomHeader-test.tsx @@ -9,7 +9,6 @@ import DMRoomMap from '../../../../src/utils/DMRoomMap'; import RoomHeader from '../../../../src/components/views/rooms/RoomHeader'; import { SearchScope } from '../../../../src/components/views/rooms/SearchBar'; import { E2EStatus } from '../../../../src/utils/ShieldUtils'; -import { PlaceCallType } from '../../../../src/CallHandler'; import { mkEvent } from '../../../test-utils'; import { IRoomState } from "../../../../src/components/structures/RoomView"; import RoomContext from '../../../../src/contexts/RoomContext'; @@ -173,13 +172,13 @@ function createRoom(info: IRoomCreationInfo) { function render(room: Room, roomContext?: Partial): ReactWrapper { return mount(( - + {}} onForgetClick={() => {}} - onCallPlaced={(_type: PlaceCallType) => {}} + onCallPlaced={(_type) => { }} onAppsClick={() => {}} e2eStatus={E2EStatus.Normal} appsShown={true} diff --git a/test/components/views/rooms/SearchResultTile-test.tsx b/test/components/views/rooms/SearchResultTile-test.tsx index 159948afd6..b87934315f 100644 --- a/test/components/views/rooms/SearchResultTile-test.tsx +++ b/test/components/views/rooms/SearchResultTile-test.tsx @@ -81,6 +81,7 @@ describe("SearchResultTile", () => { const tiles = wrapper.find(EventTile); expect(tiles.length).toEqual(2); expect(tiles.at(0).prop("mxEvent").getId()).toBe("$1:server"); + // @ts-ignore accessing private property expect(tiles.at(0).prop("callEventGrouper").events.size).toBe(2); expect(tiles.at(1).prop("mxEvent").getId()).toBe("$144429830826TWwbB:localhost"); }); diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts index 1bdb8a5ec1..b7b39d15ce 100644 --- a/test/test-utils/test-utils.ts +++ b/test/test-utils/test-utils.ts @@ -133,7 +133,9 @@ export function createTestClient(): MatrixClient { setPusher: jest.fn().mockResolvedValue(undefined), setPushRuleEnabled: jest.fn().mockResolvedValue(undefined), setPushRuleActions: jest.fn().mockResolvedValue(undefined), + relations: jest.fn().mockRejectedValue(undefined), isCryptoEnabled: jest.fn().mockReturnValue(false), + fetchRoomEvent: jest.fn(), } as unknown as MatrixClient; } diff --git a/tsconfig.json b/tsconfig.json index bbfbf020ed..2a99f50796 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,7 +21,7 @@ }, "include": [ "./src/**/*.ts", - "./src/**/*.tsx" , + "./src/**/*.tsx", "./test/test-utils/**/*.ts", "./test/test-utils/**/*.tsx", "./test/utils/**/*.ts", @@ -32,7 +32,10 @@ "./test/components/structures/**/*.tsx", "./test/components/views/context_menus/**/*.ts", "./test/components/views/context_menus/**/*.tsx", - "./test/components/views/rooms/SendMessageComposer-test.tsx" , + "./test/components/views/rooms/**/*.tsx", + "./test/components/views/rooms/**/*.ts", + "./test/components/views/right_panel/**/*.tsx", + "./test/components/views/right_panel/**/*.ts", ], "exclude": [ "./test/end-to-end-tests/"