Migrate batch of tests to vitest (#34106)
* Migrate autocomplete tests to vitest * Migrate utils/beacon tests to vitest * Migrate utils/device tests to vitest * Migrate utils/crypto tests to vitest * Migrate utils/localRoom tests to vitest * Migrate notifications tests to vitest * Fix types * Make jest test happy * Make sonar happier
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { Beacon } from "matrix-js-sdk/src/matrix";
|
||||
import { makeBeaconEvent, makeBeaconInfoEvent } from "test-utils";
|
||||
|
||||
import { type Bounds, getBeaconBounds } from "./bounds";
|
||||
|
||||
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
|
||||
beacon.checkLiveness();
|
||||
const location = makeBeaconEvent(userId, {
|
||||
beaconInfoId: beacon.beaconInfoId,
|
||||
geoUri,
|
||||
timestamp: Date.now() + 1,
|
||||
});
|
||||
beacon.addLocations([location]);
|
||||
|
||||
return beacon;
|
||||
};
|
||||
|
||||
const geo = {
|
||||
// northern hemi
|
||||
// west of greenwich
|
||||
london: { lat: 51.5, lon: -0.14 },
|
||||
reykjavik: { lat: 64.08, lon: -21.82 },
|
||||
// east of greenwich
|
||||
paris: { lat: 48.85, lon: 2.29 },
|
||||
// southern hemi
|
||||
// east
|
||||
auckland: { lat: -36.85, lon: 174.76 }, // nz
|
||||
// west
|
||||
lima: { lat: -12.013843, lon: -77.008388 }, // peru
|
||||
};
|
||||
|
||||
const london = makeBeaconWithLocation(geo.london);
|
||||
const reykjavik = makeBeaconWithLocation(geo.reykjavik);
|
||||
const paris = makeBeaconWithLocation(geo.paris);
|
||||
const auckland = makeBeaconWithLocation(geo.auckland);
|
||||
const lima = makeBeaconWithLocation(geo.lima);
|
||||
|
||||
it("should return undefined when there are no beacons", () => {
|
||||
expect(getBeaconBounds([])).toBeUndefined();
|
||||
});
|
||||
|
||||
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],
|
||||
{ north: geo.london.lat, south: geo.london.lat, east: geo.london.lon, west: geo.london.lon },
|
||||
],
|
||||
[
|
||||
"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",
|
||||
[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",
|
||||
[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",
|
||||
[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) => {
|
||||
expect(getBeaconBounds(beacons)).toEqual(expectedBounds);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { vi, describe, it, expect, afterAll, beforeEach } from "vitest";
|
||||
import { M_TIMESTAMP, Beacon } from "matrix-js-sdk/src/matrix";
|
||||
import { makeBeaconInfoEvent } from "test-utils";
|
||||
|
||||
import { msUntilExpiry, sortBeaconsByLatestExpiry, sortBeaconsByLatestCreation } from "./duration";
|
||||
|
||||
describe("beacon utils", () => {
|
||||
// 14.03.2022 16:15
|
||||
const now = 1647270879403;
|
||||
const HOUR_MS = 3600000;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.spyOn(global.Date, "now").mockReturnValue(now);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
vi.spyOn(global.Date, "now").mockRestore();
|
||||
});
|
||||
|
||||
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", () => {
|
||||
// created 3h ago
|
||||
const start = now - HOUR_MS * 3;
|
||||
// 1h durations
|
||||
const durationMs = HOUR_MS;
|
||||
|
||||
expect(msUntilExpiry(start, durationMs)).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
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"),
|
||||
);
|
||||
// 10h left
|
||||
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 noTimestampEvent = makeBeaconInfoEvent(
|
||||
aliceId,
|
||||
roomId,
|
||||
{ timeout: HOUR_MS + 1, timestamp: undefined },
|
||||
"$3",
|
||||
);
|
||||
// beacon info helper defaults to date when timestamp is falsy
|
||||
// hard set it to undefined
|
||||
// @ts-ignore
|
||||
noTimestampEvent.event.content[M_TIMESTAMP.name] = undefined;
|
||||
const beaconNoTimestamp = new Beacon(noTimestampEvent);
|
||||
|
||||
it("sorts beacons by descending expiry time", () => {
|
||||
expect([beacon2, beacon3, beacon1].sort(sortBeaconsByLatestExpiry)).toEqual([beacon1, beacon2, beacon3]);
|
||||
});
|
||||
|
||||
it("sorts beacons with timestamps before beacons without", () => {
|
||||
expect([beaconNoTimestamp, beacon3].sort(sortBeaconsByLatestExpiry)).toEqual([beacon3, beaconNoTimestamp]);
|
||||
});
|
||||
});
|
||||
|
||||
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"),
|
||||
);
|
||||
// 10h left
|
||||
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"),
|
||||
);
|
||||
|
||||
it("sorts beacons by descending creation time", () => {
|
||||
expect([beacon1, beacon2, beacon3].sort(sortBeaconsByLatestCreation)).toEqual([beacon2, beacon3, beacon1]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { vi, describe, it, expect, beforeEach, afterEach, type Mocked } from "vitest";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { makeGeolocationPosition, mockGeolocation, getMockGeolocationPositionError } from "test-utils";
|
||||
|
||||
import {
|
||||
type GenericPosition,
|
||||
GeolocationError,
|
||||
getGeoUri,
|
||||
mapGeolocationError,
|
||||
mapGeolocationPositionToTimedGeo,
|
||||
watchPosition,
|
||||
getCurrentPosition,
|
||||
} from "./geolocation";
|
||||
|
||||
describe("geolocation utilities", () => {
|
||||
let geolocation: Mocked<Geolocation>;
|
||||
const defaultPosition = makeGeolocationPosition({});
|
||||
|
||||
// 14.03.2022 16:15
|
||||
const now = 1647270879403;
|
||||
|
||||
beforeEach(() => {
|
||||
geolocation = mockGeolocation();
|
||||
vi.spyOn(Date, "now").mockReturnValue(now);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.spyOn(Date, "now").mockRestore();
|
||||
vi.spyOn(logger, "error").mockRestore();
|
||||
});
|
||||
|
||||
describe("getGeoUri", () => {
|
||||
it("Renders a URI with only lat and lon", () => {
|
||||
const pos: GenericPosition = {
|
||||
latitude: 43.2,
|
||||
longitude: 12.4,
|
||||
altitude: undefined,
|
||||
accuracy: undefined,
|
||||
|
||||
timestamp: 12334,
|
||||
};
|
||||
expect(getGeoUri(pos)).toEqual("geo:43.2,12.4");
|
||||
});
|
||||
|
||||
it("Nulls in location are not shown in URI", () => {
|
||||
const pos: GenericPosition = {
|
||||
latitude: 43.2,
|
||||
longitude: 12.4,
|
||||
|
||||
timestamp: 12334,
|
||||
};
|
||||
expect(getGeoUri(pos)).toEqual("geo:43.2,12.4");
|
||||
});
|
||||
|
||||
it("Renders a URI with 3 coords", () => {
|
||||
const pos: GenericPosition = {
|
||||
latitude: 43.2,
|
||||
longitude: 12.4,
|
||||
altitude: 332.54,
|
||||
accuracy: undefined,
|
||||
timestamp: 12334,
|
||||
};
|
||||
expect(getGeoUri(pos)).toEqual("geo:43.2,12.4,332.54");
|
||||
});
|
||||
|
||||
it("Renders a URI with accuracy", () => {
|
||||
const pos: GenericPosition = {
|
||||
latitude: 43.2,
|
||||
longitude: 12.4,
|
||||
altitude: undefined,
|
||||
accuracy: 21,
|
||||
timestamp: 12334,
|
||||
};
|
||||
expect(getGeoUri(pos)).toEqual("geo:43.2,12.4;u=21");
|
||||
});
|
||||
|
||||
it("Renders a URI with accuracy and altitude", () => {
|
||||
const pos = {
|
||||
latitude: 43.2,
|
||||
longitude: 12.4,
|
||||
altitude: 12.3,
|
||||
accuracy: 21,
|
||||
timestamp: 12334,
|
||||
};
|
||||
expect(getGeoUri(pos)).toEqual("geo:43.2,12.4,12.3;u=21");
|
||||
});
|
||||
});
|
||||
|
||||
describe("mapGeolocationError", () => {
|
||||
beforeEach(() => {
|
||||
// suppress expected errors from test log
|
||||
vi.spyOn(logger, "error").mockImplementation(() => {});
|
||||
});
|
||||
|
||||
it("returns default for other error", () => {
|
||||
const error = new Error("oh no..");
|
||||
expect(mapGeolocationError(error)).toEqual(GeolocationError.Default);
|
||||
});
|
||||
|
||||
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");
|
||||
expect(mapGeolocationError(error)).toEqual(GeolocationError.PermissionDenied);
|
||||
});
|
||||
|
||||
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");
|
||||
expect(mapGeolocationError(error)).toEqual(GeolocationError.Timeout);
|
||||
});
|
||||
});
|
||||
|
||||
describe("mapGeolocationPositionToTimedGeo()", () => {
|
||||
it("maps geolocation position correctly", () => {
|
||||
expect(mapGeolocationPositionToTimedGeo(defaultPosition)).toEqual({
|
||||
timestamp: now,
|
||||
geoUri: "geo:54.001927,-8.253491;u=1",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("watchPosition()", () => {
|
||||
it("throws with unavailable error when geolocation is not available", () => {
|
||||
// suppress expected errors from test log
|
||||
vi.spyOn(logger, "error").mockImplementation(() => {});
|
||||
|
||||
// remove the mock we added
|
||||
vi.spyOn(navigator, "geolocation", "get").mockRestore();
|
||||
|
||||
const positionHandler = vi.fn();
|
||||
const errorHandler = vi.fn();
|
||||
|
||||
expect(() => watchPosition(positionHandler, errorHandler)).toThrow(GeolocationError.Unavailable);
|
||||
});
|
||||
|
||||
it("sets up position handler with correct options", () => {
|
||||
const positionHandler = vi.fn();
|
||||
const errorHandler = vi.fn();
|
||||
watchPosition(positionHandler, errorHandler);
|
||||
|
||||
const [, , options] = geolocation.watchPosition.mock.calls[0];
|
||||
expect(options).toEqual({
|
||||
maximumAge: 60000,
|
||||
timeout: 10000,
|
||||
});
|
||||
});
|
||||
|
||||
it("returns clearWatch function", () => {
|
||||
const watchId = 1;
|
||||
geolocation.watchPosition.mockReturnValue(watchId);
|
||||
const positionHandler = vi.fn();
|
||||
const errorHandler = vi.fn();
|
||||
const clearWatch = watchPosition(positionHandler, errorHandler);
|
||||
|
||||
clearWatch();
|
||||
|
||||
expect(geolocation.clearWatch).toHaveBeenCalledWith(watchId);
|
||||
});
|
||||
|
||||
it("calls position handler with position", () => {
|
||||
const positionHandler = vi.fn();
|
||||
const errorHandler = vi.fn();
|
||||
watchPosition(positionHandler, errorHandler);
|
||||
|
||||
expect(positionHandler).toHaveBeenCalledWith(defaultPosition);
|
||||
});
|
||||
|
||||
it("maps geolocation position error and calls error handler", () => {
|
||||
// suppress expected errors from test log
|
||||
vi.spyOn(logger, "error").mockImplementation(() => {});
|
||||
geolocation.watchPosition.mockImplementation((_callback, error) => {
|
||||
error!(getMockGeolocationPositionError(1, "message"));
|
||||
return -1;
|
||||
});
|
||||
const positionHandler = vi.fn();
|
||||
const errorHandler = vi.fn();
|
||||
watchPosition(positionHandler, errorHandler);
|
||||
|
||||
expect(errorHandler).toHaveBeenCalledWith(GeolocationError.PermissionDenied);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getCurrentPosition()", () => {
|
||||
it("throws with unavailable error when geolocation is not available", async () => {
|
||||
// suppress expected errors from test log
|
||||
vi.spyOn(logger, "error").mockImplementation(() => {});
|
||||
|
||||
// remove the mock we added
|
||||
vi.spyOn(navigator, "geolocation", "get").mockRestore();
|
||||
|
||||
await expect(() => getCurrentPosition()).rejects.toThrow(GeolocationError.Unavailable);
|
||||
});
|
||||
|
||||
it("throws with geolocation error when geolocation.getCurrentPosition fails", async () => {
|
||||
// suppress expected errors from test log
|
||||
vi.spyOn(logger, "error").mockImplementation(() => {});
|
||||
|
||||
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 () => {
|
||||
geolocation.getCurrentPosition.mockImplementation((callback, error) => callback(defaultPosition));
|
||||
|
||||
const result = await getCurrentPosition();
|
||||
expect(result).toEqual(defaultPosition);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { EventType, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { makeBeaconInfoEvent, stubClient } from "test-utils";
|
||||
|
||||
import { shouldDisplayAsBeaconTile } from "./timeline";
|
||||
|
||||
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, new Room(roomId, stubClient(), userId));
|
||||
|
||||
it("returns true for a beacon with live property set to true", () => {
|
||||
expect(shouldDisplayAsBeaconTile(liveBeacon)).toBe(true);
|
||||
});
|
||||
|
||||
it("returns true for a redacted beacon", () => {
|
||||
expect(shouldDisplayAsBeaconTile(redactedBeacon)).toBe(true);
|
||||
});
|
||||
|
||||
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", () => {
|
||||
expect(shouldDisplayAsBeaconTile(memberEvent)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { vi, describe, it, expect, beforeEach, type Mocked } from "vitest";
|
||||
import { type Device, type MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { getMockClientWithEventEmitter, mockClientMethodsCrypto } from "test-utils";
|
||||
|
||||
import { getDeviceCryptoInfo, getUserDeviceIds } from "./deviceInfo";
|
||||
|
||||
describe("getDeviceCryptoInfo()", () => {
|
||||
let mockClient: Mocked<MatrixClient>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockClient = getMockClientWithEventEmitter({ ...mockClientMethodsCrypto() });
|
||||
});
|
||||
|
||||
it("should return undefined on clients with no crypto", async () => {
|
||||
vi.spyOn(mockClient, "getCrypto").mockReturnValue(undefined);
|
||||
await expect(getDeviceCryptoInfo(mockClient, "@user:id", "device_id")).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return undefined for unknown users", async () => {
|
||||
vi.mocked(mockClient.getCrypto()!.getUserDeviceInfo).mockResolvedValue(new Map());
|
||||
await expect(getDeviceCryptoInfo(mockClient, "@user:id", "device_id")).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return undefined for unknown devices", async () => {
|
||||
vi.mocked(mockClient.getCrypto()!.getUserDeviceInfo).mockResolvedValue(new Map([["@user:id", new Map()]]));
|
||||
await expect(getDeviceCryptoInfo(mockClient, "@user:id", "device_id")).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return the right result for known devices", async () => {
|
||||
const mockDevice = { deviceId: "device_id" } as Device;
|
||||
vi.mocked(mockClient.getCrypto()!.getUserDeviceInfo).mockResolvedValue(
|
||||
new Map([["@user:id", new Map([["device_id", mockDevice]])]]),
|
||||
);
|
||||
await expect(getDeviceCryptoInfo(mockClient, "@user:id", "device_id")).resolves.toBe(mockDevice);
|
||||
expect(mockClient.getCrypto()!.getUserDeviceInfo).toHaveBeenCalledWith(["@user:id"], undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getUserDeviceIds", () => {
|
||||
let mockClient: Mocked<MatrixClient>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockClient = getMockClientWithEventEmitter({ ...mockClientMethodsCrypto() });
|
||||
});
|
||||
|
||||
it("should return empty set on clients with no crypto", async () => {
|
||||
vi.spyOn(mockClient, "getCrypto").mockReturnValue(undefined);
|
||||
await expect(getUserDeviceIds(mockClient, "@user:id")).resolves.toEqual(new Set());
|
||||
});
|
||||
|
||||
it("should return empty set for unknown users", async () => {
|
||||
vi.mocked(mockClient.getCrypto()!.getUserDeviceInfo).mockResolvedValue(new Map());
|
||||
await expect(getUserDeviceIds(mockClient, "@user:id")).resolves.toEqual(new Set());
|
||||
});
|
||||
|
||||
it("should return the right result for known users", async () => {
|
||||
const mockDevice = { deviceId: "device_id" } as Device;
|
||||
vi.mocked(mockClient.getCrypto()!.getUserDeviceInfo).mockResolvedValue(
|
||||
new Map([["@user:id", new Map([["device_id", mockDevice]])]]),
|
||||
);
|
||||
await expect(getUserDeviceIds(mockClient, "@user:id")).resolves.toEqual(new Set(["device_id"]));
|
||||
expect(mockClient.getCrypto()!.getUserDeviceInfo).toHaveBeenCalledWith(["@user:id"]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { vi, describe, it, expect, beforeEach } from "vitest";
|
||||
import { getMockClientWithEventEmitter } from "test-utils";
|
||||
|
||||
import { shouldForceDisableEncryption } from "./shouldForceDisableEncryption";
|
||||
|
||||
describe("shouldForceDisableEncryption()", () => {
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getClientWellKnown: vi.fn(),
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mockClient.getClientWellKnown.mockReturnValue(undefined);
|
||||
});
|
||||
|
||||
it("should return false when there is no e2ee well known", () => {
|
||||
expect(shouldForceDisableEncryption(mockClient)).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return false when there is no force_disable property", () => {
|
||||
mockClient.getClientWellKnown.mockReturnValue({
|
||||
"io.element.e2ee": {
|
||||
// empty
|
||||
},
|
||||
});
|
||||
expect(shouldForceDisableEncryption(mockClient)).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return false when force_disable property is falsy", () => {
|
||||
mockClient.getClientWellKnown.mockReturnValue({
|
||||
"io.element.e2ee": {
|
||||
force_disable: false,
|
||||
},
|
||||
});
|
||||
expect(shouldForceDisableEncryption(mockClient)).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return false when force_disable property is not equal to true", () => {
|
||||
mockClient.getClientWellKnown.mockReturnValue({
|
||||
"io.element.e2ee": {
|
||||
force_disable: 1,
|
||||
},
|
||||
});
|
||||
expect(shouldForceDisableEncryption(mockClient)).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return true when force_disable property is true", () => {
|
||||
mockClient.getClientWellKnown.mockReturnValue({
|
||||
"io.element.e2ee": {
|
||||
force_disable: true,
|
||||
},
|
||||
});
|
||||
expect(shouldForceDisableEncryption(mockClient)).toEqual(true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { vi, describe, it, expect, afterAll, beforeEach } from "vitest";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { getMockClientWithEventEmitter } from "test-utils";
|
||||
|
||||
import type BasePlatform from "../../BasePlatform";
|
||||
import { type IConfigOptions } from "../../IConfigOptions";
|
||||
import { getDeviceClientInformation, recordClientInformation } from "./clientInformation";
|
||||
import { DEFAULTS } from "../../SdkConfig";
|
||||
import { type DeepReadonly } from "../../@types/common";
|
||||
|
||||
describe("recordClientInformation()", () => {
|
||||
const deviceId = "my-device-id";
|
||||
const version = "1.2.3";
|
||||
const isElectron = window.electron;
|
||||
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getDeviceId: vi.fn().mockReturnValue(deviceId),
|
||||
setAccountData: vi.fn(),
|
||||
});
|
||||
|
||||
const sdkConfig: DeepReadonly<IConfigOptions> = {
|
||||
...DEFAULTS,
|
||||
brand: "Test Brand",
|
||||
element_call: { use_exclusively: false, brand: "Element Call" },
|
||||
};
|
||||
|
||||
const platform = {
|
||||
getAppVersion: vi.fn().mockResolvedValue(version),
|
||||
} as unknown as BasePlatform;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
window.electron = undefined;
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
// restore global
|
||||
window.electron = isElectron;
|
||||
});
|
||||
|
||||
it("saves client information without url for electron clients", async () => {
|
||||
window.electron = {} as Electron;
|
||||
|
||||
await recordClientInformation(mockClient, sdkConfig, platform);
|
||||
|
||||
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);
|
||||
|
||||
expect(mockClient.setAccountData).toHaveBeenCalledWith(`io.element.matrix_client_information.${deviceId}`, {
|
||||
name: sdkConfig.brand,
|
||||
version,
|
||||
url: "localhost",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("getDeviceClientInformation()", () => {
|
||||
const deviceId = "my-device-id";
|
||||
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
getAccountData: vi.fn(),
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
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}`);
|
||||
});
|
||||
|
||||
it("returns client information for the device", () => {
|
||||
const eventContent = {
|
||||
name: "Element Web",
|
||||
version: "1.2.3",
|
||||
url: "test.com",
|
||||
};
|
||||
const event = new MatrixEvent({
|
||||
type: `io.element.matrix_client_information.${deviceId}`,
|
||||
content: eventContent,
|
||||
});
|
||||
mockClient.getAccountData.mockReturnValue(event);
|
||||
expect(getDeviceClientInformation(mockClient, deviceId)).toEqual(eventContent);
|
||||
});
|
||||
|
||||
it("excludes values with incorrect types", () => {
|
||||
const eventContent = {
|
||||
extraField: "hello",
|
||||
name: "Element Web",
|
||||
// wrong format
|
||||
version: { value: "1.2.3" },
|
||||
url: "test.com",
|
||||
};
|
||||
const event = new MatrixEvent({
|
||||
type: `io.element.matrix_client_information.${deviceId}`,
|
||||
content: eventContent,
|
||||
});
|
||||
mockClient.getAccountData.mockReturnValue(event);
|
||||
// invalid fields excluded
|
||||
expect(getDeviceClientInformation(mockClient, deviceId)).toEqual({
|
||||
name: eventContent.name,
|
||||
url: eventContent.url,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { DeviceType, type ExtendedDeviceInformation, parseUserAgent } from "./parseUserAgent";
|
||||
|
||||
const makeDeviceExtendedInfo = (
|
||||
deviceType: DeviceType,
|
||||
deviceModel?: string,
|
||||
deviceOperatingSystem?: string,
|
||||
clientName?: string,
|
||||
clientVersion?: string,
|
||||
): ExtendedDeviceInformation => ({
|
||||
deviceType,
|
||||
deviceModel,
|
||||
deviceOperatingSystem,
|
||||
client: clientName && [clientName, clientVersion].filter(Boolean).join(" "),
|
||||
});
|
||||
|
||||
/* eslint-disable max-len */
|
||||
const ANDROID_UA = [
|
||||
// New User Agent Implementation
|
||||
"Element dbg/1.5.0-dev (Xiaomi Mi 9T; Android 11; RKQ1.200826.002 test-keys; Flavour GooglePlay; MatrixAndroidSdk2 1.5.2)",
|
||||
"Element/1.5.0 (Samsung SM-G960F; Android 6.0.1; RKQ1.200826.002; Flavour FDroid; MatrixAndroidSdk2 1.5.2)",
|
||||
"Element/1.5.0 (Google Nexus 5; Android 7.0; RKQ1.200826.002 test test; Flavour FDroid; MatrixAndroidSdk2 1.5.2)",
|
||||
"Element/1.5.0 (Google (Nexus) 5; Android 7.0; RKQ1.200826.002 test test; Flavour FDroid; MatrixAndroidSdk2 1.5.2)",
|
||||
"Element/1.5.0 (Google (Nexus) (5); Android 7.0; RKQ1.200826.002 test test; Flavour FDroid; MatrixAndroidSdk2 1.5.2)",
|
||||
// Legacy User Agent Implementation
|
||||
"Element/1.0.0 (Linux; U; Android 6.0.1; SM-A510F Build/MMB29; Flavour GPlay; MatrixAndroidSdk2 1.0)",
|
||||
"Element/1.0.0 (Linux; Android 7.0; SM-G610M Build/NRD90M; Flavour GPlay; MatrixAndroidSdk2 1.0)",
|
||||
"Mozilla/5.0 (Linux; Android 9; SM-G973U Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
];
|
||||
|
||||
const ANDROID_EXPECTED_RESULT = [
|
||||
makeDeviceExtendedInfo(DeviceType.Mobile, "Xiaomi Mi 9T", "Android 11"),
|
||||
makeDeviceExtendedInfo(DeviceType.Mobile, "Samsung SM-G960F", "Android 6.0.1"),
|
||||
makeDeviceExtendedInfo(DeviceType.Mobile, "LG Nexus 5", "Android 7.0"),
|
||||
makeDeviceExtendedInfo(DeviceType.Mobile, "Google (Nexus) 5", "Android 7.0"),
|
||||
makeDeviceExtendedInfo(DeviceType.Mobile, "Google (Nexus) (5)", "Android 7.0"),
|
||||
makeDeviceExtendedInfo(DeviceType.Mobile, "Samsung SM-A510F", "Android 6.0.1"),
|
||||
makeDeviceExtendedInfo(DeviceType.Mobile, "Samsung SM-G610M", "Android 7.0"),
|
||||
makeDeviceExtendedInfo(DeviceType.Mobile, "Samsung SM-G973U", "Android 9", "Chrome", "69.0.3497.100"),
|
||||
];
|
||||
|
||||
const IOS_UA = [
|
||||
"Element/1.8.21 (iPhone; iOS 15.2; Scale/3.00)",
|
||||
"Element/1.8.21 (iPhone XS Max; iOS 15.2; Scale/3.00)",
|
||||
"Element/1.8.21 (iPad Pro (11-inch); iOS 15.2; Scale/3.00)",
|
||||
"Element/1.8.21 (iPad Pro (12.9-inch) (3rd generation); iOS 15.2; Scale/3.00)",
|
||||
"Mozilla/5.0 (iPad; CPU OS 8_4_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12H321 Safari/600.1.4",
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 8_4_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12H321 Safari/600.1.4",
|
||||
];
|
||||
const IOS_EXPECTED_RESULT = [
|
||||
makeDeviceExtendedInfo(DeviceType.Mobile, "Apple iPhone", "iOS 15.2"),
|
||||
makeDeviceExtendedInfo(DeviceType.Mobile, "Apple iPhone XS Max", "iOS 15.2"),
|
||||
makeDeviceExtendedInfo(DeviceType.Mobile, "iPad Pro (11-inch)", "iOS 15.2"),
|
||||
makeDeviceExtendedInfo(DeviceType.Mobile, "iPad Pro (12.9-inch) (3rd generation)", "iOS 15.2"),
|
||||
makeDeviceExtendedInfo(DeviceType.Web, "Apple iPad", "iOS", "Mobile Safari", "8.0"),
|
||||
makeDeviceExtendedInfo(DeviceType.Mobile, "Apple iPhone", "iOS 8.4.1", "Mobile Safari", "8.0"),
|
||||
];
|
||||
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",
|
||||
"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 = [
|
||||
makeDeviceExtendedInfo(DeviceType.Desktop, "Apple Macintosh", "Mac OS", "Electron", "20.1.1"),
|
||||
makeDeviceExtendedInfo(DeviceType.Desktop, undefined, "Windows", "Electron", "20.1.1"),
|
||||
];
|
||||
|
||||
const WEB_UA = [
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:39.0) Gecko/20100101 Firefox/39.0",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/600.3.18 (KHTML, like Gecko) Version/8.0.3 Safari/600.3.18",
|
||||
"Mozilla/5.0 (Windows NT 6.0; rv:40.0) Gecko/20100101 Firefox/40.0",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246",
|
||||
];
|
||||
|
||||
const WEB_EXPECTED_RESULT = [
|
||||
makeDeviceExtendedInfo(DeviceType.Web, "Apple Macintosh", "Mac OS", "Chrome", "104.0.5112.102"),
|
||||
makeDeviceExtendedInfo(DeviceType.Web, undefined, "Windows", "Chrome", "104.0.5112.102"),
|
||||
makeDeviceExtendedInfo(DeviceType.Web, "Apple Macintosh", "Mac OS", "Firefox", "39.0"),
|
||||
makeDeviceExtendedInfo(DeviceType.Web, "Apple Macintosh", "Mac OS", "Safari", "8.0.3"),
|
||||
makeDeviceExtendedInfo(DeviceType.Web, undefined, "Windows", "Firefox", "40.0"),
|
||||
makeDeviceExtendedInfo(DeviceType.Web, undefined, "Windows", "Edge", "12.246"),
|
||||
];
|
||||
|
||||
const MISC_UA = [
|
||||
"AppleTV11,1/11.1",
|
||||
"Curl Client/1.0",
|
||||
"banana",
|
||||
"",
|
||||
// fluffy chat ios
|
||||
"Dart/2.18 (dart:io)",
|
||||
];
|
||||
|
||||
const MISC_EXPECTED_RESULT = [
|
||||
makeDeviceExtendedInfo(DeviceType.Unknown, "Apple Apple TV", undefined, undefined, undefined),
|
||||
makeDeviceExtendedInfo(DeviceType.Unknown, undefined, undefined, undefined, undefined),
|
||||
makeDeviceExtendedInfo(DeviceType.Unknown, undefined, undefined, undefined, undefined),
|
||||
makeDeviceExtendedInfo(DeviceType.Unknown, undefined, undefined, undefined, undefined),
|
||||
makeDeviceExtendedInfo(DeviceType.Unknown, undefined, undefined, undefined, undefined),
|
||||
];
|
||||
/* eslint-disable max-len */
|
||||
|
||||
describe("parseUserAgent()", () => {
|
||||
it("returns deviceType unknown when user agent is falsy", () => {
|
||||
expect(parseUserAgent(undefined)).toEqual({
|
||||
deviceType: DeviceType.Unknown,
|
||||
});
|
||||
});
|
||||
|
||||
type TestCase = [string, ExtendedDeviceInformation];
|
||||
|
||||
const testPlatform = (platform: string, userAgents: string[], results: ExtendedDeviceInformation[]): void => {
|
||||
const testCases: TestCase[] = userAgents.map((userAgent, index) => [userAgent, results[index]]);
|
||||
|
||||
describe(`on platform ${platform}`, () => {
|
||||
it.each(testCases)("should parse the 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);
|
||||
});
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { vi, describe, it, expect, afterAll, beforeEach } from "vitest";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import {
|
||||
isBulkUnverifiedDeviceReminderSnoozed,
|
||||
snoozeBulkUnverifiedDeviceReminder,
|
||||
} from "./snoozeBulkUnverifiedDeviceReminder";
|
||||
|
||||
const SNOOZE_KEY = "mx_snooze_bulk_unverified_device_nag";
|
||||
|
||||
describe("snooze bulk unverified device nag", () => {
|
||||
const localStorageSetSpy = vi.spyOn(localStorage.__proto__, "setItem");
|
||||
const localStorageGetSpy = vi.spyOn(localStorage.__proto__, "getItem");
|
||||
const localStorageRemoveSpy = vi.spyOn(localStorage.__proto__, "removeItem");
|
||||
|
||||
// 14.03.2022 16:15
|
||||
const now = 1647270879403;
|
||||
|
||||
beforeEach(() => {
|
||||
localStorageSetSpy.mockClear().mockImplementation(() => {});
|
||||
localStorageGetSpy.mockClear().mockReturnValue(null);
|
||||
localStorageRemoveSpy.mockClear().mockImplementation(() => {});
|
||||
|
||||
vi.spyOn(Date, "now").mockReturnValue(now);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
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 = vi.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", () => {
|
||||
const result = isBulkUnverifiedDeviceReminderSnoozed();
|
||||
expect(localStorageGetSpy).toHaveBeenCalledWith(SNOOZE_KEY);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it("catches an error from localstorage and returns false", () => {
|
||||
const loggerErrorSpy = vi.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");
|
||||
const result = isBulkUnverifiedDeviceReminderSnoozed();
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
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);
|
||||
const result = isBulkUnverifiedDeviceReminderSnoozed();
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
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);
|
||||
const result = isBulkUnverifiedDeviceReminderSnoozed();
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { describe, it, expect, beforeEach } from "vitest";
|
||||
import { Room } from "matrix-js-sdk/src/matrix";
|
||||
import { createTestClient } from "test-utils";
|
||||
|
||||
import { LocalRoom, LOCAL_ROOM_ID_PREFIX } from "../../models/LocalRoom";
|
||||
import { isLocalRoom } from "./isLocalRoom";
|
||||
|
||||
describe("isLocalRoom", () => {
|
||||
let room: Room;
|
||||
let localRoom: LocalRoom;
|
||||
|
||||
beforeEach(() => {
|
||||
const client = createTestClient();
|
||||
room = new Room("!room:example.com", client, client.getUserId()!);
|
||||
localRoom = new LocalRoom(LOCAL_ROOM_ID_PREFIX + "test", client, client.getUserId()!);
|
||||
});
|
||||
|
||||
it("should return false for a Room", () => {
|
||||
expect(isLocalRoom(room)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for a non-local room ID", () => {
|
||||
expect(isLocalRoom(room.roomId)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true for LocalRoom", () => {
|
||||
expect(isLocalRoom(localRoom)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for local room ID", () => {
|
||||
expect(isLocalRoom(LOCAL_ROOM_ID_PREFIX + "test")).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { vi, describe, it, expect, beforeEach } from "vitest";
|
||||
import { EventType, type MatrixClient, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { KnownMembership } from "matrix-js-sdk/src/types";
|
||||
import { createTestClient, makeMembershipEvent, mkEvent } from "test-utils";
|
||||
|
||||
import { LocalRoom, LOCAL_ROOM_ID_PREFIX } from "../../models/LocalRoom";
|
||||
import { DirectoryMember } from "../direct-messages";
|
||||
import { isRoomReady } from "./isRoomReady";
|
||||
|
||||
describe("isRoomReady", () => {
|
||||
const userId1 = "@user1:example.com";
|
||||
const member1 = new DirectoryMember({ user_id: userId1 });
|
||||
const userId2 = "@user2:example.com";
|
||||
let room1: Room;
|
||||
let localRoom: LocalRoom;
|
||||
let client: MatrixClient;
|
||||
|
||||
beforeEach(() => {
|
||||
client = createTestClient();
|
||||
room1 = new Room("!room1:example.com", client, userId1);
|
||||
room1.getMyMembership = () => KnownMembership.Join;
|
||||
localRoom = new LocalRoom(LOCAL_ROOM_ID_PREFIX + "test", client, "@test:example.com");
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
localRoom.targets = [member1];
|
||||
});
|
||||
|
||||
it("should return false if the room has no actual room id", () => {
|
||||
expect(isRoomReady(client, localRoom)).toBe(false);
|
||||
});
|
||||
|
||||
describe("for a room with an actual room id", () => {
|
||||
beforeEach(() => {
|
||||
localRoom.actualRoomId = room1.roomId;
|
||||
vi.mocked(client.getRoom).mockReturnValue(null);
|
||||
});
|
||||
|
||||
it("should return false", () => {
|
||||
expect(isRoomReady(client, localRoom)).toBe(false);
|
||||
});
|
||||
|
||||
describe("and the room is known to the client", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(client.getRoom).mockImplementation((roomId?: string) => {
|
||||
if (roomId === room1.roomId) return room1;
|
||||
return null;
|
||||
});
|
||||
});
|
||||
|
||||
it("should return false", () => {
|
||||
expect(isRoomReady(client, localRoom)).toBe(false);
|
||||
});
|
||||
|
||||
describe("and all members have been invited or joined", () => {
|
||||
beforeEach(() => {
|
||||
room1.currentState.setStateEvents([
|
||||
makeMembershipEvent(room1.roomId, userId1, KnownMembership.Join),
|
||||
makeMembershipEvent(room1.roomId, userId2, KnownMembership.Invite),
|
||||
]);
|
||||
});
|
||||
|
||||
it("should return false", () => {
|
||||
expect(isRoomReady(client, localRoom)).toBe(false);
|
||||
});
|
||||
|
||||
describe("and a RoomHistoryVisibility event", () => {
|
||||
beforeEach(() => {
|
||||
room1.currentState.setStateEvents([
|
||||
mkEvent({
|
||||
user: userId1,
|
||||
event: true,
|
||||
type: EventType.RoomHistoryVisibility,
|
||||
room: room1.roomId,
|
||||
content: {},
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it("should return true", () => {
|
||||
expect(isRoomReady(client, localRoom)).toBe(true);
|
||||
});
|
||||
|
||||
describe("and an encrypted room", () => {
|
||||
beforeEach(() => {
|
||||
localRoom.encrypted = true;
|
||||
});
|
||||
|
||||
it("should return false", () => {
|
||||
expect(isRoomReady(client, localRoom)).toBe(false);
|
||||
});
|
||||
|
||||
describe("and a room encryption state event", () => {
|
||||
beforeEach(() => {
|
||||
room1.currentState.setStateEvents([
|
||||
mkEvent({
|
||||
user: userId1,
|
||||
event: true,
|
||||
type: EventType.RoomEncryption,
|
||||
room: room1.roomId,
|
||||
content: {},
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it("should return true", () => {
|
||||
expect(isRoomReady(client, localRoom)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user