add tests for geolocate self on map views
This commit is contained in:
parent
0d59532147
commit
06d8755f6b
5 changed files with 122 additions and 4 deletions
|
@ -68,7 +68,7 @@ export default class LocationViewDialog extends React.Component<IProps, IState>
|
||||||
onError={this.onError}
|
onError={this.onError}
|
||||||
interactive
|
interactive
|
||||||
className="mx_LocationViewDialog_map"
|
className="mx_LocationViewDialog_map"
|
||||||
allowGeolocate={true}
|
allowGeolocate
|
||||||
>
|
>
|
||||||
{({ map }) => (
|
{({ map }) => (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -17,6 +17,11 @@ limitations under the License.
|
||||||
import { _t } from "../../languageHandler";
|
import { _t } from "../../languageHandler";
|
||||||
import SdkConfig from "../../SdkConfig";
|
import SdkConfig from "../../SdkConfig";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a localised error message for GeolocationPositionError error codes
|
||||||
|
* @param code - error code from GeolocationPositionError
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
export const positionFailureMessage = (code: number): string | undefined => {
|
export const positionFailureMessage = (code: number): string | undefined => {
|
||||||
const brand = SdkConfig.get().brand;
|
const brand = SdkConfig.get().brand;
|
||||||
switch (code) {
|
switch (code) {
|
||||||
|
|
|
@ -49,9 +49,10 @@ describe("<LocationViewDialog />", () => {
|
||||||
it("renders marker correctly for self share", () => {
|
it("renders marker correctly for self share", () => {
|
||||||
const selfShareEvent = makeLocationEvent("geo:51.5076,-0.1276", LocationAssetType.Self);
|
const selfShareEvent = makeLocationEvent("geo:51.5076,-0.1276", LocationAssetType.Self);
|
||||||
const member = new RoomMember(roomId, userId);
|
const member = new RoomMember(roomId, userId);
|
||||||
// @ts-ignore cheat assignment to property
|
// @ts-ignore cheat assignment to property
|
||||||
selfShareEvent.sender = member;
|
selfShareEvent.sender = member;
|
||||||
const component = getComponent({ mxEvent: selfShareEvent });
|
const component = getComponent({ mxEvent: selfShareEvent });
|
||||||
|
// @ts-ignore fix when moving to rtl
|
||||||
expect(component.find("SmartMarker").props()["roomMember"]).toEqual(member);
|
expect(component.find("SmartMarker").props()["roomMember"]).toEqual(member);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,15 +16,18 @@ limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { act } from "react-dom/test-utils";
|
import { act } from "react-dom/test-utils";
|
||||||
|
import { fireEvent, getByTestId, render } from "@testing-library/react";
|
||||||
import * as maplibregl from "maplibre-gl";
|
import * as maplibregl from "maplibre-gl";
|
||||||
import { ClientEvent } from "matrix-js-sdk/src/matrix";
|
import { ClientEvent } from "matrix-js-sdk/src/matrix";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { fireEvent, getByTestId, render } from "@testing-library/react";
|
import { mocked } from "jest-mock";
|
||||||
|
|
||||||
import Map from "../../../../src/components/views/location/Map";
|
import Map from "../../../../src/components/views/location/Map";
|
||||||
import { getMockClientWithEventEmitter } from "../../../test-utils";
|
import { getMockClientWithEventEmitter, getMockGeolocationPositionError } from "../../../test-utils";
|
||||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||||
import { TILE_SERVER_WK_KEY } from "../../../../src/utils/WellKnownUtils";
|
import { TILE_SERVER_WK_KEY } from "../../../../src/utils/WellKnownUtils";
|
||||||
|
import Modal from "../../../../src/Modal";
|
||||||
|
import ErrorDialog from "../../../../src/components/views/dialogs/ErrorDialog";
|
||||||
|
|
||||||
describe("<Map />", () => {
|
describe("<Map />", () => {
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
|
@ -52,6 +55,11 @@ describe("<Map />", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.spyOn(logger, "error").mockRestore();
|
jest.spyOn(logger, "error").mockRestore();
|
||||||
|
mocked(maplibregl.GeolocateControl).mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.spyOn(logger, "error").mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapOptions = { container: {} as unknown as HTMLElement, style: "" };
|
const mapOptions = { container: {} as unknown as HTMLElement, style: "" };
|
||||||
|
@ -201,4 +209,70 @@ describe("<Map />", () => {
|
||||||
expect(onClick).toHaveBeenCalled();
|
expect(onClick).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("geolocate", () => {
|
||||||
|
it("does not add a geolocate control when allowGeolocate is falsy", () => {
|
||||||
|
getComponent({ allowGeolocate: false });
|
||||||
|
|
||||||
|
// didn't create a geolocation control
|
||||||
|
expect(maplibregl.GeolocateControl).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("creates a geolocate control and adds it to the map when allowGeolocate is truthy", () => {
|
||||||
|
getComponent({ allowGeolocate: true });
|
||||||
|
|
||||||
|
// didn't create a geolocation control
|
||||||
|
expect(maplibregl.GeolocateControl).toHaveBeenCalledWith({
|
||||||
|
positionOptions: {
|
||||||
|
enableHighAccuracy: true,
|
||||||
|
},
|
||||||
|
trackUserLocation: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// mocked maplibregl shares mock for each mocked instance
|
||||||
|
// so we can assert the geolocate control was added using this static mock
|
||||||
|
const mockGeolocate = new maplibregl.GeolocateControl({});
|
||||||
|
expect(mockMap.addControl).toHaveBeenCalledWith(mockGeolocate);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("logs and opens a dialog on a geolocation error", () => {
|
||||||
|
const mockGeolocate = new maplibregl.GeolocateControl({});
|
||||||
|
jest.spyOn(mockGeolocate, "on");
|
||||||
|
const logSpy = jest.spyOn(logger, "error").mockImplementation(() => {});
|
||||||
|
jest.spyOn(Modal, "createDialog");
|
||||||
|
|
||||||
|
const { rerender } = getComponent({ allowGeolocate: true });
|
||||||
|
|
||||||
|
// wait for component to settle
|
||||||
|
getComponent({ allowGeolocate: true }, rerender);
|
||||||
|
expect(mockGeolocate.on).toHaveBeenCalledWith("error", expect.any(Function));
|
||||||
|
const error = getMockGeolocationPositionError(1, "Test");
|
||||||
|
|
||||||
|
// @ts-ignore pretend to have geolocate emit an error
|
||||||
|
mockGeolocate.emit("error", error);
|
||||||
|
|
||||||
|
expect(logSpy).toHaveBeenCalledWith("Could not fetch location", error);
|
||||||
|
|
||||||
|
expect(Modal.createDialog).toHaveBeenCalledWith(ErrorDialog, {
|
||||||
|
title: "Could not fetch location",
|
||||||
|
description:
|
||||||
|
"Element was denied permission to fetch your location. Please allow location access in your browser settings.",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("unsubscribes from geolocate errors on destroy", () => {
|
||||||
|
const mockGeolocate = new maplibregl.GeolocateControl({});
|
||||||
|
jest.spyOn(mockGeolocate, "on");
|
||||||
|
jest.spyOn(mockGeolocate, "off");
|
||||||
|
jest.spyOn(Modal, "createDialog");
|
||||||
|
|
||||||
|
const { unmount } = getComponent({ allowGeolocate: true });
|
||||||
|
|
||||||
|
expect(mockGeolocate.on).toHaveBeenCalled();
|
||||||
|
|
||||||
|
unmount();
|
||||||
|
|
||||||
|
expect(mockGeolocate.off).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
38
test/utils/location/positionFailureMessage-test.ts
Normal file
38
test/utils/location/positionFailureMessage-test.ts
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { positionFailureMessage } from "../../../src/utils/location/positionFailureMessage";
|
||||||
|
|
||||||
|
describe("positionFailureMessage()", () => {
|
||||||
|
// error codes from GeolocationPositionError
|
||||||
|
// see: https://developer.mozilla.org/en-US/docs/Web/API/GeolocationPositionError
|
||||||
|
// 1: PERMISSION_DENIED
|
||||||
|
// 2: POSITION_UNAVAILABLE
|
||||||
|
// 3: TIMEOUT
|
||||||
|
type TestCase = [number, string | undefined];
|
||||||
|
it.each<TestCase>([
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
"Element was denied permission to fetch your location. Please allow location access in your browser settings.",
|
||||||
|
],
|
||||||
|
[2, "Failed to fetch your location. Please try again later."],
|
||||||
|
[3, "Timed out trying to fetch your location. Please try again later."],
|
||||||
|
[4, "Unknown error fetching location. Please try again later."],
|
||||||
|
[5, undefined],
|
||||||
|
])("returns correct message for error code %s", (code, expectedMessage) => {
|
||||||
|
expect(positionFailureMessage(code)).toEqual(expectedMessage);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue