convert test-utils to typescript (#7877)
* move js utils into directory Signed-off-by: Kerry Archibald <kerrya@element.io> * typescripterize js test-utils Signed-off-by: Kerry Archibald <kerrya@element.io> * move test utils to directory Signed-off-by: Kerry Archibald <kerrya@element.io> * move remaining mock functions to directory Signed-off-by: Kerry Archibald <kerrya@element.io> * update imports Signed-off-by: Kerry Archibald <kerrya@element.io> * missed copyright Signed-off-by: Kerry Archibald <kerrya@element.io> * type wait for update Signed-off-by: Kerry Archibald <kerrya@element.io>
This commit is contained in:
parent
93a9af7b3a
commit
5e76d988ca
13 changed files with 269 additions and 201 deletions
|
@ -28,7 +28,7 @@ import SettingsStore from "../../../src/settings/SettingsStore";
|
||||||
import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
|
import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
|
||||||
import RoomContext from "../../../src/contexts/RoomContext";
|
import RoomContext from "../../../src/contexts/RoomContext";
|
||||||
import DMRoomMap from "../../../src/utils/DMRoomMap";
|
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 TestUtils = require('react-dom/test-utils');
|
||||||
const expect = require('expect');
|
const expect = require('expect');
|
||||||
|
|
|
@ -23,7 +23,7 @@ import { act } from 'react-dom/test-utils';
|
||||||
import '../../../skinned-sdk';
|
import '../../../skinned-sdk';
|
||||||
import SpaceContextMenu from '../../../../src/components/views/context_menus/SpaceContextMenu';
|
import SpaceContextMenu from '../../../../src/components/views/context_menus/SpaceContextMenu';
|
||||||
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
||||||
import { findByTestId } from '../../../utils/test-utils';
|
import { findByTestId } from '../../../test-utils';
|
||||||
import {
|
import {
|
||||||
leaveSpace,
|
leaveSpace,
|
||||||
shouldShowSpaceSettings,
|
shouldShowSpaceSettings,
|
||||||
|
|
|
@ -21,7 +21,7 @@ import { act } from 'react-dom/test-utils';
|
||||||
import sdk from '../../../skinned-sdk';
|
import sdk from '../../../skinned-sdk';
|
||||||
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||||
import { stubClient } from '../../../test-utils';
|
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");
|
const AccessSecretStorageDialog = sdk.getComponent("dialogs.security.AccessSecretStorageDialog");
|
||||||
|
|
||||||
|
|
|
@ -28,11 +28,14 @@ import {
|
||||||
} from 'matrix-events-sdk';
|
} from 'matrix-events-sdk';
|
||||||
import { IContent, MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
import { IContent, MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||||
|
|
||||||
import * as TestUtils from "../../../test-utils";
|
import {
|
||||||
import { findById } from '../../../utils/test-utils';
|
wrapInMatrixClientContext,
|
||||||
|
findById,
|
||||||
|
stubClient,
|
||||||
|
} from '../../../test-utils';
|
||||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||||
import _PollCreateDialog from "../../../../src/components/views/elements/PollCreateDialog";
|
import _PollCreateDialog from "../../../../src/components/views/elements/PollCreateDialog";
|
||||||
const PollCreateDialog = TestUtils.wrapInMatrixClientContext(_PollCreateDialog);
|
const PollCreateDialog = wrapInMatrixClientContext(_PollCreateDialog);
|
||||||
|
|
||||||
// Fake date to give a predictable snapshot
|
// Fake date to give a predictable snapshot
|
||||||
const realDateNow = Date.now;
|
const realDateNow = Date.now;
|
||||||
|
@ -204,7 +207,7 @@ describe("PollCreateDialog", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("displays a spinner after submitting", () => {
|
it("displays a spinner after submitting", () => {
|
||||||
TestUtils.stubClient();
|
stubClient();
|
||||||
MatrixClientPeg.get().sendEvent = jest.fn(() => Promise.resolve());
|
MatrixClientPeg.get().sendEvent = jest.fn(() => Promise.resolve());
|
||||||
|
|
||||||
const dialog = mount(
|
const dialog = mount(
|
||||||
|
@ -220,7 +223,7 @@ describe("PollCreateDialog", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sends a poll create event when submitted", () => {
|
it("sends a poll create event when submitted", () => {
|
||||||
TestUtils.stubClient();
|
stubClient();
|
||||||
let sentEventContent: IContent = null;
|
let sentEventContent: IContent = null;
|
||||||
MatrixClientPeg.get().sendEvent = jest.fn(
|
MatrixClientPeg.get().sendEvent = jest.fn(
|
||||||
(
|
(
|
||||||
|
@ -272,7 +275,7 @@ describe("PollCreateDialog", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sends a poll edit event when editing", () => {
|
it("sends a poll edit event when editing", () => {
|
||||||
TestUtils.stubClient();
|
stubClient();
|
||||||
let sentEventContent: IContent = null;
|
let sentEventContent: IContent = null;
|
||||||
MatrixClientPeg.get().sendEvent = jest.fn(
|
MatrixClientPeg.get().sendEvent = jest.fn(
|
||||||
(
|
(
|
||||||
|
|
|
@ -24,7 +24,7 @@ import '../../../skinned-sdk';
|
||||||
import SpacePanel from '../../../../src/components/views/spaces/SpacePanel';
|
import SpacePanel from '../../../../src/components/views/spaces/SpacePanel';
|
||||||
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||||
import { SpaceKey } from '../../../../src/stores/spaces';
|
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 { shouldShowComponent } from '../../../../src/customisations/helpers/UIComponents';
|
||||||
import { UIComponent } from '../../../../src/settings/UIFeature';
|
import { UIComponent } from '../../../../src/settings/UIFeature';
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { GuestAccess, HistoryVisibility, JoinRule } from 'matrix-js-sdk/src/@typ
|
||||||
|
|
||||||
import _SpaceSettingsVisibilityTab from "../../../../src/components/views/spaces/SpaceSettingsVisibilityTab";
|
import _SpaceSettingsVisibilityTab from "../../../../src/components/views/spaces/SpaceSettingsVisibilityTab";
|
||||||
import { createTestClient, mkEvent, wrapInMatrixClientContext } from '../../../test-utils';
|
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';
|
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||||
|
|
||||||
const SpaceSettingsVisibilityTab = wrapInMatrixClientContext(_SpaceSettingsVisibilityTab);
|
const SpaceSettingsVisibilityTab = wrapInMatrixClientContext(_SpaceSettingsVisibilityTab);
|
||||||
|
|
|
@ -27,7 +27,7 @@ import {
|
||||||
UPDATE_SELECTED_SPACE,
|
UPDATE_SELECTED_SPACE,
|
||||||
UPDATE_TOP_LEVEL_SPACES,
|
UPDATE_TOP_LEVEL_SPACES,
|
||||||
} from "../../src/stores/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 { mkEvent, stubClient } from "../test-utils";
|
||||||
import DMRoomMap from "../../src/utils/DMRoomMap";
|
import DMRoomMap from "../../src/utils/DMRoomMap";
|
||||||
import { MatrixClientPeg } from "../../src/MatrixClientPeg";
|
import { MatrixClientPeg } from "../../src/MatrixClientPeg";
|
||||||
|
|
|
@ -22,8 +22,11 @@ import SpaceStore from "../../../src/stores/spaces/SpaceStore";
|
||||||
import { MetaSpace, UPDATE_HOME_BEHAVIOUR } from "../../../src/stores/spaces";
|
import { MetaSpace, UPDATE_HOME_BEHAVIOUR } from "../../../src/stores/spaces";
|
||||||
import { stubClient } from "../../test-utils";
|
import { stubClient } from "../../test-utils";
|
||||||
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
||||||
import * as testUtils from "../../utils/test-utils";
|
import {
|
||||||
import { setupAsyncStoreWithClient } from "../../utils/test-utils";
|
mkSpace,
|
||||||
|
emitPromise,
|
||||||
|
setupAsyncStoreWithClient,
|
||||||
|
} from "../../test-utils";
|
||||||
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
||||||
import { SpaceFilterCondition } from "../../../src/stores/room-list/filters/SpaceFilterCondition";
|
import { SpaceFilterCondition } from "../../../src/stores/room-list/filters/SpaceFilterCondition";
|
||||||
import DMRoomMap from "../../../src/utils/DMRoomMap";
|
import DMRoomMap from "../../../src/utils/DMRoomMap";
|
||||||
|
@ -49,12 +52,12 @@ describe("SpaceWatcher", () => {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
|
|
||||||
let rooms = [];
|
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) => {
|
const setShowAllRooms = async (value: boolean) => {
|
||||||
if (store.allRoomsInHome === value) return;
|
if (store.allRoomsInHome === value) return;
|
||||||
await SettingsStore.setValue("Spaces.allRoomsInHome", null, SettingLevel.DEVICE, value);
|
await SettingsStore.setValue("Spaces.allRoomsInHome", null, SettingLevel.DEVICE, value);
|
||||||
await testUtils.emitPromise(store, UPDATE_HOME_BEHAVIOUR);
|
await emitPromise(store, UPDATE_HOME_BEHAVIOUR);
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
@ -63,8 +66,8 @@ describe("SpaceWatcher", () => {
|
||||||
store.setActiveSpace(MetaSpace.Home);
|
store.setActiveSpace(MetaSpace.Home);
|
||||||
client.getVisibleRooms.mockReturnValue(rooms = []);
|
client.getVisibleRooms.mockReturnValue(rooms = []);
|
||||||
|
|
||||||
mkSpace(space1);
|
mkSpaceForRooms(space1);
|
||||||
mkSpace(space2);
|
mkSpaceForRooms(space2);
|
||||||
|
|
||||||
await SettingsStore.setValue("Spaces.enabledMetaSpaces", null, SettingLevel.DEVICE, {
|
await SettingsStore.setValue("Spaces.enabledMetaSpaces", null, SettingLevel.DEVICE, {
|
||||||
[MetaSpace.Home]: true,
|
[MetaSpace.Home]: true,
|
||||||
|
|
3
test/test-utils/index.ts
Normal file
3
test/test-utils/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export * from './test-utils';
|
||||||
|
export * from './wrappers';
|
||||||
|
export * from './utilities';
|
|
@ -1,13 +1,24 @@
|
||||||
import React from 'react';
|
|
||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
|
import { mocked } from 'jest-mock';
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import { JoinRule } from 'matrix-js-sdk/src/@types/partials';
|
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 { MatrixClientPeg as peg } from '../../src/MatrixClientPeg';
|
||||||
import dis from '../src/dispatcher/dispatcher';
|
import dis from '../../src/dispatcher/dispatcher';
|
||||||
import { makeType } from "../src/utils/TypeUtils";
|
import { makeType } from "../../src/utils/TypeUtils";
|
||||||
import { ValidatedServerConfig } from "../src/utils/AutoDiscoveryUtils";
|
import { ValidatedServerConfig } from "../../src/utils/AutoDiscoveryUtils";
|
||||||
import MatrixClientContext from "../src/contexts/MatrixClientContext";
|
import { EnhancedMap } from "../../src/utils/maps";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stub out the MatrixClient, and configure the MatrixClientPeg object to
|
* Stub out the MatrixClient, and configure the MatrixClientPeg object to
|
||||||
|
@ -26,7 +37,8 @@ export function stubClient() {
|
||||||
// so we do this for each method
|
// so we do this for each method
|
||||||
const methods = ['get', 'unset', 'replaceUsingCreds'];
|
const methods = ['get', 'unset', 'replaceUsingCreds'];
|
||||||
for (let i = 0; i < methods.length; i++) {
|
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
|
// MatrixClientPeg.get() is called a /lot/, so implement it with our own
|
||||||
// fast stub function rather than a sinon stub
|
// 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.
|
* Create an Event.
|
||||||
* @param {Object} opts Values for the event.
|
* @param {Object} opts Values for the event.
|
||||||
|
@ -133,11 +159,11 @@ export function createTestClient() {
|
||||||
* @param {unsigned=} opts.unsigned
|
* @param {unsigned=} opts.unsigned
|
||||||
* @return {Object} a JSON object representing this event.
|
* @return {Object} a JSON object representing this event.
|
||||||
*/
|
*/
|
||||||
export function mkEvent(opts) {
|
export function mkEvent(opts: MakeEventProps): MatrixEvent {
|
||||||
if (!opts.type || !opts.content) {
|
if (!opts.type || !opts.content) {
|
||||||
throw new Error("Missing .type or .content =>" + JSON.stringify(opts));
|
throw new Error("Missing .type or .content =>" + JSON.stringify(opts));
|
||||||
}
|
}
|
||||||
const event = {
|
const event: Partial<IEvent> = {
|
||||||
type: opts.type,
|
type: opts.type,
|
||||||
room_id: opts.room,
|
room_id: opts.room,
|
||||||
sender: opts.user,
|
sender: opts.user,
|
||||||
|
@ -156,7 +182,7 @@ export function mkEvent(opts) {
|
||||||
].indexOf(opts.type) !== -1) {
|
].indexOf(opts.type) !== -1) {
|
||||||
event.state_key = "";
|
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.
|
* @param {boolean} opts.event True to make a MatrixEvent.
|
||||||
* @return {Object|MatrixEvent} The event
|
* @return {Object|MatrixEvent} The event
|
||||||
*/
|
*/
|
||||||
export function mkMembership(opts) {
|
export function mkMembership(opts: MakeEventPassThruProps & {
|
||||||
opts.type = "m.room.member";
|
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) {
|
if (!opts.skey) {
|
||||||
opts.skey = opts.user;
|
event.skey = opts.user;
|
||||||
}
|
}
|
||||||
if (!opts.mship) {
|
if (!opts.mship) {
|
||||||
throw new Error("Missing .mship => " + JSON.stringify(opts));
|
throw new Error("Missing .mship => " + JSON.stringify(opts));
|
||||||
}
|
}
|
||||||
opts.content = {
|
|
||||||
membership: opts.mship,
|
|
||||||
};
|
|
||||||
if (opts.prevMship) {
|
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.name) { event.content.displayname = opts.name; }
|
||||||
if (opts.url) { opts.content.avatar_url = opts.url; }
|
if (opts.url) { event.content.avatar_url = opts.url; }
|
||||||
const e = mkEvent(opts);
|
const e = mkEvent(event);
|
||||||
if (opts.target) {
|
if (opts.target) {
|
||||||
e.target = 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.
|
* @param {string=} opts.msg Optional. The content.body for the event.
|
||||||
* @return {Object|MatrixEvent} The event
|
* @return {Object|MatrixEvent} The event
|
||||||
*/
|
*/
|
||||||
export function mkMessage(opts) {
|
export function mkMessage(opts: MakeEventPassThruProps & {
|
||||||
opts.type = "m.room.message";
|
room: Room["roomId"];
|
||||||
if (!opts.msg) {
|
msg?: string;
|
||||||
opts.msg = "Random->" + Math.random();
|
}): MatrixEvent {
|
||||||
}
|
|
||||||
if (!opts.room || !opts.user) {
|
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 = {
|
const message = opts.msg ?? "Random->" + Math.random();
|
||||||
msgtype: "m.text",
|
const event: MakeEventProps = {
|
||||||
body: opts.msg,
|
...opts,
|
||||||
|
type: "m.room.message",
|
||||||
|
content: {
|
||||||
|
msgtype: "m.text",
|
||||||
|
body: message,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
return mkEvent(opts);
|
|
||||||
|
return mkEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mkStubRoom(roomId = null, name, client) {
|
export function mkStubRoom(roomId = null, name: string, client: MatrixClient): Room {
|
||||||
const stubTimeline = { getEvents: () => [] };
|
const stubTimeline = { getEvents: () => [] } as unknown as EventTimeline;
|
||||||
return {
|
return {
|
||||||
roomId,
|
roomId,
|
||||||
getReceiptsForEvent: jest.fn().mockReturnValue([]),
|
getReceiptsForEvent: jest.fn().mockReturnValue([]),
|
||||||
|
@ -279,10 +322,10 @@ export function mkStubRoom(roomId = null, name, client) {
|
||||||
mayClientSendStateEvent: jest.fn().mockReturnValue(true),
|
mayClientSendStateEvent: jest.fn().mockReturnValue(true),
|
||||||
maySendStateEvent: jest.fn().mockReturnValue(true),
|
maySendStateEvent: jest.fn().mockReturnValue(true),
|
||||||
maySendEvent: jest.fn().mockReturnValue(true),
|
maySendEvent: jest.fn().mockReturnValue(true),
|
||||||
members: [],
|
members: {},
|
||||||
getJoinRule: jest.fn().mockReturnValue(JoinRule.Invite),
|
getJoinRule: jest.fn().mockReturnValue(JoinRule.Invite),
|
||||||
on: jest.fn(),
|
on: jest.fn(),
|
||||||
},
|
} as unknown as RoomState,
|
||||||
tags: {},
|
tags: {},
|
||||||
setBlacklistUnverifiedDevices: jest.fn(),
|
setBlacklistUnverifiedDevices: jest.fn(),
|
||||||
on: jest.fn(),
|
on: jest.fn(),
|
||||||
|
@ -300,7 +343,7 @@ export function mkStubRoom(roomId = null, name, client) {
|
||||||
timeline: [],
|
timeline: [],
|
||||||
getJoinRule: jest.fn().mockReturnValue("invite"),
|
getJoinRule: jest.fn().mockReturnValue("invite"),
|
||||||
client,
|
client,
|
||||||
};
|
} as unknown as Room;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mkServerConfig(hsUrl, isUrl) {
|
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
|
// Mock the dispatcher by gut-wrenching. Stores can only __emitChange whilst a
|
||||||
// dispatcher `_isDispatching` is true.
|
// dispatcher `_isDispatching` is true.
|
||||||
return (payload) => {
|
return (payload) => {
|
||||||
dis._isDispatching = true;
|
// these are private properties in flux dispatcher
|
||||||
dis._callbacks[store._dispatchToken](payload);
|
// fool ts
|
||||||
dis._isDispatching = false;
|
(dis as any)._isDispatching = true;
|
||||||
|
(dis as any)._callbacks[store._dispatchToken](payload);
|
||||||
|
(dis as any)._isDispatching = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function wrapInMatrixClientContext(WrappedComponent) {
|
// These methods make some use of some private methods on the AsyncStoreWithClient to simplify getting into a consistent
|
||||||
class Wrapper extends React.Component {
|
// ready state without needing to wire up a dispatcher and pretend to be a js-sdk client.
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this._matrixClient = peg.get();
|
export const setupAsyncStoreWithClient = async (store: AsyncStoreWithClient<any>, client: MatrixClient) => {
|
||||||
}
|
// @ts-ignore
|
||||||
|
store.readyStore.useUnitTestClient(client);
|
||||||
|
// @ts-ignore
|
||||||
|
await store.onReady();
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
export const resetAsyncStoreWithClient = async (store: AsyncStoreWithClient<any>) => {
|
||||||
return <MatrixClientContext.Provider value={this._matrixClient}>
|
// @ts-ignore
|
||||||
<WrappedComponent ref={this.props.wrappedRef} {...this.props} />
|
await store.onNotReady();
|
||||||
</MatrixClientContext.Provider>;
|
};
|
||||||
|
|
||||||
|
export const mockStateEventImplementation = (events: MatrixEvent[]): typeof RoomState['getStateEvents'] => {
|
||||||
|
const stateMap = new EnhancedMap<string, Map<string, MatrixEvent>>();
|
||||||
|
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() || []);
|
||||||
return Wrapper;
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export const mkRoom = (client: MatrixClient, roomId: string, rooms?: ReturnType<typeof mkStubRoom>[]) => {
|
||||||
|
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.
|
* Upserts given events into room.currentState
|
||||||
* @param {React.Component} inst an instance of a React component.
|
* @param room
|
||||||
* @param {number} updates Number of updates to wait for. (Defaults to 1.)
|
* @param events
|
||||||
* @returns {Promise} promise that resolves when componentDidUpdate is called on
|
|
||||||
* given component instance.
|
|
||||||
*/
|
*/
|
||||||
export function waitForUpdate(inst, updates = 1) {
|
export const upsertRoomStateEvents = (room: Room, events: MatrixEvent[]): void => {
|
||||||
return new Promise((resolve, reject) => {
|
const eventsMap = events.reduce((acc, event) => {
|
||||||
const cdu = inst.componentDidUpdate;
|
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<string, Map<string, MatrixEvent>>());
|
||||||
|
|
||||||
console.log(`Waiting for ${updates} update(s)`);
|
room.currentState.events = eventsMap;
|
||||||
|
};
|
||||||
|
|
||||||
inst.componentDidUpdate = (prevProps, prevState, snapshot) => {
|
export const mkSpace = (
|
||||||
updates--;
|
client: MatrixClient,
|
||||||
console.log(`Got update, ${updates} remaining`);
|
spaceId: string,
|
||||||
|
rooms?: ReturnType<typeof mkStubRoom>[],
|
||||||
if (updates == 0) {
|
children: string[] = [],
|
||||||
inst.componentDidUpdate = cdu;
|
) => {
|
||||||
resolve();
|
const space = mkRoom(client, spaceId, rooms);
|
||||||
}
|
mocked(space).isSpaceRoom.mockReturnValue(true);
|
||||||
|
mocked(space.currentState).getStateEvents.mockImplementation(mockStateEventImplementation(children.map(roomId =>
|
||||||
if (cdu) cdu(prevProps, prevState, snapshot);
|
mkEvent({
|
||||||
};
|
event: true,
|
||||||
});
|
type: EventType.SpaceChild,
|
||||||
}
|
room: spaceId,
|
||||||
|
user: "@user:server",
|
||||||
|
skey: roomId,
|
||||||
|
content: { via: [] },
|
||||||
|
ts: Date.now(),
|
||||||
|
}),
|
||||||
|
)));
|
||||||
|
return space;
|
||||||
|
};
|
53
test/test-utils/utilities.ts
Normal file
53
test/test-utils/utilities.ts
Normal file
|
@ -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<void> {
|
||||||
|
return new Promise<void>((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);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
39
test/test-utils/wrappers.tsx
Normal file
39
test/test-utils/wrappers.tsx
Normal file
|
@ -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 <MatrixClientContext.Provider value={this._matrixClient}>
|
||||||
|
<WrappedComponent ref={this.props.wrappedRef} {...this.props} />
|
||||||
|
</MatrixClientContext.Provider>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Wrapper;
|
||||||
|
}
|
|
@ -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<any>, client: MatrixClient) => {
|
|
||||||
// @ts-ignore
|
|
||||||
store.readyStore.useUnitTestClient(client);
|
|
||||||
// @ts-ignore
|
|
||||||
await store.onReady();
|
|
||||||
};
|
|
||||||
|
|
||||||
export const resetAsyncStoreWithClient = async (store: AsyncStoreWithClient<any>) => {
|
|
||||||
// @ts-ignore
|
|
||||||
await store.onNotReady();
|
|
||||||
};
|
|
||||||
|
|
||||||
export const mockStateEventImplementation = (events: MatrixEvent[]) => {
|
|
||||||
const stateMap = new EnhancedMap<string, Map<string, MatrixEvent>>();
|
|
||||||
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<typeof mkStubRoom>[]) => {
|
|
||||||
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<string, Map<string, MatrixEvent>>());
|
|
||||||
|
|
||||||
room.currentState.events = eventsMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const mkSpace = (
|
|
||||||
client: MatrixClient,
|
|
||||||
spaceId: string,
|
|
||||||
rooms?: ReturnType<typeof mkStubRoom>[],
|
|
||||||
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));
|
|
Loading…
Add table
Add a link
Reference in a new issue