You've already forked matrix-react-sdk
mirror of
https://github.com/matrix-org/matrix-react-sdk.git
synced 2025-07-31 13:44:28 +03:00
Apply prettier formatting
This commit is contained in:
@ -26,17 +26,17 @@ import { REPEATABLE_DATE } from "../test-utils";
|
||||
|
||||
describe("formatSeconds", () => {
|
||||
it("correctly formats time with hours", () => {
|
||||
expect(formatSeconds((60 * 60 * 3) + (60 * 31) + (55))).toBe("03:31:55");
|
||||
expect(formatSeconds((60 * 60 * 3) + (60 * 0) + (55))).toBe("03:00:55");
|
||||
expect(formatSeconds((60 * 60 * 3) + (60 * 31) + (0))).toBe("03:31:00");
|
||||
expect(formatSeconds(-((60 * 60 * 3) + (60 * 31) + (0)))).toBe("-03:31:00");
|
||||
expect(formatSeconds(60 * 60 * 3 + 60 * 31 + 55)).toBe("03:31:55");
|
||||
expect(formatSeconds(60 * 60 * 3 + 60 * 0 + 55)).toBe("03:00:55");
|
||||
expect(formatSeconds(60 * 60 * 3 + 60 * 31 + 0)).toBe("03:31:00");
|
||||
expect(formatSeconds(-(60 * 60 * 3 + 60 * 31 + 0))).toBe("-03:31:00");
|
||||
});
|
||||
|
||||
it("correctly formats time without hours", () => {
|
||||
expect(formatSeconds((60 * 60 * 0) + (60 * 31) + (55))).toBe("31:55");
|
||||
expect(formatSeconds((60 * 60 * 0) + (60 * 0) + (55))).toBe("00:55");
|
||||
expect(formatSeconds((60 * 60 * 0) + (60 * 31) + (0))).toBe("31:00");
|
||||
expect(formatSeconds(-((60 * 60 * 0) + (60 * 31) + (0)))).toBe("-31:00");
|
||||
expect(formatSeconds(60 * 60 * 0 + 60 * 31 + 55)).toBe("31:55");
|
||||
expect(formatSeconds(60 * 60 * 0 + 60 * 0 + 55)).toBe("00:55");
|
||||
expect(formatSeconds(60 * 60 * 0 + 60 * 31 + 0)).toBe("31:00");
|
||||
expect(formatSeconds(-(60 * 60 * 0 + 60 * 31 + 0))).toBe("-31:00");
|
||||
});
|
||||
});
|
||||
|
||||
@ -44,7 +44,7 @@ describe("formatRelativeTime", () => {
|
||||
let dateSpy;
|
||||
beforeAll(() => {
|
||||
dateSpy = jest
|
||||
.spyOn(global.Date, 'now')
|
||||
.spyOn(global.Date, "now")
|
||||
// Tuesday, 2 November 2021 11:18:03 UTC
|
||||
.mockImplementation(() => 1635851883000);
|
||||
});
|
||||
@ -81,24 +81,24 @@ describe("formatRelativeTime", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatDuration()', () => {
|
||||
describe("formatDuration()", () => {
|
||||
type TestCase = [string, string, number];
|
||||
|
||||
const MINUTE_MS = 60000;
|
||||
const HOUR_MS = MINUTE_MS * 60;
|
||||
|
||||
it.each<TestCase>([
|
||||
['rounds up to nearest day when more than 24h - 40 hours', '2d', 40 * HOUR_MS],
|
||||
['rounds down to nearest day when more than 24h - 26 hours', '1d', 26 * HOUR_MS],
|
||||
['24 hours', '1d', 24 * HOUR_MS],
|
||||
['rounds to nearest hour when less than 24h - 23h', '23h', 23 * HOUR_MS],
|
||||
['rounds to nearest hour when less than 24h - 6h and 10min', '6h', 6 * HOUR_MS + 10 * MINUTE_MS],
|
||||
['rounds to nearest hours when less than 24h', '2h', 2 * HOUR_MS + 124234],
|
||||
['rounds to nearest minute when less than 1h - 59 minutes', '59m', 59 * MINUTE_MS],
|
||||
['rounds to nearest minute when less than 1h - 1 minute', '1m', MINUTE_MS],
|
||||
['rounds to nearest second when less than 1min - 59 seconds', '59s', 59000],
|
||||
['rounds to 0 seconds when less than a second - 123ms', '0s', 123],
|
||||
])('%s formats to %s', (_description, expectedResult, input) => {
|
||||
["rounds up to nearest day when more than 24h - 40 hours", "2d", 40 * HOUR_MS],
|
||||
["rounds down to nearest day when more than 24h - 26 hours", "1d", 26 * HOUR_MS],
|
||||
["24 hours", "1d", 24 * HOUR_MS],
|
||||
["rounds to nearest hour when less than 24h - 23h", "23h", 23 * HOUR_MS],
|
||||
["rounds to nearest hour when less than 24h - 6h and 10min", "6h", 6 * HOUR_MS + 10 * MINUTE_MS],
|
||||
["rounds to nearest hours when less than 24h", "2h", 2 * HOUR_MS + 124234],
|
||||
["rounds to nearest minute when less than 1h - 59 minutes", "59m", 59 * MINUTE_MS],
|
||||
["rounds to nearest minute when less than 1h - 1 minute", "1m", MINUTE_MS],
|
||||
["rounds to nearest second when less than 1min - 59 seconds", "59s", 59000],
|
||||
["rounds to 0 seconds when less than a second - 123ms", "0s", 123],
|
||||
])("%s formats to %s", (_description, expectedResult, input) => {
|
||||
expect(formatDuration(input)).toEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
@ -109,12 +109,12 @@ describe("formatPreciseDuration", () => {
|
||||
const DAY_MS = HOUR_MS * 24;
|
||||
|
||||
it.each<[string, string, number]>([
|
||||
['3 days, 6 hours, 48 minutes, 59 seconds', '3d 6h 48m 59s', 3 * DAY_MS + 6 * HOUR_MS + 48 * MINUTE_MS + 59000],
|
||||
['6 hours, 48 minutes, 59 seconds', '6h 48m 59s', 6 * HOUR_MS + 48 * MINUTE_MS + 59000],
|
||||
['48 minutes, 59 seconds', '48m 59s', 48 * MINUTE_MS + 59000],
|
||||
['59 seconds', '59s', 59000],
|
||||
['0 seconds', '0s', 0],
|
||||
])('%s formats to %s', (_description, expectedResult, input) => {
|
||||
["3 days, 6 hours, 48 minutes, 59 seconds", "3d 6h 48m 59s", 3 * DAY_MS + 6 * HOUR_MS + 48 * MINUTE_MS + 59000],
|
||||
["6 hours, 48 minutes, 59 seconds", "6h 48m 59s", 6 * HOUR_MS + 48 * MINUTE_MS + 59000],
|
||||
["48 minutes, 59 seconds", "48m 59s", 48 * MINUTE_MS + 59000],
|
||||
["59 seconds", "59s", 59000],
|
||||
["0 seconds", "0s", 0],
|
||||
])("%s formats to %s", (_description, expectedResult, input) => {
|
||||
expect(formatPreciseDuration(input)).toEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
|
@ -41,9 +41,9 @@ import {
|
||||
} from "../../src/utils/EventUtils";
|
||||
import { getMockClientWithEventEmitter, makeBeaconInfoEvent, makePollStartEvent, stubClient } from "../test-utils";
|
||||
|
||||
describe('EventUtils', () => {
|
||||
const userId = '@user:server';
|
||||
const roomId = '!room:server';
|
||||
describe("EventUtils", () => {
|
||||
const userId = "@user:server";
|
||||
const roomId = "!room:server";
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getUserId: jest.fn().mockReturnValue(userId),
|
||||
});
|
||||
@ -52,7 +52,7 @@ describe('EventUtils', () => {
|
||||
mockClient.getUserId.mockClear().mockReturnValue(userId);
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.spyOn(MatrixClientPeg, 'get').mockRestore();
|
||||
jest.spyOn(MatrixClientPeg, "get").mockRestore();
|
||||
});
|
||||
|
||||
// setup events
|
||||
@ -70,7 +70,7 @@ describe('EventUtils', () => {
|
||||
|
||||
const stateEvent = new MatrixEvent({
|
||||
type: EventType.RoomTopic,
|
||||
state_key: '',
|
||||
state_key: "",
|
||||
});
|
||||
const beaconInfoEvent = makeBeaconInfoEvent(userId, roomId);
|
||||
|
||||
@ -84,13 +84,13 @@ describe('EventUtils', () => {
|
||||
sender: userId,
|
||||
});
|
||||
|
||||
const pollStartEvent = makePollStartEvent('What?', userId);
|
||||
const pollStartEvent = makePollStartEvent("What?", userId);
|
||||
|
||||
const notDecryptedEvent = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
sender: userId,
|
||||
content: {
|
||||
msgtype: 'm.bad.encrypted',
|
||||
msgtype: "m.bad.encrypted",
|
||||
},
|
||||
});
|
||||
|
||||
@ -115,7 +115,7 @@ describe('EventUtils', () => {
|
||||
sender: userId,
|
||||
content: {
|
||||
msgtype: MsgType.Text,
|
||||
body: '',
|
||||
body: "",
|
||||
},
|
||||
});
|
||||
|
||||
@ -133,54 +133,54 @@ describe('EventUtils', () => {
|
||||
sender: userId,
|
||||
content: {
|
||||
msgtype: MsgType.Text,
|
||||
body: 'Hello',
|
||||
body: "Hello",
|
||||
},
|
||||
});
|
||||
|
||||
const bobsTextMessage = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
sender: '@bob:server',
|
||||
sender: "@bob:server",
|
||||
content: {
|
||||
msgtype: MsgType.Text,
|
||||
body: 'Hello from Bob',
|
||||
body: "Hello from Bob",
|
||||
},
|
||||
});
|
||||
|
||||
describe('isContentActionable()', () => {
|
||||
describe("isContentActionable()", () => {
|
||||
type TestCase = [string, MatrixEvent];
|
||||
it.each<TestCase>([
|
||||
['unsent event', unsentEvent],
|
||||
['redacted event', redactedEvent],
|
||||
['state event', stateEvent],
|
||||
['undecrypted event', notDecryptedEvent],
|
||||
['room member event', roomMemberEvent],
|
||||
['event without msgtype', noMsgType],
|
||||
['event without content body property', noContentBody],
|
||||
])('returns false for %s', (_description, event) => {
|
||||
["unsent event", unsentEvent],
|
||||
["redacted event", redactedEvent],
|
||||
["state event", stateEvent],
|
||||
["undecrypted event", notDecryptedEvent],
|
||||
["room member event", roomMemberEvent],
|
||||
["event without msgtype", noMsgType],
|
||||
["event without content body property", noContentBody],
|
||||
])("returns false for %s", (_description, event) => {
|
||||
expect(isContentActionable(event)).toBe(false);
|
||||
});
|
||||
|
||||
it.each<TestCase>([
|
||||
['sticker event', stickerEvent],
|
||||
['poll start event', pollStartEvent],
|
||||
['event with empty content body', emptyContentBody],
|
||||
['event with a content body', niceTextMessage],
|
||||
['beacon_info event', beaconInfoEvent],
|
||||
])('returns true for %s', (_description, event) => {
|
||||
["sticker event", stickerEvent],
|
||||
["poll start event", pollStartEvent],
|
||||
["event with empty content body", emptyContentBody],
|
||||
["event with a content body", niceTextMessage],
|
||||
["beacon_info event", beaconInfoEvent],
|
||||
])("returns true for %s", (_description, event) => {
|
||||
expect(isContentActionable(event)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('editable content helpers', () => {
|
||||
describe("editable content helpers", () => {
|
||||
const replaceRelationEvent = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
sender: userId,
|
||||
content: {
|
||||
msgtype: MsgType.Text,
|
||||
body: 'Hello',
|
||||
['m.relates_to']: {
|
||||
body: "Hello",
|
||||
["m.relates_to"]: {
|
||||
rel_type: RelationType.Replace,
|
||||
event_id: '1',
|
||||
event_id: "1",
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -190,10 +190,10 @@ describe('EventUtils', () => {
|
||||
sender: userId,
|
||||
content: {
|
||||
msgtype: MsgType.Text,
|
||||
body: 'Hello',
|
||||
['m.relates_to']: {
|
||||
body: "Hello",
|
||||
["m.relates_to"]: {
|
||||
rel_type: RelationType.Reference,
|
||||
event_id: '1',
|
||||
event_id: "1",
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -203,79 +203,79 @@ describe('EventUtils', () => {
|
||||
sender: userId,
|
||||
content: {
|
||||
msgtype: MsgType.Emote,
|
||||
body: '🧪',
|
||||
body: "🧪",
|
||||
},
|
||||
});
|
||||
|
||||
type TestCase = [string, MatrixEvent];
|
||||
|
||||
const uneditableCases: TestCase[] = [
|
||||
['redacted event', redactedEvent],
|
||||
['state event', stateEvent],
|
||||
['event that is not room message', roomMemberEvent],
|
||||
['event without msgtype', noMsgType],
|
||||
['event without content body property', noContentBody],
|
||||
['event with empty content body property', emptyContentBody],
|
||||
['event with non-string body', objectContentBody],
|
||||
['event not sent by current user', bobsTextMessage],
|
||||
['event with a replace relation', replaceRelationEvent],
|
||||
["redacted event", redactedEvent],
|
||||
["state event", stateEvent],
|
||||
["event that is not room message", roomMemberEvent],
|
||||
["event without msgtype", noMsgType],
|
||||
["event without content body property", noContentBody],
|
||||
["event with empty content body property", emptyContentBody],
|
||||
["event with non-string body", objectContentBody],
|
||||
["event not sent by current user", bobsTextMessage],
|
||||
["event with a replace relation", replaceRelationEvent],
|
||||
];
|
||||
|
||||
const editableCases: TestCase[] = [
|
||||
['event with reference relation', referenceRelationEvent],
|
||||
['emote event', emoteEvent],
|
||||
['poll start event', pollStartEvent],
|
||||
['event with a content body', niceTextMessage],
|
||||
["event with reference relation", referenceRelationEvent],
|
||||
["emote event", emoteEvent],
|
||||
["poll start event", pollStartEvent],
|
||||
["event with a content body", niceTextMessage],
|
||||
];
|
||||
|
||||
describe('canEditContent()', () => {
|
||||
it.each<TestCase>(uneditableCases)('returns false for %s', (_description, event) => {
|
||||
describe("canEditContent()", () => {
|
||||
it.each<TestCase>(uneditableCases)("returns false for %s", (_description, event) => {
|
||||
expect(canEditContent(event)).toBe(false);
|
||||
});
|
||||
|
||||
it.each<TestCase>(editableCases)('returns true for %s', (_description, event) => {
|
||||
it.each<TestCase>(editableCases)("returns true for %s", (_description, event) => {
|
||||
expect(canEditContent(event)).toBe(true);
|
||||
});
|
||||
});
|
||||
describe('canEditOwnContent()', () => {
|
||||
it.each<TestCase>(uneditableCases)('returns false for %s', (_description, event) => {
|
||||
describe("canEditOwnContent()", () => {
|
||||
it.each<TestCase>(uneditableCases)("returns false for %s", (_description, event) => {
|
||||
expect(canEditOwnEvent(event)).toBe(false);
|
||||
});
|
||||
|
||||
it.each<TestCase>(editableCases)('returns true for %s', (_description, event) => {
|
||||
it.each<TestCase>(editableCases)("returns true for %s", (_description, event) => {
|
||||
expect(canEditOwnEvent(event)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isVoiceMessage()', () => {
|
||||
it('returns true for an event with msc2516.voice content', () => {
|
||||
describe("isVoiceMessage()", () => {
|
||||
it("returns true for an event with msc2516.voice content", () => {
|
||||
const event = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
content: {
|
||||
['org.matrix.msc2516.voice']: {},
|
||||
["org.matrix.msc2516.voice"]: {},
|
||||
},
|
||||
});
|
||||
|
||||
expect(isVoiceMessage(event)).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for an event with msc3245.voice content', () => {
|
||||
it("returns true for an event with msc3245.voice content", () => {
|
||||
const event = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
content: {
|
||||
['org.matrix.msc3245.voice']: {},
|
||||
["org.matrix.msc3245.voice"]: {},
|
||||
},
|
||||
});
|
||||
|
||||
expect(isVoiceMessage(event)).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false for an event with voice content', () => {
|
||||
it("returns false for an event with voice content", () => {
|
||||
const event = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
content: {
|
||||
body: 'hello',
|
||||
body: "hello",
|
||||
},
|
||||
});
|
||||
|
||||
@ -283,20 +283,20 @@ describe('EventUtils', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('isLocationEvent()', () => {
|
||||
it('returns true for an event with m.location stable type', () => {
|
||||
describe("isLocationEvent()", () => {
|
||||
it("returns true for an event with m.location stable type", () => {
|
||||
const event = new MatrixEvent({
|
||||
type: M_LOCATION.altName,
|
||||
});
|
||||
expect(isLocationEvent(event)).toBe(true);
|
||||
});
|
||||
it('returns true for an event with m.location unstable prefixed type', () => {
|
||||
it("returns true for an event with m.location unstable prefixed type", () => {
|
||||
const event = new MatrixEvent({
|
||||
type: M_LOCATION.name,
|
||||
});
|
||||
expect(isLocationEvent(event)).toBe(true);
|
||||
});
|
||||
it('returns true for a room message with stable m.location msgtype', () => {
|
||||
it("returns true for a room message with stable m.location msgtype", () => {
|
||||
const event = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
content: {
|
||||
@ -305,7 +305,7 @@ describe('EventUtils', () => {
|
||||
});
|
||||
expect(isLocationEvent(event)).toBe(true);
|
||||
});
|
||||
it('returns true for a room message with unstable m.location msgtype', () => {
|
||||
it("returns true for a room message with unstable m.location msgtype", () => {
|
||||
const event = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
content: {
|
||||
@ -314,32 +314,31 @@ describe('EventUtils', () => {
|
||||
});
|
||||
expect(isLocationEvent(event)).toBe(true);
|
||||
});
|
||||
it('returns false for a non location event', () => {
|
||||
it("returns false for a non location event", () => {
|
||||
const event = new MatrixEvent({
|
||||
type: EventType.RoomMessage,
|
||||
content: {
|
||||
body: 'Hello',
|
||||
body: "Hello",
|
||||
},
|
||||
});
|
||||
expect(isLocationEvent(event)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('canCancel()', () => {
|
||||
it.each([
|
||||
[EventStatus.QUEUED],
|
||||
[EventStatus.NOT_SENT],
|
||||
[EventStatus.ENCRYPTING],
|
||||
])('return true for status %s', (status) => {
|
||||
expect(canCancel(status)).toBe(true);
|
||||
});
|
||||
describe("canCancel()", () => {
|
||||
it.each([[EventStatus.QUEUED], [EventStatus.NOT_SENT], [EventStatus.ENCRYPTING]])(
|
||||
"return true for status %s",
|
||||
(status) => {
|
||||
expect(canCancel(status)).toBe(true);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
[EventStatus.SENDING],
|
||||
[EventStatus.CANCELLED],
|
||||
[EventStatus.SENT],
|
||||
['invalid-status' as unknown as EventStatus],
|
||||
])('return false for status %s', (status) => {
|
||||
["invalid-status" as unknown as EventStatus],
|
||||
])("return false for status %s", (status) => {
|
||||
expect(canCancel(status)).toBe(false);
|
||||
});
|
||||
});
|
||||
@ -358,16 +357,16 @@ describe('EventUtils', () => {
|
||||
event_id: NORMAL_EVENT,
|
||||
type: EventType.RoomMessage,
|
||||
content: {
|
||||
"body": "Classic event",
|
||||
"msgtype": MsgType.Text,
|
||||
body: "Classic event",
|
||||
msgtype: MsgType.Text,
|
||||
},
|
||||
},
|
||||
[THREAD_ROOT]: {
|
||||
event_id: THREAD_ROOT,
|
||||
type: EventType.RoomMessage,
|
||||
content: {
|
||||
"body": "Thread root",
|
||||
"msgtype": "m.text",
|
||||
body: "Thread root",
|
||||
msgtype: "m.text",
|
||||
},
|
||||
unsigned: {
|
||||
"m.relations": {
|
||||
@ -434,10 +433,12 @@ describe('EventUtils', () => {
|
||||
|
||||
describe("findEditableEvent", () => {
|
||||
it("should not explode when given empty events array", () => {
|
||||
expect(findEditableEvent({
|
||||
events: [],
|
||||
isForward: true,
|
||||
})).toBeUndefined();
|
||||
expect(
|
||||
findEditableEvent({
|
||||
events: [],
|
||||
isForward: true,
|
||||
}),
|
||||
).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -16,17 +16,17 @@ limitations under the License.
|
||||
|
||||
import { FixedRollingArray } from "../../src/utils/FixedRollingArray";
|
||||
|
||||
describe('FixedRollingArray', () => {
|
||||
it('should seed the array with the given value', () => {
|
||||
describe("FixedRollingArray", () => {
|
||||
it("should seed the array with the given value", () => {
|
||||
const seed = "test";
|
||||
const width = 24;
|
||||
const array = new FixedRollingArray(width, seed);
|
||||
|
||||
expect(array.value.length).toBe(width);
|
||||
expect(array.value.every(v => v === seed)).toBe(true);
|
||||
expect(array.value.every((v) => v === seed)).toBe(true);
|
||||
});
|
||||
|
||||
it('should insert at the correct end', () => {
|
||||
it("should insert at the correct end", () => {
|
||||
const seed = "test";
|
||||
const value = "changed";
|
||||
const width = 24;
|
||||
@ -37,7 +37,7 @@ describe('FixedRollingArray', () => {
|
||||
expect(array.value[0]).toBe(value);
|
||||
});
|
||||
|
||||
it('should roll over', () => {
|
||||
it("should roll over", () => {
|
||||
const seed = -1;
|
||||
const width = 24;
|
||||
const array = new FixedRollingArray(width, seed);
|
||||
|
@ -25,43 +25,43 @@ function getRandomValues<T extends ArrayBufferView>(buf: T): T {
|
||||
return nodeCrypto.randomFillSync(buf);
|
||||
}
|
||||
|
||||
const TEST_VECTORS=[
|
||||
const TEST_VECTORS = [
|
||||
[
|
||||
"plain",
|
||||
"password",
|
||||
"-----BEGIN MEGOLM SESSION DATA-----\n" +
|
||||
"AXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx\n" +
|
||||
"cissyYBxjsfsAndErh065A8=\n" +
|
||||
"-----END MEGOLM SESSION DATA-----",
|
||||
"AXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx\n" +
|
||||
"cissyYBxjsfsAndErh065A8=\n" +
|
||||
"-----END MEGOLM SESSION DATA-----",
|
||||
],
|
||||
[
|
||||
"Hello, World",
|
||||
"betterpassword",
|
||||
"-----BEGIN MEGOLM SESSION DATA-----\n" +
|
||||
"AW1vcmVzYWx0bW9yZXNhbHT//////////wAAAAAAAAAAAAAD6KyBpe1Niv5M5NPm4ZATsJo5nghk\n" +
|
||||
"KYu63a0YQ5DRhUWEKk7CcMkrKnAUiZny\n" +
|
||||
"-----END MEGOLM SESSION DATA-----",
|
||||
"AW1vcmVzYWx0bW9yZXNhbHT//////////wAAAAAAAAAAAAAD6KyBpe1Niv5M5NPm4ZATsJo5nghk\n" +
|
||||
"KYu63a0YQ5DRhUWEKk7CcMkrKnAUiZny\n" +
|
||||
"-----END MEGOLM SESSION DATA-----",
|
||||
],
|
||||
[
|
||||
"alphanumericallyalphanumericallyalphanumericallyalphanumerically",
|
||||
"SWORDFISH",
|
||||
"-----BEGIN MEGOLM SESSION DATA-----\n" +
|
||||
"AXllc3NhbHR5Z29vZG5lc3P//////////wAAAAAAAAAAAAAD6OIW+Je7gwvjd4kYrb+49gKCfExw\n" +
|
||||
"MgJBMD4mrhLkmgAngwR1pHjbWXaoGybtiAYr0moQ93GrBQsCzPbvl82rZhaXO3iH5uHo/RCEpOqp\n" +
|
||||
"Pgg29363BGR+/Ripq/VCLKGNbw==\n" +
|
||||
"-----END MEGOLM SESSION DATA-----",
|
||||
"AXllc3NhbHR5Z29vZG5lc3P//////////wAAAAAAAAAAAAAD6OIW+Je7gwvjd4kYrb+49gKCfExw\n" +
|
||||
"MgJBMD4mrhLkmgAngwR1pHjbWXaoGybtiAYr0moQ93GrBQsCzPbvl82rZhaXO3iH5uHo/RCEpOqp\n" +
|
||||
"Pgg29363BGR+/Ripq/VCLKGNbw==\n" +
|
||||
"-----END MEGOLM SESSION DATA-----",
|
||||
],
|
||||
[
|
||||
"alphanumericallyalphanumericallyalphanumericallyalphanumerically",
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpassword",
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpassword",
|
||||
"-----BEGIN MEGOLM SESSION DATA-----\n" +
|
||||
"Af//////////////////////////////////////////AAAD6IAZJy7IQ7Y0idqSw/bmpngEEVVh\n" +
|
||||
"gsH+8ptgqxw6ZVWQnohr8JsuwH9SwGtiebZuBu5smPCO+RFVWH2cQYslZijXv/BEH/txvhUrrtCd\n" +
|
||||
"bWnSXS9oymiqwUIGs08sXI33ZA==\n" +
|
||||
"-----END MEGOLM SESSION DATA-----",
|
||||
"Af//////////////////////////////////////////AAAD6IAZJy7IQ7Y0idqSw/bmpngEEVVh\n" +
|
||||
"gsH+8ptgqxw6ZVWQnohr8JsuwH9SwGtiebZuBu5smPCO+RFVWH2cQYslZijXv/BEH/txvhUrrtCd\n" +
|
||||
"bWnSXS9oymiqwUIGs08sXI33ZA==\n" +
|
||||
"-----END MEGOLM SESSION DATA-----",
|
||||
],
|
||||
];
|
||||
|
||||
@ -69,7 +69,7 @@ function stringToArray(s: string): ArrayBufferLike {
|
||||
return new TextEncoder().encode(s).buffer;
|
||||
}
|
||||
|
||||
describe('MegolmExportEncryption', function() {
|
||||
describe("MegolmExportEncryption", function () {
|
||||
let MegolmExportEncryption;
|
||||
|
||||
beforeEach(() => {
|
||||
@ -87,76 +87,78 @@ describe('MegolmExportEncryption', function() {
|
||||
window.crypto = undefined;
|
||||
});
|
||||
|
||||
describe('decrypt', function() {
|
||||
it('should handle missing header', function() {
|
||||
const input=stringToArray(`-----`);
|
||||
return MegolmExportEncryption.decryptMegolmKeyFile(input, '')
|
||||
.then((res) => {
|
||||
throw new Error('expected to throw');
|
||||
}, (error) => {
|
||||
expect(error.message).toEqual('Header line not found');
|
||||
});
|
||||
describe("decrypt", function () {
|
||||
it("should handle missing header", function () {
|
||||
const input = stringToArray(`-----`);
|
||||
return MegolmExportEncryption.decryptMegolmKeyFile(input, "").then(
|
||||
(res) => {
|
||||
throw new Error("expected to throw");
|
||||
},
|
||||
(error) => {
|
||||
expect(error.message).toEqual("Header line not found");
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle missing trailer', function() {
|
||||
const input=stringToArray(`-----BEGIN MEGOLM SESSION DATA-----
|
||||
it("should handle missing trailer", function () {
|
||||
const input = stringToArray(`-----BEGIN MEGOLM SESSION DATA-----
|
||||
-----`);
|
||||
return MegolmExportEncryption.decryptMegolmKeyFile(input, '')
|
||||
.then((res) => {
|
||||
throw new Error('expected to throw');
|
||||
}, (error) => {
|
||||
expect(error.message).toEqual('Trailer line not found');
|
||||
});
|
||||
return MegolmExportEncryption.decryptMegolmKeyFile(input, "").then(
|
||||
(res) => {
|
||||
throw new Error("expected to throw");
|
||||
},
|
||||
(error) => {
|
||||
expect(error.message).toEqual("Trailer line not found");
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle a too-short body', function() {
|
||||
const input=stringToArray(`-----BEGIN MEGOLM SESSION DATA-----
|
||||
it("should handle a too-short body", function () {
|
||||
const input = stringToArray(`-----BEGIN MEGOLM SESSION DATA-----
|
||||
AXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx
|
||||
cissyYBxjsfsAn
|
||||
-----END MEGOLM SESSION DATA-----
|
||||
`);
|
||||
return MegolmExportEncryption.decryptMegolmKeyFile(input, '')
|
||||
.then((res) => {
|
||||
throw new Error('expected to throw');
|
||||
}, (error) => {
|
||||
expect(error.message).toEqual('Invalid file: too short');
|
||||
});
|
||||
return MegolmExportEncryption.decryptMegolmKeyFile(input, "").then(
|
||||
(res) => {
|
||||
throw new Error("expected to throw");
|
||||
},
|
||||
(error) => {
|
||||
expect(error.message).toEqual("Invalid file: too short");
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
// TODO find a subtlecrypto shim which doesn't break this test
|
||||
it.skip('should decrypt a range of inputs', function() {
|
||||
it.skip("should decrypt a range of inputs", function () {
|
||||
function next(i) {
|
||||
if (i >= TEST_VECTORS.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [plain, password, input] = TEST_VECTORS[i];
|
||||
return MegolmExportEncryption.decryptMegolmKeyFile(
|
||||
stringToArray(input), password,
|
||||
).then((decrypted) => {
|
||||
return MegolmExportEncryption.decryptMegolmKeyFile(stringToArray(input), password).then((decrypted) => {
|
||||
expect(decrypted).toEqual(plain);
|
||||
return next(i+1);
|
||||
return next(i + 1);
|
||||
});
|
||||
}
|
||||
return next(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('encrypt', function() {
|
||||
it('should round-trip', function() {
|
||||
const input = 'words words many words in plain text here'.repeat(100);
|
||||
describe("encrypt", function () {
|
||||
it("should round-trip", function () {
|
||||
const input = "words words many words in plain text here".repeat(100);
|
||||
|
||||
const password = 'my super secret passphrase';
|
||||
const password = "my super secret passphrase";
|
||||
|
||||
return MegolmExportEncryption.encryptMegolmKeyFile(
|
||||
input, password, { kdf_rounds: 1000 },
|
||||
).then((ciphertext) => {
|
||||
return MegolmExportEncryption.decryptMegolmKeyFile(
|
||||
ciphertext, password,
|
||||
);
|
||||
}).then((plaintext) => {
|
||||
expect(plaintext).toEqual(input);
|
||||
});
|
||||
return MegolmExportEncryption.encryptMegolmKeyFile(input, password, { kdf_rounds: 1000 })
|
||||
.then((ciphertext) => {
|
||||
return MegolmExportEncryption.decryptMegolmKeyFile(ciphertext, password);
|
||||
})
|
||||
.then((plaintext) => {
|
||||
expect(plaintext).toEqual(input);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -14,32 +14,32 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { mocked } from 'jest-mock';
|
||||
import { MatrixClient } from 'matrix-js-sdk/src/matrix';
|
||||
import { mocked } from "jest-mock";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { MatrixClientPeg } from '../../src/MatrixClientPeg';
|
||||
import Modal, { ModalManager } from '../../src/Modal';
|
||||
import SettingsStore from '../../src/settings/SettingsStore';
|
||||
import MultiInviter, { CompletionStates } from '../../src/utils/MultiInviter';
|
||||
import * as TestUtilsMatrix from '../test-utils';
|
||||
import { MatrixClientPeg } from "../../src/MatrixClientPeg";
|
||||
import Modal, { ModalManager } from "../../src/Modal";
|
||||
import SettingsStore from "../../src/settings/SettingsStore";
|
||||
import MultiInviter, { CompletionStates } from "../../src/utils/MultiInviter";
|
||||
import * as TestUtilsMatrix from "../test-utils";
|
||||
|
||||
const ROOMID = '!room:server';
|
||||
const ROOMID = "!room:server";
|
||||
|
||||
const MXID1 = '@user1:server';
|
||||
const MXID2 = '@user2:server';
|
||||
const MXID3 = '@user3:server';
|
||||
const MXID1 = "@user1:server";
|
||||
const MXID2 = "@user2:server";
|
||||
const MXID3 = "@user3:server";
|
||||
|
||||
const MXID_PROFILE_STATES = {
|
||||
[MXID1]: Promise.resolve({}),
|
||||
[MXID2]: Promise.reject({ errcode: 'M_FORBIDDEN' }),
|
||||
[MXID3]: Promise.reject({ errcode: 'M_NOT_FOUND' }),
|
||||
[MXID2]: Promise.reject({ errcode: "M_FORBIDDEN" }),
|
||||
[MXID3]: Promise.reject({ errcode: "M_NOT_FOUND" }),
|
||||
};
|
||||
|
||||
jest.mock('../../src/Modal', () => ({
|
||||
jest.mock("../../src/Modal", () => ({
|
||||
createDialog: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../src/settings/SettingsStore', () => ({
|
||||
jest.mock("../../src/settings/SettingsStore", () => ({
|
||||
getValue: jest.fn(),
|
||||
monitorSetting: jest.fn(),
|
||||
watchSetting: jest.fn(),
|
||||
@ -48,30 +48,28 @@ jest.mock('../../src/settings/SettingsStore', () => ({
|
||||
const mockPromptBeforeInviteUnknownUsers = (value: boolean) => {
|
||||
mocked(SettingsStore.getValue).mockImplementation(
|
||||
(settingName: string, roomId: string = null, _excludeDefault = false): any => {
|
||||
if (settingName === 'promptBeforeInviteUnknownUsers' && roomId === ROOMID) {
|
||||
if (settingName === "promptBeforeInviteUnknownUsers" && roomId === ROOMID) {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
const mockCreateTrackedDialog = (callbackName: 'onInviteAnyways'|'onGiveUp') => {
|
||||
mocked(Modal.createDialog).mockImplementation(
|
||||
(...rest: Parameters<ModalManager['createDialog']>): any => {
|
||||
rest[1][callbackName]();
|
||||
},
|
||||
);
|
||||
const mockCreateTrackedDialog = (callbackName: "onInviteAnyways" | "onGiveUp") => {
|
||||
mocked(Modal.createDialog).mockImplementation((...rest: Parameters<ModalManager["createDialog"]>): any => {
|
||||
rest[1][callbackName]();
|
||||
});
|
||||
};
|
||||
|
||||
const expectAllInvitedResult = (result: CompletionStates) => {
|
||||
expect(result).toEqual({
|
||||
[MXID1]: 'invited',
|
||||
[MXID2]: 'invited',
|
||||
[MXID3]: 'invited',
|
||||
[MXID1]: "invited",
|
||||
[MXID2]: "invited",
|
||||
[MXID3]: "invited",
|
||||
});
|
||||
};
|
||||
|
||||
describe('MultiInviter', () => {
|
||||
describe("MultiInviter", () => {
|
||||
let client: jest.Mocked<MatrixClient>;
|
||||
let inviter: MultiInviter;
|
||||
|
||||
@ -92,11 +90,11 @@ describe('MultiInviter', () => {
|
||||
inviter = new MultiInviter(ROOMID);
|
||||
});
|
||||
|
||||
describe('invite', () => {
|
||||
describe('with promptBeforeInviteUnknownUsers = false', () => {
|
||||
describe("invite", () => {
|
||||
describe("with promptBeforeInviteUnknownUsers = false", () => {
|
||||
beforeEach(() => mockPromptBeforeInviteUnknownUsers(false));
|
||||
|
||||
it('should invite all users', async () => {
|
||||
it("should invite all users", async () => {
|
||||
const result = await inviter.invite([MXID1, MXID2, MXID3]);
|
||||
|
||||
expect(client.invite).toHaveBeenCalledTimes(3);
|
||||
@ -108,13 +106,13 @@ describe('MultiInviter', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('with promptBeforeInviteUnknownUsers = true and', () => {
|
||||
describe("with promptBeforeInviteUnknownUsers = true and", () => {
|
||||
beforeEach(() => mockPromptBeforeInviteUnknownUsers(true));
|
||||
|
||||
describe('confirming the unknown user dialog', () => {
|
||||
beforeEach(() => mockCreateTrackedDialog('onInviteAnyways'));
|
||||
describe("confirming the unknown user dialog", () => {
|
||||
beforeEach(() => mockCreateTrackedDialog("onInviteAnyways"));
|
||||
|
||||
it('should invite all users', async () => {
|
||||
it("should invite all users", async () => {
|
||||
const result = await inviter.invite([MXID1, MXID2, MXID3]);
|
||||
|
||||
expect(client.invite).toHaveBeenCalledTimes(3);
|
||||
@ -126,10 +124,10 @@ describe('MultiInviter', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('declining the unknown user dialog', () => {
|
||||
beforeEach(() => mockCreateTrackedDialog('onGiveUp'));
|
||||
describe("declining the unknown user dialog", () => {
|
||||
beforeEach(() => mockCreateTrackedDialog("onGiveUp"));
|
||||
|
||||
it('should only invite existing users', async () => {
|
||||
it("should only invite existing users", async () => {
|
||||
const result = await inviter.invite([MXID1, MXID2, MXID3]);
|
||||
|
||||
expect(client.invite).toHaveBeenCalledTimes(1);
|
||||
|
@ -14,13 +14,10 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
MatrixClient,
|
||||
Room,
|
||||
} from 'matrix-js-sdk/src/matrix';
|
||||
import { MatrixClient, Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { shieldStatusForRoom } from '../../src/utils/ShieldUtils';
|
||||
import DMRoomMap from '../../src/utils/DMRoomMap';
|
||||
import { shieldStatusForRoom } from "../../src/utils/ShieldUtils";
|
||||
import DMRoomMap from "../../src/utils/DMRoomMap";
|
||||
|
||||
function mkClient(selfTrust = false) {
|
||||
return {
|
||||
@ -30,13 +27,13 @@ function mkClient(selfTrust = false) {
|
||||
wasCrossSigningVerified: () => userId[1] == "T" || userId[1] == "W",
|
||||
}),
|
||||
checkDeviceTrust: (userId, deviceId) => ({
|
||||
isVerified: () => userId === "@self:localhost" ? selfTrust : userId[2] == "T",
|
||||
isVerified: () => (userId === "@self:localhost" ? selfTrust : userId[2] == "T"),
|
||||
}),
|
||||
getStoredDevicesForUser: (userId) => ["DEVICE"],
|
||||
} as unknown as MatrixClient;
|
||||
}
|
||||
|
||||
describe("mkClient self-test", function() {
|
||||
describe("mkClient self-test", function () {
|
||||
test.each([true, false])("behaves well for self-trust=%s", (v) => {
|
||||
const client = mkClient(v);
|
||||
expect(client.checkDeviceTrust("@self:localhost", "DEVICE").isVerified()).toBe(v);
|
||||
@ -46,8 +43,8 @@ describe("mkClient self-test", function() {
|
||||
["@TT:h", true],
|
||||
["@TF:h", true],
|
||||
["@FT:h", false],
|
||||
["@FF:h", false]],
|
||||
)("behaves well for user trust %s", (userId, trust) => {
|
||||
["@FF:h", false],
|
||||
])("behaves well for user trust %s", (userId, trust) => {
|
||||
expect(mkClient().checkUserTrust(userId).isCrossSigningVerified()).toBe(trust);
|
||||
});
|
||||
|
||||
@ -55,28 +52,30 @@ describe("mkClient self-test", function() {
|
||||
["@TT:h", true],
|
||||
["@TF:h", false],
|
||||
["@FT:h", true],
|
||||
["@FF:h", false]],
|
||||
)("behaves well for device trust %s", (userId, trust) => {
|
||||
["@FF:h", false],
|
||||
])("behaves well for device trust %s", (userId, trust) => {
|
||||
expect(mkClient().checkDeviceTrust(userId, "device").isVerified()).toBe(trust);
|
||||
});
|
||||
});
|
||||
|
||||
describe("shieldStatusForMembership self-trust behaviour", function() {
|
||||
describe("shieldStatusForMembership self-trust behaviour", function () {
|
||||
beforeAll(() => {
|
||||
const mockInstance = {
|
||||
getUserIdForRoomId: (roomId) => roomId === "DM" ? "@any:h" : null,
|
||||
getUserIdForRoomId: (roomId) => (roomId === "DM" ? "@any:h" : null),
|
||||
} as unknown as DMRoomMap;
|
||||
jest.spyOn(DMRoomMap, 'shared').mockReturnValue(mockInstance);
|
||||
jest.spyOn(DMRoomMap, "shared").mockReturnValue(mockInstance);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(DMRoomMap, 'shared').mockRestore();
|
||||
jest.spyOn(DMRoomMap, "shared").mockRestore();
|
||||
});
|
||||
|
||||
it.each(
|
||||
[[true, true], [true, false],
|
||||
[false, true], [false, false]],
|
||||
)("2 unverified: returns 'normal', self-trust = %s, DM = %s", async (trusted, dm) => {
|
||||
it.each([
|
||||
[true, true],
|
||||
[true, false],
|
||||
[false, true],
|
||||
[false, false],
|
||||
])("2 unverified: returns 'normal', self-trust = %s, DM = %s", async (trusted, dm) => {
|
||||
const client = mkClient(trusted);
|
||||
const room = {
|
||||
roomId: dm ? "DM" : "other",
|
||||
@ -86,10 +85,12 @@ describe("shieldStatusForMembership self-trust behaviour", function() {
|
||||
expect(status).toEqual("normal");
|
||||
});
|
||||
|
||||
it.each(
|
||||
[["verified", true, true], ["verified", true, false],
|
||||
["verified", false, true], ["warning", false, false]],
|
||||
)("2 verified: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => {
|
||||
it.each([
|
||||
["verified", true, true],
|
||||
["verified", true, 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 = {
|
||||
roomId: dm ? "DM" : "other",
|
||||
@ -99,10 +100,12 @@ describe("shieldStatusForMembership self-trust behaviour", function() {
|
||||
expect(status).toEqual(result);
|
||||
});
|
||||
|
||||
it.each(
|
||||
[["normal", true, true], ["normal", true, false],
|
||||
["normal", false, true], ["warning", false, false]],
|
||||
)("2 mixed: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => {
|
||||
it.each([
|
||||
["normal", true, true],
|
||||
["normal", true, 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 = {
|
||||
roomId: dm ? "DM" : "other",
|
||||
@ -112,10 +115,12 @@ describe("shieldStatusForMembership self-trust behaviour", function() {
|
||||
expect(status).toEqual(result);
|
||||
});
|
||||
|
||||
it.each(
|
||||
[["verified", true, true], ["verified", true, false],
|
||||
["warning", false, true], ["warning", false, false]],
|
||||
)("0 others: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => {
|
||||
it.each([
|
||||
["verified", true, true],
|
||||
["verified", true, 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 = {
|
||||
roomId: dm ? "DM" : "other",
|
||||
@ -125,10 +130,12 @@ describe("shieldStatusForMembership self-trust behaviour", function() {
|
||||
expect(status).toEqual(result);
|
||||
});
|
||||
|
||||
it.each(
|
||||
[["verified", true, true], ["verified", true, false],
|
||||
["verified", false, true], ["verified", false, false]],
|
||||
)("1 verified: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => {
|
||||
it.each([
|
||||
["verified", true, true],
|
||||
["verified", true, 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 = {
|
||||
roomId: dm ? "DM" : "other",
|
||||
@ -138,10 +145,12 @@ describe("shieldStatusForMembership self-trust behaviour", function() {
|
||||
expect(status).toEqual(result);
|
||||
});
|
||||
|
||||
it.each(
|
||||
[["normal", true, true], ["normal", true, false],
|
||||
["normal", false, true], ["normal", false, false]],
|
||||
)("1 unverified: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => {
|
||||
it.each([
|
||||
["normal", true, true],
|
||||
["normal", true, 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 = {
|
||||
roomId: dm ? "DM" : "other",
|
||||
@ -152,17 +161,18 @@ describe("shieldStatusForMembership self-trust behaviour", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("shieldStatusForMembership other-trust behaviour", function() {
|
||||
describe("shieldStatusForMembership other-trust behaviour", function () {
|
||||
beforeAll(() => {
|
||||
const mockInstance = {
|
||||
getUserIdForRoomId: (roomId) => roomId === "DM" ? "@any:h" : null,
|
||||
getUserIdForRoomId: (roomId) => (roomId === "DM" ? "@any:h" : null),
|
||||
} as unknown as DMRoomMap;
|
||||
jest.spyOn(DMRoomMap, 'shared').mockReturnValue(mockInstance);
|
||||
jest.spyOn(DMRoomMap, "shared").mockReturnValue(mockInstance);
|
||||
});
|
||||
|
||||
it.each(
|
||||
[["warning", true], ["warning", false]],
|
||||
)("1 verified/untrusted: returns '%s', DM = %s", async (result, dm) => {
|
||||
it.each([
|
||||
["warning", true],
|
||||
["warning", false],
|
||||
])("1 verified/untrusted: returns '%s', DM = %s", async (result, dm) => {
|
||||
const client = mkClient(true);
|
||||
const room = {
|
||||
roomId: dm ? "DM" : "other",
|
||||
@ -172,9 +182,10 @@ describe("shieldStatusForMembership other-trust behaviour", function() {
|
||||
expect(status).toEqual(result);
|
||||
});
|
||||
|
||||
it.each(
|
||||
[["warning", true], ["warning", false]],
|
||||
)("2 verified/untrusted: returns '%s', DM = %s", async (result, dm) => {
|
||||
it.each([
|
||||
["warning", true],
|
||||
["warning", false],
|
||||
])("2 verified/untrusted: returns '%s', DM = %s", async (result, dm) => {
|
||||
const client = mkClient(true);
|
||||
const room = {
|
||||
roomId: dm ? "DM" : "other",
|
||||
@ -184,9 +195,10 @@ describe("shieldStatusForMembership other-trust behaviour", function() {
|
||||
expect(status).toEqual(result);
|
||||
});
|
||||
|
||||
it.each(
|
||||
[["normal", true], ["normal", false]],
|
||||
)("2 unverified/untrusted: returns '%s', DM = %s", async (result, dm) => {
|
||||
it.each([
|
||||
["normal", true],
|
||||
["normal", false],
|
||||
])("2 unverified/untrusted: returns '%s', DM = %s", async (result, dm) => {
|
||||
const client = mkClient(true);
|
||||
const room = {
|
||||
roomId: dm ? "DM" : "other",
|
||||
@ -196,9 +208,10 @@ describe("shieldStatusForMembership other-trust behaviour", function() {
|
||||
expect(status).toEqual(result);
|
||||
});
|
||||
|
||||
it.each(
|
||||
[["warning", true], ["warning", false]],
|
||||
)("2 was verified: returns '%s', DM = %s", async (result, dm) => {
|
||||
it.each([
|
||||
["warning", true],
|
||||
["warning", false],
|
||||
])("2 was verified: returns '%s', DM = %s", async (result, dm) => {
|
||||
const client = mkClient(true);
|
||||
const room = {
|
||||
roomId: dm ? "DM" : "other",
|
||||
|
@ -16,12 +16,12 @@ limitations under the License.
|
||||
|
||||
import { Singleflight } from "../../src/utils/Singleflight";
|
||||
|
||||
describe('Singleflight', () => {
|
||||
describe("Singleflight", () => {
|
||||
afterEach(() => {
|
||||
Singleflight.forgetAll();
|
||||
});
|
||||
|
||||
it('should throw for bad context variables', () => {
|
||||
it("should throw for bad context variables", () => {
|
||||
const permutations: [Object, string][] = [
|
||||
[null, null],
|
||||
[{}, null],
|
||||
@ -38,7 +38,7 @@ describe('Singleflight', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('should execute the function once', () => {
|
||||
it("should execute the function once", () => {
|
||||
const instance = {};
|
||||
const key = "test";
|
||||
const val = {}; // unique object for reference check
|
||||
@ -52,7 +52,7 @@ describe('Singleflight', () => {
|
||||
expect(fn.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should execute the function once, even with new contexts', () => {
|
||||
it("should execute the function once, even with new contexts", () => {
|
||||
const instance = {};
|
||||
const key = "test";
|
||||
const val = {}; // unique object for reference check
|
||||
@ -67,7 +67,7 @@ describe('Singleflight', () => {
|
||||
expect(fn.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should execute the function twice if the result was forgotten', () => {
|
||||
it("should execute the function twice if the result was forgotten", () => {
|
||||
const instance = {};
|
||||
const key = "test";
|
||||
const val = {}; // unique object for reference check
|
||||
@ -82,7 +82,7 @@ describe('Singleflight', () => {
|
||||
expect(fn.mock.calls.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should execute the function twice if the instance was forgotten', () => {
|
||||
it("should execute the function twice if the instance was forgotten", () => {
|
||||
const instance = {};
|
||||
const key = "test";
|
||||
const val = {}; // unique object for reference check
|
||||
@ -97,7 +97,7 @@ describe('Singleflight', () => {
|
||||
expect(fn.mock.calls.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should execute the function twice if everything was forgotten', () => {
|
||||
it("should execute the function twice if everything was forgotten", () => {
|
||||
const instance = {};
|
||||
const key = "test";
|
||||
const val = {}; // unique object for reference check
|
||||
@ -112,4 +112,3 @@ describe('Singleflight', () => {
|
||||
expect(fn.mock.calls.length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -16,15 +16,15 @@ limitations under the License.
|
||||
|
||||
import { SnakedObject, snakeToCamel } from "../../src/utils/SnakedObject";
|
||||
|
||||
describe('snakeToCamel', () => {
|
||||
it('should convert snake_case to camelCase in simple scenarios', () => {
|
||||
describe("snakeToCamel", () => {
|
||||
it("should convert snake_case to camelCase in simple scenarios", () => {
|
||||
expect(snakeToCamel("snake_case")).toBe("snakeCase");
|
||||
expect(snakeToCamel("snake_case_but_longer")).toBe("snakeCaseButLonger");
|
||||
expect(snakeToCamel("numbered_123")).toBe("numbered123"); // not a thing we would see normally
|
||||
});
|
||||
|
||||
// Not really something we expect to see, but it's defined behaviour of the function
|
||||
it('should not camelCase a trailing or leading underscore', () => {
|
||||
it("should not camelCase a trailing or leading underscore", () => {
|
||||
expect(snakeToCamel("_snake")).toBe("_snake");
|
||||
expect(snakeToCamel("snake_")).toBe("snake_");
|
||||
expect(snakeToCamel("_snake_case")).toBe("_snakeCase");
|
||||
@ -32,13 +32,13 @@ describe('snakeToCamel', () => {
|
||||
});
|
||||
|
||||
// Another thing we don't really expect to see, but is "defined behaviour"
|
||||
it('should be predictable with double underscores', () => {
|
||||
it("should be predictable with double underscores", () => {
|
||||
expect(snakeToCamel("__snake__")).toBe("_Snake_");
|
||||
expect(snakeToCamel("snake__case")).toBe("snake_case");
|
||||
});
|
||||
});
|
||||
|
||||
describe('SnakedObject', () => {
|
||||
describe("SnakedObject", () => {
|
||||
/* eslint-disable camelcase*/
|
||||
const input = {
|
||||
snake_case: "woot",
|
||||
@ -48,12 +48,12 @@ describe('SnakedObject', () => {
|
||||
const snake = new SnakedObject(input);
|
||||
/* eslint-enable camelcase*/
|
||||
|
||||
it('should prefer snake_case keys', () => {
|
||||
it("should prefer snake_case keys", () => {
|
||||
expect(snake.get("snake_case")).toBe(input.snake_case);
|
||||
expect(snake.get("snake_case", "camelCase")).toBe(input.snake_case);
|
||||
});
|
||||
|
||||
it('should fall back to camelCase keys when needed', () => {
|
||||
it("should fall back to camelCase keys when needed", () => {
|
||||
// @ts-ignore - we're deliberately supplying a key that doesn't exist
|
||||
expect(snake.get("camel_case")).toBe(input.camelCase);
|
||||
|
||||
|
@ -19,23 +19,23 @@ import WidgetUtils from "../../src/utils/WidgetUtils";
|
||||
import { mockPlatformPeg } from "../test-utils";
|
||||
|
||||
describe("getLocalJitsiWrapperUrl", () => {
|
||||
it('should generate jitsi URL (for defaults)', () => {
|
||||
it("should generate jitsi URL (for defaults)", () => {
|
||||
mockPlatformPeg();
|
||||
|
||||
expect(WidgetUtils.getLocalJitsiWrapperUrl()).toEqual(
|
||||
'https://app.element.io/jitsi.html'
|
||||
+ '#conferenceDomain=$domain'
|
||||
+ '&conferenceId=$conferenceId'
|
||||
+ '&isAudioOnly=$isAudioOnly'
|
||||
+ '&isVideoChannel=$isVideoChannel'
|
||||
+ '&displayName=$matrix_display_name'
|
||||
+ '&avatarUrl=$matrix_avatar_url'
|
||||
+ '&userId=$matrix_user_id'
|
||||
+ '&roomId=$matrix_room_id'
|
||||
+ '&theme=$theme'
|
||||
+ '&roomName=$roomName'
|
||||
+ '&supportsScreensharing=true'
|
||||
+ '&language=$org.matrix.msc2873.client_language',
|
||||
"https://app.element.io/jitsi.html" +
|
||||
"#conferenceDomain=$domain" +
|
||||
"&conferenceId=$conferenceId" +
|
||||
"&isAudioOnly=$isAudioOnly" +
|
||||
"&isVideoChannel=$isVideoChannel" +
|
||||
"&displayName=$matrix_display_name" +
|
||||
"&avatarUrl=$matrix_avatar_url" +
|
||||
"&userId=$matrix_user_id" +
|
||||
"&roomId=$matrix_room_id" +
|
||||
"&theme=$theme" +
|
||||
"&roomName=$roomName" +
|
||||
"&supportsScreensharing=true" +
|
||||
"&language=$org.matrix.msc2873.client_language",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -31,7 +31,7 @@ import {
|
||||
concat,
|
||||
} from "../../src/utils/arrays";
|
||||
|
||||
type TestParams = { input: number[], output: number[] };
|
||||
type TestParams = { input: number[]; output: number[] };
|
||||
type TestCase = [string, TestParams];
|
||||
|
||||
function expectSample(input: number[], expected: number[], smooth = false) {
|
||||
@ -41,74 +41,70 @@ function expectSample(input: number[], expected: number[], smooth = false) {
|
||||
expect(result).toEqual(expected);
|
||||
}
|
||||
|
||||
describe('arrays', () => {
|
||||
describe('arrayFastResample', () => {
|
||||
describe("arrays", () => {
|
||||
describe("arrayFastResample", () => {
|
||||
const downsampleCases: TestCase[] = [
|
||||
['Odd -> Even', { input: [1, 2, 3, 4, 5], output: [1, 4] }],
|
||||
['Odd -> Odd', { input: [1, 2, 3, 4, 5], output: [1, 3, 5] }],
|
||||
['Even -> Odd', { input: [1, 2, 3, 4], output: [1, 2, 3] }],
|
||||
['Even -> Even', { input: [1, 2, 3, 4], output: [1, 3] }],
|
||||
["Odd -> Even", { input: [1, 2, 3, 4, 5], output: [1, 4] }],
|
||||
["Odd -> Odd", { input: [1, 2, 3, 4, 5], output: [1, 3, 5] }],
|
||||
["Even -> Odd", { input: [1, 2, 3, 4], output: [1, 2, 3] }],
|
||||
["Even -> Even", { input: [1, 2, 3, 4], output: [1, 3] }],
|
||||
];
|
||||
it.each(downsampleCases)('downsamples correctly from %s', (_d, { input, output }) =>
|
||||
it.each(downsampleCases)("downsamples correctly from %s", (_d, { input, output }) =>
|
||||
expectSample(input, output),
|
||||
);
|
||||
|
||||
const upsampleCases: TestCase[] = [
|
||||
['Odd -> Even', { input: [1, 2, 3], output: [1, 1, 2, 2, 3, 3] }],
|
||||
['Odd -> Odd', { input: [1, 2, 3], output: [1, 1, 2, 2, 3] }],
|
||||
['Even -> Odd', { input: [1, 2], output: [1, 1, 1, 2, 2] }],
|
||||
['Even -> Even', { input: [1, 2], output: [1, 1, 1, 2, 2, 2] }],
|
||||
["Odd -> Even", { input: [1, 2, 3], output: [1, 1, 2, 2, 3, 3] }],
|
||||
["Odd -> Odd", { input: [1, 2, 3], output: [1, 1, 2, 2, 3] }],
|
||||
["Even -> Odd", { input: [1, 2], output: [1, 1, 1, 2, 2] }],
|
||||
["Even -> Even", { input: [1, 2], output: [1, 1, 1, 2, 2, 2] }],
|
||||
];
|
||||
it.each(upsampleCases)('upsamples correctly from %s', (_d, { input, output }) =>
|
||||
expectSample(input, output),
|
||||
);
|
||||
it.each(upsampleCases)("upsamples correctly from %s", (_d, { input, output }) => expectSample(input, output));
|
||||
|
||||
const maintainSampleCases: TestCase[] = [
|
||||
['Odd', { input: [1, 2, 3], output: [1, 2, 3] }], // Odd
|
||||
['Even', { input: [1, 2], output: [1, 2] }], // Even
|
||||
["Odd", { input: [1, 2, 3], output: [1, 2, 3] }], // Odd
|
||||
["Even", { input: [1, 2], output: [1, 2] }], // Even
|
||||
];
|
||||
|
||||
it.each(maintainSampleCases)('maintains samples for %s', (_d, { input, output }) =>
|
||||
it.each(maintainSampleCases)("maintains samples for %s", (_d, { input, output }) =>
|
||||
expectSample(input, output),
|
||||
);
|
||||
});
|
||||
|
||||
describe('arraySmoothingResample', () => {
|
||||
describe("arraySmoothingResample", () => {
|
||||
// Dev note: these aren't great samples, but they demonstrate the bare minimum. Ideally
|
||||
// we'd be feeding a thousand values in and seeing what a curve of 250 values looks like,
|
||||
// but that's not really feasible to manually verify accuracy.
|
||||
const downsampleCases: TestCase[] = [
|
||||
['Odd -> Even', { input: [4, 4, 1, 4, 4, 1, 4, 4, 1], output: [3, 3, 3, 3] }],
|
||||
['Odd -> Odd', { input: [4, 4, 1, 4, 4, 1, 4, 4, 1], output: [3, 3, 3] }],
|
||||
['Even -> Odd', { input: [4, 4, 1, 4, 4, 1, 4, 4], output: [3, 3, 3] }],
|
||||
['Even -> Even', { input: [4, 4, 1, 4, 4, 1, 4, 4], output: [3, 3] }],
|
||||
["Odd -> Even", { input: [4, 4, 1, 4, 4, 1, 4, 4, 1], output: [3, 3, 3, 3] }],
|
||||
["Odd -> Odd", { input: [4, 4, 1, 4, 4, 1, 4, 4, 1], output: [3, 3, 3] }],
|
||||
["Even -> Odd", { input: [4, 4, 1, 4, 4, 1, 4, 4], output: [3, 3, 3] }],
|
||||
["Even -> Even", { input: [4, 4, 1, 4, 4, 1, 4, 4], output: [3, 3] }],
|
||||
];
|
||||
|
||||
it.each(downsampleCases)('downsamples correctly from %s', (_d, { input, output }) =>
|
||||
it.each(downsampleCases)("downsamples correctly from %s", (_d, { input, output }) =>
|
||||
expectSample(input, output, true),
|
||||
);
|
||||
|
||||
const upsampleCases: TestCase[] = [
|
||||
['Odd -> Even', { input: [2, 0, 2], output: [2, 2, 0, 0, 2, 2] }],
|
||||
['Odd -> Odd', { input: [2, 0, 2], output: [2, 2, 0, 0, 2] }],
|
||||
['Even -> Odd', { input: [2, 0], output: [2, 2, 2, 0, 0] }],
|
||||
['Even -> Even', { input: [2, 0], output: [2, 2, 2, 0, 0, 0] }],
|
||||
["Odd -> Even", { input: [2, 0, 2], output: [2, 2, 0, 0, 2, 2] }],
|
||||
["Odd -> Odd", { input: [2, 0, 2], output: [2, 2, 0, 0, 2] }],
|
||||
["Even -> Odd", { input: [2, 0], output: [2, 2, 2, 0, 0] }],
|
||||
["Even -> Even", { input: [2, 0], output: [2, 2, 2, 0, 0, 0] }],
|
||||
];
|
||||
it.each(upsampleCases)('upsamples correctly from %s', (_d, { input, output }) =>
|
||||
it.each(upsampleCases)("upsamples correctly from %s", (_d, { input, output }) =>
|
||||
expectSample(input, output, true),
|
||||
);
|
||||
|
||||
const maintainCases: TestCase[] = [
|
||||
['Odd', { input: [2, 0, 2], output: [2, 0, 2] }],
|
||||
['Even', { input: [2, 0], output: [2, 0] }],
|
||||
["Odd", { input: [2, 0, 2], output: [2, 0, 2] }],
|
||||
["Even", { input: [2, 0], output: [2, 0] }],
|
||||
];
|
||||
it.each(maintainCases)('maintains samples for %s', (_d, { input, output }) =>
|
||||
expectSample(input, output),
|
||||
);
|
||||
it.each(maintainCases)("maintains samples for %s", (_d, { input, output }) => expectSample(input, output));
|
||||
});
|
||||
|
||||
describe('arrayRescale', () => {
|
||||
it('should rescale', () => {
|
||||
describe("arrayRescale", () => {
|
||||
it("should rescale", () => {
|
||||
const input = [8, 9, 1, 0, 2, 7, 10];
|
||||
const output = [80, 90, 10, 0, 20, 70, 100];
|
||||
const result = arrayRescale(input, 0, 100);
|
||||
@ -118,8 +114,8 @@ describe('arrays', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('arrayTrimFill', () => {
|
||||
it('should shrink arrays', () => {
|
||||
describe("arrayTrimFill", () => {
|
||||
it("should shrink arrays", () => {
|
||||
const input = [1, 2, 3];
|
||||
const output = [1, 2];
|
||||
const seed = [4, 5, 6];
|
||||
@ -129,7 +125,7 @@ describe('arrays', () => {
|
||||
expect(result).toEqual(output);
|
||||
});
|
||||
|
||||
it('should expand arrays', () => {
|
||||
it("should expand arrays", () => {
|
||||
const input = [1, 2, 3];
|
||||
const output = [1, 2, 3, 4, 5];
|
||||
const seed = [4, 5, 6];
|
||||
@ -139,7 +135,7 @@ describe('arrays', () => {
|
||||
expect(result).toEqual(output);
|
||||
});
|
||||
|
||||
it('should keep arrays the same', () => {
|
||||
it("should keep arrays the same", () => {
|
||||
const input = [1, 2, 3];
|
||||
const output = [1, 2, 3];
|
||||
const seed = [4, 5, 6];
|
||||
@ -150,8 +146,8 @@ describe('arrays', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('arraySeed', () => {
|
||||
it('should create an array of given length', () => {
|
||||
describe("arraySeed", () => {
|
||||
it("should create an array of given length", () => {
|
||||
const val = 1;
|
||||
const output = [val, val, val];
|
||||
const result = arraySeed(val, output.length);
|
||||
@ -159,7 +155,7 @@ describe('arrays', () => {
|
||||
expect(result).toHaveLength(output.length);
|
||||
expect(result).toEqual(output);
|
||||
});
|
||||
it('should maintain pointers', () => {
|
||||
it("should maintain pointers", () => {
|
||||
const val = {}; // this works because `{} !== {}`, which is what toEqual checks
|
||||
const output = [val, val, val];
|
||||
const result = arraySeed(val, output.length);
|
||||
@ -169,8 +165,8 @@ describe('arrays', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('arrayFastClone', () => {
|
||||
it('should break pointer reference on source array', () => {
|
||||
describe("arrayFastClone", () => {
|
||||
it("should break pointer reference on source array", () => {
|
||||
const val = {}; // we'll test to make sure the values maintain pointers too
|
||||
const input = [val, val, val];
|
||||
const result = arrayFastClone(input);
|
||||
@ -181,29 +177,29 @@ describe('arrays', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('arrayHasOrderChange', () => {
|
||||
it('should flag true on B ordering difference', () => {
|
||||
describe("arrayHasOrderChange", () => {
|
||||
it("should flag true on B ordering difference", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [3, 2, 1];
|
||||
const result = arrayHasOrderChange(a, b);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should flag false on no ordering difference', () => {
|
||||
it("should flag false on no ordering difference", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [1, 2, 3];
|
||||
const result = arrayHasOrderChange(a, b);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should flag true on A length > B length', () => {
|
||||
it("should flag true on A length > B length", () => {
|
||||
const a = [1, 2, 3, 4];
|
||||
const b = [1, 2, 3];
|
||||
const result = arrayHasOrderChange(a, b);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should flag true on A length < B length', () => {
|
||||
it("should flag true on A length < B length", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [1, 2, 3, 4];
|
||||
const result = arrayHasOrderChange(a, b);
|
||||
@ -211,36 +207,36 @@ describe('arrays', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('arrayHasDiff', () => {
|
||||
it('should flag true on A length > B length', () => {
|
||||
describe("arrayHasDiff", () => {
|
||||
it("should flag true on A length > B length", () => {
|
||||
const a = [1, 2, 3, 4];
|
||||
const b = [1, 2, 3];
|
||||
const result = arrayHasDiff(a, b);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should flag true on A length < B length', () => {
|
||||
it("should flag true on A length < B length", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [1, 2, 3, 4];
|
||||
const result = arrayHasDiff(a, b);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should flag true on element differences', () => {
|
||||
it("should flag true on element differences", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [4, 5, 6];
|
||||
const result = arrayHasDiff(a, b);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should flag false if same but order different', () => {
|
||||
it("should flag false if same but order different", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [3, 1, 2];
|
||||
const result = arrayHasDiff(a, b);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should flag false if same', () => {
|
||||
it("should flag false if same", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [1, 2, 3];
|
||||
const result = arrayHasDiff(a, b);
|
||||
@ -248,8 +244,8 @@ describe('arrays', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('arrayDiff', () => {
|
||||
it('should see added from A->B', () => {
|
||||
describe("arrayDiff", () => {
|
||||
it("should see added from A->B", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [1, 2, 3, 4];
|
||||
const result = arrayDiff(a, b);
|
||||
@ -261,7 +257,7 @@ describe('arrays', () => {
|
||||
expect(result.added).toEqual([4]);
|
||||
});
|
||||
|
||||
it('should see removed from A->B', () => {
|
||||
it("should see removed from A->B", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [1, 2];
|
||||
const result = arrayDiff(a, b);
|
||||
@ -273,7 +269,7 @@ describe('arrays', () => {
|
||||
expect(result.removed).toEqual([3]);
|
||||
});
|
||||
|
||||
it('should see added and removed in the same set', () => {
|
||||
it("should see added and removed in the same set", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [1, 2, 4]; // note diff
|
||||
const result = arrayDiff(a, b);
|
||||
@ -287,8 +283,8 @@ describe('arrays', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('arrayIntersection', () => {
|
||||
it('should return the intersection', () => {
|
||||
describe("arrayIntersection", () => {
|
||||
it("should return the intersection", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [1, 2, 4]; // note diff
|
||||
const result = arrayIntersection(a, b);
|
||||
@ -297,7 +293,7 @@ describe('arrays', () => {
|
||||
expect(result).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
it('should return an empty array on no matches', () => {
|
||||
it("should return an empty array on no matches", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [4, 5, 6];
|
||||
const result = arrayIntersection(a, b);
|
||||
@ -306,8 +302,8 @@ describe('arrays', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('arrayUnion', () => {
|
||||
it('should union 3 arrays with deduplication', () => {
|
||||
describe("arrayUnion", () => {
|
||||
it("should union 3 arrays with deduplication", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [1, 2, 4, 5]; // note missing 3
|
||||
const c = [6, 7, 8, 9];
|
||||
@ -317,7 +313,7 @@ describe('arrays', () => {
|
||||
expect(result).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||
});
|
||||
|
||||
it('should deduplicate a single array', () => {
|
||||
it("should deduplicate a single array", () => {
|
||||
// dev note: this is technically an edge case, but it is described behaviour if the
|
||||
// function is only provided one array (it'll merge the array against itself)
|
||||
const a = [1, 1, 2, 2, 3, 3];
|
||||
@ -328,21 +324,35 @@ describe('arrays', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('ArrayUtil', () => {
|
||||
it('should maintain the pointer to the given array', () => {
|
||||
describe("ArrayUtil", () => {
|
||||
it("should maintain the pointer to the given array", () => {
|
||||
const input = [1, 2, 3];
|
||||
const result = new ArrayUtil(input);
|
||||
expect(result.value).toBe(input);
|
||||
});
|
||||
|
||||
it('should group appropriately', () => {
|
||||
const input = [['a', 1], ['b', 2], ['c', 3], ['a', 4], ['a', 5], ['b', 6]];
|
||||
it("should group appropriately", () => {
|
||||
const input = [
|
||||
["a", 1],
|
||||
["b", 2],
|
||||
["c", 3],
|
||||
["a", 4],
|
||||
["a", 5],
|
||||
["b", 6],
|
||||
];
|
||||
const output = {
|
||||
'a': [['a', 1], ['a', 4], ['a', 5]],
|
||||
'b': [['b', 2], ['b', 6]],
|
||||
'c': [['c', 3]],
|
||||
a: [
|
||||
["a", 1],
|
||||
["a", 4],
|
||||
["a", 5],
|
||||
],
|
||||
b: [
|
||||
["b", 2],
|
||||
["b", 6],
|
||||
],
|
||||
c: [["c", 3]],
|
||||
};
|
||||
const result = new ArrayUtil(input).groupBy(p => p[0]);
|
||||
const result = new ArrayUtil(input).groupBy((p) => p[0]);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.value).toBeDefined();
|
||||
|
||||
@ -351,25 +361,25 @@ describe('arrays', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('GroupedArray', () => {
|
||||
it('should maintain the pointer to the given map', () => {
|
||||
describe("GroupedArray", () => {
|
||||
it("should maintain the pointer to the given map", () => {
|
||||
const input = new Map([
|
||||
['a', [1, 2, 3]],
|
||||
['b', [7, 8, 9]],
|
||||
['c', [4, 5, 6]],
|
||||
["a", [1, 2, 3]],
|
||||
["b", [7, 8, 9]],
|
||||
["c", [4, 5, 6]],
|
||||
]);
|
||||
const result = new GroupedArray(input);
|
||||
expect(result.value).toBe(input);
|
||||
});
|
||||
|
||||
it('should ordering by the provided key order', () => {
|
||||
it("should ordering by the provided key order", () => {
|
||||
const input = new Map([
|
||||
['a', [1, 2, 3]],
|
||||
['b', [7, 8, 9]], // note counting diff
|
||||
['c', [4, 5, 6]],
|
||||
["a", [1, 2, 3]],
|
||||
["b", [7, 8, 9]], // note counting diff
|
||||
["c", [4, 5, 6]],
|
||||
]);
|
||||
const output = [4, 5, 6, 1, 2, 3, 7, 8, 9];
|
||||
const keyOrder = ['c', 'a', 'b']; // note weird order to cause the `output` to be strange
|
||||
const keyOrder = ["c", "a", "b"]; // note weird order to cause the `output` to be strange
|
||||
const result = new GroupedArray(input).orderBy(keyOrder);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.value).toBeDefined();
|
||||
@ -404,4 +414,3 @@ describe('arrays', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -19,10 +19,10 @@ import { Beacon } from "matrix-js-sdk/src/matrix";
|
||||
import { Bounds, getBeaconBounds } from "../../../src/utils/beacon/bounds";
|
||||
import { makeBeaconEvent, makeBeaconInfoEvent } from "../../test-utils";
|
||||
|
||||
describe('getBeaconBounds()', () => {
|
||||
const userId = '@user:server';
|
||||
const roomId = '!room:server';
|
||||
const makeBeaconWithLocation = (latLon: {lat: number, lon: number}) => {
|
||||
describe("getBeaconBounds()", () => {
|
||||
const userId = "@user:server";
|
||||
const roomId = "!room:server";
|
||||
const makeBeaconWithLocation = (latLon: { lat: number; lon: number }) => {
|
||||
const geoUri = `geo:${latLon.lat},${latLon.lon}`;
|
||||
const beacon = new Beacon(makeBeaconInfoEvent(userId, roomId, { isLive: true }));
|
||||
// @ts-ignore private prop, sets internal live property so addLocations works
|
||||
@ -57,39 +57,45 @@ describe('getBeaconBounds()', () => {
|
||||
const auckland = makeBeaconWithLocation(geo.auckland);
|
||||
const lima = makeBeaconWithLocation(geo.lima);
|
||||
|
||||
it('should return undefined when there are no beacons', () => {
|
||||
it("should return undefined when there are no beacons", () => {
|
||||
expect(getBeaconBounds([])).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return undefined when no beacons have locations', () => {
|
||||
it("should return undefined when no beacons have locations", () => {
|
||||
const beacon = new Beacon(makeBeaconInfoEvent(userId, roomId));
|
||||
expect(getBeaconBounds([beacon])).toBeUndefined();
|
||||
});
|
||||
|
||||
type TestCase = [string, Beacon[], Bounds];
|
||||
it.each<TestCase>([
|
||||
['one beacon', [london],
|
||||
[
|
||||
"one beacon",
|
||||
[london],
|
||||
{ north: geo.london.lat, south: geo.london.lat, east: geo.london.lon, west: geo.london.lon },
|
||||
],
|
||||
['beacons in the northern hemisphere, west of meridian',
|
||||
[
|
||||
"beacons in the northern hemisphere, west of meridian",
|
||||
[london, reykjavik],
|
||||
{ north: geo.reykjavik.lat, south: geo.london.lat, east: geo.london.lon, west: geo.reykjavik.lon },
|
||||
],
|
||||
['beacons in the northern hemisphere, both sides of meridian',
|
||||
[
|
||||
"beacons in the northern hemisphere, both sides of meridian",
|
||||
[london, reykjavik, paris],
|
||||
// reykjavik northmost and westmost, paris southmost and eastmost
|
||||
{ north: geo.reykjavik.lat, south: geo.paris.lat, east: geo.paris.lon, west: geo.reykjavik.lon },
|
||||
],
|
||||
['beacons in the southern hemisphere',
|
||||
[
|
||||
"beacons in the southern hemisphere",
|
||||
[auckland, lima],
|
||||
// lima northmost and westmost, auckland southmost and eastmost
|
||||
{ north: geo.lima.lat, south: geo.auckland.lat, east: geo.auckland.lon, west: geo.lima.lon },
|
||||
],
|
||||
['beacons in both hemispheres',
|
||||
[
|
||||
"beacons in both hemispheres",
|
||||
[auckland, lima, paris],
|
||||
{ north: geo.paris.lat, south: geo.auckland.lat, east: geo.auckland.lon, west: geo.lima.lon },
|
||||
],
|
||||
])('gets correct bounds for %s', (_description, beacons, expectedBounds) => {
|
||||
])("gets correct bounds for %s", (_description, beacons, expectedBounds) => {
|
||||
expect(getBeaconBounds(beacons)).toEqual(expectedBounds);
|
||||
});
|
||||
});
|
||||
|
@ -16,35 +16,31 @@ limitations under the License.
|
||||
|
||||
import { Beacon } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import {
|
||||
msUntilExpiry,
|
||||
sortBeaconsByLatestExpiry,
|
||||
sortBeaconsByLatestCreation,
|
||||
} from "../../../src/utils/beacon";
|
||||
import { msUntilExpiry, sortBeaconsByLatestExpiry, sortBeaconsByLatestCreation } from "../../../src/utils/beacon";
|
||||
import { makeBeaconInfoEvent } from "../../test-utils";
|
||||
|
||||
describe('beacon utils', () => {
|
||||
describe("beacon utils", () => {
|
||||
// 14.03.2022 16:15
|
||||
const now = 1647270879403;
|
||||
const HOUR_MS = 3600000;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(now);
|
||||
jest.spyOn(global.Date, "now").mockReturnValue(now);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(global.Date, 'now').mockRestore();
|
||||
jest.spyOn(global.Date, "now").mockRestore();
|
||||
});
|
||||
|
||||
describe('msUntilExpiry', () => {
|
||||
it('returns remaining duration', () => {
|
||||
describe("msUntilExpiry", () => {
|
||||
it("returns remaining duration", () => {
|
||||
const start = now - HOUR_MS;
|
||||
const durationMs = HOUR_MS * 3;
|
||||
|
||||
expect(msUntilExpiry(start, durationMs)).toEqual(HOUR_MS * 2);
|
||||
});
|
||||
|
||||
it('returns 0 when expiry has already passed', () => {
|
||||
it("returns 0 when expiry has already passed", () => {
|
||||
// created 3h ago
|
||||
const start = now - HOUR_MS * 3;
|
||||
// 1h durations
|
||||
@ -54,65 +50,49 @@ describe('beacon utils', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('sortBeaconsByLatestExpiry()', () => {
|
||||
const roomId = '!room:server';
|
||||
const aliceId = '@alive:server';
|
||||
describe("sortBeaconsByLatestExpiry()", () => {
|
||||
const roomId = "!room:server";
|
||||
const aliceId = "@alive:server";
|
||||
|
||||
// 12h old, 12h left
|
||||
const beacon1 = new Beacon(makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ timeout: HOUR_MS * 24, timestamp: now - 12 * HOUR_MS },
|
||||
'$1',
|
||||
));
|
||||
const beacon1 = new Beacon(
|
||||
makeBeaconInfoEvent(aliceId, roomId, { timeout: HOUR_MS * 24, timestamp: now - 12 * HOUR_MS }, "$1"),
|
||||
);
|
||||
// 10h left
|
||||
const beacon2 = new Beacon(makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ timeout: HOUR_MS * 10, timestamp: now },
|
||||
'$2',
|
||||
));
|
||||
const beacon2 = new Beacon(
|
||||
makeBeaconInfoEvent(aliceId, roomId, { timeout: HOUR_MS * 10, timestamp: now }, "$2"),
|
||||
);
|
||||
|
||||
// 1ms left
|
||||
const beacon3 = new Beacon(makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ timeout: HOUR_MS + 1, timestamp: now - HOUR_MS },
|
||||
'$3',
|
||||
));
|
||||
const beacon3 = new Beacon(
|
||||
makeBeaconInfoEvent(aliceId, roomId, { timeout: HOUR_MS + 1, timestamp: now - HOUR_MS }, "$3"),
|
||||
);
|
||||
|
||||
it('sorts beacons by descending expiry time', () => {
|
||||
expect([beacon2, beacon3, beacon1].sort(sortBeaconsByLatestExpiry)).toEqual([
|
||||
beacon1, beacon2, beacon3,
|
||||
]);
|
||||
it("sorts beacons by descending expiry time", () => {
|
||||
expect([beacon2, beacon3, beacon1].sort(sortBeaconsByLatestExpiry)).toEqual([beacon1, beacon2, beacon3]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sortBeaconsByLatestCreation()', () => {
|
||||
const roomId = '!room:server';
|
||||
const aliceId = '@alive:server';
|
||||
describe("sortBeaconsByLatestCreation()", () => {
|
||||
const roomId = "!room:server";
|
||||
const aliceId = "@alive:server";
|
||||
|
||||
// 12h old, 12h left
|
||||
const beacon1 = new Beacon(makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ timeout: HOUR_MS * 24, timestamp: now - 12 * HOUR_MS },
|
||||
'$1',
|
||||
));
|
||||
const beacon1 = new Beacon(
|
||||
makeBeaconInfoEvent(aliceId, roomId, { timeout: HOUR_MS * 24, timestamp: now - 12 * HOUR_MS }, "$1"),
|
||||
);
|
||||
// 10h left
|
||||
const beacon2 = new Beacon(makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ timeout: HOUR_MS * 10, timestamp: now },
|
||||
'$2',
|
||||
));
|
||||
const beacon2 = new Beacon(
|
||||
makeBeaconInfoEvent(aliceId, roomId, { timeout: HOUR_MS * 10, timestamp: now }, "$2"),
|
||||
);
|
||||
|
||||
// 1ms left
|
||||
const beacon3 = new Beacon(makeBeaconInfoEvent(aliceId,
|
||||
roomId,
|
||||
{ timeout: HOUR_MS + 1, timestamp: now - HOUR_MS },
|
||||
'$3',
|
||||
));
|
||||
const beacon3 = new Beacon(
|
||||
makeBeaconInfoEvent(aliceId, roomId, { timeout: HOUR_MS + 1, timestamp: now - HOUR_MS }, "$3"),
|
||||
);
|
||||
|
||||
it('sorts beacons by descending creation time', () => {
|
||||
expect([beacon1, beacon2, beacon3].sort(sortBeaconsByLatestCreation)).toEqual([
|
||||
beacon2, beacon3, beacon1,
|
||||
]);
|
||||
it("sorts beacons by descending creation time", () => {
|
||||
expect([beacon1, beacon2, beacon3].sort(sortBeaconsByLatestCreation)).toEqual([beacon2, beacon3, beacon1]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -24,13 +24,9 @@ import {
|
||||
watchPosition,
|
||||
} from "../../../src/utils/beacon";
|
||||
import { getCurrentPosition } from "../../../src/utils/beacon/geolocation";
|
||||
import {
|
||||
makeGeolocationPosition,
|
||||
mockGeolocation,
|
||||
getMockGeolocationPositionError,
|
||||
} from "../../test-utils";
|
||||
import { makeGeolocationPosition, mockGeolocation, getMockGeolocationPositionError } from "../../test-utils";
|
||||
|
||||
describe('geolocation utilities', () => {
|
||||
describe("geolocation utilities", () => {
|
||||
let geolocation;
|
||||
const defaultPosition = makeGeolocationPosition({});
|
||||
|
||||
@ -39,15 +35,15 @@ describe('geolocation utilities', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
geolocation = mockGeolocation();
|
||||
jest.spyOn(Date, 'now').mockReturnValue(now);
|
||||
jest.spyOn(Date, "now").mockReturnValue(now);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.spyOn(Date, 'now').mockRestore();
|
||||
jest.spyOn(logger, 'error').mockRestore();
|
||||
jest.spyOn(Date, "now").mockRestore();
|
||||
jest.spyOn(logger, "error").mockRestore();
|
||||
});
|
||||
|
||||
describe('getGeoUri', () => {
|
||||
describe("getGeoUri", () => {
|
||||
it("Renders a URI with only lat and lon", () => {
|
||||
const pos = {
|
||||
latitude: 43.2,
|
||||
@ -106,50 +102,51 @@ describe('geolocation utilities', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapGeolocationError', () => {
|
||||
describe("mapGeolocationError", () => {
|
||||
beforeEach(() => {
|
||||
// suppress expected errors from test log
|
||||
jest.spyOn(logger, 'error').mockImplementation(() => { });
|
||||
jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||
});
|
||||
|
||||
it('returns default for other error', () => {
|
||||
const error = new Error('oh no..');
|
||||
it("returns default for other error", () => {
|
||||
const error = new Error("oh no..");
|
||||
expect(mapGeolocationError(error)).toEqual(GeolocationError.Default);
|
||||
});
|
||||
|
||||
it('returns unavailable for unavailable error', () => {
|
||||
it("returns unavailable for unavailable error", () => {
|
||||
const error = new Error(GeolocationError.Unavailable);
|
||||
expect(mapGeolocationError(error)).toEqual(GeolocationError.Unavailable);
|
||||
});
|
||||
|
||||
it('maps geo error permissiondenied correctly', () => {
|
||||
const error = getMockGeolocationPositionError(1, 'message');
|
||||
it("maps geo error permissiondenied correctly", () => {
|
||||
const error = getMockGeolocationPositionError(1, "message");
|
||||
expect(mapGeolocationError(error)).toEqual(GeolocationError.PermissionDenied);
|
||||
});
|
||||
|
||||
it('maps geo position unavailable error correctly', () => {
|
||||
const error = getMockGeolocationPositionError(2, 'message');
|
||||
it("maps geo position unavailable error correctly", () => {
|
||||
const error = getMockGeolocationPositionError(2, "message");
|
||||
expect(mapGeolocationError(error)).toEqual(GeolocationError.PositionUnavailable);
|
||||
});
|
||||
|
||||
it('maps geo timeout error correctly', () => {
|
||||
const error = getMockGeolocationPositionError(3, 'message');
|
||||
it("maps geo timeout error correctly", () => {
|
||||
const error = getMockGeolocationPositionError(3, "message");
|
||||
expect(mapGeolocationError(error)).toEqual(GeolocationError.Timeout);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapGeolocationPositionToTimedGeo()', () => {
|
||||
it('maps geolocation position correctly', () => {
|
||||
describe("mapGeolocationPositionToTimedGeo()", () => {
|
||||
it("maps geolocation position correctly", () => {
|
||||
expect(mapGeolocationPositionToTimedGeo(defaultPosition)).toEqual({
|
||||
timestamp: now, geoUri: 'geo:54.001927,-8.253491;u=1',
|
||||
timestamp: now,
|
||||
geoUri: "geo:54.001927,-8.253491;u=1",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('watchPosition()', () => {
|
||||
it('throws with unavailable error when geolocation is not available', () => {
|
||||
describe("watchPosition()", () => {
|
||||
it("throws with unavailable error when geolocation is not available", () => {
|
||||
// suppress expected errors from test log
|
||||
jest.spyOn(logger, 'error').mockImplementation(() => { });
|
||||
jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||
|
||||
// remove the mock we added
|
||||
// @ts-ignore illegal assignment to readonly property
|
||||
@ -161,7 +158,7 @@ describe('geolocation utilities', () => {
|
||||
expect(() => watchPosition(positionHandler, errorHandler)).toThrow(GeolocationError.Unavailable);
|
||||
});
|
||||
|
||||
it('sets up position handler with correct options', () => {
|
||||
it("sets up position handler with correct options", () => {
|
||||
const positionHandler = jest.fn();
|
||||
const errorHandler = jest.fn();
|
||||
watchPosition(positionHandler, errorHandler);
|
||||
@ -173,7 +170,7 @@ describe('geolocation utilities', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns clearWatch function', () => {
|
||||
it("returns clearWatch function", () => {
|
||||
const watchId = 1;
|
||||
geolocation.watchPosition.mockReturnValue(watchId);
|
||||
const positionHandler = jest.fn();
|
||||
@ -185,7 +182,7 @@ describe('geolocation utilities', () => {
|
||||
expect(geolocation.clearWatch).toHaveBeenCalledWith(watchId);
|
||||
});
|
||||
|
||||
it('calls position handler with position', () => {
|
||||
it("calls position handler with position", () => {
|
||||
const positionHandler = jest.fn();
|
||||
const errorHandler = jest.fn();
|
||||
watchPosition(positionHandler, errorHandler);
|
||||
@ -193,11 +190,11 @@ describe('geolocation utilities', () => {
|
||||
expect(positionHandler).toHaveBeenCalledWith(defaultPosition);
|
||||
});
|
||||
|
||||
it('maps geolocation position error and calls error handler', () => {
|
||||
it("maps geolocation position error and calls error handler", () => {
|
||||
// suppress expected errors from test log
|
||||
jest.spyOn(logger, 'error').mockImplementation(() => { });
|
||||
geolocation.watchPosition.mockImplementation(
|
||||
(_callback, error) => error(getMockGeolocationPositionError(1, 'message')),
|
||||
jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||
geolocation.watchPosition.mockImplementation((_callback, error) =>
|
||||
error(getMockGeolocationPositionError(1, "message")),
|
||||
);
|
||||
const positionHandler = jest.fn();
|
||||
const errorHandler = jest.fn();
|
||||
@ -207,10 +204,10 @@ describe('geolocation utilities', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCurrentPosition()', () => {
|
||||
it('throws with unavailable error when geolocation is not available', async () => {
|
||||
describe("getCurrentPosition()", () => {
|
||||
it("throws with unavailable error when geolocation is not available", async () => {
|
||||
// suppress expected errors from test log
|
||||
jest.spyOn(logger, 'error').mockImplementation(() => { });
|
||||
jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||
|
||||
// remove the mock we added
|
||||
// @ts-ignore illegal assignment to readonly property
|
||||
@ -219,17 +216,17 @@ describe('geolocation utilities', () => {
|
||||
await expect(() => getCurrentPosition()).rejects.toThrow(GeolocationError.Unavailable);
|
||||
});
|
||||
|
||||
it('throws with geolocation error when geolocation.getCurrentPosition fails', async () => {
|
||||
it("throws with geolocation error when geolocation.getCurrentPosition fails", async () => {
|
||||
// suppress expected errors from test log
|
||||
jest.spyOn(logger, 'error').mockImplementation(() => { });
|
||||
jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||
|
||||
const timeoutError = getMockGeolocationPositionError(3, 'message');
|
||||
const timeoutError = getMockGeolocationPositionError(3, "message");
|
||||
geolocation.getCurrentPosition.mockImplementation((callback, error) => error(timeoutError));
|
||||
|
||||
await expect(() => getCurrentPosition()).rejects.toThrow(GeolocationError.Timeout);
|
||||
});
|
||||
|
||||
it('resolves with current location', async () => {
|
||||
it("resolves with current location", async () => {
|
||||
geolocation.getCurrentPosition.mockImplementation((callback, error) => callback(defaultPosition));
|
||||
|
||||
const result = await getCurrentPosition();
|
||||
|
@ -19,28 +19,28 @@ import { EventType, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { shouldDisplayAsBeaconTile } from "../../../src/utils/beacon/timeline";
|
||||
import { makeBeaconInfoEvent } from "../../test-utils";
|
||||
|
||||
describe('shouldDisplayAsBeaconTile', () => {
|
||||
const userId = '@user:server';
|
||||
const roomId = '!room:server';
|
||||
describe("shouldDisplayAsBeaconTile", () => {
|
||||
const userId = "@user:server";
|
||||
const roomId = "!room:server";
|
||||
const liveBeacon = makeBeaconInfoEvent(userId, roomId, { isLive: true });
|
||||
const notLiveBeacon = makeBeaconInfoEvent(userId, roomId, { isLive: false });
|
||||
const memberEvent = new MatrixEvent({ type: EventType.RoomMember });
|
||||
const redactedBeacon = makeBeaconInfoEvent(userId, roomId, { isLive: false });
|
||||
redactedBeacon.makeRedacted(redactedBeacon);
|
||||
|
||||
it('returns true for a beacon with live property set to true', () => {
|
||||
it("returns true for a beacon with live property set to true", () => {
|
||||
expect(shouldDisplayAsBeaconTile(liveBeacon)).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for a redacted beacon', () => {
|
||||
it("returns true for a redacted beacon", () => {
|
||||
expect(shouldDisplayAsBeaconTile(redactedBeacon)).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false for a beacon with live property set to false', () => {
|
||||
it("returns false for a beacon with live property set to false", () => {
|
||||
expect(shouldDisplayAsBeaconTile(notLiveBeacon)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for a non beacon event', () => {
|
||||
it("returns false for a non beacon event", () => {
|
||||
expect(shouldDisplayAsBeaconTile(memberEvent)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@ -17,8 +17,8 @@ limitations under the License.
|
||||
import { textToHtmlRainbow } from "../../src/utils/colour";
|
||||
|
||||
describe("textToHtmlRainbow", () => {
|
||||
it('correctly transform text to html without splitting the emoji in two', () => {
|
||||
expect(textToHtmlRainbow('🐻')).toBe('<font color="#ff00be">🐻</font>');
|
||||
expect(textToHtmlRainbow('🐕🦺')).toBe('<font color="#ff00be">🐕🦺</font>');
|
||||
it("correctly transform text to html without splitting the emoji in two", () => {
|
||||
expect(textToHtmlRainbow("🐻")).toBe('<font color="#ff00be">🐻</font>');
|
||||
expect(textToHtmlRainbow("🐕🦺")).toBe('<font color="#ff00be">🐕🦺</font>');
|
||||
});
|
||||
});
|
||||
|
@ -20,13 +20,15 @@ import { createVoiceMessageContent } from "../../src/utils/createVoiceMessageCon
|
||||
|
||||
describe("createVoiceMessageContent", () => {
|
||||
it("should create a voice message content", () => {
|
||||
expect(createVoiceMessageContent(
|
||||
"mxc://example.com/file",
|
||||
"ogg/opus",
|
||||
23000,
|
||||
42000,
|
||||
{} as unknown as IEncryptedFile,
|
||||
[1, 2, 3],
|
||||
)).toMatchSnapshot();
|
||||
expect(
|
||||
createVoiceMessageContent(
|
||||
"mxc://example.com/file",
|
||||
"ogg/opus",
|
||||
23000,
|
||||
42000,
|
||||
{} as unknown as IEncryptedFile,
|
||||
[1, 2, 3],
|
||||
),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -18,15 +18,12 @@ import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import BasePlatform from "../../../src/BasePlatform";
|
||||
import { IConfigOptions } from "../../../src/IConfigOptions";
|
||||
import {
|
||||
getDeviceClientInformation,
|
||||
recordClientInformation,
|
||||
} from "../../../src/utils/device/clientInformation";
|
||||
import { getDeviceClientInformation, recordClientInformation } from "../../../src/utils/device/clientInformation";
|
||||
import { getMockClientWithEventEmitter } from "../../test-utils";
|
||||
|
||||
describe('recordClientInformation()', () => {
|
||||
const deviceId = 'my-device-id';
|
||||
const version = '1.2.3';
|
||||
describe("recordClientInformation()", () => {
|
||||
const deviceId = "my-device-id";
|
||||
const version = "1.2.3";
|
||||
const isElectron = window.electron;
|
||||
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
@ -35,8 +32,8 @@ describe('recordClientInformation()', () => {
|
||||
});
|
||||
|
||||
const sdkConfig: IConfigOptions = {
|
||||
brand: 'Test Brand',
|
||||
element_call: { url: '', use_exclusively: false, brand: "Element Call" },
|
||||
brand: "Test Brand",
|
||||
element_call: { url: "", use_exclusively: false, brand: "Element Call" },
|
||||
};
|
||||
|
||||
const platform = {
|
||||
@ -53,45 +50,31 @@ describe('recordClientInformation()', () => {
|
||||
window.electron = isElectron;
|
||||
});
|
||||
|
||||
it('saves client information without url for electron clients', async () => {
|
||||
it("saves client information without url for electron clients", async () => {
|
||||
window.electron = true;
|
||||
|
||||
await recordClientInformation(
|
||||
mockClient,
|
||||
sdkConfig,
|
||||
platform,
|
||||
);
|
||||
await recordClientInformation(mockClient, sdkConfig, platform);
|
||||
|
||||
expect(mockClient.setAccountData).toHaveBeenCalledWith(
|
||||
`io.element.matrix_client_information.${deviceId}`,
|
||||
{
|
||||
name: sdkConfig.brand,
|
||||
version,
|
||||
url: undefined,
|
||||
},
|
||||
);
|
||||
expect(mockClient.setAccountData).toHaveBeenCalledWith(`io.element.matrix_client_information.${deviceId}`, {
|
||||
name: sdkConfig.brand,
|
||||
version,
|
||||
url: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('saves client information with url for non-electron clients', async () => {
|
||||
await recordClientInformation(
|
||||
mockClient,
|
||||
sdkConfig,
|
||||
platform,
|
||||
);
|
||||
it("saves client information with url for non-electron clients", async () => {
|
||||
await recordClientInformation(mockClient, sdkConfig, platform);
|
||||
|
||||
expect(mockClient.setAccountData).toHaveBeenCalledWith(
|
||||
`io.element.matrix_client_information.${deviceId}`,
|
||||
{
|
||||
name: sdkConfig.brand,
|
||||
version,
|
||||
url: 'localhost',
|
||||
},
|
||||
);
|
||||
expect(mockClient.setAccountData).toHaveBeenCalledWith(`io.element.matrix_client_information.${deviceId}`, {
|
||||
name: sdkConfig.brand,
|
||||
version,
|
||||
url: "localhost",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDeviceClientInformation()', () => {
|
||||
const deviceId = 'my-device-id';
|
||||
describe("getDeviceClientInformation()", () => {
|
||||
const deviceId = "my-device-id";
|
||||
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getAccountData: jest.fn(),
|
||||
@ -101,19 +84,17 @@ describe('getDeviceClientInformation()', () => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('returns an empty object when no event exists for the device', () => {
|
||||
it("returns an empty object when no event exists for the device", () => {
|
||||
expect(getDeviceClientInformation(mockClient, deviceId)).toEqual({});
|
||||
|
||||
expect(mockClient.getAccountData).toHaveBeenCalledWith(
|
||||
`io.element.matrix_client_information.${deviceId}`,
|
||||
);
|
||||
expect(mockClient.getAccountData).toHaveBeenCalledWith(`io.element.matrix_client_information.${deviceId}`);
|
||||
});
|
||||
|
||||
it('returns client information for the device', () => {
|
||||
it("returns client information for the device", () => {
|
||||
const eventContent = {
|
||||
name: 'Element Web',
|
||||
version: '1.2.3',
|
||||
url: 'test.com',
|
||||
name: "Element Web",
|
||||
version: "1.2.3",
|
||||
url: "test.com",
|
||||
};
|
||||
const event = new MatrixEvent({
|
||||
type: `io.element.matrix_client_information.${deviceId}`,
|
||||
@ -123,13 +104,13 @@ describe('getDeviceClientInformation()', () => {
|
||||
expect(getDeviceClientInformation(mockClient, deviceId)).toEqual(eventContent);
|
||||
});
|
||||
|
||||
it('excludes values with incorrect types', () => {
|
||||
it("excludes values with incorrect types", () => {
|
||||
const eventContent = {
|
||||
extraField: 'hello',
|
||||
name: 'Element Web',
|
||||
extraField: "hello",
|
||||
name: "Element Web",
|
||||
// wrong format
|
||||
version: { value: '1.2.3' },
|
||||
url: 'test.com',
|
||||
version: { value: "1.2.3" },
|
||||
url: "test.com",
|
||||
};
|
||||
const event = new MatrixEvent({
|
||||
type: `io.element.matrix_client_information.${deviceId}`,
|
||||
@ -143,4 +124,3 @@ describe('getDeviceClientInformation()', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -26,7 +26,7 @@ const makeDeviceExtendedInfo = (
|
||||
deviceType,
|
||||
deviceModel,
|
||||
deviceOperatingSystem,
|
||||
client: clientName && [clientName, clientVersion].filter(Boolean).join(' '),
|
||||
client: clientName && [clientName, clientVersion].filter(Boolean).join(" "),
|
||||
});
|
||||
|
||||
/* eslint-disable max-len */
|
||||
@ -66,7 +66,7 @@ const IOS_EXPECTED_RESULT = [
|
||||
];
|
||||
const DESKTOP_UA = [
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) ElementNightly/2022091301 Chrome/104.0.5112.102" +
|
||||
" Electron/20.1.1 Safari/537.36",
|
||||
" Electron/20.1.1 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) ElementNightly/2022091301 Chrome/104.0.5112.102 Electron/20.1.1 Safari/537.36",
|
||||
];
|
||||
const DESKTOP_EXPECTED_RESULT = [
|
||||
@ -98,7 +98,6 @@ const WEB_EXPECTED_RESULT = [
|
||||
makeDeviceExtendedInfo(DeviceType.Web, "Apple iPad", "iOS", "Mobile Safari", "8.0"),
|
||||
makeDeviceExtendedInfo(DeviceType.Web, "Apple iPhone", "iOS", "Mobile Safari", "8.0"),
|
||||
makeDeviceExtendedInfo(DeviceType.Web, "Samsung SM-G973U", "Android", "Chrome", "69.0.3497.100"),
|
||||
|
||||
];
|
||||
|
||||
const MISC_UA = [
|
||||
@ -119,8 +118,8 @@ const MISC_EXPECTED_RESULT = [
|
||||
];
|
||||
/* eslint-disable max-len */
|
||||
|
||||
describe('parseUserAgent()', () => {
|
||||
it('returns deviceType unknown when user agent is falsy', () => {
|
||||
describe("parseUserAgent()", () => {
|
||||
it("returns deviceType unknown when user agent is falsy", () => {
|
||||
expect(parseUserAgent(undefined)).toEqual({
|
||||
deviceType: DeviceType.Unknown,
|
||||
});
|
||||
@ -132,17 +131,15 @@ describe('parseUserAgent()', () => {
|
||||
const testCases: TestCase[] = userAgents.map((userAgent, index) => [userAgent, results[index]]);
|
||||
|
||||
describe(platform, () => {
|
||||
it.each(
|
||||
testCases,
|
||||
)('Parses user agent correctly - %s', (userAgent, expectedResult) => {
|
||||
it.each(testCases)("Parses user agent correctly - %s", (userAgent, expectedResult) => {
|
||||
expect(parseUserAgent(userAgent)).toEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
testPlatform('Android', ANDROID_UA, ANDROID_EXPECTED_RESULT);
|
||||
testPlatform('iOS', IOS_UA, IOS_EXPECTED_RESULT);
|
||||
testPlatform('Desktop', DESKTOP_UA, DESKTOP_EXPECTED_RESULT);
|
||||
testPlatform('Web', WEB_UA, WEB_EXPECTED_RESULT);
|
||||
testPlatform('Misc', MISC_UA, MISC_EXPECTED_RESULT);
|
||||
testPlatform("Android", ANDROID_UA, ANDROID_EXPECTED_RESULT);
|
||||
testPlatform("iOS", IOS_UA, IOS_EXPECTED_RESULT);
|
||||
testPlatform("Desktop", DESKTOP_UA, DESKTOP_EXPECTED_RESULT);
|
||||
testPlatform("Web", WEB_UA, WEB_EXPECTED_RESULT);
|
||||
testPlatform("Misc", MISC_UA, MISC_EXPECTED_RESULT);
|
||||
});
|
||||
|
@ -21,12 +21,12 @@ import {
|
||||
snoozeBulkUnverifiedDeviceReminder,
|
||||
} from "../../../src/utils/device/snoozeBulkUnverifiedDeviceReminder";
|
||||
|
||||
const SNOOZE_KEY = 'mx_snooze_bulk_unverified_device_nag';
|
||||
const SNOOZE_KEY = "mx_snooze_bulk_unverified_device_nag";
|
||||
|
||||
describe('snooze bulk unverified device nag', () => {
|
||||
const localStorageSetSpy = jest.spyOn(localStorage.__proto__, 'setItem');
|
||||
const localStorageGetSpy = jest.spyOn(localStorage.__proto__, 'getItem');
|
||||
const localStorageRemoveSpy = jest.spyOn(localStorage.__proto__, 'removeItem');
|
||||
describe("snooze bulk unverified device nag", () => {
|
||||
const localStorageSetSpy = jest.spyOn(localStorage.__proto__, "setItem");
|
||||
const localStorageGetSpy = jest.spyOn(localStorage.__proto__, "getItem");
|
||||
const localStorageRemoveSpy = jest.spyOn(localStorage.__proto__, "removeItem");
|
||||
|
||||
// 14.03.2022 16:15
|
||||
const now = 1647270879403;
|
||||
@ -36,61 +36,65 @@ describe('snooze bulk unverified device nag', () => {
|
||||
localStorageGetSpy.mockClear().mockReturnValue(null);
|
||||
localStorageRemoveSpy.mockClear().mockImplementation(() => {});
|
||||
|
||||
jest.spyOn(Date, 'now').mockReturnValue(now);
|
||||
jest.spyOn(Date, "now").mockReturnValue(now);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('snoozeBulkUnverifiedDeviceReminder()', () => {
|
||||
it('sets the current time in local storage', () => {
|
||||
describe("snoozeBulkUnverifiedDeviceReminder()", () => {
|
||||
it("sets the current time in local storage", () => {
|
||||
snoozeBulkUnverifiedDeviceReminder();
|
||||
|
||||
expect(localStorageSetSpy).toHaveBeenCalledWith(SNOOZE_KEY, now.toString());
|
||||
});
|
||||
|
||||
it('catches an error from localstorage', () => {
|
||||
const loggerErrorSpy = jest.spyOn(logger, 'error');
|
||||
localStorageSetSpy.mockImplementation(() => { throw new Error('oups'); });
|
||||
it("catches an error from localstorage", () => {
|
||||
const loggerErrorSpy = jest.spyOn(logger, "error");
|
||||
localStorageSetSpy.mockImplementation(() => {
|
||||
throw new Error("oups");
|
||||
});
|
||||
snoozeBulkUnverifiedDeviceReminder();
|
||||
expect(loggerErrorSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isBulkUnverifiedDeviceReminderSnoozed()', () => {
|
||||
it('returns false when there is no snooze in storage', () => {
|
||||
describe("isBulkUnverifiedDeviceReminderSnoozed()", () => {
|
||||
it("returns false when there is no snooze in storage", () => {
|
||||
const result = isBulkUnverifiedDeviceReminderSnoozed();
|
||||
expect(localStorageGetSpy).toHaveBeenCalledWith(SNOOZE_KEY);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('catches an error from localstorage and returns false', () => {
|
||||
const loggerErrorSpy = jest.spyOn(logger, 'error');
|
||||
localStorageGetSpy.mockImplementation(() => { throw new Error('oups'); });
|
||||
it("catches an error from localstorage and returns false", () => {
|
||||
const loggerErrorSpy = jest.spyOn(logger, "error");
|
||||
localStorageGetSpy.mockImplementation(() => {
|
||||
throw new Error("oups");
|
||||
});
|
||||
const result = isBulkUnverifiedDeviceReminderSnoozed();
|
||||
expect(result).toBe(false);
|
||||
expect(loggerErrorSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returns false when snooze timestamp in storage is not a number', () => {
|
||||
localStorageGetSpy.mockReturnValue('test');
|
||||
it("returns false when snooze timestamp in storage is not a number", () => {
|
||||
localStorageGetSpy.mockReturnValue("test");
|
||||
const result = isBulkUnverifiedDeviceReminderSnoozed();
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false when snooze timestamp in storage is over a week ago', () => {
|
||||
it("returns false when snooze timestamp in storage is over a week ago", () => {
|
||||
const msDay = 1000 * 60 * 60 * 24;
|
||||
// snoozed 8 days ago
|
||||
localStorageGetSpy.mockReturnValue(now - (msDay * 8));
|
||||
localStorageGetSpy.mockReturnValue(now - msDay * 8);
|
||||
const result = isBulkUnverifiedDeviceReminderSnoozed();
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('returns true when snooze timestamp in storage is less than a week ago', () => {
|
||||
it("returns true when snooze timestamp in storage is less than a week ago", () => {
|
||||
const msDay = 1000 * 60 * 60 * 24;
|
||||
// snoozed 8 days ago
|
||||
localStorageGetSpy.mockReturnValue(now - (msDay * 6));
|
||||
localStorageGetSpy.mockReturnValue(now - msDay * 6);
|
||||
const result = isBulkUnverifiedDeviceReminderSnoozed();
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
@ -158,18 +158,12 @@ describe("direct-messages", () => {
|
||||
mocked(startDm).mockResolvedValue(room1.roomId);
|
||||
});
|
||||
|
||||
it(
|
||||
"should set the room into creating state and call waitForRoomReadyAndApplyAfterCreateCallbacks",
|
||||
async () => {
|
||||
const result = await dmModule.createRoomFromLocalRoom(mockClient, localRoom);
|
||||
expect(result).toBe(room1.roomId);
|
||||
expect(localRoom.state).toBe(LocalRoomState.CREATING);
|
||||
expect(waitForRoomReadyAndApplyAfterCreateCallbacks).toHaveBeenCalledWith(
|
||||
mockClient,
|
||||
localRoom,
|
||||
);
|
||||
},
|
||||
);
|
||||
it("should set the room into creating state and call waitForRoomReadyAndApplyAfterCreateCallbacks", async () => {
|
||||
const result = await dmModule.createRoomFromLocalRoom(mockClient, localRoom);
|
||||
expect(result).toBe(room1.roomId);
|
||||
expect(localRoom.state).toBe(LocalRoomState.CREATING);
|
||||
expect(waitForRoomReadyAndApplyAfterCreateCallbacks).toHaveBeenCalledWith(mockClient, localRoom);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -26,16 +26,16 @@ enum TestNumberEnum {
|
||||
SecondKey = 20,
|
||||
}
|
||||
|
||||
describe('enums', () => {
|
||||
describe('getEnumValues', () => {
|
||||
it('should work on string enums', () => {
|
||||
describe("enums", () => {
|
||||
describe("getEnumValues", () => {
|
||||
it("should work on string enums", () => {
|
||||
const result = getEnumValues(TestStringEnum);
|
||||
expect(result).toBeDefined();
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result).toEqual(['__first__', '__second__']);
|
||||
expect(result).toEqual(["__first__", "__second__"]);
|
||||
});
|
||||
|
||||
it('should work on number enums', () => {
|
||||
it("should work on number enums", () => {
|
||||
const result = getEnumValues(TestNumberEnum);
|
||||
expect(result).toBeDefined();
|
||||
expect(result).toHaveLength(2);
|
||||
@ -43,23 +43,23 @@ describe('enums', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('isEnumValue', () => {
|
||||
it('should return true on values in a string enum', () => {
|
||||
const result = isEnumValue(TestStringEnum, '__first__');
|
||||
describe("isEnumValue", () => {
|
||||
it("should return true on values in a string enum", () => {
|
||||
const result = isEnumValue(TestStringEnum, "__first__");
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false on values not in a string enum', () => {
|
||||
const result = isEnumValue(TestStringEnum, 'not a value');
|
||||
it("should return false on values not in a string enum", () => {
|
||||
const result = isEnumValue(TestStringEnum, "not a value");
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true on values in a number enum', () => {
|
||||
it("should return true on values in a number enum", () => {
|
||||
const result = isEnumValue(TestNumberEnum, 10);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false on values not in a number enum', () => {
|
||||
it("should return false on values not in a number enum", () => {
|
||||
const result = isEnumValue(TestStringEnum, 99);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
@ -29,22 +29,22 @@ import { MatrixClientPeg } from "../../src/MatrixClientPeg";
|
||||
import { IExportOptions, ExportType, ExportFormat } from "../../src/utils/exportUtils/exportUtils";
|
||||
import PlainTextExporter from "../../src/utils/exportUtils/PlainTextExport";
|
||||
import HTMLExporter from "../../src/utils/exportUtils/HtmlExport";
|
||||
import * as TestUtilsMatrix from '../test-utils';
|
||||
import { stubClient } from '../test-utils';
|
||||
import * as TestUtilsMatrix from "../test-utils";
|
||||
import { stubClient } from "../test-utils";
|
||||
|
||||
let client: MatrixClient;
|
||||
|
||||
const MY_USER_ID = "@me:here";
|
||||
|
||||
function generateRoomId() {
|
||||
return '!' + Math.random().toString().slice(2, 10) + ':domain';
|
||||
return "!" + Math.random().toString().slice(2, 10) + ":domain";
|
||||
}
|
||||
|
||||
interface ITestContent extends IContent {
|
||||
expectedText: string;
|
||||
}
|
||||
|
||||
describe('export', function() {
|
||||
describe("export", function () {
|
||||
stubClient();
|
||||
client = MatrixClientPeg.get();
|
||||
client.getUserId = () => {
|
||||
@ -71,20 +71,20 @@ describe('export', function() {
|
||||
sender: MY_USER_ID,
|
||||
content: {},
|
||||
unsigned: {
|
||||
"age": 72,
|
||||
"transaction_id": "m1212121212.23",
|
||||
"redacted_because": {
|
||||
"content": {},
|
||||
"origin_server_ts": ts0 + i*1000,
|
||||
"redacts": "$9999999999999999999999999999999999999999998",
|
||||
"sender": "@me:here",
|
||||
"type": EventType.RoomRedaction,
|
||||
"unsigned": {
|
||||
"age": 94,
|
||||
"transaction_id": "m1111111111.1",
|
||||
age: 72,
|
||||
transaction_id: "m1212121212.23",
|
||||
redacted_because: {
|
||||
content: {},
|
||||
origin_server_ts: ts0 + i * 1000,
|
||||
redacts: "$9999999999999999999999999999999999999999998",
|
||||
sender: "@me:here",
|
||||
type: EventType.RoomRedaction,
|
||||
unsigned: {
|
||||
age: 94,
|
||||
transaction_id: "m1111111111.1",
|
||||
},
|
||||
"event_id": "$9999999999999999999999999999999999999999998",
|
||||
"room_id": mockRoom.roomId,
|
||||
event_id: "$9999999999999999999999999999999999999999998",
|
||||
room_id: mockRoom.roomId,
|
||||
},
|
||||
},
|
||||
event_id: "$9999999999999999999999999999999999999999999",
|
||||
@ -94,47 +94,47 @@ describe('export', function() {
|
||||
|
||||
function mkFileEvent() {
|
||||
return new MatrixEvent({
|
||||
"content": {
|
||||
"body": "index.html",
|
||||
"info": {
|
||||
"mimetype": "text/html",
|
||||
"size": 31613,
|
||||
content: {
|
||||
body: "index.html",
|
||||
info: {
|
||||
mimetype: "text/html",
|
||||
size: 31613,
|
||||
},
|
||||
"msgtype": "m.file",
|
||||
"url": "mxc://test.org",
|
||||
msgtype: "m.file",
|
||||
url: "mxc://test.org",
|
||||
},
|
||||
"origin_server_ts": 1628872988364,
|
||||
"sender": MY_USER_ID,
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 266,
|
||||
"transaction_id": "m99999999.2",
|
||||
origin_server_ts: 1628872988364,
|
||||
sender: MY_USER_ID,
|
||||
type: "m.room.message",
|
||||
unsigned: {
|
||||
age: 266,
|
||||
transaction_id: "m99999999.2",
|
||||
},
|
||||
"event_id": "$99999999999999999999",
|
||||
"room_id": mockRoom.roomId,
|
||||
event_id: "$99999999999999999999",
|
||||
room_id: mockRoom.roomId,
|
||||
});
|
||||
}
|
||||
|
||||
function mkImageEvent() {
|
||||
return new MatrixEvent({
|
||||
"content": {
|
||||
"body": "image.png",
|
||||
"info": {
|
||||
"mimetype": "image/png",
|
||||
"size": 31613,
|
||||
content: {
|
||||
body: "image.png",
|
||||
info: {
|
||||
mimetype: "image/png",
|
||||
size: 31613,
|
||||
},
|
||||
"msgtype": "m.image",
|
||||
"url": "mxc://test.org",
|
||||
msgtype: "m.image",
|
||||
url: "mxc://test.org",
|
||||
},
|
||||
"origin_server_ts": 1628872988364,
|
||||
"sender": MY_USER_ID,
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 266,
|
||||
"transaction_id": "m99999999.2",
|
||||
origin_server_ts: 1628872988364,
|
||||
sender: MY_USER_ID,
|
||||
type: "m.room.message",
|
||||
unsigned: {
|
||||
age: 266,
|
||||
transaction_id: "m99999999.2",
|
||||
},
|
||||
"event_id": "$99999999999999999999",
|
||||
"room_id": mockRoom.roomId,
|
||||
event_id: "$99999999999999999999",
|
||||
room_id: mockRoom.roomId,
|
||||
});
|
||||
}
|
||||
|
||||
@ -143,62 +143,74 @@ describe('export', function() {
|
||||
let i: number;
|
||||
// plain text
|
||||
for (i = 0; i < 10; i++) {
|
||||
matrixEvents.push(TestUtilsMatrix.mkMessage({
|
||||
event: true, room: "!room:id", user: "@user:id",
|
||||
ts: ts0 + i * 1000,
|
||||
}));
|
||||
matrixEvents.push(
|
||||
TestUtilsMatrix.mkMessage({
|
||||
event: true,
|
||||
room: "!room:id",
|
||||
user: "@user:id",
|
||||
ts: ts0 + i * 1000,
|
||||
}),
|
||||
);
|
||||
}
|
||||
// reply events
|
||||
for (i = 0; i < 10; i++) {
|
||||
const eventId = "$" + Math.random() + "-" + Math.random();
|
||||
matrixEvents.push(TestUtilsMatrix.mkEvent({
|
||||
"content": {
|
||||
"body": "> <@me:here> Hi\n\nTest",
|
||||
"format": "org.matrix.custom.html",
|
||||
"m.relates_to": {
|
||||
"rel_type": RelationType.Reference,
|
||||
"event_id": eventId,
|
||||
"m.in_reply_to": {
|
||||
matrixEvents.push(
|
||||
TestUtilsMatrix.mkEvent({
|
||||
content: {
|
||||
"body": "> <@me:here> Hi\n\nTest",
|
||||
"format": "org.matrix.custom.html",
|
||||
"m.relates_to": {
|
||||
"rel_type": RelationType.Reference,
|
||||
"event_id": eventId,
|
||||
"m.in_reply_to": {
|
||||
event_id: eventId,
|
||||
},
|
||||
},
|
||||
"msgtype": "m.text",
|
||||
},
|
||||
"msgtype": "m.text",
|
||||
},
|
||||
"user": "@me:here",
|
||||
"type": "m.room.message",
|
||||
"room": mockRoom.roomId,
|
||||
"event": true,
|
||||
}));
|
||||
user: "@me:here",
|
||||
type: "m.room.message",
|
||||
room: mockRoom.roomId,
|
||||
event: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
// membership events
|
||||
for (i = 0; i < 10; i++) {
|
||||
matrixEvents.push(TestUtilsMatrix.mkMembership({
|
||||
event: true, room: "!room:id", user: "@user:id",
|
||||
target: {
|
||||
userId: "@user:id",
|
||||
name: "Bob",
|
||||
getAvatarUrl: () => {
|
||||
return "avatar.jpeg";
|
||||
},
|
||||
getMxcAvatarUrl: () => 'mxc://avatar.url/image.png',
|
||||
} as unknown as RoomMember,
|
||||
ts: ts0 + i*1000,
|
||||
mship: 'join',
|
||||
prevMship: 'join',
|
||||
name: 'A user',
|
||||
}));
|
||||
matrixEvents.push(
|
||||
TestUtilsMatrix.mkMembership({
|
||||
event: true,
|
||||
room: "!room:id",
|
||||
user: "@user:id",
|
||||
target: {
|
||||
userId: "@user:id",
|
||||
name: "Bob",
|
||||
getAvatarUrl: () => {
|
||||
return "avatar.jpeg";
|
||||
},
|
||||
getMxcAvatarUrl: () => "mxc://avatar.url/image.png",
|
||||
} as unknown as RoomMember,
|
||||
ts: ts0 + i * 1000,
|
||||
mship: "join",
|
||||
prevMship: "join",
|
||||
name: "A user",
|
||||
}),
|
||||
);
|
||||
}
|
||||
// emote
|
||||
matrixEvents.push(TestUtilsMatrix.mkEvent({
|
||||
"content": {
|
||||
"body": "waves",
|
||||
"msgtype": "m.emote",
|
||||
},
|
||||
"user": "@me:here",
|
||||
"type": "m.room.message",
|
||||
"room": mockRoom.roomId,
|
||||
"event": true,
|
||||
}));
|
||||
matrixEvents.push(
|
||||
TestUtilsMatrix.mkEvent({
|
||||
content: {
|
||||
body: "waves",
|
||||
msgtype: "m.emote",
|
||||
},
|
||||
user: "@me:here",
|
||||
type: "m.room.message",
|
||||
room: mockRoom.roomId,
|
||||
event: true,
|
||||
}),
|
||||
);
|
||||
// redacted events
|
||||
for (i = 0; i < 10; i++) {
|
||||
matrixEvents.push(mkRedactedEvent(i));
|
||||
@ -208,7 +220,7 @@ describe('export', function() {
|
||||
|
||||
const events: MatrixEvent[] = mkEvents();
|
||||
|
||||
it('checks if the export format is valid', function() {
|
||||
it("checks if the export format is valid", function () {
|
||||
function isValidFormat(format: string): boolean {
|
||||
const options: string[] = Object.values(ExportFormat);
|
||||
return options.includes(format);
|
||||
@ -219,51 +231,60 @@ describe('export', function() {
|
||||
expect(isValidFormat("Pdf")).toBeFalsy();
|
||||
});
|
||||
|
||||
it("checks if the icons' html corresponds to export regex", function() {
|
||||
it("checks if the icons' html corresponds to export regex", function () {
|
||||
const exporter = new HTMLExporter(mockRoom, ExportType.Beginning, mockExportOptions, null);
|
||||
const fileRegex = /<span class="mx_MFileBody_info_icon">.*?<\/span>/;
|
||||
expect(fileRegex.test(
|
||||
renderToString(exporter.getEventTile(mkFileEvent(), true))),
|
||||
).toBeTruthy();
|
||||
expect(fileRegex.test(renderToString(exporter.getEventTile(mkFileEvent(), true)))).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should export images if attachments are enabled", () => {
|
||||
const exporter = new HTMLExporter(mockRoom, ExportType.Beginning, {
|
||||
numberOfMessages: 5,
|
||||
maxSize: 100 * 1024 * 1024,
|
||||
attachmentsIncluded: true,
|
||||
}, null);
|
||||
const exporter = new HTMLExporter(
|
||||
mockRoom,
|
||||
ExportType.Beginning,
|
||||
{
|
||||
numberOfMessages: 5,
|
||||
maxSize: 100 * 1024 * 1024,
|
||||
attachmentsIncluded: true,
|
||||
},
|
||||
null,
|
||||
);
|
||||
const imageRegex = /<img.+ src="mxc:\/\/test.org" alt="image.png"\/>/;
|
||||
expect(imageRegex.test(
|
||||
renderToString(exporter.getEventTile(mkImageEvent(), true))),
|
||||
).toBeTruthy();
|
||||
expect(imageRegex.test(renderToString(exporter.getEventTile(mkImageEvent(), true)))).toBeTruthy();
|
||||
});
|
||||
|
||||
const invalidExportOptions: [string, IExportOptions][] = [
|
||||
['numberOfMessages exceeds max', {
|
||||
numberOfMessages: 10 ** 9,
|
||||
maxSize: 1024 * 1024 * 1024,
|
||||
attachmentsIncluded: false,
|
||||
}],
|
||||
['maxSize exceeds 8GB', {
|
||||
numberOfMessages: -1,
|
||||
maxSize: 8001 * 1024 * 1024,
|
||||
attachmentsIncluded: false,
|
||||
}],
|
||||
['maxSize is less than 1mb', {
|
||||
numberOfMessages: 0,
|
||||
maxSize: 0,
|
||||
attachmentsIncluded: false,
|
||||
}],
|
||||
[
|
||||
"numberOfMessages exceeds max",
|
||||
{
|
||||
numberOfMessages: 10 ** 9,
|
||||
maxSize: 1024 * 1024 * 1024,
|
||||
attachmentsIncluded: false,
|
||||
},
|
||||
],
|
||||
[
|
||||
"maxSize exceeds 8GB",
|
||||
{
|
||||
numberOfMessages: -1,
|
||||
maxSize: 8001 * 1024 * 1024,
|
||||
attachmentsIncluded: false,
|
||||
},
|
||||
],
|
||||
[
|
||||
"maxSize is less than 1mb",
|
||||
{
|
||||
numberOfMessages: 0,
|
||||
maxSize: 0,
|
||||
attachmentsIncluded: false,
|
||||
},
|
||||
],
|
||||
];
|
||||
it.each(invalidExportOptions)('%s', (_d, options) => {
|
||||
expect(
|
||||
() =>
|
||||
new PlainTextExporter(mockRoom, ExportType.Beginning, options, null),
|
||||
).toThrowError("Invalid export options");
|
||||
it.each(invalidExportOptions)("%s", (_d, options) => {
|
||||
expect(() => new PlainTextExporter(mockRoom, ExportType.Beginning, options, null)).toThrowError(
|
||||
"Invalid export options",
|
||||
);
|
||||
});
|
||||
|
||||
it('tests the file extension splitter', function() {
|
||||
it("tests the file extension splitter", function () {
|
||||
const exporter = new PlainTextExporter(mockRoom, ExportType.Beginning, mockExportOptions, null);
|
||||
const fileNameWithExtensions = {
|
||||
"": ["", ""],
|
||||
@ -277,28 +298,28 @@ describe('export', function() {
|
||||
}
|
||||
});
|
||||
|
||||
it('checks if the reply regex executes correctly', function() {
|
||||
it("checks if the reply regex executes correctly", function () {
|
||||
const eventContents: ITestContent[] = [
|
||||
{
|
||||
"msgtype": "m.text",
|
||||
"body": "> <@me:here> Source\n\nReply",
|
||||
"expectedText": "<@me:here \"Source\"> Reply",
|
||||
msgtype: "m.text",
|
||||
body: "> <@me:here> Source\n\nReply",
|
||||
expectedText: '<@me:here "Source"> Reply',
|
||||
},
|
||||
{
|
||||
"msgtype": "m.text",
|
||||
msgtype: "m.text",
|
||||
// if the reply format is invalid, then return the body
|
||||
"body": "Invalid reply format",
|
||||
"expectedText": "Invalid reply format",
|
||||
body: "Invalid reply format",
|
||||
expectedText: "Invalid reply format",
|
||||
},
|
||||
{
|
||||
"msgtype": "m.text",
|
||||
"body": "> <@me:here> The source is more than 32 characters\n\nReply",
|
||||
"expectedText": "<@me:here \"The source is more than 32 chara...\"> Reply",
|
||||
msgtype: "m.text",
|
||||
body: "> <@me:here> The source is more than 32 characters\n\nReply",
|
||||
expectedText: '<@me:here "The source is more than 32 chara..."> Reply',
|
||||
},
|
||||
{
|
||||
"msgtype": "m.text",
|
||||
"body": "> <@me:here> This\nsource\nhas\nnew\nlines\n\nReply",
|
||||
"expectedText": "<@me:here \"This\"> Reply",
|
||||
msgtype: "m.text",
|
||||
body: "> <@me:here> This\nsource\nhas\nnew\nlines\n\nReply",
|
||||
expectedText: '<@me:here "This"> Reply',
|
||||
},
|
||||
];
|
||||
const exporter = new PlainTextExporter(mockRoom, ExportType.Beginning, mockExportOptions, null);
|
||||
@ -307,11 +328,10 @@ describe('export', function() {
|
||||
}
|
||||
});
|
||||
|
||||
it("checks if the render to string doesn't throw any error for different types of events", function() {
|
||||
it("checks if the render to string doesn't throw any error for different types of events", function () {
|
||||
const exporter = new HTMLExporter(mockRoom, ExportType.Beginning, mockExportOptions, null);
|
||||
for (const event of events) {
|
||||
expect(renderToString(exporter.getEventTile(event, false))).toBeTruthy();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -16,9 +16,9 @@ limitations under the License.
|
||||
|
||||
import { iterableDiff, iterableIntersection } from "../../src/utils/iterables";
|
||||
|
||||
describe('iterables', () => {
|
||||
describe('iterableIntersection', () => {
|
||||
it('should return the intersection', () => {
|
||||
describe("iterables", () => {
|
||||
describe("iterableIntersection", () => {
|
||||
it("should return the intersection", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [1, 2, 4]; // note diff
|
||||
const result = iterableIntersection(a, b);
|
||||
@ -27,7 +27,7 @@ describe('iterables', () => {
|
||||
expect(result).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
it('should return an empty array on no matches', () => {
|
||||
it("should return an empty array on no matches", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [4, 5, 6];
|
||||
const result = iterableIntersection(a, b);
|
||||
@ -36,8 +36,8 @@ describe('iterables', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('iterableDiff', () => {
|
||||
it('should see added from A->B', () => {
|
||||
describe("iterableDiff", () => {
|
||||
it("should see added from A->B", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [1, 2, 3, 4];
|
||||
const result = iterableDiff(a, b);
|
||||
@ -49,7 +49,7 @@ describe('iterables', () => {
|
||||
expect(result.added).toEqual([4]);
|
||||
});
|
||||
|
||||
it('should see removed from A->B', () => {
|
||||
it("should see removed from A->B", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [1, 2];
|
||||
const result = iterableDiff(a, b);
|
||||
@ -61,7 +61,7 @@ describe('iterables', () => {
|
||||
expect(result.removed).toEqual([3]);
|
||||
});
|
||||
|
||||
it('should see added and removed in the same set', () => {
|
||||
it("should see added and removed in the same set", () => {
|
||||
const a = [1, 2, 3];
|
||||
const b = [1, 2, 4]; // note diff
|
||||
const result = iterableDiff(a, b);
|
||||
|
@ -45,11 +45,14 @@ describe("leaveRoomBehaviour", () => {
|
||||
room = mkRoom(client, "!1:example.org");
|
||||
space = mkRoom(client, "!2:example.org");
|
||||
space.isSpaceRoom.mockReturnValue(true);
|
||||
client.getRoom.mockImplementation(roomId => {
|
||||
client.getRoom.mockImplementation((roomId) => {
|
||||
switch (roomId) {
|
||||
case room.roomId: return room;
|
||||
case space.roomId: return space;
|
||||
default: return null;
|
||||
case room.roomId:
|
||||
return room;
|
||||
case space.roomId:
|
||||
return space;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
@ -62,16 +65,20 @@ describe("leaveRoomBehaviour", () => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
const viewRoom = (room: Room) => defaultDispatcher.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
metricsTrigger: undefined,
|
||||
}, true);
|
||||
const viewRoom = (room: Room) =>
|
||||
defaultDispatcher.dispatch<ViewRoomPayload>(
|
||||
{
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
metricsTrigger: undefined,
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
const expectDispatch = async <T extends ActionPayload>(payload: T) => {
|
||||
const dispatcherSpy = jest.fn();
|
||||
const dispatcherRef = defaultDispatcher.register(dispatcherSpy);
|
||||
await new Promise<void>(resolve => setImmediate(resolve)); // Flush the dispatcher
|
||||
await new Promise<void>((resolve) => setImmediate(resolve)); // Flush the dispatcher
|
||||
expect(dispatcherSpy).toHaveBeenCalledWith(payload);
|
||||
defaultDispatcher.unregister(dispatcherRef);
|
||||
};
|
||||
@ -84,8 +91,8 @@ describe("leaveRoomBehaviour", () => {
|
||||
});
|
||||
|
||||
it("returns to the parent space after leaving a room inside of a space that was being viewed", async () => {
|
||||
jest.spyOn(SpaceStore.instance, "getCanonicalParent").mockImplementation(
|
||||
roomId => roomId === room.roomId ? space : null,
|
||||
jest.spyOn(SpaceStore.instance, "getCanonicalParent").mockImplementation((roomId) =>
|
||||
roomId === room.roomId ? space : null,
|
||||
);
|
||||
viewRoom(room);
|
||||
SpaceStore.instance.setActiveSpace(space.roomId, false);
|
||||
@ -108,8 +115,8 @@ describe("leaveRoomBehaviour", () => {
|
||||
|
||||
it("returns to the parent space after leaving a subspace that was being viewed", async () => {
|
||||
room.isSpaceRoom.mockReturnValue(true);
|
||||
jest.spyOn(SpaceStore.instance, "getCanonicalParent").mockImplementation(
|
||||
roomId => roomId === room.roomId ? space : null,
|
||||
jest.spyOn(SpaceStore.instance, "getCanonicalParent").mockImplementation((roomId) =>
|
||||
roomId === room.roomId ? space : null,
|
||||
);
|
||||
viewRoom(room);
|
||||
SpaceStore.instance.setActiveSpace(room.roomId, false);
|
||||
|
@ -80,13 +80,15 @@ describe("isRoomReady", () => {
|
||||
|
||||
describe("and a RoomHistoryVisibility event", () => {
|
||||
beforeEach(() => {
|
||||
room1.currentState.setStateEvents([mkEvent({
|
||||
user: userId1,
|
||||
event: true,
|
||||
type: EventType.RoomHistoryVisibility,
|
||||
room: room1.roomId,
|
||||
content: {},
|
||||
})]);
|
||||
room1.currentState.setStateEvents([
|
||||
mkEvent({
|
||||
user: userId1,
|
||||
event: true,
|
||||
type: EventType.RoomHistoryVisibility,
|
||||
room: room1.roomId,
|
||||
content: {},
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it("it should return true", () => {
|
||||
@ -104,13 +106,15 @@ describe("isRoomReady", () => {
|
||||
|
||||
describe("and a room encryption state event", () => {
|
||||
beforeEach(() => {
|
||||
room1.currentState.setStateEvents([mkEvent({
|
||||
user: userId1,
|
||||
event: true,
|
||||
type: EventType.RoomEncryption,
|
||||
room: room1.roomId,
|
||||
content: {},
|
||||
})]);
|
||||
room1.currentState.setStateEvents([
|
||||
mkEvent({
|
||||
user: userId1,
|
||||
event: true,
|
||||
type: EventType.RoomEncryption,
|
||||
room: room1.roomId,
|
||||
content: {},
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it("it should return true", () => {
|
||||
@ -123,4 +127,3 @@ describe("isRoomReady", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -28,7 +28,7 @@ import { isSelfLocation } from "../../../src/utils/location";
|
||||
|
||||
describe("isSelfLocation", () => {
|
||||
it("Returns true for a full m.asset event", () => {
|
||||
const content = makeLocationContent("", '0', Date.now());
|
||||
const content = makeLocationContent("", "0", Date.now());
|
||||
expect(isSelfLocation(content)).toBe(true);
|
||||
});
|
||||
|
||||
@ -62,11 +62,12 @@ describe("isSelfLocation", () => {
|
||||
|
||||
it("Returns false for an unknown asset type", () => {
|
||||
const content = makeLocationContent(
|
||||
undefined, /* text */
|
||||
undefined /* text */,
|
||||
"geo:foo",
|
||||
0,
|
||||
undefined, /* description */
|
||||
"org.example.unknown" as unknown as LocationAssetType);
|
||||
undefined /* description */,
|
||||
"org.example.unknown" as unknown as LocationAssetType,
|
||||
);
|
||||
expect(isSelfLocation(content)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@ -17,12 +17,12 @@ limitations under the License.
|
||||
import { locationEventGeoUri } from "../../../src/utils/location";
|
||||
import { makeLegacyLocationEvent, makeLocationEvent } from "../../test-utils/location";
|
||||
|
||||
describe('locationEventGeoUri()', () => {
|
||||
it('returns m.location uri when available', () => {
|
||||
describe("locationEventGeoUri()", () => {
|
||||
it("returns m.location uri when available", () => {
|
||||
expect(locationEventGeoUri(makeLocationEvent("geo:51.5076,-0.1276"))).toEqual("geo:51.5076,-0.1276");
|
||||
});
|
||||
|
||||
it('returns legacy uri when m.location content not found', () => {
|
||||
it("returns legacy uri when m.location content not found", () => {
|
||||
expect(locationEventGeoUri(makeLegacyLocationEvent("geo:51.5076,-0.1276"))).toEqual("geo:51.5076,-0.1276");
|
||||
});
|
||||
});
|
||||
|
@ -20,28 +20,26 @@ import { makeLegacyLocationEvent, makeLocationEvent } from "../../test-utils/loc
|
||||
|
||||
describe("createMapSiteLinkFromEvent", () => {
|
||||
it("returns null if event does not contain geouri", () => {
|
||||
expect(createMapSiteLinkFromEvent(mkMessage({
|
||||
room: '1', user: '@sender:server', event: true,
|
||||
}))).toBeNull();
|
||||
expect(
|
||||
createMapSiteLinkFromEvent(
|
||||
mkMessage({
|
||||
room: "1",
|
||||
user: "@sender:server",
|
||||
event: true,
|
||||
}),
|
||||
),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it("returns OpenStreetMap link if event contains m.location", () => {
|
||||
expect(
|
||||
createMapSiteLinkFromEvent(makeLocationEvent("geo:51.5076,-0.1276")),
|
||||
).toEqual(
|
||||
"https://www.openstreetmap.org/" +
|
||||
"?mlat=51.5076&mlon=-0.1276" +
|
||||
"#map=16/51.5076/-0.1276",
|
||||
expect(createMapSiteLinkFromEvent(makeLocationEvent("geo:51.5076,-0.1276"))).toEqual(
|
||||
"https://www.openstreetmap.org/" + "?mlat=51.5076&mlon=-0.1276" + "#map=16/51.5076/-0.1276",
|
||||
);
|
||||
});
|
||||
|
||||
it("returns OpenStreetMap link if event contains geo_uri", () => {
|
||||
expect(
|
||||
createMapSiteLinkFromEvent(makeLegacyLocationEvent("geo:51.5076,-0.1276")),
|
||||
).toEqual(
|
||||
"https://www.openstreetmap.org/" +
|
||||
"?mlat=51.5076&mlon=-0.1276" +
|
||||
"#map=16/51.5076/-0.1276",
|
||||
expect(createMapSiteLinkFromEvent(makeLegacyLocationEvent("geo:51.5076,-0.1276"))).toEqual(
|
||||
"https://www.openstreetmap.org/" + "?mlat=51.5076&mlon=-0.1276" + "#map=16/51.5076/-0.1276",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -30,128 +30,110 @@ describe("parseGeoUri", () => {
|
||||
// these, but it is permitted, and we will fail to parse in that case.
|
||||
|
||||
it("rfc5870 6.1 Simple 3-dimensional", () => {
|
||||
expect(parseGeoUri("geo:48.2010,16.3695,183")).toEqual(
|
||||
{
|
||||
latitude: 48.2010,
|
||||
longitude: 16.3695,
|
||||
altitude: 183,
|
||||
accuracy: undefined,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
},
|
||||
);
|
||||
expect(parseGeoUri("geo:48.2010,16.3695,183")).toEqual({
|
||||
latitude: 48.201,
|
||||
longitude: 16.3695,
|
||||
altitude: 183,
|
||||
accuracy: undefined,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("rfc5870 6.2 Explicit CRS and accuracy", () => {
|
||||
expect(parseGeoUri("geo:48.198634,16.371648;crs=wgs84;u=40")).toEqual(
|
||||
{
|
||||
latitude: 48.198634,
|
||||
longitude: 16.371648,
|
||||
altitude: undefined,
|
||||
accuracy: 40,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
},
|
||||
);
|
||||
expect(parseGeoUri("geo:48.198634,16.371648;crs=wgs84;u=40")).toEqual({
|
||||
latitude: 48.198634,
|
||||
longitude: 16.371648,
|
||||
altitude: undefined,
|
||||
accuracy: 40,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("rfc5870 6.4 Negative longitude and explicit CRS", () => {
|
||||
expect(parseGeoUri("geo:90,-22.43;crs=WGS84")).toEqual(
|
||||
{
|
||||
latitude: 90,
|
||||
longitude: -22.43,
|
||||
altitude: undefined,
|
||||
accuracy: undefined,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
},
|
||||
);
|
||||
expect(parseGeoUri("geo:90,-22.43;crs=WGS84")).toEqual({
|
||||
latitude: 90,
|
||||
longitude: -22.43,
|
||||
altitude: undefined,
|
||||
accuracy: undefined,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("rfc5870 6.4 Integer lat and lon", () => {
|
||||
expect(parseGeoUri("geo:90,46")).toEqual(
|
||||
{
|
||||
latitude: 90,
|
||||
longitude: 46,
|
||||
altitude: undefined,
|
||||
accuracy: undefined,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
},
|
||||
);
|
||||
expect(parseGeoUri("geo:90,46")).toEqual({
|
||||
latitude: 90,
|
||||
longitude: 46,
|
||||
altitude: undefined,
|
||||
accuracy: undefined,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("rfc5870 6.4 Percent-encoded param value", () => {
|
||||
expect(parseGeoUri("geo:66,30;u=6.500;FOo=this%2dthat")).toEqual(
|
||||
{
|
||||
latitude: 66,
|
||||
longitude: 30,
|
||||
altitude: undefined,
|
||||
accuracy: 6.500,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
},
|
||||
);
|
||||
expect(parseGeoUri("geo:66,30;u=6.500;FOo=this%2dthat")).toEqual({
|
||||
latitude: 66,
|
||||
longitude: 30,
|
||||
altitude: undefined,
|
||||
accuracy: 6.5,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("rfc5870 6.4 Unknown param", () => {
|
||||
expect(parseGeoUri("geo:66.0,30;u=6.5;foo=this-that>")).toEqual(
|
||||
{
|
||||
latitude: 66.0,
|
||||
longitude: 30,
|
||||
altitude: undefined,
|
||||
accuracy: 6.5,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
},
|
||||
);
|
||||
expect(parseGeoUri("geo:66.0,30;u=6.5;foo=this-that>")).toEqual({
|
||||
latitude: 66.0,
|
||||
longitude: 30,
|
||||
altitude: undefined,
|
||||
accuracy: 6.5,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("rfc5870 6.4 Multiple unknown params", () => {
|
||||
expect(parseGeoUri("geo:70,20;foo=1.00;bar=white")).toEqual(
|
||||
{
|
||||
latitude: 70,
|
||||
longitude: 20,
|
||||
altitude: undefined,
|
||||
accuracy: undefined,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
},
|
||||
);
|
||||
expect(parseGeoUri("geo:70,20;foo=1.00;bar=white")).toEqual({
|
||||
latitude: 70,
|
||||
longitude: 20,
|
||||
altitude: undefined,
|
||||
accuracy: undefined,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("Negative latitude", () => {
|
||||
expect(parseGeoUri("geo:-7.5,20")).toEqual(
|
||||
{
|
||||
latitude: -7.5,
|
||||
longitude: 20,
|
||||
altitude: undefined,
|
||||
accuracy: undefined,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
},
|
||||
);
|
||||
expect(parseGeoUri("geo:-7.5,20")).toEqual({
|
||||
latitude: -7.5,
|
||||
longitude: 20,
|
||||
altitude: undefined,
|
||||
accuracy: undefined,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("Zero altitude is not unknown", () => {
|
||||
expect(parseGeoUri("geo:-7.5,-20,0")).toEqual(
|
||||
{
|
||||
latitude: -7.5,
|
||||
longitude: -20,
|
||||
altitude: 0,
|
||||
accuracy: undefined,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
},
|
||||
);
|
||||
expect(parseGeoUri("geo:-7.5,-20,0")).toEqual({
|
||||
latitude: -7.5,
|
||||
longitude: -20,
|
||||
altitude: 0,
|
||||
accuracy: undefined,
|
||||
altitudeAccuracy: undefined,
|
||||
heading: undefined,
|
||||
speed: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -16,10 +16,14 @@ limitations under the License.
|
||||
|
||||
import { EnhancedMap, mapDiff } from "../../src/utils/maps";
|
||||
|
||||
describe('maps', () => {
|
||||
describe('mapDiff', () => {
|
||||
it('should indicate no differences when the pointers are the same', () => {
|
||||
const a = new Map([[1, 1], [2, 2], [3, 3]]);
|
||||
describe("maps", () => {
|
||||
describe("mapDiff", () => {
|
||||
it("should indicate no differences when the pointers are the same", () => {
|
||||
const a = new Map([
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
]);
|
||||
const result = mapDiff(a, a);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.added).toBeDefined();
|
||||
@ -30,9 +34,17 @@ describe('maps', () => {
|
||||
expect(result.changed).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should indicate no differences when there are none', () => {
|
||||
const a = new Map([[1, 1], [2, 2], [3, 3]]);
|
||||
const b = new Map([[1, 1], [2, 2], [3, 3]]);
|
||||
it("should indicate no differences when there are none", () => {
|
||||
const a = new Map([
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
]);
|
||||
const b = new Map([
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
]);
|
||||
const result = mapDiff(a, b);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.added).toBeDefined();
|
||||
@ -43,9 +55,18 @@ describe('maps', () => {
|
||||
expect(result.changed).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should indicate added properties', () => {
|
||||
const a = new Map([[1, 1], [2, 2], [3, 3]]);
|
||||
const b = new Map([[1, 1], [2, 2], [3, 3], [4, 4]]);
|
||||
it("should indicate added properties", () => {
|
||||
const a = new Map([
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
]);
|
||||
const b = new Map([
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
]);
|
||||
const result = mapDiff(a, b);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.added).toBeDefined();
|
||||
@ -57,9 +78,16 @@ describe('maps', () => {
|
||||
expect(result.added).toEqual([4]);
|
||||
});
|
||||
|
||||
it('should indicate removed properties', () => {
|
||||
const a = new Map([[1, 1], [2, 2], [3, 3]]);
|
||||
const b = new Map([[1, 1], [2, 2]]);
|
||||
it("should indicate removed properties", () => {
|
||||
const a = new Map([
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
]);
|
||||
const b = new Map([
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
]);
|
||||
const result = mapDiff(a, b);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.added).toBeDefined();
|
||||
@ -71,9 +99,17 @@ describe('maps', () => {
|
||||
expect(result.removed).toEqual([3]);
|
||||
});
|
||||
|
||||
it('should indicate changed properties', () => {
|
||||
const a = new Map([[1, 1], [2, 2], [3, 3]]);
|
||||
const b = new Map([[1, 1], [2, 2], [3, 4]]); // note change
|
||||
it("should indicate changed properties", () => {
|
||||
const a = new Map([
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
]);
|
||||
const b = new Map([
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[3, 4],
|
||||
]); // note change
|
||||
const result = mapDiff(a, b);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.added).toBeDefined();
|
||||
@ -85,9 +121,17 @@ describe('maps', () => {
|
||||
expect(result.changed).toEqual([3]);
|
||||
});
|
||||
|
||||
it('should indicate changed, added, and removed properties', () => {
|
||||
const a = new Map([[1, 1], [2, 2], [3, 3]]);
|
||||
const b = new Map([[1, 1], [2, 8], [4, 4]]); // note change
|
||||
it("should indicate changed, added, and removed properties", () => {
|
||||
const a = new Map([
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
]);
|
||||
const b = new Map([
|
||||
[1, 1],
|
||||
[2, 8],
|
||||
[4, 4],
|
||||
]); // note change
|
||||
const result = mapDiff(a, b);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.added).toBeDefined();
|
||||
@ -101,7 +145,7 @@ describe('maps', () => {
|
||||
expect(result.changed).toEqual([2]);
|
||||
});
|
||||
|
||||
it('should indicate changes for difference in pointers', () => {
|
||||
it("should indicate changes for difference in pointers", () => {
|
||||
const a = new Map([[1, {}]]); // {} always creates a new object
|
||||
const b = new Map([[1, {}]]);
|
||||
const result = mapDiff(a, b);
|
||||
@ -116,24 +160,24 @@ describe('maps', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('EnhancedMap', () => {
|
||||
describe("EnhancedMap", () => {
|
||||
// Most of these tests will make sure it implements the Map<K, V> class
|
||||
|
||||
it('should be empty by default', () => {
|
||||
it("should be empty by default", () => {
|
||||
const result = new EnhancedMap();
|
||||
expect(result.size).toBe(0);
|
||||
});
|
||||
|
||||
it('should use the provided entries', () => {
|
||||
it("should use the provided entries", () => {
|
||||
const obj = { a: 1, b: 2 };
|
||||
const result = new EnhancedMap(Object.entries(obj));
|
||||
expect(result.size).toBe(2);
|
||||
expect(result.get('a')).toBe(1);
|
||||
expect(result.get('b')).toBe(2);
|
||||
expect(result.get("a")).toBe(1);
|
||||
expect(result.get("b")).toBe(2);
|
||||
});
|
||||
|
||||
it('should create keys if they do not exist', () => {
|
||||
const key = 'a';
|
||||
it("should create keys if they do not exist", () => {
|
||||
const key = "a";
|
||||
const val = {}; // we'll check pointers
|
||||
|
||||
const result = new EnhancedMap<string, any>();
|
||||
@ -155,27 +199,27 @@ describe('maps', () => {
|
||||
expect(result.size).toBe(1);
|
||||
});
|
||||
|
||||
it('should proxy remove to delete and return it', () => {
|
||||
it("should proxy remove to delete and return it", () => {
|
||||
const val = {};
|
||||
const result = new EnhancedMap<string, any>();
|
||||
result.set('a', val);
|
||||
result.set("a", val);
|
||||
|
||||
expect(result.size).toBe(1);
|
||||
|
||||
const removed = result.remove('a');
|
||||
const removed = result.remove("a");
|
||||
expect(result.size).toBe(0);
|
||||
expect(removed).toBeDefined();
|
||||
expect(removed).toBe(val);
|
||||
});
|
||||
|
||||
it('should support removing unknown keys', () => {
|
||||
it("should support removing unknown keys", () => {
|
||||
const val = {};
|
||||
const result = new EnhancedMap<string, any>();
|
||||
result.set('a', val);
|
||||
result.set("a", val);
|
||||
|
||||
expect(result.size).toBe(1);
|
||||
|
||||
const removed = result.remove('not-a');
|
||||
const removed = result.remove("not-a");
|
||||
expect(result.size).toBe(1);
|
||||
expect(removed).not.toBeDefined();
|
||||
});
|
||||
|
@ -28,10 +28,7 @@ describe("requestMediaPermissions", () => {
|
||||
|
||||
const itShouldLogTheErrorAndShowTheNoMediaPermissionsModal = () => {
|
||||
it("should log the error and show the »No media permissions« modal", () => {
|
||||
expect(logger.log).toHaveBeenCalledWith(
|
||||
"Failed to list userMedia devices",
|
||||
error,
|
||||
);
|
||||
expect(logger.log).toHaveBeenCalledWith("Failed to list userMedia devices", error);
|
||||
screen.getByText("No media permissions");
|
||||
});
|
||||
};
|
||||
@ -91,11 +88,9 @@ describe("requestMediaPermissions", () => {
|
||||
describe("when no device is available", () => {
|
||||
beforeEach(async () => {
|
||||
error.name = "NotFoundError";
|
||||
mocked(navigator.mediaDevices.getUserMedia).mockImplementation(
|
||||
async (): Promise<MediaStream> => {
|
||||
throw error;
|
||||
},
|
||||
);
|
||||
mocked(navigator.mediaDevices.getUserMedia).mockImplementation(async (): Promise<MediaStream> => {
|
||||
throw error;
|
||||
});
|
||||
await requestMediaPermissions();
|
||||
// required for the modal to settle
|
||||
await flushPromises();
|
||||
|
@ -34,7 +34,7 @@ import { MatrixClientPeg } from "../../src/MatrixClientPeg";
|
||||
|
||||
jest.mock("../../src/settings/SettingsStore");
|
||||
|
||||
describe('notifications', () => {
|
||||
describe("notifications", () => {
|
||||
let accountDataStore = {};
|
||||
let mockClient;
|
||||
let accountDataEventKey;
|
||||
@ -43,7 +43,7 @@ describe('notifications', () => {
|
||||
jest.clearAllMocks();
|
||||
mockClient = getMockClientWithEventEmitter({
|
||||
isGuest: jest.fn().mockReturnValue(false),
|
||||
getAccountData: jest.fn().mockImplementation(eventType => accountDataStore[eventType]),
|
||||
getAccountData: jest.fn().mockImplementation((eventType) => accountDataStore[eventType]),
|
||||
setAccountData: jest.fn().mockImplementation((eventType, content) => {
|
||||
accountDataStore[eventType] = new MatrixEvent({
|
||||
type: eventType,
|
||||
@ -56,14 +56,14 @@ describe('notifications', () => {
|
||||
mocked(SettingsStore).getValue.mockReturnValue(false);
|
||||
});
|
||||
|
||||
describe('createLocalNotification', () => {
|
||||
it('creates account data event', async () => {
|
||||
describe("createLocalNotification", () => {
|
||||
it("creates account data event", async () => {
|
||||
await createLocalNotificationSettingsIfNeeded(mockClient);
|
||||
const event = mockClient.getAccountData(accountDataEventKey);
|
||||
expect(event?.getContent().is_silenced).toBe(true);
|
||||
});
|
||||
|
||||
it('does not do anything for guests', async () => {
|
||||
it("does not do anything for guests", async () => {
|
||||
mockClient.isGuest.mockReset().mockReturnValue(true);
|
||||
await createLocalNotificationSettingsIfNeeded(mockClient);
|
||||
const event = mockClient.getAccountData(accountDataEventKey);
|
||||
@ -71,7 +71,7 @@ describe('notifications', () => {
|
||||
});
|
||||
|
||||
it.each(deviceNotificationSettingsKeys)(
|
||||
'unsilenced for existing sessions when %s setting is truthy',
|
||||
"unsilenced for existing sessions when %s setting is truthy",
|
||||
async (settingKey) => {
|
||||
mocked(SettingsStore).getValue.mockImplementation((key): any => {
|
||||
return key === settingKey;
|
||||
@ -80,7 +80,8 @@ describe('notifications', () => {
|
||||
await createLocalNotificationSettingsIfNeeded(mockClient);
|
||||
const event = mockClient.getAccountData(accountDataEventKey);
|
||||
expect(event?.getContent().is_silenced).toBe(false);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it("does not override an existing account event data", async () => {
|
||||
mockClient.setAccountData(accountDataEventKey, {
|
||||
@ -93,11 +94,11 @@ describe('notifications', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('localNotificationsAreSilenced', () => {
|
||||
it('defaults to false when no setting exists', () => {
|
||||
describe("localNotificationsAreSilenced", () => {
|
||||
it("defaults to false when no setting exists", () => {
|
||||
expect(localNotificationsAreSilenced(mockClient)).toBeFalsy();
|
||||
});
|
||||
it('checks the persisted value', () => {
|
||||
it("checks the persisted value", () => {
|
||||
mockClient.setAccountData(accountDataEventKey, { is_silenced: true });
|
||||
expect(localNotificationsAreSilenced(mockClient)).toBeTruthy();
|
||||
|
||||
|
@ -16,9 +16,9 @@ limitations under the License.
|
||||
|
||||
import { clamp, defaultNumber, percentageOf, percentageWithin, sum } from "../../src/utils/numbers";
|
||||
|
||||
describe('numbers', () => {
|
||||
describe('defaultNumber', () => {
|
||||
it('should use the default when the input is not a number', () => {
|
||||
describe("numbers", () => {
|
||||
describe("defaultNumber", () => {
|
||||
it("should use the default when the input is not a number", () => {
|
||||
const def = 42;
|
||||
|
||||
let result = defaultNumber(null, def);
|
||||
@ -31,7 +31,7 @@ describe('numbers', () => {
|
||||
expect(result).toBe(def);
|
||||
});
|
||||
|
||||
it('should use the number when it is a number', () => {
|
||||
it("should use the number when it is a number", () => {
|
||||
const input = 24;
|
||||
const def = 42;
|
||||
const result = defaultNumber(input, def);
|
||||
@ -39,8 +39,8 @@ describe('numbers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('clamp', () => {
|
||||
it('should clamp high numbers', () => {
|
||||
describe("clamp", () => {
|
||||
it("should clamp high numbers", () => {
|
||||
const input = 101;
|
||||
const min = 0;
|
||||
const max = 100;
|
||||
@ -48,7 +48,7 @@ describe('numbers', () => {
|
||||
expect(result).toBe(max);
|
||||
});
|
||||
|
||||
it('should clamp low numbers', () => {
|
||||
it("should clamp low numbers", () => {
|
||||
const input = -1;
|
||||
const min = 0;
|
||||
const max = 100;
|
||||
@ -56,7 +56,7 @@ describe('numbers', () => {
|
||||
expect(result).toBe(min);
|
||||
});
|
||||
|
||||
it('should not clamp numbers in range', () => {
|
||||
it("should not clamp numbers in range", () => {
|
||||
const input = 50;
|
||||
const min = 0;
|
||||
const max = 100;
|
||||
@ -64,9 +64,9 @@ describe('numbers', () => {
|
||||
expect(result).toBe(input);
|
||||
});
|
||||
|
||||
it('should clamp floats', () => {
|
||||
const min = -0.10;
|
||||
const max = +0.10;
|
||||
it("should clamp floats", () => {
|
||||
const min = -0.1;
|
||||
const max = +0.1;
|
||||
|
||||
let result = clamp(-1.2, min, max);
|
||||
expect(result).toBe(min);
|
||||
@ -79,83 +79,84 @@ describe('numbers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('sum', () => {
|
||||
it('should sum', () => { // duh
|
||||
describe("sum", () => {
|
||||
it("should sum", () => {
|
||||
// duh
|
||||
const result = sum(1, 2, 1, 4);
|
||||
expect(result).toBe(8);
|
||||
});
|
||||
});
|
||||
|
||||
describe('percentageWithin', () => {
|
||||
it('should work within 0-100', () => {
|
||||
describe("percentageWithin", () => {
|
||||
it("should work within 0-100", () => {
|
||||
const result = percentageWithin(0.4, 0, 100);
|
||||
expect(result).toBe(40);
|
||||
});
|
||||
|
||||
it('should work within 0-100 when pct > 1', () => {
|
||||
it("should work within 0-100 when pct > 1", () => {
|
||||
const result = percentageWithin(1.4, 0, 100);
|
||||
expect(result).toBe(140);
|
||||
});
|
||||
|
||||
it('should work within 0-100 when pct < 0', () => {
|
||||
it("should work within 0-100 when pct < 0", () => {
|
||||
const result = percentageWithin(-1.4, 0, 100);
|
||||
expect(result).toBe(-140);
|
||||
});
|
||||
|
||||
it('should work with ranges other than 0-100', () => {
|
||||
it("should work with ranges other than 0-100", () => {
|
||||
const result = percentageWithin(0.4, 10, 20);
|
||||
expect(result).toBe(14);
|
||||
});
|
||||
|
||||
it('should work with ranges other than 0-100 when pct > 1', () => {
|
||||
it("should work with ranges other than 0-100 when pct > 1", () => {
|
||||
const result = percentageWithin(1.4, 10, 20);
|
||||
expect(result).toBe(24);
|
||||
});
|
||||
|
||||
it('should work with ranges other than 0-100 when pct < 0', () => {
|
||||
it("should work with ranges other than 0-100 when pct < 0", () => {
|
||||
const result = percentageWithin(-1.4, 10, 20);
|
||||
expect(result).toBe(-4);
|
||||
});
|
||||
|
||||
it('should work with floats', () => {
|
||||
it("should work with floats", () => {
|
||||
const result = percentageWithin(0.4, 10.2, 20.4);
|
||||
expect(result).toBe(14.28);
|
||||
});
|
||||
});
|
||||
|
||||
// These are the inverse of percentageWithin
|
||||
describe('percentageOf', () => {
|
||||
it('should work within 0-100', () => {
|
||||
describe("percentageOf", () => {
|
||||
it("should work within 0-100", () => {
|
||||
const result = percentageOf(40, 0, 100);
|
||||
expect(result).toBe(0.4);
|
||||
});
|
||||
|
||||
it('should work within 0-100 when val > 100', () => {
|
||||
it("should work within 0-100 when val > 100", () => {
|
||||
const result = percentageOf(140, 0, 100);
|
||||
expect(result).toBe(1.40);
|
||||
expect(result).toBe(1.4);
|
||||
});
|
||||
|
||||
it('should work within 0-100 when val < 0', () => {
|
||||
it("should work within 0-100 when val < 0", () => {
|
||||
const result = percentageOf(-140, 0, 100);
|
||||
expect(result).toBe(-1.40);
|
||||
expect(result).toBe(-1.4);
|
||||
});
|
||||
|
||||
it('should work with ranges other than 0-100', () => {
|
||||
it("should work with ranges other than 0-100", () => {
|
||||
const result = percentageOf(14, 10, 20);
|
||||
expect(result).toBe(0.4);
|
||||
});
|
||||
|
||||
it('should work with ranges other than 0-100 when val > 100', () => {
|
||||
it("should work with ranges other than 0-100 when val > 100", () => {
|
||||
const result = percentageOf(24, 10, 20);
|
||||
expect(result).toBe(1.4);
|
||||
});
|
||||
|
||||
it('should work with ranges other than 0-100 when val < 0', () => {
|
||||
it("should work with ranges other than 0-100 when val < 0", () => {
|
||||
const result = percentageOf(-4, 10, 20);
|
||||
expect(result).toBe(-1.4);
|
||||
});
|
||||
|
||||
it('should work with floats', () => {
|
||||
it("should work with floats", () => {
|
||||
const result = percentageOf(14.28, 10.2, 20.4);
|
||||
expect(result).toBe(0.4);
|
||||
});
|
||||
|
@ -24,9 +24,9 @@ import {
|
||||
objectWithOnly,
|
||||
} from "../../src/utils/objects";
|
||||
|
||||
describe('objects', () => {
|
||||
describe('objectExcluding', () => {
|
||||
it('should exclude the given properties', () => {
|
||||
describe("objects", () => {
|
||||
describe("objectExcluding", () => {
|
||||
it("should exclude the given properties", () => {
|
||||
const input = { hello: "world", test: true };
|
||||
const output = { hello: "world" };
|
||||
const props = ["test", "doesnotexist"]; // we also make sure it doesn't explode on missing props
|
||||
@ -36,8 +36,8 @@ describe('objects', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('objectWithOnly', () => {
|
||||
it('should exclusively use the given properties', () => {
|
||||
describe("objectWithOnly", () => {
|
||||
it("should exclusively use the given properties", () => {
|
||||
const input = { hello: "world", test: true };
|
||||
const output = { hello: "world" };
|
||||
const props = ["hello", "doesnotexist"]; // we also make sure it doesn't explode on missing props
|
||||
@ -47,8 +47,8 @@ describe('objects', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('objectShallowClone', () => {
|
||||
it('should create a new object', () => {
|
||||
describe("objectShallowClone", () => {
|
||||
it("should create a new object", () => {
|
||||
const input = { test: 1 };
|
||||
const result = objectShallowClone(input);
|
||||
expect(result).toBeDefined();
|
||||
@ -56,7 +56,7 @@ describe('objects', () => {
|
||||
expect(result).toMatchObject(input);
|
||||
});
|
||||
|
||||
it('should only clone the top level properties', () => {
|
||||
it("should only clone the top level properties", () => {
|
||||
const input = { a: 1, b: { c: 2 } };
|
||||
const result = objectShallowClone(input);
|
||||
expect(result).toBeDefined();
|
||||
@ -64,7 +64,7 @@ describe('objects', () => {
|
||||
expect(result.b).toBe(input.b);
|
||||
});
|
||||
|
||||
it('should support custom clone functions', () => {
|
||||
it("should support custom clone functions", () => {
|
||||
const input = { a: 1, b: 2 };
|
||||
const output = { a: 4, b: 8 };
|
||||
const result = objectShallowClone(input, (k, v) => {
|
||||
@ -78,35 +78,35 @@ describe('objects', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('objectHasDiff', () => {
|
||||
it('should return false for the same pointer', () => {
|
||||
describe("objectHasDiff", () => {
|
||||
it("should return false for the same pointer", () => {
|
||||
const a = {};
|
||||
const result = objectHasDiff(a, a);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true if keys for A > keys for B', () => {
|
||||
it("should return true if keys for A > keys for B", () => {
|
||||
const a = { a: 1, b: 2 };
|
||||
const b = { a: 1 };
|
||||
const result = objectHasDiff(a, b);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true if keys for A < keys for B', () => {
|
||||
it("should return true if keys for A < keys for B", () => {
|
||||
const a = { a: 1 };
|
||||
const b = { a: 1, b: 2 };
|
||||
const result = objectHasDiff(a, b);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if the objects are the same but different pointers', () => {
|
||||
it("should return false if the objects are the same but different pointers", () => {
|
||||
const a = { a: 1, b: 2 };
|
||||
const b = { a: 1, b: 2 };
|
||||
const result = objectHasDiff(a, b);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should consider pointers when testing values', () => {
|
||||
it("should consider pointers when testing values", () => {
|
||||
const a = { a: {}, b: 2 }; // `{}` is shorthand for `new Object()`
|
||||
const b = { a: {}, b: 2 };
|
||||
const result = objectHasDiff(a, b);
|
||||
@ -114,8 +114,8 @@ describe('objects', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('objectDiff', () => {
|
||||
it('should return empty sets for the same object', () => {
|
||||
describe("objectDiff", () => {
|
||||
it("should return empty sets for the same object", () => {
|
||||
const a = { a: 1, b: 2 };
|
||||
const b = { a: 1, b: 2 };
|
||||
const result = objectDiff(a, b);
|
||||
@ -128,7 +128,7 @@ describe('objects', () => {
|
||||
expect(result.removed).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should return empty sets for the same object pointer', () => {
|
||||
it("should return empty sets for the same object pointer", () => {
|
||||
const a = { a: 1, b: 2 };
|
||||
const result = objectDiff(a, a);
|
||||
expect(result).toBeDefined();
|
||||
@ -140,7 +140,7 @@ describe('objects', () => {
|
||||
expect(result.removed).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should indicate when property changes are made', () => {
|
||||
it("should indicate when property changes are made", () => {
|
||||
const a = { a: 1, b: 2 };
|
||||
const b = { a: 11, b: 2 };
|
||||
const result = objectDiff(a, b);
|
||||
@ -150,10 +150,10 @@ describe('objects', () => {
|
||||
expect(result.changed).toHaveLength(1);
|
||||
expect(result.added).toHaveLength(0);
|
||||
expect(result.removed).toHaveLength(0);
|
||||
expect(result.changed).toEqual(['a']);
|
||||
expect(result.changed).toEqual(["a"]);
|
||||
});
|
||||
|
||||
it('should indicate when properties are added', () => {
|
||||
it("should indicate when properties are added", () => {
|
||||
const a = { a: 1, b: 2 };
|
||||
const b = { a: 1, b: 2, c: 3 };
|
||||
const result = objectDiff(a, b);
|
||||
@ -163,10 +163,10 @@ describe('objects', () => {
|
||||
expect(result.changed).toHaveLength(0);
|
||||
expect(result.added).toHaveLength(1);
|
||||
expect(result.removed).toHaveLength(0);
|
||||
expect(result.added).toEqual(['c']);
|
||||
expect(result.added).toEqual(["c"]);
|
||||
});
|
||||
|
||||
it('should indicate when properties are removed', () => {
|
||||
it("should indicate when properties are removed", () => {
|
||||
const a = { a: 1, b: 2 };
|
||||
const b = { a: 1 };
|
||||
const result = objectDiff(a, b);
|
||||
@ -176,12 +176,12 @@ describe('objects', () => {
|
||||
expect(result.changed).toHaveLength(0);
|
||||
expect(result.added).toHaveLength(0);
|
||||
expect(result.removed).toHaveLength(1);
|
||||
expect(result.removed).toEqual(['b']);
|
||||
expect(result.removed).toEqual(["b"]);
|
||||
});
|
||||
|
||||
it('should indicate when multiple aspects change', () => {
|
||||
it("should indicate when multiple aspects change", () => {
|
||||
const a = { a: 1, b: 2, c: 3 };
|
||||
const b: (typeof a | {d: number}) = { a: 1, b: 22, d: 4 };
|
||||
const b: typeof a | { d: number } = { a: 1, b: 22, d: 4 };
|
||||
const result = objectDiff(a, b);
|
||||
expect(result.changed).toBeDefined();
|
||||
expect(result.added).toBeDefined();
|
||||
@ -189,14 +189,14 @@ describe('objects', () => {
|
||||
expect(result.changed).toHaveLength(1);
|
||||
expect(result.added).toHaveLength(1);
|
||||
expect(result.removed).toHaveLength(1);
|
||||
expect(result.changed).toEqual(['b']);
|
||||
expect(result.removed).toEqual(['c']);
|
||||
expect(result.added).toEqual(['d']);
|
||||
expect(result.changed).toEqual(["b"]);
|
||||
expect(result.removed).toEqual(["c"]);
|
||||
expect(result.added).toEqual(["d"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('objectKeyChanges', () => {
|
||||
it('should return an empty set if no properties changed', () => {
|
||||
describe("objectKeyChanges", () => {
|
||||
it("should return an empty set if no properties changed", () => {
|
||||
const a = { a: 1, b: 2 };
|
||||
const b = { a: 1, b: 2 };
|
||||
const result = objectKeyChanges(a, b);
|
||||
@ -204,25 +204,25 @@ describe('objects', () => {
|
||||
expect(result).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should return an empty set if no properties changed for the same pointer', () => {
|
||||
it("should return an empty set if no properties changed for the same pointer", () => {
|
||||
const a = { a: 1, b: 2 };
|
||||
const result = objectKeyChanges(a, a);
|
||||
expect(result).toBeDefined();
|
||||
expect(result).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should return properties which were changed, added, or removed', () => {
|
||||
it("should return properties which were changed, added, or removed", () => {
|
||||
const a = { a: 1, b: 2, c: 3 };
|
||||
const b: (typeof a | {d: number}) = { a: 1, b: 22, d: 4 };
|
||||
const b: typeof a | { d: number } = { a: 1, b: 22, d: 4 };
|
||||
const result = objectKeyChanges(a, b);
|
||||
expect(result).toBeDefined();
|
||||
expect(result).toHaveLength(3);
|
||||
expect(result).toEqual(['c', 'd', 'b']); // order isn't important, but the test cares
|
||||
expect(result).toEqual(["c", "d", "b"]); // order isn't important, but the test cares
|
||||
});
|
||||
});
|
||||
|
||||
describe('objectClone', () => {
|
||||
it('should deep clone an object', () => {
|
||||
describe("objectClone", () => {
|
||||
it("should deep clone an object", () => {
|
||||
const a = {
|
||||
hello: "world",
|
||||
test: {
|
||||
|
@ -12,40 +12,37 @@ 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 {
|
||||
Room,
|
||||
RoomMember,
|
||||
EventType,
|
||||
MatrixEvent,
|
||||
} from 'matrix-js-sdk/src/matrix';
|
||||
import { Room, RoomMember, EventType, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { MatrixClientPeg } from '../../../src/MatrixClientPeg';
|
||||
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
||||
import {
|
||||
makeRoomPermalink,
|
||||
makeUserPermalink,
|
||||
parsePermalink,
|
||||
RoomPermalinkCreator,
|
||||
} from "../../../src/utils/permalinks/Permalinks";
|
||||
import { getMockClientWithEventEmitter } from '../../test-utils';
|
||||
import { getMockClientWithEventEmitter } from "../../test-utils";
|
||||
|
||||
describe('Permalinks', function() {
|
||||
const userId = '@test:example.com';
|
||||
describe("Permalinks", function () {
|
||||
const userId = "@test:example.com";
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getUserId: jest.fn().mockReturnValue(userId),
|
||||
getRoom: jest.fn(),
|
||||
});
|
||||
mockClient.credentials = { userId };
|
||||
|
||||
const makeMemberWithPL = (roomId: Room['roomId'], userId: string, powerLevel: number): RoomMember => {
|
||||
const makeMemberWithPL = (roomId: Room["roomId"], userId: string, powerLevel: number): RoomMember => {
|
||||
const member = new RoomMember(roomId, userId);
|
||||
member.powerLevel = powerLevel;
|
||||
return member;
|
||||
};
|
||||
|
||||
function mockRoom(
|
||||
roomId: Room['roomId'], members: RoomMember[], serverACLContent?: { deny?: string[], allow?: string[]},
|
||||
roomId: Room["roomId"],
|
||||
members: RoomMember[],
|
||||
serverACLContent?: { deny?: string[]; allow?: string[] },
|
||||
): Room {
|
||||
members.forEach(m => m.membership = "join");
|
||||
members.forEach((m) => (m.membership = "join"));
|
||||
const powerLevelsUsers = members.reduce((pl, member) => {
|
||||
if (Number.isFinite(member.powerLevel)) {
|
||||
pl[member.userId] = member.powerLevel;
|
||||
@ -58,35 +55,38 @@ describe('Permalinks', function() {
|
||||
const powerLevels = new MatrixEvent({
|
||||
type: EventType.RoomPowerLevels,
|
||||
room_id: roomId,
|
||||
state_key: '',
|
||||
state_key: "",
|
||||
content: {
|
||||
users: powerLevelsUsers, users_default: 0,
|
||||
users: powerLevelsUsers,
|
||||
users_default: 0,
|
||||
},
|
||||
});
|
||||
const serverACL = serverACLContent ? new MatrixEvent({
|
||||
type: EventType.RoomServerAcl,
|
||||
room_id: roomId,
|
||||
state_key: '',
|
||||
content: serverACLContent,
|
||||
}) : undefined;
|
||||
const serverACL = serverACLContent
|
||||
? new MatrixEvent({
|
||||
type: EventType.RoomServerAcl,
|
||||
room_id: roomId,
|
||||
state_key: "",
|
||||
content: serverACLContent,
|
||||
})
|
||||
: undefined;
|
||||
const stateEvents = serverACL ? [powerLevels, serverACL] : [powerLevels];
|
||||
room.currentState.setStateEvents(stateEvents);
|
||||
|
||||
jest.spyOn(room, 'getCanonicalAlias').mockReturnValue(null);
|
||||
jest.spyOn(room, 'getJoinedMembers').mockReturnValue(members);
|
||||
jest.spyOn(room, 'getMember').mockImplementation((userId) => members.find(m => m.userId === userId));
|
||||
jest.spyOn(room, "getCanonicalAlias").mockReturnValue(null);
|
||||
jest.spyOn(room, "getJoinedMembers").mockReturnValue(members);
|
||||
jest.spyOn(room, "getMember").mockImplementation((userId) => members.find((m) => m.userId === userId));
|
||||
|
||||
return room;
|
||||
}
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(MatrixClientPeg, 'get').mockRestore();
|
||||
jest.spyOn(MatrixClientPeg, "get").mockRestore();
|
||||
});
|
||||
|
||||
it('should pick no candidate servers when the room has no members', function() {
|
||||
it("should pick no candidate servers when the room has no members", function () {
|
||||
const room = mockRoom("!fake:example.org", []);
|
||||
const creator = new RoomPermalinkCreator(room);
|
||||
creator.load();
|
||||
@ -94,7 +94,7 @@ describe('Permalinks', function() {
|
||||
expect(creator.serverCandidates.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should gracefully handle invalid MXIDs', () => {
|
||||
it("should gracefully handle invalid MXIDs", () => {
|
||||
const roomId = "!fake:example.org";
|
||||
const alice50 = makeMemberWithPL(roomId, "@alice:pl_50:org", 50);
|
||||
const room = mockRoom(roomId, [alice50]);
|
||||
@ -103,16 +103,12 @@ describe('Permalinks', function() {
|
||||
expect(creator.serverCandidates).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should pick a candidate server for the highest power level user in the room', function() {
|
||||
it("should pick a candidate server for the highest power level user in the room", function () {
|
||||
const roomId = "!fake:example.org";
|
||||
const alice50 = makeMemberWithPL(roomId, "@alice:pl_50", 50);
|
||||
const alice75 = makeMemberWithPL(roomId, "@alice:pl_75", 75);
|
||||
const alice95 = makeMemberWithPL(roomId, "@alice:pl_95", 95);
|
||||
const room = mockRoom("!fake:example.org", [
|
||||
alice50,
|
||||
alice75,
|
||||
alice95,
|
||||
]);
|
||||
const room = mockRoom("!fake:example.org", [alice50, alice75, alice95]);
|
||||
const creator = new RoomPermalinkCreator(room);
|
||||
creator.load();
|
||||
expect(creator.serverCandidates).toBeTruthy();
|
||||
@ -121,7 +117,7 @@ describe('Permalinks', function() {
|
||||
// we don't check the 2nd and 3rd servers because that is done by the next test
|
||||
});
|
||||
|
||||
it('should change candidate server when highest power level user leaves the room', function() {
|
||||
it("should change candidate server when highest power level user leaves the room", function () {
|
||||
const roomId = "!fake:example.org";
|
||||
const member95 = makeMemberWithPL(roomId, "@alice:pl_95", 95);
|
||||
|
||||
@ -143,7 +139,7 @@ describe('Permalinks', function() {
|
||||
expect(creator.serverCandidates[0]).toBe("pl_95");
|
||||
});
|
||||
|
||||
it('should pick candidate servers based on user population', function() {
|
||||
it("should pick candidate servers based on user population", function () {
|
||||
const roomId = "!fake:example.org";
|
||||
const room = mockRoom(roomId, [
|
||||
makeMemberWithPL(roomId, "@alice:first", 0),
|
||||
@ -162,7 +158,7 @@ describe('Permalinks', function() {
|
||||
expect(creator.serverCandidates[2]).toBe("third");
|
||||
});
|
||||
|
||||
it('should pick prefer candidate servers with higher power levels', function() {
|
||||
it("should pick prefer candidate servers with higher power levels", function () {
|
||||
const roomId = "!fake:example.org";
|
||||
const room = mockRoom(roomId, [
|
||||
makeMemberWithPL(roomId, "@alice:first", 100),
|
||||
@ -178,7 +174,7 @@ describe('Permalinks', function() {
|
||||
expect(creator.serverCandidates[2]).toBe("third");
|
||||
});
|
||||
|
||||
it('should pick a maximum of 3 candidate servers', function() {
|
||||
it("should pick a maximum of 3 candidate servers", function () {
|
||||
const roomId = "!fake:example.org";
|
||||
const room = mockRoom(roomId, [
|
||||
makeMemberWithPL(roomId, "@alice:alpha", 100),
|
||||
@ -193,55 +189,45 @@ describe('Permalinks', function() {
|
||||
expect(creator.serverCandidates.length).toBe(3);
|
||||
});
|
||||
|
||||
it('should not consider IPv4 hosts', function() {
|
||||
it("should not consider IPv4 hosts", function () {
|
||||
const roomId = "!fake:example.org";
|
||||
const room = mockRoom(roomId, [
|
||||
makeMemberWithPL(roomId, "@alice:127.0.0.1", 100),
|
||||
]);
|
||||
const room = mockRoom(roomId, [makeMemberWithPL(roomId, "@alice:127.0.0.1", 100)]);
|
||||
const creator = new RoomPermalinkCreator(room);
|
||||
creator.load();
|
||||
expect(creator.serverCandidates).toBeTruthy();
|
||||
expect(creator.serverCandidates.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should not consider IPv6 hosts', function() {
|
||||
it("should not consider IPv6 hosts", function () {
|
||||
const roomId = "!fake:example.org";
|
||||
const room = mockRoom(roomId, [
|
||||
makeMemberWithPL(roomId, "@alice:[::1]", 100),
|
||||
]);
|
||||
const room = mockRoom(roomId, [makeMemberWithPL(roomId, "@alice:[::1]", 100)]);
|
||||
const creator = new RoomPermalinkCreator(room);
|
||||
creator.load();
|
||||
expect(creator.serverCandidates).toBeTruthy();
|
||||
expect(creator.serverCandidates.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should not consider IPv4 hostnames with ports', function() {
|
||||
it("should not consider IPv4 hostnames with ports", function () {
|
||||
const roomId = "!fake:example.org";
|
||||
const room = mockRoom(roomId, [
|
||||
makeMemberWithPL(roomId, "@alice:127.0.0.1:8448", 100),
|
||||
]);
|
||||
const room = mockRoom(roomId, [makeMemberWithPL(roomId, "@alice:127.0.0.1:8448", 100)]);
|
||||
const creator = new RoomPermalinkCreator(room);
|
||||
creator.load();
|
||||
expect(creator.serverCandidates).toBeTruthy();
|
||||
expect(creator.serverCandidates.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should not consider IPv6 hostnames with ports', function() {
|
||||
it("should not consider IPv6 hostnames with ports", function () {
|
||||
const roomId = "!fake:example.org";
|
||||
const room = mockRoom(roomId, [
|
||||
makeMemberWithPL(roomId, "@alice:[::1]:8448", 100),
|
||||
]);
|
||||
const room = mockRoom(roomId, [makeMemberWithPL(roomId, "@alice:[::1]:8448", 100)]);
|
||||
const creator = new RoomPermalinkCreator(room);
|
||||
creator.load();
|
||||
expect(creator.serverCandidates).toBeTruthy();
|
||||
expect(creator.serverCandidates.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should work with hostnames with ports', function() {
|
||||
it("should work with hostnames with ports", function () {
|
||||
const roomId = "!fake:example.org";
|
||||
const room = mockRoom(roomId, [
|
||||
makeMemberWithPL(roomId, "@alice:example.org:8448", 100),
|
||||
]);
|
||||
const room = mockRoom(roomId, [makeMemberWithPL(roomId, "@alice:example.org:8448", 100)]);
|
||||
|
||||
const creator = new RoomPermalinkCreator(room);
|
||||
creator.load();
|
||||
@ -250,45 +236,57 @@ describe('Permalinks', function() {
|
||||
expect(creator.serverCandidates[0]).toBe("example.org:8448");
|
||||
});
|
||||
|
||||
it('should not consider servers explicitly denied by ACLs', function() {
|
||||
it("should not consider servers explicitly denied by ACLs", function () {
|
||||
const roomId = "!fake:example.org";
|
||||
const room = mockRoom(roomId, [
|
||||
makeMemberWithPL(roomId, "@alice:evilcorp.com", 100),
|
||||
makeMemberWithPL(roomId, "@bob:chat.evilcorp.com", 0),
|
||||
], {
|
||||
deny: ["evilcorp.com", "*.evilcorp.com"],
|
||||
allow: ["*"],
|
||||
});
|
||||
const room = mockRoom(
|
||||
roomId,
|
||||
[
|
||||
makeMemberWithPL(roomId, "@alice:evilcorp.com", 100),
|
||||
makeMemberWithPL(roomId, "@bob:chat.evilcorp.com", 0),
|
||||
],
|
||||
{
|
||||
deny: ["evilcorp.com", "*.evilcorp.com"],
|
||||
allow: ["*"],
|
||||
},
|
||||
);
|
||||
const creator = new RoomPermalinkCreator(room);
|
||||
creator.load();
|
||||
expect(creator.serverCandidates).toBeTruthy();
|
||||
expect(creator.serverCandidates.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should not consider servers not allowed by ACLs', function() {
|
||||
it("should not consider servers not allowed by ACLs", function () {
|
||||
const roomId = "!fake:example.org";
|
||||
const room = mockRoom(roomId, [
|
||||
makeMemberWithPL(roomId, "@alice:evilcorp.com", 100),
|
||||
makeMemberWithPL(roomId, "@bob:chat.evilcorp.com", 0),
|
||||
], {
|
||||
deny: [],
|
||||
allow: [], // implies "ban everyone"
|
||||
});
|
||||
const room = mockRoom(
|
||||
roomId,
|
||||
[
|
||||
makeMemberWithPL(roomId, "@alice:evilcorp.com", 100),
|
||||
makeMemberWithPL(roomId, "@bob:chat.evilcorp.com", 0),
|
||||
],
|
||||
{
|
||||
deny: [],
|
||||
allow: [], // implies "ban everyone"
|
||||
},
|
||||
);
|
||||
const creator = new RoomPermalinkCreator(room);
|
||||
creator.load();
|
||||
expect(creator.serverCandidates).toBeTruthy();
|
||||
expect(creator.serverCandidates.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should consider servers not explicitly banned by ACLs', function() {
|
||||
it("should consider servers not explicitly banned by ACLs", function () {
|
||||
const roomId = "!fake:example.org";
|
||||
const room = mockRoom(roomId, [
|
||||
makeMemberWithPL(roomId, "@alice:evilcorp.com", 100),
|
||||
makeMemberWithPL(roomId, "@bob:chat.evilcorp.com", 0),
|
||||
], {
|
||||
deny: ["*.evilcorp.com"], // evilcorp.com is still good though
|
||||
allow: ["*"],
|
||||
});
|
||||
const room = mockRoom(
|
||||
roomId,
|
||||
[
|
||||
makeMemberWithPL(roomId, "@alice:evilcorp.com", 100),
|
||||
makeMemberWithPL(roomId, "@bob:chat.evilcorp.com", 0),
|
||||
],
|
||||
{
|
||||
deny: ["*.evilcorp.com"], // evilcorp.com is still good though
|
||||
allow: ["*"],
|
||||
},
|
||||
);
|
||||
const creator = new RoomPermalinkCreator(room);
|
||||
creator.load();
|
||||
expect(creator.serverCandidates).toBeTruthy();
|
||||
@ -296,15 +294,19 @@ describe('Permalinks', function() {
|
||||
expect(creator.serverCandidates[0]).toEqual("evilcorp.com");
|
||||
});
|
||||
|
||||
it('should consider servers not disallowed by ACLs', function() {
|
||||
it("should consider servers not disallowed by ACLs", function () {
|
||||
const roomId = "!fake:example.org";
|
||||
const room = mockRoom("!fake:example.org", [
|
||||
makeMemberWithPL(roomId, "@alice:evilcorp.com", 100),
|
||||
makeMemberWithPL(roomId, "@bob:chat.evilcorp.com", 0),
|
||||
], {
|
||||
deny: [],
|
||||
allow: ["evilcorp.com"], // implies "ban everyone else"
|
||||
});
|
||||
const room = mockRoom(
|
||||
"!fake:example.org",
|
||||
[
|
||||
makeMemberWithPL(roomId, "@alice:evilcorp.com", 100),
|
||||
makeMemberWithPL(roomId, "@bob:chat.evilcorp.com", 0),
|
||||
],
|
||||
{
|
||||
deny: [],
|
||||
allow: ["evilcorp.com"], // implies "ban everyone else"
|
||||
},
|
||||
);
|
||||
const creator = new RoomPermalinkCreator(room);
|
||||
creator.load();
|
||||
expect(creator.serverCandidates).toBeTruthy();
|
||||
@ -312,7 +314,7 @@ describe('Permalinks', function() {
|
||||
expect(creator.serverCandidates[0]).toEqual("evilcorp.com");
|
||||
});
|
||||
|
||||
it('should generate an event permalink for room IDs with no candidate servers', function() {
|
||||
it("should generate an event permalink for room IDs with no candidate servers", function () {
|
||||
const room = mockRoom("!somewhere:example.org", []);
|
||||
const creator = new RoomPermalinkCreator(room);
|
||||
creator.load();
|
||||
@ -320,7 +322,7 @@ describe('Permalinks', function() {
|
||||
expect(result).toBe("https://matrix.to/#/!somewhere:example.org/$something:example.com");
|
||||
});
|
||||
|
||||
it('should generate an event permalink for room IDs with some candidate servers', function() {
|
||||
it("should generate an event permalink for room IDs with some candidate servers", function () {
|
||||
const roomId = "!somewhere:example.org";
|
||||
const room = mockRoom(roomId, [
|
||||
makeMemberWithPL(roomId, "@alice:first", 100),
|
||||
@ -332,8 +334,8 @@ describe('Permalinks', function() {
|
||||
expect(result).toBe("https://matrix.to/#/!somewhere:example.org/$something:example.com?via=first&via=second");
|
||||
});
|
||||
|
||||
it('should generate a room permalink for room IDs with some candidate servers', function() {
|
||||
mockClient.getRoom.mockImplementation((roomId: Room['roomId']) => {
|
||||
it("should generate a room permalink for room IDs with some candidate servers", function () {
|
||||
mockClient.getRoom.mockImplementation((roomId: Room["roomId"]) => {
|
||||
return mockRoom(roomId, [
|
||||
makeMemberWithPL(roomId, "@alice:first", 100),
|
||||
makeMemberWithPL(roomId, "@bob:second", 0),
|
||||
@ -343,14 +345,14 @@ describe('Permalinks', function() {
|
||||
expect(result).toBe("https://matrix.to/#/!somewhere:example.org?via=first&via=second");
|
||||
});
|
||||
|
||||
it('should generate a room permalink for room aliases with no candidate servers', function() {
|
||||
it("should generate a room permalink for room aliases with no candidate servers", function () {
|
||||
mockClient.getRoom.mockReturnValue(null);
|
||||
const result = makeRoomPermalink("#somewhere:example.org");
|
||||
expect(result).toBe("https://matrix.to/#/#somewhere:example.org");
|
||||
});
|
||||
|
||||
it('should generate a room permalink for room aliases without candidate servers', function() {
|
||||
mockClient.getRoom.mockImplementation((roomId: Room['roomId']) => {
|
||||
it("should generate a room permalink for room aliases without candidate servers", function () {
|
||||
mockClient.getRoom.mockImplementation((roomId: Room["roomId"]) => {
|
||||
return mockRoom(roomId, [
|
||||
makeMemberWithPL(roomId, "@alice:first", 100),
|
||||
makeMemberWithPL(roomId, "@bob:second", 0),
|
||||
@ -360,26 +362,27 @@ describe('Permalinks', function() {
|
||||
expect(result).toBe("https://matrix.to/#/#somewhere:example.org");
|
||||
});
|
||||
|
||||
it('should generate a user permalink', function() {
|
||||
it("should generate a user permalink", function () {
|
||||
const result = makeUserPermalink("@someone:example.org");
|
||||
expect(result).toBe("https://matrix.to/#/@someone:example.org");
|
||||
});
|
||||
|
||||
it('should correctly parse room permalinks with a via argument', () => {
|
||||
it("should correctly parse room permalinks with a via argument", () => {
|
||||
const result = parsePermalink("https://matrix.to/#/!room_id:server?via=some.org");
|
||||
expect(result.roomIdOrAlias).toBe("!room_id:server");
|
||||
expect(result.viaServers).toEqual(["some.org"]);
|
||||
});
|
||||
|
||||
it('should correctly parse room permalink via arguments', () => {
|
||||
it("should correctly parse room permalink via arguments", () => {
|
||||
const result = parsePermalink("https://matrix.to/#/!room_id:server?via=foo.bar&via=bar.foo");
|
||||
expect(result.roomIdOrAlias).toBe("!room_id:server");
|
||||
expect(result.viaServers).toEqual(["foo.bar", "bar.foo"]);
|
||||
});
|
||||
|
||||
it('should correctly parse event permalink via arguments', () => {
|
||||
const result = parsePermalink("https://matrix.to/#/!room_id:server/$event_id/some_thing_here/foobar" +
|
||||
"?via=m1.org&via=m2.org");
|
||||
it("should correctly parse event permalink via arguments", () => {
|
||||
const result = parsePermalink(
|
||||
"https://matrix.to/#/!room_id:server/$event_id/some_thing_here/foobar" + "?via=m1.org&via=m2.org",
|
||||
);
|
||||
expect(result.eventId).toBe("$event_id/some_thing_here/foobar");
|
||||
expect(result.roomIdOrAlias).toBe("!room_id:server");
|
||||
expect(result.viaServers).toEqual(["m1.org", "m2.org"]);
|
||||
|
@ -44,11 +44,13 @@ describe("pillify", () => {
|
||||
rule_id: ".m.rule.roomnotif",
|
||||
default: true,
|
||||
enabled: true,
|
||||
conditions: [{
|
||||
kind: ConditionKind.EventMatch,
|
||||
key: "content.body",
|
||||
pattern: "@room",
|
||||
}],
|
||||
conditions: [
|
||||
{
|
||||
kind: ConditionKind.EventMatch,
|
||||
key: "content.body",
|
||||
pattern: "@room",
|
||||
},
|
||||
],
|
||||
actions: [
|
||||
PushRuleActionName.Notify,
|
||||
{
|
||||
|
@ -50,10 +50,7 @@ describe("getJoinedNonFunctionalMembers", () => {
|
||||
|
||||
describe("if there are only regular room members", () => {
|
||||
beforeEach(() => {
|
||||
mocked(room.getJoinedMembers).mockReturnValue([
|
||||
roomMember1,
|
||||
roomMember2,
|
||||
]);
|
||||
mocked(room.getJoinedMembers).mockReturnValue([roomMember1, roomMember2]);
|
||||
mocked(getFunctionalMembers).mockReturnValue([]);
|
||||
});
|
||||
|
||||
@ -67,9 +64,7 @@ describe("getJoinedNonFunctionalMembers", () => {
|
||||
describe("if there are only functional room members", () => {
|
||||
beforeEach(() => {
|
||||
mocked(room.getJoinedMembers).mockReturnValue([]);
|
||||
mocked(getFunctionalMembers).mockReturnValue([
|
||||
"@functional:example.com",
|
||||
]);
|
||||
mocked(getFunctionalMembers).mockReturnValue(["@functional:example.com"]);
|
||||
});
|
||||
|
||||
it("should return an empty list", () => {
|
||||
@ -79,13 +74,8 @@ describe("getJoinedNonFunctionalMembers", () => {
|
||||
|
||||
describe("if there are some functional room members", () => {
|
||||
beforeEach(() => {
|
||||
mocked(room.getJoinedMembers).mockReturnValue([
|
||||
roomMember1,
|
||||
roomMember2,
|
||||
]);
|
||||
mocked(getFunctionalMembers).mockReturnValue([
|
||||
roomMember1.userId,
|
||||
]);
|
||||
mocked(room.getJoinedMembers).mockReturnValue([roomMember1, roomMember2]);
|
||||
mocked(getFunctionalMembers).mockReturnValue([roomMember1.userId]);
|
||||
});
|
||||
|
||||
it("should only return the non-functional members", () => {
|
||||
|
@ -28,26 +28,30 @@ describe("getRoomFunctionalMembers", () => {
|
||||
});
|
||||
|
||||
it("should return an empty array if functional members state event does not have a service_members field", () => {
|
||||
room.currentState.setStateEvents([mkEvent({
|
||||
event: true,
|
||||
type: UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name,
|
||||
user: "@user:example.com)",
|
||||
room: room.roomId,
|
||||
skey: "",
|
||||
content: {},
|
||||
})]);
|
||||
room.currentState.setStateEvents([
|
||||
mkEvent({
|
||||
event: true,
|
||||
type: UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name,
|
||||
user: "@user:example.com)",
|
||||
room: room.roomId,
|
||||
skey: "",
|
||||
content: {},
|
||||
}),
|
||||
]);
|
||||
expect(getFunctionalMembers(room)).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("should return service_members field of the functional users state event", () => {
|
||||
room.currentState.setStateEvents([mkEvent({
|
||||
event: true,
|
||||
type: UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name,
|
||||
user: "@user:example.com)",
|
||||
room: room.roomId,
|
||||
skey: "",
|
||||
content: { service_members: ["@user:example.com"] },
|
||||
})]);
|
||||
room.currentState.setStateEvents([
|
||||
mkEvent({
|
||||
event: true,
|
||||
type: UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name,
|
||||
user: "@user:example.com)",
|
||||
room: room.roomId,
|
||||
skey: "",
|
||||
content: { service_members: ["@user:example.com"] },
|
||||
}),
|
||||
]);
|
||||
expect(getFunctionalMembers(room)).toEqual(["@user:example.com"]);
|
||||
});
|
||||
});
|
||||
|
@ -16,37 +16,37 @@ limitations under the License.
|
||||
|
||||
import { setHasDiff } from "../../src/utils/sets";
|
||||
|
||||
describe('sets', () => {
|
||||
describe('setHasDiff', () => {
|
||||
it('should flag true on A length > B length', () => {
|
||||
describe("sets", () => {
|
||||
describe("setHasDiff", () => {
|
||||
it("should flag true on A length > B length", () => {
|
||||
const a = new Set([1, 2, 3, 4]);
|
||||
const b = new Set([1, 2, 3]);
|
||||
const result = setHasDiff(a, b);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should flag true on A length < B length', () => {
|
||||
it("should flag true on A length < B length", () => {
|
||||
const a = new Set([1, 2, 3]);
|
||||
const b = new Set([1, 2, 3, 4]);
|
||||
const result = setHasDiff(a, b);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should flag true on element differences', () => {
|
||||
it("should flag true on element differences", () => {
|
||||
const a = new Set([1, 2, 3]);
|
||||
const b = new Set([4, 5, 6]);
|
||||
const result = setHasDiff(a, b);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should flag false if same but order different', () => {
|
||||
it("should flag false if same but order different", () => {
|
||||
const a = new Set([1, 2, 3]);
|
||||
const b = new Set([3, 1, 2]);
|
||||
const result = setHasDiff(a, b);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should flag false if same', () => {
|
||||
it("should flag false if same", () => {
|
||||
const a = new Set([1, 2, 3]);
|
||||
const b = new Set([1, 2, 3]);
|
||||
const result = setHasDiff(a, b);
|
||||
|
@ -33,7 +33,7 @@ const moveLexicographicallyTest = (
|
||||
zipped[index][1] = order;
|
||||
});
|
||||
|
||||
const newOrders = sortBy(zipped, i => i[1]);
|
||||
const newOrders = sortBy(zipped, (i) => i[1]);
|
||||
expect(newOrders[toIndex][0]).toBe(fromIndex);
|
||||
expect(ops).toHaveLength(expectedChanges);
|
||||
};
|
||||
@ -64,73 +64,33 @@ describe("stringOrderField", () => {
|
||||
});
|
||||
|
||||
it("should work when all orders are undefined", () => {
|
||||
moveLexicographicallyTest(
|
||||
[undefined, undefined, undefined, undefined, undefined, undefined],
|
||||
4,
|
||||
1,
|
||||
2,
|
||||
);
|
||||
moveLexicographicallyTest([undefined, undefined, undefined, undefined, undefined, undefined], 4, 1, 2);
|
||||
});
|
||||
|
||||
it("should work when moving to end and all orders are undefined", () => {
|
||||
moveLexicographicallyTest(
|
||||
[undefined, undefined, undefined, undefined, undefined, undefined],
|
||||
1,
|
||||
4,
|
||||
5,
|
||||
);
|
||||
moveLexicographicallyTest([undefined, undefined, undefined, undefined, undefined, undefined], 1, 4, 5);
|
||||
});
|
||||
|
||||
it("should work when moving left and some orders are undefined", () => {
|
||||
moveLexicographicallyTest(
|
||||
["a", "c", "e", undefined, undefined, undefined],
|
||||
5,
|
||||
2,
|
||||
1,
|
||||
);
|
||||
moveLexicographicallyTest(["a", "c", "e", undefined, undefined, undefined], 5, 2, 1);
|
||||
|
||||
moveLexicographicallyTest(
|
||||
["a", "a", "e", undefined, undefined, undefined],
|
||||
5,
|
||||
1,
|
||||
2,
|
||||
);
|
||||
moveLexicographicallyTest(["a", "a", "e", undefined, undefined, undefined], 5, 1, 2);
|
||||
});
|
||||
|
||||
it("should work moving to the start when all is undefined", () => {
|
||||
moveLexicographicallyTest(
|
||||
[undefined, undefined, undefined, undefined],
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
);
|
||||
moveLexicographicallyTest([undefined, undefined, undefined, undefined], 2, 0, 1);
|
||||
});
|
||||
|
||||
it("should work moving to the end when all is undefined", () => {
|
||||
moveLexicographicallyTest(
|
||||
[undefined, undefined, undefined, undefined],
|
||||
1,
|
||||
3,
|
||||
4,
|
||||
);
|
||||
moveLexicographicallyTest([undefined, undefined, undefined, undefined], 1, 3, 4);
|
||||
});
|
||||
|
||||
it("should work moving left when all is undefined", () => {
|
||||
moveLexicographicallyTest(
|
||||
[undefined, undefined, undefined, undefined, undefined, undefined],
|
||||
4,
|
||||
1,
|
||||
2,
|
||||
);
|
||||
moveLexicographicallyTest([undefined, undefined, undefined, undefined, undefined, undefined], 4, 1, 2);
|
||||
});
|
||||
|
||||
it("should work moving right when all is undefined", () => {
|
||||
moveLexicographicallyTest(
|
||||
[undefined, undefined, undefined, undefined],
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
);
|
||||
moveLexicographicallyTest([undefined, undefined, undefined, undefined], 1, 2, 3);
|
||||
});
|
||||
|
||||
it("should work moving more right when all is undefined", () => {
|
||||
@ -143,12 +103,7 @@ describe("stringOrderField", () => {
|
||||
});
|
||||
|
||||
it("should work moving left when right is undefined", () => {
|
||||
moveLexicographicallyTest(
|
||||
["20", undefined, undefined, undefined, undefined, undefined],
|
||||
4,
|
||||
2,
|
||||
2,
|
||||
);
|
||||
moveLexicographicallyTest(["20", undefined, undefined, undefined, undefined, undefined], 4, 2, 2);
|
||||
});
|
||||
|
||||
it("should work moving right when right is undefined", () => {
|
||||
@ -161,49 +116,23 @@ describe("stringOrderField", () => {
|
||||
});
|
||||
|
||||
it("should work moving left when right is defined", () => {
|
||||
moveLexicographicallyTest(
|
||||
["10", "20", "30", "40", undefined, undefined],
|
||||
3,
|
||||
1,
|
||||
1,
|
||||
);
|
||||
moveLexicographicallyTest(["10", "20", "30", "40", undefined, undefined], 3, 1, 1);
|
||||
});
|
||||
|
||||
it("should work moving right when right is defined", () => {
|
||||
moveLexicographicallyTest(
|
||||
["10", "20", "30", "40", "50", undefined],
|
||||
1,
|
||||
3,
|
||||
1,
|
||||
);
|
||||
moveLexicographicallyTest(["10", "20", "30", "40", "50", undefined], 1, 3, 1);
|
||||
});
|
||||
|
||||
it("should work moving left when all is defined", () => {
|
||||
moveLexicographicallyTest(
|
||||
["11", "13", "15", "17", "19"],
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
);
|
||||
moveLexicographicallyTest(["11", "13", "15", "17", "19"], 2, 1, 1);
|
||||
});
|
||||
|
||||
it("should work moving right when all is defined", () => {
|
||||
moveLexicographicallyTest(
|
||||
["11", "13", "15", "17", "19"],
|
||||
1,
|
||||
2,
|
||||
1,
|
||||
);
|
||||
moveLexicographicallyTest(["11", "13", "15", "17", "19"], 1, 2, 1);
|
||||
});
|
||||
|
||||
it("should work moving left into no left space", () => {
|
||||
moveLexicographicallyTest(
|
||||
["11", "12", "13", "14", "19"],
|
||||
3,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
);
|
||||
moveLexicographicallyTest(["11", "12", "13", "14", "19"], 3, 1, 2, 2);
|
||||
|
||||
moveLexicographicallyTest(
|
||||
[
|
||||
@ -223,13 +152,7 @@ describe("stringOrderField", () => {
|
||||
});
|
||||
|
||||
it("should work moving right into no right space", () => {
|
||||
moveLexicographicallyTest(
|
||||
["15", "16", "17", "18", "19"],
|
||||
1,
|
||||
3,
|
||||
3,
|
||||
2,
|
||||
);
|
||||
moveLexicographicallyTest(["15", "16", "17", "18", "19"], 1, 3, 3, 2);
|
||||
|
||||
moveLexicographicallyTest(
|
||||
[
|
||||
@ -247,30 +170,13 @@ describe("stringOrderField", () => {
|
||||
});
|
||||
|
||||
it("should work moving right into no left space", () => {
|
||||
moveLexicographicallyTest(
|
||||
["11", "12", "13", "14", "15", "16", undefined],
|
||||
1,
|
||||
3,
|
||||
3,
|
||||
);
|
||||
moveLexicographicallyTest(["11", "12", "13", "14", "15", "16", undefined], 1, 3, 3);
|
||||
|
||||
moveLexicographicallyTest(
|
||||
["0", "1", "2", "3", "4", "5"],
|
||||
1,
|
||||
3,
|
||||
3,
|
||||
1,
|
||||
);
|
||||
moveLexicographicallyTest(["0", "1", "2", "3", "4", "5"], 1, 3, 3, 1);
|
||||
});
|
||||
|
||||
it("should work moving left into no right space", () => {
|
||||
moveLexicographicallyTest(
|
||||
["15", "16", "17", "18", "19"],
|
||||
4,
|
||||
3,
|
||||
4,
|
||||
2,
|
||||
);
|
||||
moveLexicographicallyTest(["15", "16", "17", "18", "19"], 4, 3, 4, 2);
|
||||
|
||||
moveLexicographicallyTest(
|
||||
[
|
||||
@ -288,4 +194,3 @@ describe("stringOrderField", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -14,18 +14,17 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import React from "react";
|
||||
import { render } from "@testing-library/react";
|
||||
|
||||
import { tooltipifyLinks } from '../../src/utils/tooltipify';
|
||||
import PlatformPeg from '../../src/PlatformPeg';
|
||||
import BasePlatform from '../../src/BasePlatform';
|
||||
import { tooltipifyLinks } from "../../src/utils/tooltipify";
|
||||
import PlatformPeg from "../../src/PlatformPeg";
|
||||
import BasePlatform from "../../src/BasePlatform";
|
||||
|
||||
describe('tooltipify', () => {
|
||||
jest.spyOn(PlatformPeg, 'get')
|
||||
.mockReturnValue({ needsUrlTooltips: () => true } as unknown as BasePlatform);
|
||||
describe("tooltipify", () => {
|
||||
jest.spyOn(PlatformPeg, "get").mockReturnValue({ needsUrlTooltips: () => true } as unknown as BasePlatform);
|
||||
|
||||
it('does nothing for empty element', () => {
|
||||
it("does nothing for empty element", () => {
|
||||
const { container: root } = render(<div />);
|
||||
const originalHtml = root.outerHTML;
|
||||
const containers: Element[] = [];
|
||||
@ -34,8 +33,12 @@ describe('tooltipify', () => {
|
||||
expect(root.outerHTML).toEqual(originalHtml);
|
||||
});
|
||||
|
||||
it('wraps single anchor', () => {
|
||||
const { container: root } = render(<div><a href="/foo">click</a></div>);
|
||||
it("wraps single anchor", () => {
|
||||
const { container: root } = render(
|
||||
<div>
|
||||
<a href="/foo">click</a>
|
||||
</div>,
|
||||
);
|
||||
const containers: Element[] = [];
|
||||
tooltipifyLinks([root], [], containers);
|
||||
expect(containers).toHaveLength(1);
|
||||
@ -45,8 +48,12 @@ describe('tooltipify', () => {
|
||||
expect(tooltip).toBeDefined();
|
||||
});
|
||||
|
||||
it('ignores node', () => {
|
||||
const { container: root } = render(<div><a href="/foo">click</a></div>);
|
||||
it("ignores node", () => {
|
||||
const { container: root } = render(
|
||||
<div>
|
||||
<a href="/foo">click</a>
|
||||
</div>,
|
||||
);
|
||||
const originalHtml = root.outerHTML;
|
||||
const containers: Element[] = [];
|
||||
tooltipifyLinks([root], [root.children[0]], containers);
|
||||
@ -55,7 +62,11 @@ describe('tooltipify', () => {
|
||||
});
|
||||
|
||||
it("does not re-wrap if called multiple times", () => {
|
||||
const { container: root } = render(<div><a href="/foo">click</a></div>);
|
||||
const { container: root } = render(
|
||||
<div>
|
||||
<a href="/foo">click</a>
|
||||
</div>,
|
||||
);
|
||||
const containers: Element[] = [];
|
||||
tooltipifyLinks([root], [], containers);
|
||||
tooltipifyLinks([root], [], containers);
|
||||
|
@ -14,29 +14,30 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { validateNumberInRange } from '../../../src/utils/validate';
|
||||
import { validateNumberInRange } from "../../../src/utils/validate";
|
||||
|
||||
describe('validateNumberInRange', () => {
|
||||
const min = 1; const max = 10;
|
||||
it('returns false when value is a not a number', () => {
|
||||
expect(validateNumberInRange(min, max)('test' as unknown as number)).toEqual(false);
|
||||
describe("validateNumberInRange", () => {
|
||||
const min = 1;
|
||||
const max = 10;
|
||||
it("returns false when value is a not a number", () => {
|
||||
expect(validateNumberInRange(min, max)("test" as unknown as number)).toEqual(false);
|
||||
});
|
||||
it('returns false when value is undefined', () => {
|
||||
it("returns false when value is undefined", () => {
|
||||
expect(validateNumberInRange(min, max)(undefined)).toEqual(false);
|
||||
});
|
||||
it('returns false when value is NaN', () => {
|
||||
it("returns false when value is NaN", () => {
|
||||
expect(validateNumberInRange(min, max)(NaN)).toEqual(false);
|
||||
});
|
||||
it('returns true when value is equal to min', () => {
|
||||
it("returns true when value is equal to min", () => {
|
||||
expect(validateNumberInRange(min, max)(min)).toEqual(true);
|
||||
});
|
||||
it('returns true when value is equal to max', () => {
|
||||
it("returns true when value is equal to max", () => {
|
||||
expect(validateNumberInRange(min, max)(max)).toEqual(true);
|
||||
});
|
||||
it('returns true when value is an int in range', () => {
|
||||
it("returns true when value is an int in range", () => {
|
||||
expect(validateNumberInRange(min, max)(2)).toEqual(true);
|
||||
});
|
||||
it('returns true when value is a float in range', () => {
|
||||
it("returns true when value is a float in range", () => {
|
||||
expect(validateNumberInRange(min, max)(2.2)).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user