From 5e76d988ca53afbe0cca9e8084b962a4bb51e2c1 Mon Sep 17 00:00:00 2001 From: Kerry Date: Wed, 23 Feb 2022 12:21:11 +0100 Subject: [PATCH] convert test-utils to typescript (#7877) * move js utils into directory Signed-off-by: Kerry Archibald * typescripterize js test-utils Signed-off-by: Kerry Archibald * move test utils to directory Signed-off-by: Kerry Archibald * move remaining mock functions to directory Signed-off-by: Kerry Archibald * update imports Signed-off-by: Kerry Archibald * missed copyright Signed-off-by: Kerry Archibald * type wait for update Signed-off-by: Kerry Archibald --- .../structures/MessagePanel-test.js | 2 +- .../context_menus/SpaceContextMenu-test.tsx | 2 +- .../dialogs/AccessSecretStorageDialog-test.js | 2 +- .../views/elements/PollCreateDialog-test.tsx | 15 +- .../views/spaces/SpacePanel-test.tsx | 2 +- .../SpaceSettingsVisibilityTab-test.tsx | 2 +- test/stores/SpaceStore-test.ts | 2 +- test/stores/room-list/SpaceWatcher-test.ts | 15 +- test/test-utils/index.ts | 3 + .../test-utils.ts} | 223 ++++++++++++------ test/test-utils/utilities.ts | 53 +++++ test/test-utils/wrappers.tsx | 39 +++ test/utils/test-utils.ts | 110 --------- 13 files changed, 269 insertions(+), 201 deletions(-) create mode 100644 test/test-utils/index.ts rename test/{test-utils.js => test-utils/test-utils.ts} (67%) create mode 100644 test/test-utils/utilities.ts create mode 100644 test/test-utils/wrappers.tsx delete mode 100644 test/utils/test-utils.ts diff --git a/test/components/structures/MessagePanel-test.js b/test/components/structures/MessagePanel-test.js index afa99f1da4..c0ca398ce1 100644 --- a/test/components/structures/MessagePanel-test.js +++ b/test/components/structures/MessagePanel-test.js @@ -28,7 +28,7 @@ import SettingsStore from "../../../src/settings/SettingsStore"; import MatrixClientContext from "../../../src/contexts/MatrixClientContext"; import RoomContext from "../../../src/contexts/RoomContext"; import DMRoomMap from "../../../src/utils/DMRoomMap"; -import { upsertRoomStateEvents } from '../../utils/test-utils'; +import { upsertRoomStateEvents } from '../../test-utils'; const TestUtils = require('react-dom/test-utils'); const expect = require('expect'); diff --git a/test/components/views/context_menus/SpaceContextMenu-test.tsx b/test/components/views/context_menus/SpaceContextMenu-test.tsx index d4c9f726b9..ff6def1902 100644 --- a/test/components/views/context_menus/SpaceContextMenu-test.tsx +++ b/test/components/views/context_menus/SpaceContextMenu-test.tsx @@ -23,7 +23,7 @@ import { act } from 'react-dom/test-utils'; import '../../../skinned-sdk'; import SpaceContextMenu from '../../../../src/components/views/context_menus/SpaceContextMenu'; import MatrixClientContext from '../../../../src/contexts/MatrixClientContext'; -import { findByTestId } from '../../../utils/test-utils'; +import { findByTestId } from '../../../test-utils'; import { leaveSpace, shouldShowSpaceSettings, diff --git a/test/components/views/dialogs/AccessSecretStorageDialog-test.js b/test/components/views/dialogs/AccessSecretStorageDialog-test.js index f6c2db3718..b429da4bc6 100644 --- a/test/components/views/dialogs/AccessSecretStorageDialog-test.js +++ b/test/components/views/dialogs/AccessSecretStorageDialog-test.js @@ -21,7 +21,7 @@ import { act } from 'react-dom/test-utils'; import sdk from '../../../skinned-sdk'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; import { stubClient } from '../../../test-utils'; -import { findById, flushPromises } from '../../../utils/test-utils'; +import { findById, flushPromises } from '../../../test-utils'; const AccessSecretStorageDialog = sdk.getComponent("dialogs.security.AccessSecretStorageDialog"); diff --git a/test/components/views/elements/PollCreateDialog-test.tsx b/test/components/views/elements/PollCreateDialog-test.tsx index 2c79225a84..7ac68ccf3b 100644 --- a/test/components/views/elements/PollCreateDialog-test.tsx +++ b/test/components/views/elements/PollCreateDialog-test.tsx @@ -28,11 +28,14 @@ import { } from 'matrix-events-sdk'; import { IContent, MatrixEvent } from 'matrix-js-sdk/src/models/event'; -import * as TestUtils from "../../../test-utils"; -import { findById } from '../../../utils/test-utils'; +import { + wrapInMatrixClientContext, + findById, + stubClient, +} from '../../../test-utils'; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import _PollCreateDialog from "../../../../src/components/views/elements/PollCreateDialog"; -const PollCreateDialog = TestUtils.wrapInMatrixClientContext(_PollCreateDialog); +const PollCreateDialog = wrapInMatrixClientContext(_PollCreateDialog); // Fake date to give a predictable snapshot const realDateNow = Date.now; @@ -204,7 +207,7 @@ describe("PollCreateDialog", () => { }); it("displays a spinner after submitting", () => { - TestUtils.stubClient(); + stubClient(); MatrixClientPeg.get().sendEvent = jest.fn(() => Promise.resolve()); const dialog = mount( @@ -220,7 +223,7 @@ describe("PollCreateDialog", () => { }); it("sends a poll create event when submitted", () => { - TestUtils.stubClient(); + stubClient(); let sentEventContent: IContent = null; MatrixClientPeg.get().sendEvent = jest.fn( ( @@ -272,7 +275,7 @@ describe("PollCreateDialog", () => { }); it("sends a poll edit event when editing", () => { - TestUtils.stubClient(); + stubClient(); let sentEventContent: IContent = null; MatrixClientPeg.get().sendEvent = jest.fn( ( diff --git a/test/components/views/spaces/SpacePanel-test.tsx b/test/components/views/spaces/SpacePanel-test.tsx index af7fcea8ff..d9226ae221 100644 --- a/test/components/views/spaces/SpacePanel-test.tsx +++ b/test/components/views/spaces/SpacePanel-test.tsx @@ -24,7 +24,7 @@ import '../../../skinned-sdk'; import SpacePanel from '../../../../src/components/views/spaces/SpacePanel'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; import { SpaceKey } from '../../../../src/stores/spaces'; -import { findByTestId } from '../../../utils/test-utils'; +import { findByTestId } from '../../../test-utils'; import { shouldShowComponent } from '../../../../src/customisations/helpers/UIComponents'; import { UIComponent } from '../../../../src/settings/UIFeature'; diff --git a/test/components/views/spaces/SpaceSettingsVisibilityTab-test.tsx b/test/components/views/spaces/SpaceSettingsVisibilityTab-test.tsx index d5157ecf7b..6c6bb3466a 100644 --- a/test/components/views/spaces/SpaceSettingsVisibilityTab-test.tsx +++ b/test/components/views/spaces/SpaceSettingsVisibilityTab-test.tsx @@ -11,7 +11,7 @@ import { GuestAccess, HistoryVisibility, JoinRule } from 'matrix-js-sdk/src/@typ import _SpaceSettingsVisibilityTab from "../../../../src/components/views/spaces/SpaceSettingsVisibilityTab"; import { createTestClient, mkEvent, wrapInMatrixClientContext } from '../../../test-utils'; -import { mkSpace, mockStateEventImplementation } from '../../../utils/test-utils'; +import { mkSpace, mockStateEventImplementation } from '../../../test-utils'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; const SpaceSettingsVisibilityTab = wrapInMatrixClientContext(_SpaceSettingsVisibilityTab); diff --git a/test/stores/SpaceStore-test.ts b/test/stores/SpaceStore-test.ts index d6c4fa8915..c6f834a896 100644 --- a/test/stores/SpaceStore-test.ts +++ b/test/stores/SpaceStore-test.ts @@ -27,7 +27,7 @@ import { UPDATE_SELECTED_SPACE, UPDATE_TOP_LEVEL_SPACES, } from "../../src/stores/spaces"; -import * as testUtils from "../utils/test-utils"; +import * as testUtils from "../test-utils"; import { mkEvent, stubClient } from "../test-utils"; import DMRoomMap from "../../src/utils/DMRoomMap"; import { MatrixClientPeg } from "../../src/MatrixClientPeg"; diff --git a/test/stores/room-list/SpaceWatcher-test.ts b/test/stores/room-list/SpaceWatcher-test.ts index 66570a8e81..74c58fc359 100644 --- a/test/stores/room-list/SpaceWatcher-test.ts +++ b/test/stores/room-list/SpaceWatcher-test.ts @@ -22,8 +22,11 @@ import SpaceStore from "../../../src/stores/spaces/SpaceStore"; import { MetaSpace, UPDATE_HOME_BEHAVIOUR } from "../../../src/stores/spaces"; import { stubClient } from "../../test-utils"; import { SettingLevel } from "../../../src/settings/SettingLevel"; -import * as testUtils from "../../utils/test-utils"; -import { setupAsyncStoreWithClient } from "../../utils/test-utils"; +import { + mkSpace, + emitPromise, + setupAsyncStoreWithClient, +} from "../../test-utils"; import { MatrixClientPeg } from "../../../src/MatrixClientPeg"; import { SpaceFilterCondition } from "../../../src/stores/room-list/filters/SpaceFilterCondition"; import DMRoomMap from "../../../src/utils/DMRoomMap"; @@ -49,12 +52,12 @@ describe("SpaceWatcher", () => { const client = MatrixClientPeg.get(); let rooms = []; - const mkSpace = (spaceId: string, children: string[] = []) => testUtils.mkSpace(client, spaceId, rooms, children); + const mkSpaceForRooms = (spaceId: string, children: string[] = []) => mkSpace(client, spaceId, rooms, children); const setShowAllRooms = async (value: boolean) => { if (store.allRoomsInHome === value) return; await SettingsStore.setValue("Spaces.allRoomsInHome", null, SettingLevel.DEVICE, value); - await testUtils.emitPromise(store, UPDATE_HOME_BEHAVIOUR); + await emitPromise(store, UPDATE_HOME_BEHAVIOUR); }; beforeEach(async () => { @@ -63,8 +66,8 @@ describe("SpaceWatcher", () => { store.setActiveSpace(MetaSpace.Home); client.getVisibleRooms.mockReturnValue(rooms = []); - mkSpace(space1); - mkSpace(space2); + mkSpaceForRooms(space1); + mkSpaceForRooms(space2); await SettingsStore.setValue("Spaces.enabledMetaSpaces", null, SettingLevel.DEVICE, { [MetaSpace.Home]: true, diff --git a/test/test-utils/index.ts b/test/test-utils/index.ts new file mode 100644 index 0000000000..68fc4c7414 --- /dev/null +++ b/test/test-utils/index.ts @@ -0,0 +1,3 @@ +export * from './test-utils'; +export * from './wrappers'; +export * from './utilities'; diff --git a/test/test-utils.js b/test/test-utils/test-utils.ts similarity index 67% rename from test/test-utils.js rename to test/test-utils/test-utils.ts index 46fc588967..66ca40e482 100644 --- a/test/test-utils.js +++ b/test/test-utils/test-utils.ts @@ -1,13 +1,24 @@ -import React from 'react'; import EventEmitter from "events"; +import { mocked } from 'jest-mock'; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { JoinRule } from 'matrix-js-sdk/src/@types/partials'; +import { + Room, + User, + IContent, + IEvent, + RoomMember, + MatrixClient, + EventTimeline, + RoomState, + EventType, +} from 'matrix-js-sdk'; -import { MatrixClientPeg as peg } from '../src/MatrixClientPeg'; -import dis from '../src/dispatcher/dispatcher'; -import { makeType } from "../src/utils/TypeUtils"; -import { ValidatedServerConfig } from "../src/utils/AutoDiscoveryUtils"; -import MatrixClientContext from "../src/contexts/MatrixClientContext"; +import { MatrixClientPeg as peg } from '../../src/MatrixClientPeg'; +import dis from '../../src/dispatcher/dispatcher'; +import { makeType } from "../../src/utils/TypeUtils"; +import { ValidatedServerConfig } from "../../src/utils/AutoDiscoveryUtils"; +import { EnhancedMap } from "../../src/utils/maps"; /** * Stub out the MatrixClient, and configure the MatrixClientPeg object to @@ -26,7 +37,8 @@ export function stubClient() { // so we do this for each method const methods = ['get', 'unset', 'replaceUsingCreds']; for (let i = 0; i < methods.length; i++) { - peg[methods[i]] = jest.spyOn(peg, methods[i]); + const methodName = methods[i]; + peg[methods[i]] = jest.spyOn(peg, methodName); } // MatrixClientPeg.get() is called a /lot/, so implement it with our own // fast stub function rather than a sinon stub @@ -120,6 +132,20 @@ export function createTestClient() { }; } +type MakeEventPassThruProps = { + user: User["userId"]; + event?: boolean; + ts?: number; + skey?: string; +}; +type MakeEventProps = MakeEventPassThruProps & { + type: string; + content: IContent; + room: Room["roomId"]; + // eslint-disable-next-line camelcase + prev_content?: IContent; +}; + /** * Create an Event. * @param {Object} opts Values for the event. @@ -133,11 +159,11 @@ export function createTestClient() { * @param {unsigned=} opts.unsigned * @return {Object} a JSON object representing this event. */ -export function mkEvent(opts) { +export function mkEvent(opts: MakeEventProps): MatrixEvent { if (!opts.type || !opts.content) { throw new Error("Missing .type or .content =>" + JSON.stringify(opts)); } - const event = { + const event: Partial = { type: opts.type, room_id: opts.room, sender: opts.user, @@ -156,7 +182,7 @@ export function mkEvent(opts) { ].indexOf(opts.type) !== -1) { event.state_key = ""; } - return opts.event ? new MatrixEvent(event) : event; + return opts.event ? new MatrixEvent(event) : event as unknown as MatrixEvent; } /** @@ -198,23 +224,35 @@ export function mkPresence(opts) { * @param {boolean} opts.event True to make a MatrixEvent. * @return {Object|MatrixEvent} The event */ -export function mkMembership(opts) { - opts.type = "m.room.member"; +export function mkMembership(opts: MakeEventPassThruProps & { + room: Room["roomId"]; + mship: string; + prevMship?: string; + name?: string; + url?: string; + skey?: string; + target?: RoomMember; +}): MatrixEvent { + const event: MakeEventProps = { + ...opts, + type: "m.room.member", + content: { + membership: opts.mship, + }, + }; if (!opts.skey) { - opts.skey = opts.user; + event.skey = opts.user; } if (!opts.mship) { throw new Error("Missing .mship => " + JSON.stringify(opts)); } - opts.content = { - membership: opts.mship, - }; + if (opts.prevMship) { - opts.prev_content = { membership: opts.prevMship }; + event.prev_content = { membership: opts.prevMship }; } - if (opts.name) { opts.content.displayname = opts.name; } - if (opts.url) { opts.content.avatar_url = opts.url; } - const e = mkEvent(opts); + if (opts.name) { event.content.displayname = opts.name; } + if (opts.url) { event.content.avatar_url = opts.url; } + const e = mkEvent(event); if (opts.target) { e.target = opts.target; } @@ -231,23 +269,28 @@ export function mkMembership(opts) { * @param {string=} opts.msg Optional. The content.body for the event. * @return {Object|MatrixEvent} The event */ -export function mkMessage(opts) { - opts.type = "m.room.message"; - if (!opts.msg) { - opts.msg = "Random->" + Math.random(); - } +export function mkMessage(opts: MakeEventPassThruProps & { + room: Room["roomId"]; + msg?: string; +}): MatrixEvent { if (!opts.room || !opts.user) { - throw new Error("Missing .room or .user from", opts); + throw new Error("Missing .room or .user from options"); } - opts.content = { - msgtype: "m.text", - body: opts.msg, + const message = opts.msg ?? "Random->" + Math.random(); + const event: MakeEventProps = { + ...opts, + type: "m.room.message", + content: { + msgtype: "m.text", + body: message, + }, }; - return mkEvent(opts); + + return mkEvent(event); } -export function mkStubRoom(roomId = null, name, client) { - const stubTimeline = { getEvents: () => [] }; +export function mkStubRoom(roomId = null, name: string, client: MatrixClient): Room { + const stubTimeline = { getEvents: () => [] } as unknown as EventTimeline; return { roomId, getReceiptsForEvent: jest.fn().mockReturnValue([]), @@ -279,10 +322,10 @@ export function mkStubRoom(roomId = null, name, client) { mayClientSendStateEvent: jest.fn().mockReturnValue(true), maySendStateEvent: jest.fn().mockReturnValue(true), maySendEvent: jest.fn().mockReturnValue(true), - members: [], + members: {}, getJoinRule: jest.fn().mockReturnValue(JoinRule.Invite), on: jest.fn(), - }, + } as unknown as RoomState, tags: {}, setBlacklistUnverifiedDevices: jest.fn(), on: jest.fn(), @@ -300,7 +343,7 @@ export function mkStubRoom(roomId = null, name, client) { timeline: [], getJoinRule: jest.fn().mockReturnValue("invite"), client, - }; + } as unknown as Room; } export function mkServerConfig(hsUrl, isUrl) { @@ -316,52 +359,86 @@ export function getDispatchForStore(store) { // Mock the dispatcher by gut-wrenching. Stores can only __emitChange whilst a // dispatcher `_isDispatching` is true. return (payload) => { - dis._isDispatching = true; - dis._callbacks[store._dispatchToken](payload); - dis._isDispatching = false; + // these are private properties in flux dispatcher + // fool ts + (dis as any)._isDispatching = true; + (dis as any)._callbacks[store._dispatchToken](payload); + (dis as any)._isDispatching = false; }; } -export function wrapInMatrixClientContext(WrappedComponent) { - class Wrapper extends React.Component { - constructor(props) { - super(props); +// These methods make some use of some private methods on the AsyncStoreWithClient to simplify getting into a consistent +// ready state without needing to wire up a dispatcher and pretend to be a js-sdk client. - this._matrixClient = peg.get(); - } +export const setupAsyncStoreWithClient = async (store: AsyncStoreWithClient, client: MatrixClient) => { + // @ts-ignore + store.readyStore.useUnitTestClient(client); + // @ts-ignore + await store.onReady(); +}; - render() { - return - - ; +export const resetAsyncStoreWithClient = async (store: AsyncStoreWithClient) => { + // @ts-ignore + await store.onNotReady(); +}; + +export const mockStateEventImplementation = (events: MatrixEvent[]): typeof RoomState['getStateEvents'] => { + const stateMap = new EnhancedMap>(); + events.forEach(event => { + stateMap.getOrCreate(event.getType(), new Map()).set(event.getStateKey(), event); + }); + + return (eventType: string, stateKey?: string) => { + if (stateKey || stateKey === "") { + return stateMap.get(eventType)?.get(stateKey) || null; } - } - return Wrapper; -} + return Array.from(stateMap.get(eventType)?.values() || []); + }; +}; + +export const mkRoom = (client: MatrixClient, roomId: string, rooms?: ReturnType[]) => { + const room = mkStubRoom(roomId, roomId, client); + mocked(room.currentState).getStateEvents.mockImplementation(mockStateEventImplementation([])); + rooms?.push(room); + return room; +}; /** - * Call fn before calling componentDidUpdate on a react component instance, inst. - * @param {React.Component} inst an instance of a React component. - * @param {number} updates Number of updates to wait for. (Defaults to 1.) - * @returns {Promise} promise that resolves when componentDidUpdate is called on - * given component instance. + * Upserts given events into room.currentState + * @param room + * @param events */ -export function waitForUpdate(inst, updates = 1) { - return new Promise((resolve, reject) => { - const cdu = inst.componentDidUpdate; +export const upsertRoomStateEvents = (room: Room, events: MatrixEvent[]): void => { + const eventsMap = events.reduce((acc, event) => { + const eventType = event.getType(); + if (!acc.has(eventType)) { + acc.set(eventType, new Map()); + } + acc.get(eventType).set(event.getStateKey(), event); + return acc; + }, room.currentState.events || new Map>()); - console.log(`Waiting for ${updates} update(s)`); + room.currentState.events = eventsMap; +}; - inst.componentDidUpdate = (prevProps, prevState, snapshot) => { - updates--; - console.log(`Got update, ${updates} remaining`); - - if (updates == 0) { - inst.componentDidUpdate = cdu; - resolve(); - } - - if (cdu) cdu(prevProps, prevState, snapshot); - }; - }); -} +export const mkSpace = ( + client: MatrixClient, + spaceId: string, + rooms?: ReturnType[], + children: string[] = [], +) => { + const space = mkRoom(client, spaceId, rooms); + mocked(space).isSpaceRoom.mockReturnValue(true); + mocked(space.currentState).getStateEvents.mockImplementation(mockStateEventImplementation(children.map(roomId => + mkEvent({ + event: true, + type: EventType.SpaceChild, + room: spaceId, + user: "@user:server", + skey: roomId, + content: { via: [] }, + ts: Date.now(), + }), + ))); + return space; +}; diff --git a/test/test-utils/utilities.ts b/test/test-utils/utilities.ts new file mode 100644 index 0000000000..9f7941e32a --- /dev/null +++ b/test/test-utils/utilities.ts @@ -0,0 +1,53 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { ReactWrapper } from "enzyme"; +import EventEmitter from "events"; + +export const emitPromise = (e: EventEmitter, k: string | symbol) => new Promise(r => e.once(k, r)); + +const findByAttr = (attr: string) => (component: ReactWrapper, value: string) => component.find(`[${attr}="${value}"]`); +export const findByTestId = findByAttr('data-test-id'); +export const findById = findByAttr('id'); + +export const flushPromises = async () => await new Promise(resolve => setTimeout(resolve)); + +/** + * Call fn before calling componentDidUpdate on a react component instance, inst. + * @param {React.Component} inst an instance of a React component. + * @param {number} updates Number of updates to wait for. (Defaults to 1.) + * @returns {Promise} promise that resolves when componentDidUpdate is called on + * given component instance. + */ +export function waitForUpdate(inst: React.Component, updates = 1): Promise { + return new Promise((resolve, reject) => { + const cdu = inst.componentDidUpdate; + + console.log(`Waiting for ${updates} update(s)`); + + inst.componentDidUpdate = (prevProps, prevState, snapshot) => { + updates--; + console.log(`Got update, ${updates} remaining`); + + if (updates == 0) { + inst.componentDidUpdate = cdu; + resolve(); + } + + if (cdu) cdu(prevProps, prevState, snapshot); + }; + }); +} diff --git a/test/test-utils/wrappers.tsx b/test/test-utils/wrappers.tsx new file mode 100644 index 0000000000..97b85a8eff --- /dev/null +++ b/test/test-utils/wrappers.tsx @@ -0,0 +1,39 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { RefCallback } from "react"; +import { MatrixClient } from "matrix-js-sdk"; + +import { MatrixClientPeg as peg } from '../../src/MatrixClientPeg'; +import MatrixClientContext from "../../src/contexts/MatrixClientContext"; + +export function wrapInMatrixClientContext(WrappedComponent) { + class Wrapper extends React.Component<{ wrappedRef?: RefCallback }> { + _matrixClient: MatrixClient; + constructor(props) { + super(props); + + this._matrixClient = peg.get(); + } + + render() { + return + + ; + } + } + return Wrapper; +} diff --git a/test/utils/test-utils.ts b/test/utils/test-utils.ts deleted file mode 100644 index 81c05cc6bb..0000000000 --- a/test/utils/test-utils.ts +++ /dev/null @@ -1,110 +0,0 @@ -/* -Copyright 2021 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import { MatrixClient } from "matrix-js-sdk/src/client"; -import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import { EventType } from "matrix-js-sdk/src/@types/event"; -import { EventEmitter } from "events"; -import { ReactWrapper } from "enzyme"; -import { Room } from "matrix-js-sdk"; - -import { AsyncStoreWithClient } from "../../src/stores/AsyncStoreWithClient"; -import { mkEvent, mkStubRoom } from "../test-utils"; -import { EnhancedMap } from "../../src/utils/maps"; - -// These methods make some use of some private methods on the AsyncStoreWithClient to simplify getting into a consistent -// ready state without needing to wire up a dispatcher and pretend to be a js-sdk client. - -export const setupAsyncStoreWithClient = async (store: AsyncStoreWithClient, client: MatrixClient) => { - // @ts-ignore - store.readyStore.useUnitTestClient(client); - // @ts-ignore - await store.onReady(); -}; - -export const resetAsyncStoreWithClient = async (store: AsyncStoreWithClient) => { - // @ts-ignore - await store.onNotReady(); -}; - -export const mockStateEventImplementation = (events: MatrixEvent[]) => { - const stateMap = new EnhancedMap>(); - events.forEach(event => { - stateMap.getOrCreate(event.getType(), new Map()).set(event.getStateKey(), event); - }); - - return (eventType: string, stateKey?: string) => { - if (stateKey || stateKey === "") { - return stateMap.get(eventType)?.get(stateKey) || null; - } - return Array.from(stateMap.get(eventType)?.values() || []); - }; -}; - -export const mkRoom = (client: MatrixClient, roomId: string, rooms?: ReturnType[]) => { - const room = mkStubRoom(roomId, roomId, client); - room.currentState.getStateEvents.mockImplementation(mockStateEventImplementation([])); - rooms?.push(room); - return room; -}; - -/** - * Upserts given events into room.currentState - * @param room - * @param events - */ -export const upsertRoomStateEvents = (room: Room, events: MatrixEvent[]): void => { - const eventsMap = events.reduce((acc, event) => { - const eventType = event.getType(); - if (!acc.has(eventType)) { - acc.set(eventType, new Map()); - } - acc.get(eventType).set(event.getStateKey(), event); - return acc; - }, room.currentState.events || new Map>()); - - room.currentState.events = eventsMap; -}; - -export const mkSpace = ( - client: MatrixClient, - spaceId: string, - rooms?: ReturnType[], - children: string[] = [], -) => { - const space = mkRoom(client, spaceId, rooms); - space.isSpaceRoom.mockReturnValue(true); - space.currentState.getStateEvents.mockImplementation(mockStateEventImplementation(children.map(roomId => - mkEvent({ - event: true, - type: EventType.SpaceChild, - room: spaceId, - user: "@user:server", - skey: roomId, - content: { via: [] }, - ts: Date.now(), - }), - ))); - return space; -}; - -export const emitPromise = (e: EventEmitter, k: string | symbol) => new Promise(r => e.once(k, r)); - -const findByAttr = (attr: string) => (component: ReactWrapper, value: string) => component.find(`[${attr}="${value}"]`); -export const findByTestId = findByAttr('data-test-id'); -export const findById = findByAttr('id'); - -export const flushPromises = async () => await new Promise(resolve => setTimeout(resolve));