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}
|
||||
interactive
|
||||
className="mx_LocationViewDialog_map"
|
||||
allowGeolocate={true}
|
||||
allowGeolocate
|
||||
>
|
||||
{({ map }) => (
|
||||
<>
|
||||
|
|
|
@ -17,6 +17,11 @@ limitations under the License.
|
|||
import { _t } from "../../languageHandler";
|
||||
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 => {
|
||||
const brand = SdkConfig.get().brand;
|
||||
switch (code) {
|
||||
|
|
|
@ -49,9 +49,10 @@ describe("<LocationViewDialog />", () => {
|
|||
it("renders marker correctly for self share", () => {
|
||||
const selfShareEvent = makeLocationEvent("geo:51.5076,-0.1276", LocationAssetType.Self);
|
||||
const member = new RoomMember(roomId, userId);
|
||||
// @ts-ignore cheat assignment to property
|
||||
// @ts-ignore cheat assignment to property
|
||||
selfShareEvent.sender = member;
|
||||
const component = getComponent({ mxEvent: selfShareEvent });
|
||||
// @ts-ignore fix when moving to rtl
|
||||
expect(component.find("SmartMarker").props()["roomMember"]).toEqual(member);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -16,15 +16,18 @@ limitations under the License.
|
|||
|
||||
import React from "react";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { fireEvent, getByTestId, render } from "@testing-library/react";
|
||||
import * as maplibregl from "maplibre-gl";
|
||||
import { ClientEvent } from "matrix-js-sdk/src/matrix";
|
||||
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 { getMockClientWithEventEmitter } from "../../../test-utils";
|
||||
import { getMockClientWithEventEmitter, getMockGeolocationPositionError } from "../../../test-utils";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import { TILE_SERVER_WK_KEY } from "../../../../src/utils/WellKnownUtils";
|
||||
import Modal from "../../../../src/Modal";
|
||||
import ErrorDialog from "../../../../src/components/views/dialogs/ErrorDialog";
|
||||
|
||||
describe("<Map />", () => {
|
||||
const defaultProps = {
|
||||
|
@ -52,6 +55,11 @@ describe("<Map />", () => {
|
|||
});
|
||||
|
||||
jest.spyOn(logger, "error").mockRestore();
|
||||
mocked(maplibregl.GeolocateControl).mockClear();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.spyOn(logger, "error").mockRestore();
|
||||
});
|
||||
|
||||
const mapOptions = { container: {} as unknown as HTMLElement, style: "" };
|
||||
|
@ -201,4 +209,70 @@ describe("<Map />", () => {
|
|||
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