Merge remote-tracking branch 'upstream/develop' into fix/ringing-sound/15591

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
This commit is contained in:
Šimon Brandner 2021-08-04 16:30:03 +02:00
commit 881cac0d21
No known key found for this signature in database
GPG key ID: CC823428E9B582FB
94 changed files with 3022 additions and 1131 deletions

View file

@ -156,13 +156,14 @@ describe('CallHandler', () => {
DMRoomMap.setShared(null);
// @ts-ignore
window.mxCallHandler = null;
fakeCall = null;
MatrixClientPeg.unset();
document.body.removeChild(audioElement);
SdkConfig.unset();
});
it('should look up the correct user and open the room when a phone number is dialled', async () => {
it('should look up the correct user and start a call in the room when a phone number is dialled', async () => {
MatrixClientPeg.get().getThirdpartyUser = jest.fn().mockResolvedValue([{
userid: '@user2:example.org',
protocol: "im.vector.protocol.sip_native",
@ -179,6 +180,9 @@ describe('CallHandler', () => {
const viewRoomPayload = await untilDispatch('view_room');
expect(viewRoomPayload.room_id).toEqual(MAPPED_ROOM_ID);
// Check that a call was started
expect(fakeCall.roomId).toEqual(MAPPED_ROOM_ID);
});
it('should move calls between rooms when remote asserted identity changes', async () => {

View file

@ -0,0 +1,232 @@
/*
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 {
Anonymity,
getRedactedCurrentLocation,
IAnonymousEvent,
IPseudonymousEvent,
IRoomEvent,
PosthogAnalytics,
} from '../src/PosthogAnalytics';
import SdkConfig from '../src/SdkConfig';
class FakePosthog {
public capture;
public init;
public identify;
public reset;
public register;
constructor() {
this.capture = jest.fn();
this.init = jest.fn();
this.identify = jest.fn();
this.reset = jest.fn();
this.register = jest.fn();
}
}
export interface ITestEvent extends IAnonymousEvent {
key: "jest_test_event";
properties: {
foo: string;
};
}
export interface ITestPseudonymousEvent extends IPseudonymousEvent {
key: "jest_test_pseudo_event";
properties: {
foo: string;
};
}
export interface ITestRoomEvent extends IRoomEvent {
key: "jest_test_room_event";
properties: {
foo: string;
};
}
describe("PosthogAnalytics", () => {
let fakePosthog: FakePosthog;
const shaHashes = {
"42": "73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049",
"some": "a6b46dd0d1ae5e86cbc8f37e75ceeb6760230c1ca4ffbcb0c97b96dd7d9c464b",
"pii": "bd75b3e080945674c0351f75e0db33d1e90986fa07b318ea7edf776f5eef38d4",
"foo": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae",
};
beforeEach(() => {
fakePosthog = new FakePosthog();
window.crypto = {
subtle: {
digest: async (_, encodedMessage) => {
const message = new TextDecoder().decode(encodedMessage);
const hexHash = shaHashes[message];
const bytes = [];
for (let c = 0; c < hexHash.length; c += 2) {
bytes.push(parseInt(hexHash.substr(c, 2), 16));
}
return bytes;
},
},
};
});
afterEach(() => {
window.crypto = null;
});
describe("Initialisation", () => {
it("Should not be enabled without config being set", () => {
jest.spyOn(SdkConfig, "get").mockReturnValue({});
const analytics = new PosthogAnalytics(fakePosthog);
expect(analytics.isEnabled()).toBe(false);
});
it("Should be enabled if config is set", () => {
jest.spyOn(SdkConfig, "get").mockReturnValue({
posthog: {
projectApiKey: "foo",
apiHost: "bar",
},
});
const analytics = new PosthogAnalytics(fakePosthog);
analytics.setAnonymity(Anonymity.Pseudonymous);
expect(analytics.isEnabled()).toBe(true);
});
});
describe("Tracking", () => {
let analytics: PosthogAnalytics;
beforeEach(() => {
jest.spyOn(SdkConfig, "get").mockReturnValue({
posthog: {
projectApiKey: "foo",
apiHost: "bar",
},
});
analytics = new PosthogAnalytics(fakePosthog);
});
it("Should pass trackAnonymousEvent() to posthog", async () => {
analytics.setAnonymity(Anonymity.Pseudonymous);
await analytics.trackAnonymousEvent<ITestEvent>("jest_test_event", {
foo: "bar",
});
expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_event");
expect(fakePosthog.capture.mock.calls[0][1]["foo"]).toEqual("bar");
});
it("Should pass trackRoomEvent to posthog", async () => {
analytics.setAnonymity(Anonymity.Pseudonymous);
const roomId = "42";
await analytics.trackRoomEvent<IRoomEvent>("jest_test_event", roomId, {
foo: "bar",
});
expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_event");
expect(fakePosthog.capture.mock.calls[0][1]["foo"]).toEqual("bar");
expect(fakePosthog.capture.mock.calls[0][1]["hashedRoomId"])
.toEqual("73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049");
});
it("Should pass trackPseudonymousEvent() to posthog", async () => {
analytics.setAnonymity(Anonymity.Pseudonymous);
await analytics.trackPseudonymousEvent<ITestEvent>("jest_test_pseudo_event", {
foo: "bar",
});
expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_pseudo_event");
expect(fakePosthog.capture.mock.calls[0][1]["foo"]).toEqual("bar");
});
it("Should not track pseudonymous messages if anonymous", async () => {
analytics.setAnonymity(Anonymity.Anonymous);
await analytics.trackPseudonymousEvent<ITestEvent>("jest_test_event", {
foo: "bar",
});
expect(fakePosthog.capture.mock.calls.length).toBe(0);
});
it("Should not track any events if disabled", async () => {
analytics.setAnonymity(Anonymity.Disabled);
await analytics.trackPseudonymousEvent<ITestEvent>("jest_test_event", {
foo: "bar",
});
await analytics.trackAnonymousEvent<ITestEvent>("jest_test_event", {
foo: "bar",
});
await analytics.trackRoomEvent<ITestRoomEvent>("room id", "foo", {
foo: "bar",
});
await analytics.trackPageView(200);
expect(fakePosthog.capture.mock.calls.length).toBe(0);
});
it("Should pseudonymise a location of a known screen", async () => {
const location = await getRedactedCurrentLocation(
"https://foo.bar", "#/register/some/pii", "/", Anonymity.Pseudonymous);
expect(location).toBe(
`https://foo.bar/#/register/\
a6b46dd0d1ae5e86cbc8f37e75ceeb6760230c1ca4ffbcb0c97b96dd7d9c464b/\
bd75b3e080945674c0351f75e0db33d1e90986fa07b318ea7edf776f5eef38d4`);
});
it("Should anonymise a location of a known screen", async () => {
const location = await getRedactedCurrentLocation(
"https://foo.bar", "#/register/some/pii", "/", Anonymity.Anonymous);
expect(location).toBe("https://foo.bar/#/register/<redacted>/<redacted>");
});
it("Should pseudonymise a location of an unknown screen", async () => {
const location = await getRedactedCurrentLocation(
"https://foo.bar", "#/not_a_screen_name/some/pii", "/", Anonymity.Pseudonymous);
expect(location).toBe(
`https://foo.bar/#/<redacted_screen_name>/\
a6b46dd0d1ae5e86cbc8f37e75ceeb6760230c1ca4ffbcb0c97b96dd7d9c464b/\
bd75b3e080945674c0351f75e0db33d1e90986fa07b318ea7edf776f5eef38d4`);
});
it("Should anonymise a location of an unknown screen", async () => {
const location = await getRedactedCurrentLocation(
"https://foo.bar", "#/not_a_screen_name/some/pii", "/", Anonymity.Anonymous);
expect(location).toBe("https://foo.bar/#/<redacted_screen_name>/<redacted>/<redacted>");
});
it("Should handle an empty hash", async () => {
const location = await getRedactedCurrentLocation(
"https://foo.bar", "", "/", Anonymity.Anonymous);
expect(location).toBe("https://foo.bar/");
});
it("Should identify the user to posthog if pseudonymous", async () => {
analytics.setAnonymity(Anonymity.Pseudonymous);
await analytics.identifyUser("foo");
expect(fakePosthog.identify.mock.calls[0][0])
.toBe("2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae");
});
it("Should not identify the user to posthog if anonymous", async () => {
analytics.setAnonymity(Anonymity.Anonymous);
await analytics.identifyUser("foo");
expect(fakePosthog.identify.mock.calls.length).toBe(0);
});
});
});

View file

@ -106,7 +106,7 @@ describe('MemberEventListSummary', function() {
const result = wrapper.props.children;
expect(result.props.children).toEqual([
<div className="event_tile" key="event0">Expanded membership</div>,
<div className="event_tile" key="event0">Expanded membership</div>,
]);
});
@ -129,8 +129,8 @@ describe('MemberEventListSummary', function() {
const result = wrapper.props.children;
expect(result.props.children).toEqual([
<div className="event_tile" key="event0">Expanded membership</div>,
<div className="event_tile" key="event1">Expanded membership</div>,
<div className="event_tile" key="event0">Expanded membership</div>,
<div className="event_tile" key="event1">Expanded membership</div>,
]);
});

View file

@ -56,7 +56,7 @@ describe("ContentRules", function() {
describe("parseContentRules", function() {
it("should handle there being no keyword rules", function() {
const rules = { 'global': { 'content': [
USERNAME_RULE,
USERNAME_RULE,
] } };
const parsed = ContentRules.parseContentRules(rules);
expect(parsed.rules).toEqual([]);

View file

@ -18,4 +18,3 @@ limitations under the License.
// SpaceStore reads the SettingsStore which needs the localStorage values set at init time.
localStorage.setItem("mx_labs_feature_feature_spaces", "true");
localStorage.setItem("mx_labs_feature_feature_spaces.all_rooms", "true");

View file

@ -16,41 +16,26 @@ limitations under the License.
import { EventEmitter } from "events";
import { EventType } from "matrix-js-sdk/src/@types/event";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import "./SpaceStore-setup"; // enable space lab
import "../skinned-sdk"; // Must be first for skinning to work
import SpaceStore, {
UPDATE_HOME_BEHAVIOUR,
UPDATE_INVITED_SPACES,
UPDATE_SELECTED_SPACE,
UPDATE_TOP_LEVEL_SPACES,
} from "../../src/stores/SpaceStore";
import { resetAsyncStoreWithClient, setupAsyncStoreWithClient } from "../utils/test-utils";
import { mkEvent, mkStubRoom, stubClient } from "../test-utils";
import { EnhancedMap } from "../../src/utils/maps";
import * as testUtils from "../utils/test-utils";
import { mkEvent, stubClient } from "../test-utils";
import DMRoomMap from "../../src/utils/DMRoomMap";
import { MatrixClientPeg } from "../../src/MatrixClientPeg";
import defaultDispatcher from "../../src/dispatcher/dispatcher";
import SettingsStore from "../../src/settings/SettingsStore";
import { SettingLevel } from "../../src/settings/SettingLevel";
jest.useFakeTimers();
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() || []);
};
};
const emitPromise = (e: EventEmitter, k: string | symbol) => new Promise(r => e.once(k, r));
const testUserId = "@test:user";
const getUserIdForRoomId = jest.fn();
@ -87,45 +72,30 @@ describe("SpaceStore", () => {
const client = MatrixClientPeg.get();
let rooms = [];
const mkRoom = (roomId: string) => {
const room = mkStubRoom(roomId, roomId, client);
room.currentState.getStateEvents.mockImplementation(mockStateEventImplementation([]));
rooms.push(room);
return room;
};
const mkSpace = (spaceId: string, children: string[] = []) => {
const space = mkRoom(spaceId);
space.isSpaceRoom.mockReturnValue(true);
space.currentState.getStateEvents.mockImplementation(mockStateEventImplementation(children.map(roomId =>
mkEvent({
event: true,
type: EventType.SpaceChild,
room: spaceId,
user: testUserId,
skey: roomId,
content: { via: [] },
ts: Date.now(),
}),
)));
return space;
};
const mkRoom = (roomId: string) => testUtils.mkRoom(client, roomId, rooms);
const mkSpace = (spaceId: string, children: string[] = []) => testUtils.mkSpace(client, spaceId, rooms, children);
const viewRoom = roomId => defaultDispatcher.dispatch({ action: "view_room", room_id: roomId }, true);
const run = async () => {
client.getRoom.mockImplementation(roomId => rooms.find(room => room.roomId === roomId));
await setupAsyncStoreWithClient(store, client);
await testUtils.setupAsyncStoreWithClient(store, client);
jest.runAllTimers();
};
const setShowAllRooms = async (value: boolean) => {
if (store.allRoomsInHome === value) return;
const emitProm = testUtils.emitPromise(store, UPDATE_HOME_BEHAVIOUR);
await SettingsStore.setValue("Spaces.allRoomsInHome", null, SettingLevel.DEVICE, value);
jest.runAllTimers(); // run async dispatch
await emitProm;
};
beforeEach(() => {
jest.runAllTimers();
jest.runAllTimers(); // run async dispatch
client.getVisibleRooms.mockReturnValue(rooms = []);
});
afterEach(async () => {
await resetAsyncStoreWithClient(store);
await testUtils.resetAsyncStoreWithClient(store);
});
describe("static hierarchy resolution tests", () => {
@ -387,10 +357,16 @@ describe("SpaceStore", () => {
expect(store.getSpaceFilteredRoomIds(null).has(invite2)).toBeTruthy();
});
it("home space does contain rooms/low priority even if they are also shown in a space", () => {
it("all rooms space does contain rooms/low priority even if they are also shown in a space", async () => {
await setShowAllRooms(true);
expect(store.getSpaceFilteredRoomIds(null).has(room1)).toBeTruthy();
});
it("home space doesn't contain rooms/low priority if they are also shown in a space", async () => {
await setShowAllRooms(false);
expect(store.getSpaceFilteredRoomIds(null).has(room1)).toBeFalsy();
});
it("space contains child rooms", () => {
const space = client.getRoom(space1);
expect(store.getSpaceFilteredRoomIds(space).has(fav1)).toBeTruthy();
@ -488,7 +464,7 @@ describe("SpaceStore", () => {
await run();
expect(store.spacePanelSpaces).toStrictEqual([]);
const space = mkSpace(space1);
const prom = emitPromise(store, UPDATE_TOP_LEVEL_SPACES);
const prom = testUtils.emitPromise(store, UPDATE_TOP_LEVEL_SPACES);
emitter.emit("Room", space);
await prom;
expect(store.spacePanelSpaces).toStrictEqual([space]);
@ -501,7 +477,7 @@ describe("SpaceStore", () => {
expect(store.spacePanelSpaces).toStrictEqual([space]);
space.getMyMembership.mockReturnValue("leave");
const prom = emitPromise(store, UPDATE_TOP_LEVEL_SPACES);
const prom = testUtils.emitPromise(store, UPDATE_TOP_LEVEL_SPACES);
emitter.emit("Room.myMembership", space, "leave", "join");
await prom;
expect(store.spacePanelSpaces).toStrictEqual([]);
@ -513,7 +489,7 @@ describe("SpaceStore", () => {
expect(store.invitedSpaces).toStrictEqual([]);
const space = mkSpace(space1);
space.getMyMembership.mockReturnValue("invite");
const prom = emitPromise(store, UPDATE_INVITED_SPACES);
const prom = testUtils.emitPromise(store, UPDATE_INVITED_SPACES);
emitter.emit("Room", space);
await prom;
expect(store.spacePanelSpaces).toStrictEqual([]);
@ -528,7 +504,7 @@ describe("SpaceStore", () => {
expect(store.spacePanelSpaces).toStrictEqual([]);
expect(store.invitedSpaces).toStrictEqual([space]);
space.getMyMembership.mockReturnValue("join");
const prom = emitPromise(store, UPDATE_TOP_LEVEL_SPACES);
const prom = testUtils.emitPromise(store, UPDATE_TOP_LEVEL_SPACES);
emitter.emit("Room.myMembership", space, "join", "invite");
await prom;
expect(store.spacePanelSpaces).toStrictEqual([space]);
@ -543,7 +519,7 @@ describe("SpaceStore", () => {
expect(store.spacePanelSpaces).toStrictEqual([]);
expect(store.invitedSpaces).toStrictEqual([space]);
space.getMyMembership.mockReturnValue("leave");
const prom = emitPromise(store, UPDATE_INVITED_SPACES);
const prom = testUtils.emitPromise(store, UPDATE_INVITED_SPACES);
emitter.emit("Room.myMembership", space, "leave", "invite");
await prom;
expect(store.spacePanelSpaces).toStrictEqual([]);
@ -563,7 +539,7 @@ describe("SpaceStore", () => {
const invite = mkRoom(invite1);
invite.getMyMembership.mockReturnValue("invite");
const prom = emitPromise(store, space1);
const prom = testUtils.emitPromise(store, space1);
emitter.emit("Room", space);
await prom;
@ -633,20 +609,30 @@ describe("SpaceStore", () => {
});
describe("context switching tests", () => {
const fn = jest.spyOn(defaultDispatcher, "dispatch");
let dispatcherRef;
let currentRoom = null;
beforeEach(async () => {
[room1, room2, orphan1].forEach(mkRoom);
mkSpace(space1, [room1, room2]);
mkSpace(space2, [room2]);
await run();
dispatcherRef = defaultDispatcher.register(payload => {
if (payload.action === "view_room" || payload.action === "view_home_page") {
currentRoom = payload.room_id || null;
}
});
});
afterEach(() => {
fn.mockClear();
localStorage.clear();
defaultDispatcher.unregister(dispatcherRef);
});
const getCurrentRoom = () => fn.mock.calls.reverse().find(([p]) => p.action === "view_room")?.[0].room_id;
const getCurrentRoom = () => {
jest.runAllTimers();
return currentRoom;
};
it("last viewed room in target space is the current viewed and in both spaces", async () => {
await store.setActiveSpace(client.getRoom(space1));
@ -683,6 +669,14 @@ describe("SpaceStore", () => {
expect(getCurrentRoom()).toBe(space2);
});
it("last viewed room is target space is no longer in that space", async () => {
await store.setActiveSpace(client.getRoom(space1));
viewRoom(room1);
localStorage.setItem(`mx_space_context_${space2}`, room1);
await store.setActiveSpace(client.getRoom(space2));
expect(getCurrentRoom()).toBe(space2); // Space home instead of room1
});
it("no last viewed room in target space", async () => {
await store.setActiveSpace(client.getRoom(space1));
viewRoom(room1);
@ -694,7 +688,7 @@ describe("SpaceStore", () => {
await store.setActiveSpace(client.getRoom(space1));
viewRoom(room1);
await store.setActiveSpace(null);
expect(fn.mock.calls[fn.mock.calls.length - 1][0]).toStrictEqual({ action: "view_home_page" });
expect(getCurrentRoom()).toBeNull(); // Home
});
});
@ -704,7 +698,8 @@ describe("SpaceStore", () => {
mkSpace(space1, [room1, room2, room3]);
mkSpace(space2, [room1, room2]);
client.getRoom(room2).currentState.getStateEvents.mockImplementation(mockStateEventImplementation([
const cliRoom2 = client.getRoom(room2);
cliRoom2.currentState.getStateEvents.mockImplementation(testUtils.mockStateEventImplementation([
mkEvent({
event: true,
type: EventType.SpaceParent,
@ -747,6 +742,7 @@ describe("SpaceStore", () => {
});
it("when switching rooms in the all rooms home space don't switch to related space", async () => {
await setShowAllRooms(true);
viewRoom(room2);
await store.setActiveSpace(null, false);
viewRoom(room1);

View file

@ -0,0 +1,186 @@
/*
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 "../SpaceStore-setup"; // enable space lab
import "../../skinned-sdk"; // Must be first for skinning to work
import { SpaceWatcher } from "../../../src/stores/room-list/SpaceWatcher";
import type { RoomListStoreClass } from "../../../src/stores/room-list/RoomListStore";
import SettingsStore from "../../../src/settings/SettingsStore";
import SpaceStore, { UPDATE_HOME_BEHAVIOUR } from "../../../src/stores/SpaceStore";
import { stubClient } from "../../test-utils";
import { SettingLevel } from "../../../src/settings/SettingLevel";
import { setupAsyncStoreWithClient } from "../../utils/test-utils";
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
import * as testUtils from "../../utils/test-utils";
import { SpaceFilterCondition } from "../../../src/stores/room-list/filters/SpaceFilterCondition";
let filter: SpaceFilterCondition = null;
const mockRoomListStore = {
addFilter: f => filter = f,
removeFilter: () => filter = null,
} as unknown as RoomListStoreClass;
const space1Id = "!space1:server";
const space2Id = "!space2:server";
describe("SpaceWatcher", () => {
stubClient();
const store = SpaceStore.instance;
const client = MatrixClientPeg.get();
let rooms = [];
const mkSpace = (spaceId: string, children: string[] = []) => testUtils.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);
};
let space1;
let space2;
beforeEach(async () => {
filter = null;
store.removeAllListeners();
await store.setActiveSpace(null);
client.getVisibleRooms.mockReturnValue(rooms = []);
space1 = mkSpace(space1Id);
space2 = mkSpace(space2Id);
client.getRoom.mockImplementation(roomId => rooms.find(room => room.roomId === roomId));
await setupAsyncStoreWithClient(store, client);
});
it("initialises sanely with home behaviour", async () => {
await setShowAllRooms(false);
new SpaceWatcher(mockRoomListStore);
expect(filter).toBeInstanceOf(SpaceFilterCondition);
});
it("initialises sanely with all behaviour", async () => {
await setShowAllRooms(true);
new SpaceWatcher(mockRoomListStore);
expect(filter).toBeNull();
});
it("sets space=null filter for all -> home transition", async () => {
await setShowAllRooms(true);
new SpaceWatcher(mockRoomListStore);
await setShowAllRooms(false);
expect(filter).toBeInstanceOf(SpaceFilterCondition);
expect(filter["space"]).toBeNull();
});
it("sets filter correctly for all -> space transition", async () => {
await setShowAllRooms(true);
new SpaceWatcher(mockRoomListStore);
await SpaceStore.instance.setActiveSpace(space1);
expect(filter).toBeInstanceOf(SpaceFilterCondition);
expect(filter["space"]).toBe(space1);
});
it("removes filter for home -> all transition", async () => {
await setShowAllRooms(false);
new SpaceWatcher(mockRoomListStore);
await setShowAllRooms(true);
expect(filter).toBeNull();
});
it("sets filter correctly for home -> space transition", async () => {
await setShowAllRooms(false);
new SpaceWatcher(mockRoomListStore);
await SpaceStore.instance.setActiveSpace(space1);
expect(filter).toBeInstanceOf(SpaceFilterCondition);
expect(filter["space"]).toBe(space1);
});
it("removes filter for space -> all transition", async () => {
await setShowAllRooms(true);
new SpaceWatcher(mockRoomListStore);
await SpaceStore.instance.setActiveSpace(space1);
expect(filter).toBeInstanceOf(SpaceFilterCondition);
expect(filter["space"]).toBe(space1);
await SpaceStore.instance.setActiveSpace(null);
expect(filter).toBeNull();
});
it("updates filter correctly for space -> home transition", async () => {
await setShowAllRooms(false);
await SpaceStore.instance.setActiveSpace(space1);
new SpaceWatcher(mockRoomListStore);
expect(filter).toBeInstanceOf(SpaceFilterCondition);
expect(filter["space"]).toBe(space1);
await SpaceStore.instance.setActiveSpace(null);
expect(filter).toBeInstanceOf(SpaceFilterCondition);
expect(filter["space"]).toBe(null);
});
it("updates filter correctly for space -> space transition", async () => {
await setShowAllRooms(false);
await SpaceStore.instance.setActiveSpace(space1);
new SpaceWatcher(mockRoomListStore);
expect(filter).toBeInstanceOf(SpaceFilterCondition);
expect(filter["space"]).toBe(space1);
await SpaceStore.instance.setActiveSpace(space2);
expect(filter).toBeInstanceOf(SpaceFilterCondition);
expect(filter["space"]).toBe(space2);
});
it("doesn't change filter when changing showAllRooms mode to true", async () => {
await setShowAllRooms(false);
await SpaceStore.instance.setActiveSpace(space1);
new SpaceWatcher(mockRoomListStore);
expect(filter).toBeInstanceOf(SpaceFilterCondition);
expect(filter["space"]).toBe(space1);
await setShowAllRooms(true);
expect(filter).toBeInstanceOf(SpaceFilterCondition);
expect(filter["space"]).toBe(space1);
});
it("doesn't change filter when changing showAllRooms mode to false", async () => {
await setShowAllRooms(true);
await SpaceStore.instance.setActiveSpace(space1);
new SpaceWatcher(mockRoomListStore);
expect(filter).toBeInstanceOf(SpaceFilterCondition);
expect(filter["space"]).toBe(space1);
await setShowAllRooms(false);
expect(filter).toBeInstanceOf(SpaceFilterCondition);
expect(filter["space"]).toBe(space1);
});
});

View file

@ -78,6 +78,7 @@ export function createTestClient() {
},
mxcUrlToHttp: (mxc) => 'http://this.is.a.url/',
setAccountData: jest.fn(),
setRoomAccountData: jest.fn(),
sendTyping: jest.fn().mockResolvedValue({}),
sendMessage: () => jest.fn().mockResolvedValue({}),
getSyncState: () => "SYNCING",
@ -130,8 +131,8 @@ export function mkEvent(opts) {
if (opts.skey) {
event.state_key = opts.skey;
} else if (["m.room.name", "m.room.topic", "m.room.create", "m.room.join_rules",
"m.room.power_levels", "m.room.topic", "m.room.history_visibility", "m.room.encryption",
"com.example.state"].indexOf(opts.type) !== -1) {
"m.room.power_levels", "m.room.topic", "m.room.history_visibility", "m.room.encryption",
"com.example.state"].indexOf(opts.type) !== -1) {
event.state_key = "";
}
return opts.event ? new MatrixEvent(event) : event;

View file

@ -49,7 +49,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() {
it.each(
[[true, true], [true, false],
[false, true], [false, false]],
[false, true], [false, false]],
)("2 unverified: returns 'normal', self-trust = %s, DM = %s", async (trusted, dm) => {
const client = mkClient(trusted);
const room = {
@ -62,7 +62,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() {
it.each(
[["verified", true, true], ["verified", true, false],
["verified", false, true], ["warning", false, false]],
["verified", false, true], ["warning", false, false]],
)("2 verified: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => {
const client = mkClient(trusted);
const room = {
@ -75,7 +75,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() {
it.each(
[["normal", true, true], ["normal", true, false],
["normal", false, true], ["warning", false, false]],
["normal", false, true], ["warning", false, false]],
)("2 mixed: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => {
const client = mkClient(trusted);
const room = {
@ -88,7 +88,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() {
it.each(
[["verified", true, true], ["verified", true, false],
["warning", false, true], ["warning", false, false]],
["warning", false, true], ["warning", false, false]],
)("0 others: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => {
const client = mkClient(trusted);
const room = {
@ -101,7 +101,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() {
it.each(
[["verified", true, true], ["verified", true, false],
["verified", false, true], ["verified", false, false]],
["verified", false, true], ["verified", false, false]],
)("1 verified: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => {
const client = mkClient(trusted);
const room = {
@ -114,7 +114,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() {
it.each(
[["normal", true, true], ["normal", true, false],
["normal", false, true], ["normal", false, false]],
["normal", false, true], ["normal", false, false]],
)("1 unverified: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => {
const client = mkClient(trusted);
const room = {

View file

@ -15,7 +15,13 @@ 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 { AsyncStoreWithClient } from "../../src/stores/AsyncStoreWithClient";
import { mkEvent, mkStubRoom } from "../test-utils";
import { EnhancedMap } from "../../src/utils/maps";
import { EventEmitter } from "events";
// 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.
@ -31,3 +37,48 @@ 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;
};
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));