2022-03-17 08:25:57 +00:00
|
|
|
/*
|
2024-09-09 13:57:16 +00:00
|
|
|
Copyright 2024 New Vector Ltd.
|
2022-03-17 08:25:57 +00:00
|
|
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
|
|
|
|
2024-09-09 13:57:16 +00:00
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
|
|
|
Please see LICENSE files in the repository root for full details.
|
2022-03-17 08:25:57 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
import React from "react";
|
|
|
|
import { mocked } from "jest-mock";
|
2024-10-14 16:11:58 +00:00
|
|
|
import { act, fireEvent, render } from "jest-matrix-react";
|
2022-04-28 12:03:51 +00:00
|
|
|
import { Beacon, BeaconIdentifier } from "matrix-js-sdk/src/matrix";
|
2022-03-17 08:25:57 +00:00
|
|
|
|
|
|
|
import LeftPanelLiveShareWarning from "../../../../src/components/views/beacon/LeftPanelLiveShareWarning";
|
|
|
|
import { OwnBeaconStore, OwnBeaconStoreEvent } from "../../../../src/stores/OwnBeaconStore";
|
2022-03-31 11:51:44 +00:00
|
|
|
import { flushPromises, makeBeaconInfoEvent } from "../../../test-utils";
|
|
|
|
import dispatcher from "../../../../src/dispatcher/dispatcher";
|
|
|
|
import { Action } from "../../../../src/dispatcher/actions";
|
2022-03-17 08:25:57 +00:00
|
|
|
|
|
|
|
jest.mock("../../../../src/stores/OwnBeaconStore", () => {
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
|
|
const EventEmitter = require("events");
|
|
|
|
class MockOwnBeaconStore extends EventEmitter {
|
2022-04-25 12:44:18 +00:00
|
|
|
public getLiveBeaconIdsWithLocationPublishError = jest.fn().mockReturnValue([]);
|
2022-03-31 11:51:44 +00:00
|
|
|
public getBeaconById = jest.fn();
|
|
|
|
public getLiveBeaconIds = jest.fn().mockReturnValue([]);
|
2022-04-28 12:03:51 +00:00
|
|
|
public readonly beaconUpdateErrors = new Map<BeaconIdentifier, Error>();
|
2022-05-06 09:33:09 +00:00
|
|
|
public readonly beacons = new Map<BeaconIdentifier, Beacon>();
|
2022-03-17 08:25:57 +00:00
|
|
|
}
|
|
|
|
return {
|
|
|
|
// @ts-ignore
|
|
|
|
...jest.requireActual("../../../../src/stores/OwnBeaconStore"),
|
|
|
|
OwnBeaconStore: {
|
|
|
|
instance: new MockOwnBeaconStore() as unknown as OwnBeaconStore,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
describe("<LeftPanelLiveShareWarning />", () => {
|
2022-10-24 08:06:20 +00:00
|
|
|
const getComponent = (props = {}) => render(<LeftPanelLiveShareWarning {...props} />);
|
2022-03-17 08:25:57 +00:00
|
|
|
|
2022-03-31 11:51:44 +00:00
|
|
|
const roomId1 = "!room1:server";
|
|
|
|
const roomId2 = "!room2:server";
|
|
|
|
const aliceId = "@alive:server";
|
|
|
|
|
|
|
|
const now = 1647270879403;
|
|
|
|
const HOUR_MS = 3600000;
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
jest.spyOn(global.Date, "now").mockReturnValue(now);
|
|
|
|
jest.spyOn(dispatcher, "dispatch")
|
|
|
|
.mockClear()
|
|
|
|
.mockImplementation(() => {});
|
2022-04-28 12:03:51 +00:00
|
|
|
|
|
|
|
OwnBeaconStore.instance.beaconUpdateErrors.clear();
|
2022-03-31 11:51:44 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(() => {
|
|
|
|
jest.spyOn(global.Date, "now").mockRestore();
|
|
|
|
|
|
|
|
jest.restoreAllMocks();
|
|
|
|
});
|
|
|
|
// 12h old, 12h left
|
|
|
|
const beacon1 = new Beacon(
|
|
|
|
makeBeaconInfoEvent(aliceId, roomId1, { timeout: HOUR_MS * 24, timestamp: now - 12 * HOUR_MS }, "$1"),
|
|
|
|
);
|
|
|
|
// 10h left
|
|
|
|
const beacon2 = new Beacon(makeBeaconInfoEvent(aliceId, roomId2, { timeout: HOUR_MS * 10, timestamp: now }, "$2"));
|
|
|
|
|
2022-03-17 08:25:57 +00:00
|
|
|
it("renders nothing when user has no live beacons", () => {
|
2022-10-24 08:06:20 +00:00
|
|
|
const { container } = getComponent();
|
|
|
|
expect(container.innerHTML).toBeFalsy();
|
2022-03-17 08:25:57 +00:00
|
|
|
});
|
|
|
|
|
2022-03-28 16:46:39 +00:00
|
|
|
describe("when user has live location monitor", () => {
|
2022-03-31 11:51:44 +00:00
|
|
|
beforeAll(() => {
|
|
|
|
mocked(OwnBeaconStore.instance).getBeaconById.mockImplementation((beaconId) => {
|
|
|
|
if (beaconId === beacon1.identifier) {
|
|
|
|
return beacon1;
|
|
|
|
}
|
|
|
|
return beacon2;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-03-17 08:25:57 +00:00
|
|
|
beforeEach(() => {
|
2022-11-04 10:48:08 +00:00
|
|
|
// @ts-ignore writing to readonly variable
|
2022-03-28 16:46:39 +00:00
|
|
|
mocked(OwnBeaconStore.instance).isMonitoringLiveLocation = true;
|
2022-04-25 12:44:18 +00:00
|
|
|
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue([]);
|
2022-03-31 11:51:44 +00:00
|
|
|
mocked(OwnBeaconStore.instance).getLiveBeaconIds.mockReturnValue([beacon2.identifier, beacon1.identifier]);
|
2022-03-17 08:25:57 +00:00
|
|
|
});
|
2022-03-31 11:51:44 +00:00
|
|
|
|
2022-05-06 09:33:09 +00:00
|
|
|
afterAll(() => {
|
|
|
|
jest.spyOn(document, "addEventListener").mockRestore();
|
|
|
|
});
|
|
|
|
|
2022-03-17 08:25:57 +00:00
|
|
|
it("renders correctly when not minimized", () => {
|
2022-10-24 08:06:20 +00:00
|
|
|
const { asFragment } = getComponent();
|
|
|
|
expect(asFragment()).toMatchSnapshot();
|
2022-03-17 08:25:57 +00:00
|
|
|
});
|
|
|
|
|
2022-03-31 11:51:44 +00:00
|
|
|
it("goes to room of latest beacon when clicked", () => {
|
2022-10-24 08:06:20 +00:00
|
|
|
const { container } = getComponent();
|
2022-03-31 11:51:44 +00:00
|
|
|
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
|
|
|
|
|
2023-02-15 13:36:22 +00:00
|
|
|
fireEvent.click(container.querySelector("[role=button]")!);
|
2022-03-31 11:51:44 +00:00
|
|
|
|
|
|
|
expect(dispatchSpy).toHaveBeenCalledWith({
|
|
|
|
action: Action.ViewRoom,
|
|
|
|
metricsTrigger: undefined,
|
|
|
|
// latest beacon's room
|
|
|
|
room_id: roomId2,
|
2022-06-07 10:15:09 +00:00
|
|
|
event_id: beacon2.beaconInfoId,
|
|
|
|
highlighted: true,
|
|
|
|
scroll_into_view: true,
|
2022-03-31 11:51:44 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-03-17 08:25:57 +00:00
|
|
|
it("renders correctly when minimized", () => {
|
2022-10-24 08:06:20 +00:00
|
|
|
const { asFragment } = getComponent({ isMinimized: true });
|
|
|
|
expect(asFragment()).toMatchSnapshot();
|
2022-03-17 08:25:57 +00:00
|
|
|
});
|
|
|
|
|
2022-04-25 12:44:18 +00:00
|
|
|
it("renders location publish error", () => {
|
|
|
|
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue([
|
|
|
|
beacon1.identifier,
|
|
|
|
]);
|
2022-10-24 08:06:20 +00:00
|
|
|
const { asFragment } = getComponent();
|
|
|
|
expect(asFragment()).toMatchSnapshot();
|
2022-03-31 11:51:44 +00:00
|
|
|
});
|
|
|
|
|
2022-04-25 12:44:18 +00:00
|
|
|
it("goes to room of latest beacon with location publish error when clicked", () => {
|
|
|
|
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue([
|
|
|
|
beacon1.identifier,
|
|
|
|
]);
|
2022-10-24 08:06:20 +00:00
|
|
|
const { container } = getComponent();
|
2022-03-31 11:51:44 +00:00
|
|
|
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
|
|
|
|
|
2023-02-15 13:36:22 +00:00
|
|
|
fireEvent.click(container.querySelector("[role=button]")!);
|
2022-03-31 11:51:44 +00:00
|
|
|
|
|
|
|
expect(dispatchSpy).toHaveBeenCalledWith({
|
|
|
|
action: Action.ViewRoom,
|
|
|
|
metricsTrigger: undefined,
|
|
|
|
// error beacon's room
|
|
|
|
room_id: roomId1,
|
2022-06-07 10:15:09 +00:00
|
|
|
event_id: beacon1.beaconInfoId,
|
|
|
|
highlighted: true,
|
|
|
|
scroll_into_view: true,
|
2022-03-31 11:51:44 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("goes back to default style when wire errors are cleared", () => {
|
2022-04-25 12:44:18 +00:00
|
|
|
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue([
|
|
|
|
beacon1.identifier,
|
|
|
|
]);
|
2022-10-24 08:06:20 +00:00
|
|
|
const { container, rerender } = getComponent();
|
2022-03-31 11:51:44 +00:00
|
|
|
// error mode
|
2023-02-15 13:36:22 +00:00
|
|
|
expect(container.querySelector(".mx_LeftPanelLiveShareWarning")?.textContent).toEqual(
|
2022-05-09 22:52:05 +00:00
|
|
|
"An error occurred whilst sharing your live location",
|
2022-03-31 11:51:44 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
act(() => {
|
2022-04-25 12:44:18 +00:00
|
|
|
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue([]);
|
|
|
|
OwnBeaconStore.instance.emit(OwnBeaconStoreEvent.LocationPublishError, "abc");
|
2022-03-31 11:51:44 +00:00
|
|
|
});
|
|
|
|
|
2022-10-24 08:06:20 +00:00
|
|
|
rerender(<LeftPanelLiveShareWarning />);
|
2022-03-31 11:51:44 +00:00
|
|
|
|
|
|
|
// default mode
|
2023-02-15 13:36:22 +00:00
|
|
|
expect(container.querySelector(".mx_LeftPanelLiveShareWarning")?.textContent).toEqual(
|
2022-03-31 11:51:44 +00:00
|
|
|
"You are sharing your live location",
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2022-03-17 08:25:57 +00:00
|
|
|
it("removes itself when user stops having live beacons", async () => {
|
2022-10-24 08:06:20 +00:00
|
|
|
const { container, rerender } = getComponent({ isMinimized: true });
|
2022-03-17 08:25:57 +00:00
|
|
|
// started out rendered
|
2022-10-24 08:06:20 +00:00
|
|
|
expect(container.innerHTML).toBeTruthy();
|
2022-03-17 08:25:57 +00:00
|
|
|
|
2022-03-31 11:51:44 +00:00
|
|
|
act(() => {
|
2022-11-04 10:48:08 +00:00
|
|
|
// @ts-ignore writing to readonly variable
|
2022-03-31 11:51:44 +00:00
|
|
|
mocked(OwnBeaconStore.instance).isMonitoringLiveLocation = false;
|
|
|
|
OwnBeaconStore.instance.emit(OwnBeaconStoreEvent.MonitoringLivePosition);
|
|
|
|
});
|
2022-03-17 08:25:57 +00:00
|
|
|
|
|
|
|
await flushPromises();
|
2022-10-24 08:06:20 +00:00
|
|
|
rerender(<LeftPanelLiveShareWarning />);
|
2022-03-17 08:25:57 +00:00
|
|
|
|
2022-10-24 08:06:20 +00:00
|
|
|
expect(container.innerHTML).toBeFalsy();
|
2022-03-17 08:25:57 +00:00
|
|
|
});
|
2022-04-28 12:03:51 +00:00
|
|
|
|
2022-05-06 09:33:09 +00:00
|
|
|
it("refreshes beacon liveness monitors when pagevisibilty changes to visible", () => {
|
|
|
|
OwnBeaconStore.instance.beacons.set(beacon1.identifier, beacon1);
|
|
|
|
OwnBeaconStore.instance.beacons.set(beacon2.identifier, beacon2);
|
|
|
|
const beacon1MonitorSpy = jest.spyOn(beacon1, "monitorLiveness");
|
|
|
|
const beacon2MonitorSpy = jest.spyOn(beacon1, "monitorLiveness");
|
|
|
|
|
|
|
|
jest.spyOn(document, "addEventListener").mockImplementation((_e, listener) =>
|
|
|
|
(listener as EventListener)(new Event("")),
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(beacon1MonitorSpy).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
getComponent();
|
|
|
|
|
|
|
|
expect(beacon1MonitorSpy).toHaveBeenCalled();
|
|
|
|
expect(beacon2MonitorSpy).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
2022-04-28 12:03:51 +00:00
|
|
|
describe("stopping errors", () => {
|
|
|
|
it("renders stopping error", () => {
|
|
|
|
OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error("error"));
|
2022-10-24 08:06:20 +00:00
|
|
|
const { container } = getComponent();
|
|
|
|
expect(container.textContent).toEqual("An error occurred while stopping your live location");
|
2022-04-28 12:03:51 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it("starts rendering stopping error on beaconUpdateError emit", () => {
|
2022-10-24 08:06:20 +00:00
|
|
|
const { container } = getComponent();
|
2022-04-28 12:03:51 +00:00
|
|
|
// no error
|
2022-10-24 08:06:20 +00:00
|
|
|
expect(container.textContent).toEqual("You are sharing your live location");
|
2022-04-28 12:03:51 +00:00
|
|
|
|
|
|
|
act(() => {
|
|
|
|
OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error("error"));
|
|
|
|
OwnBeaconStore.instance.emit(OwnBeaconStoreEvent.BeaconUpdateError, beacon2.identifier, true);
|
|
|
|
});
|
|
|
|
|
2022-10-24 08:06:20 +00:00
|
|
|
expect(container.textContent).toEqual("An error occurred while stopping your live location");
|
2022-04-28 12:03:51 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it("renders stopping error when beacons have stopping and location errors", () => {
|
|
|
|
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue([
|
|
|
|
beacon1.identifier,
|
|
|
|
]);
|
|
|
|
OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error("error"));
|
2022-10-24 08:06:20 +00:00
|
|
|
const { container } = getComponent();
|
|
|
|
expect(container.textContent).toEqual("An error occurred while stopping your live location");
|
2022-04-28 12:03:51 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it("goes to room of latest beacon with stopping error when clicked", () => {
|
|
|
|
mocked(OwnBeaconStore.instance).getLiveBeaconIdsWithLocationPublishError.mockReturnValue([
|
|
|
|
beacon1.identifier,
|
|
|
|
]);
|
|
|
|
OwnBeaconStore.instance.beaconUpdateErrors.set(beacon2.identifier, new Error("error"));
|
2022-10-24 08:06:20 +00:00
|
|
|
const { container } = getComponent();
|
2022-04-28 12:03:51 +00:00
|
|
|
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
|
|
|
|
|
2023-02-15 13:36:22 +00:00
|
|
|
fireEvent.click(container.querySelector("[role=button]")!);
|
2022-04-28 12:03:51 +00:00
|
|
|
|
|
|
|
expect(dispatchSpy).toHaveBeenCalledWith({
|
|
|
|
action: Action.ViewRoom,
|
|
|
|
metricsTrigger: undefined,
|
|
|
|
// stopping error beacon's room
|
|
|
|
room_id: beacon2.roomId,
|
2022-06-07 10:15:09 +00:00
|
|
|
event_id: beacon2.beaconInfoId,
|
|
|
|
highlighted: true,
|
|
|
|
scroll_into_view: true,
|
2022-04-28 12:03:51 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2022-03-17 08:25:57 +00:00
|
|
|
});
|
|
|
|
});
|