1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-25 05:23:13 +03:00

Early implementation of MSC3089 (file trees)

MSC: https://github.com/matrix-org/matrix-doc/pull/3089
Includes part of MSC3088 (room subtyping): https://github.com/matrix-org/matrix-doc/pull/3088

The NamespacedValue stuff is borrowed from the Extensible Events implementation PR in the react-sdk as a useful thing to put here. When/if the MSCs become stable, we'd convert the values to enums and drop the constants (or keep them for migration purposes, but switch to stable). 

This flags the whole thing as unstable because it's highly subject to change.
This commit is contained in:
Travis Ralston
2021-06-04 18:34:37 -06:00
parent 4b8f47e2b4
commit 9084b4e7aa
8 changed files with 765 additions and 1 deletions

View File

@@ -1,6 +1,16 @@
import { logger } from "../../src/logger";
import { MatrixClient } from "../../src/client";
import { Filter } from "../../src/filter";
import {DEFAULT_TREE_POWER_LEVELS_TEMPLATE} from "../../src/models/MSC3089TreeSpace";
import {
EventType,
RoomCreateTypeField, RoomType,
UNSTABLE_MSC3088_ENABLED,
UNSTABLE_MSC3088_PURPOSE,
UNSTABLE_MSC3089_TREE_SUBTYPE
} from "../../src/@types/event";
import {MEGOLM_ALGORITHM} from "../../src/crypto/olmlib";
import {MatrixEvent} from "../../src/models/event";
jest.useFakeTimers();
@@ -171,6 +181,160 @@ describe("MatrixClient", function() {
});
});
it("should create (unstable) file trees", async () => {
const userId = "@test:example.org";
const roomId = "!room:example.org";
const roomName = "Test Tree";
const mockRoom = {};
const fn = jest.fn().mockImplementation((opts) => {
expect(opts).toMatchObject({
name: roomName,
preset: "private_chat",
power_level_content_override: {
...DEFAULT_TREE_POWER_LEVELS_TEMPLATE,
users: {
[userId]: 100,
},
},
creation_content: {
[RoomCreateTypeField]: RoomType.Space,
},
initial_state: [
{
// We use `unstable` to ensure that the code is actually using the right identifier
type: UNSTABLE_MSC3088_PURPOSE.unstable,
state_key: UNSTABLE_MSC3089_TREE_SUBTYPE.unstable,
content: {
[UNSTABLE_MSC3088_ENABLED.unstable]: true,
},
},
{
type: EventType.RoomEncryption,
state_key: "",
content: {
algorithm: MEGOLM_ALGORITHM,
},
},
],
});
return {room_id: roomId};
});
client.getUserId = () => userId;
client.createRoom = fn;
client.getRoom = (getRoomId) => {
expect(getRoomId).toEqual(roomId);
return mockRoom;
};
const tree = await client.unstableCreateFileTree(roomName);
expect(tree).toBeDefined();
expect(tree.roomId).toEqual(roomId);
expect(tree.room).toBe(mockRoom);
expect(fn.mock.calls.length).toBe(1);
});
it("should get (unstable) file trees with valid state", async () => {
const roomId = "!room:example.org";
const mockRoom = {
currentState: {
getStateEvents: (eventType, stateKey) => {
if (eventType === EventType.RoomCreate) {
expect(stateKey).toEqual("");
return new MatrixEvent({
content: {
[RoomCreateTypeField]: RoomType.Space,
},
});
} else if (eventType === UNSTABLE_MSC3088_PURPOSE.unstable) {
// We use `unstable` to ensure that the code is actually using the right identifier
expect(stateKey).toEqual(UNSTABLE_MSC3089_TREE_SUBTYPE.unstable);
return new MatrixEvent({
content: {
[UNSTABLE_MSC3088_ENABLED.unstable]: true,
},
});
} else {
throw new Error("Unexpected event type or state key");
}
},
},
};
client.getRoom = (getRoomId) => {
expect(getRoomId).toEqual(roomId);
return mockRoom;
};
const tree = client.unstableGetFileTreeSpace(roomId);
expect(tree).toBeDefined();
expect(tree.roomId).toEqual(roomId);
expect(tree.room).toBe(mockRoom);
});
it("should not get (unstable) file trees with invalid create contents", async () => {
const roomId = "!room:example.org";
const mockRoom = {
currentState: {
getStateEvents: (eventType, stateKey) => {
if (eventType === EventType.RoomCreate) {
expect(stateKey).toEqual("");
return new MatrixEvent({
content: {
[RoomCreateTypeField]: "org.example.not_space",
},
});
} else if (eventType === UNSTABLE_MSC3088_PURPOSE.unstable) {
// We use `unstable` to ensure that the code is actually using the right identifier
expect(stateKey).toEqual(UNSTABLE_MSC3089_TREE_SUBTYPE.unstable);
return new MatrixEvent({
content: {
[UNSTABLE_MSC3088_ENABLED.unstable]: true,
},
});
} else {
throw new Error("Unexpected event type or state key");
}
},
},
};
client.getRoom = (getRoomId) => {
expect(getRoomId).toEqual(roomId);
return mockRoom;
};
const tree = client.unstableGetFileTreeSpace(roomId);
expect(tree).toBeFalsy();
});
it("should not get (unstable) file trees with invalid purpose/subtype contents", async () => {
const roomId = "!room:example.org";
const mockRoom = {
currentState: {
getStateEvents: (eventType, stateKey) => {
if (eventType === EventType.RoomCreate) {
expect(stateKey).toEqual("");
return new MatrixEvent({
content: {
[RoomCreateTypeField]: RoomType.Space,
},
});
} else if (eventType === UNSTABLE_MSC3088_PURPOSE.unstable) {
expect(stateKey).toEqual(UNSTABLE_MSC3089_TREE_SUBTYPE.unstable);
return new MatrixEvent({
content: {
[UNSTABLE_MSC3088_ENABLED.unstable]: false,
},
});
} else {
throw new Error("Unexpected event type or state key");
}
},
},
};
client.getRoom = (getRoomId) => {
expect(getRoomId).toEqual(roomId);
return mockRoom;
};
const tree = client.unstableGetFileTreeSpace(roomId);
expect(tree).toBeFalsy();
});
it("should not POST /filter if a matching filter already exists", async function() {
httpLookups = [];
httpLookups.push(PUSH_RULES_RESPONSE);