Port location unit tests from enzyme to react-testing-library (#10181)

* SmartMarker test to rtl

* LocationPicker to rtl

* LocationViewDialog to rtl

* LocationShareMenu to rtl

* use toBeDisabled assertion
pull/28217/head
Kerry 2023-02-21 07:35:39 +13:00 committed by GitHub
parent a06163ee98
commit 3fafa4b58d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 290 additions and 613 deletions

View File

@ -27,7 +27,7 @@ describe("Location sharing", () => {
};
const submitShareLocation = (): void => {
cy.get('[data-test-id="location-picker-submit-button"]').click();
cy.get('[data-testid="location-picker-submit-button"]').click();
};
beforeEach(() => {

View File

@ -29,7 +29,7 @@ interface Props {
export const EnableLiveShare: React.FC<Props> = ({ onSubmit }) => {
const [isEnabled, setEnabled] = useState(false);
return (
<div data-test-id="location-picker-enable-live-share" className="mx_EnableLiveShare">
<div data-testid="location-picker-enable-live-share" className="mx_EnableLiveShare">
<StyledLiveBeaconIcon className="mx_EnableLiveShare_icon" />
<Heading className="mx_EnableLiveShare_heading" size="h3">
{_t("Live location sharing")}
@ -43,13 +43,13 @@ export const EnableLiveShare: React.FC<Props> = ({ onSubmit }) => {
)}
</p>
<LabelledToggleSwitch
data-test-id="enable-live-share-toggle"
data-testid="enable-live-share-toggle"
value={isEnabled}
onChange={setEnabled}
label={_t("Enable live location sharing")}
/>
<AccessibleButton
data-test-id="enable-live-share-submit"
data-testid="enable-live-share-submit"
className="mx_EnableLiveShare_button"
element="button"
kind="primary"

View File

@ -62,7 +62,7 @@ const LiveDurationDropdown: React.FC<Props> = ({ timeout, onChange }) => {
return (
<Dropdown
id="live-duration"
data-test-id="live-duration-dropdown"
data-testid="live-duration-dropdown"
label={getLabel(timeout)}
value={timeout.toString()}
onOptionChange={onOptionChange}

View File

@ -231,7 +231,7 @@ class LocationPicker extends React.Component<ILocationPickerProps, IState> {
<LiveDurationDropdown onChange={this.onTimeoutChange} timeout={this.state.timeout} />
)}
<AccessibleButton
data-test-id="location-picker-submit-button"
data-testid="location-picker-submit-button"
type="submit"
element="button"
kind="primary"

View File

@ -33,7 +33,7 @@ export interface MapErrorProps {
export const MapError: React.FC<MapErrorProps> = ({ error, isMinimised, className, onFinished, onClick }) => (
<div
data-test-id="map-rendering-error"
data-testid="map-rendering-error"
className={classNames("mx_MapError", className, { mx_MapError_isMinimised: isMinimised })}
onClick={onClick}
>

View File

@ -19,6 +19,7 @@ import React from "react";
import AccessibleButton from "../elements/AccessibleButton";
import { Icon as BackIcon } from "../../../../res/img/element-icons/caret-left.svg";
import { Icon as CloseIcon } from "../../../../res/img/element-icons/cancel-rounded.svg";
import { _t } from "../../../languageHandler";
interface Props {
onCancel: () => void;
@ -32,7 +33,8 @@ const ShareDialogButtons: React.FC<Props> = ({ onBack, onCancel, displayBack })
{displayBack && (
<AccessibleButton
className="mx_ShareDialogButtons_button left"
data-test-id="share-dialog-buttons-back"
data-testid="share-dialog-buttons-back"
aria-label={_t("Back")}
onClick={onBack}
element="button"
>
@ -41,7 +43,8 @@ const ShareDialogButtons: React.FC<Props> = ({ onBack, onCancel, displayBack })
)}
<AccessibleButton
className="mx_ShareDialogButtons_button right"
data-test-id="share-dialog-buttons-cancel"
data-testid="share-dialog-buttons-cancel"
aria-label={_t("Close")}
onClick={onCancel}
element="button"
>

View File

@ -15,9 +15,8 @@ limitations under the License.
*/
import React from "react";
import { fireEvent, render, RenderResult } from "@testing-library/react";
import * as maplibregl from "maplibre-gl";
// eslint-disable-next-line deprecate/import
import { mount, ReactWrapper } from "enzyme";
import { act } from "react-dom/test-utils";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { MatrixClient } from "matrix-js-sdk/src/client";
@ -28,7 +27,7 @@ import LocationPicker from "../../../../src/components/views/location/LocationPi
import { LocationShareType } from "../../../../src/components/views/location/shareLocation";
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
import { findById, findByTestId, mockPlatformPeg } from "../../../test-utils";
import { getMockClientWithEventEmitter, mockPlatformPeg } from "../../../test-utils";
import { findMapStyleUrl, LocationShareError } from "../../../../src/utils/location";
jest.mock("../../../../src/utils/location/findMapStyleUrl", () => ({
@ -49,17 +48,15 @@ describe("LocationPicker", () => {
onChoose: jest.fn(),
onFinished: jest.fn(),
};
const mockClient = {
on: jest.fn(),
removeListener: jest.fn(),
off: jest.fn(),
const mockClient = getMockClientWithEventEmitter({
isGuest: jest.fn(),
getClientWellKnown: jest.fn(),
};
const getComponent = (props = {}) =>
mount(<LocationPicker {...defaultProps} {...props} />, {
wrappingComponent: MatrixClientContext.Provider,
wrappingComponentProps: { value: mockClient },
});
const getComponent = (props = {}): RenderResult =>
render(<LocationPicker {...defaultProps} {...props} />, {
wrapper: ({ children }) => (
<MatrixClientContext.Provider value={mockClient}>{children}</MatrixClientContext.Provider>
),
});
const mapOptions = { container: {} as unknown as HTMLElement, style: "" };
@ -94,18 +91,20 @@ describe("LocationPicker", () => {
it("displays error when map emits an error", () => {
// suppress expected error log
jest.spyOn(logger, "error").mockImplementation(() => {});
const wrapper = getComponent();
const { getByTestId, getByText } = getComponent();
act(() => {
// @ts-ignore
mocked(mockMap).emit("error", { error: "Something went wrong" });
wrapper.setProps({});
});
expect(findByTestId(wrapper, "map-rendering-error").find("p").text()).toEqual(
"This homeserver is not configured correctly to display maps, " +
"or the configured map server may be unreachable.",
);
expect(getByTestId("map-rendering-error")).toBeInTheDocument();
expect(
getByText(
"This homeserver is not configured correctly to display maps, " +
"or the configured map server may be unreachable.",
),
).toBeInTheDocument();
});
it("displays error when map display is not configured properly", () => {
@ -115,12 +114,9 @@ describe("LocationPicker", () => {
throw new Error(LocationShareError.MapStyleUrlNotConfigured);
});
const wrapper = getComponent();
wrapper.setProps({});
const { getByText } = getComponent();
expect(findByTestId(wrapper, "map-rendering-error").find("p").text()).toEqual(
"This homeserver is not configured to display maps.",
);
expect(getByText("This homeserver is not configured to display maps.")).toBeInTheDocument();
});
it("displays error when map setup throws", () => {
@ -132,13 +128,14 @@ describe("LocationPicker", () => {
throw new Error("oups");
});
const wrapper = getComponent();
wrapper.setProps({});
const { getByText } = getComponent();
expect(findByTestId(wrapper, "map-rendering-error").find("p").text()).toEqual(
"This homeserver is not configured correctly to display maps, " +
"or the configured map server may be unreachable.",
);
expect(
getByText(
"This homeserver is not configured correctly to display maps, " +
"or the configured map server may be unreachable.",
),
).toBeInTheDocument();
});
it("initiates map with geolocation", () => {
@ -174,57 +171,49 @@ describe("LocationPicker", () => {
});
it("sets position on geolocate event", () => {
const wrapper = getComponent({ shareType });
const { container, getByTestId } = getComponent({ shareType });
act(() => {
// @ts-ignore
mocked(mockGeolocate).emit("geolocate", mockGeolocationPosition);
wrapper.setProps({});
});
// marker added
expect(maplibregl.Marker).toHaveBeenCalled();
expect(mockMarker.setLngLat).toHaveBeenCalledWith(new maplibregl.LngLat(12.4, 43.2));
// submit button is enabled when position is truthy
expect(findByTestId(wrapper, "location-picker-submit-button").at(0).props().disabled).toBeFalsy();
expect(wrapper.find("MemberAvatar").length).toBeTruthy();
expect(getByTestId("location-picker-submit-button")).not.toBeDisabled();
expect(container.querySelector(".mx_BaseAvatar")).toBeInTheDocument();
});
it("disables submit button until geolocation completes", () => {
const onChoose = jest.fn();
const wrapper = getComponent({ shareType, onChoose });
const { getByTestId } = getComponent({ shareType, onChoose });
// submit button is enabled when position is truthy
expect(findByTestId(wrapper, "location-picker-submit-button").at(0).props().disabled).toBeTruthy();
act(() => {
findByTestId(wrapper, "location-picker-submit-button").at(0).simulate("click");
});
// button is disabled
expect(getByTestId("location-picker-submit-button")).toBeDisabled();
fireEvent.click(getByTestId("location-picker-submit-button"));
// nothing happens on button click
expect(onChoose).not.toHaveBeenCalled();
act(() => {
// @ts-ignore
mocked(mockGeolocate).emit("geolocate", mockGeolocationPosition);
wrapper.setProps({});
});
// submit button is enabled when position is truthy
expect(findByTestId(wrapper, "location-picker-submit-button").at(0).props().disabled).toBeFalsy();
expect(getByTestId("location-picker-submit-button")).not.toBeDisabled();
});
it("submits location", () => {
const onChoose = jest.fn();
const wrapper = getComponent({ onChoose, shareType });
const { getByTestId } = getComponent({ onChoose, shareType });
act(() => {
// @ts-ignore
mocked(mockGeolocate).emit("geolocate", mockGeolocationPosition);
// make sure button is enabled
wrapper.setProps({});
});
act(() => {
findByTestId(wrapper, "location-picker-submit-button").at(0).simulate("click");
});
fireEvent.click(getByTestId("location-picker-submit-button"));
// content of this call is tested in LocationShareMenu-test
expect(onChoose).toHaveBeenCalled();
});
@ -239,34 +228,21 @@ describe("LocationPicker", () => {
const shareType = LocationShareType.Live;
testUserLocationShareTypes(shareType);
const getOption = (wrapper: ReactWrapper, timeout: number) =>
findById(wrapper, `live-duration__${timeout}`).at(0);
const getDropdown = (wrapper: ReactWrapper) => findByTestId(wrapper, "live-duration-dropdown");
const getSelectedOption = (wrapper: ReactWrapper) => findById(wrapper, "live-duration_value");
const openDropdown = (wrapper: ReactWrapper) =>
act(() => {
const dropdown = getDropdown(wrapper);
dropdown.find('[role="button"]').at(0).simulate("click");
wrapper.setProps({});
});
it("renders live duration dropdown with default option", () => {
const wrapper = getComponent({ shareType });
expect(getSelectedOption(getDropdown(wrapper)).text()).toEqual("Share for 15m");
const { getByText } = getComponent({ shareType });
expect(getByText("Share for 15m")).toBeInTheDocument();
});
it("updates selected duration", () => {
const wrapper = getComponent({ shareType });
const { getByText, getByLabelText } = getComponent({ shareType });
openDropdown(wrapper);
const dropdown = getDropdown(wrapper);
act(() => {
getOption(dropdown, 3600000).simulate("click");
});
// open dropdown
fireEvent.click(getByLabelText("Share for 15m"));
fireEvent.click(getByText("Share for 1h"));
// value updated
expect(getSelectedOption(getDropdown(wrapper)).text()).toEqual("Share for 1h");
expect(getByText("Share for 1h")).toMatchSnapshot();
});
});
@ -303,22 +279,21 @@ describe("LocationPicker", () => {
it("does not set position on geolocate event", () => {
mocked(maplibregl.Marker).mockClear();
const wrapper = getComponent({ shareType });
const { container } = getComponent({ shareType });
act(() => {
// @ts-ignore
mocked(mockGeolocate).emit("geolocate", mockGeolocationPosition);
});
// marker not added
expect(wrapper.find("Marker").length).toBeFalsy();
expect(container.querySelector("mx_Marker")).not.toBeInTheDocument();
});
it("sets position on click event", () => {
const wrapper = getComponent({ shareType });
const { container } = getComponent({ shareType });
act(() => {
// @ts-ignore
mocked(mockMap).emit("click", mockClickEvent);
wrapper.setProps({});
});
// marker added
@ -326,21 +301,18 @@ describe("LocationPicker", () => {
expect(mockMarker.setLngLat).toHaveBeenCalledWith(new maplibregl.LngLat(12.4, 43.2));
// marker is set, icon not avatar
expect(wrapper.find(".mx_Marker_icon").length).toBeTruthy();
expect(container.querySelector(".mx_Marker_icon")).toBeInTheDocument();
});
it("submits location", () => {
const onChoose = jest.fn();
const wrapper = getComponent({ onChoose, shareType });
const { getByTestId } = getComponent({ onChoose, shareType });
act(() => {
// @ts-ignore
mocked(mockMap).emit("click", mockClickEvent);
wrapper.setProps({});
});
act(() => {
findByTestId(wrapper, "location-picker-submit-button").at(0).simulate("click");
});
fireEvent.click(getByTestId("location-picker-submit-button"));
// content of this call is tested in LocationShareMenu-test
expect(onChoose).toHaveBeenCalled();

View File

@ -15,8 +15,6 @@ limitations under the License.
*/
import React from "react";
// eslint-disable-next-line deprecate/import
import { mount, ReactWrapper } from "enzyme";
import { mocked } from "jest-mock";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { MatrixClient } from "matrix-js-sdk/src/client";
@ -24,6 +22,8 @@ import { RelationType } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import { M_ASSET, LocationAssetType } from "matrix-js-sdk/src/@types/location";
import { act } from "react-dom/test-utils";
import { fireEvent, render, RenderResult } from "@testing-library/react";
import * as maplibregl from "maplibre-gl";
import LocationShareMenu from "../../../../src/components/views/location/LocationShareMenu";
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
@ -32,8 +32,6 @@ import SettingsStore from "../../../../src/settings/SettingsStore";
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
import { LocationShareType } from "../../../../src/components/views/location/shareLocation";
import {
findByTagAndTestId,
findByTestId,
flushPromisesWithFakeTimers,
getMockClientWithEventEmitter,
setupAsyncStoreWithClient,
@ -99,6 +97,12 @@ describe("<LocationShareMenu />", () => {
sender: new RoomMember("!room:server.org", userId),
};
const mockGeolocate = new maplibregl.GeolocateControl({});
jest.spyOn(mockGeolocate, "on");
const mapOptions = { container: {} as unknown as HTMLElement, style: "" };
const mockMap = new maplibregl.Map(mapOptions);
jest.spyOn(mockMap, "on");
const position = {
coords: {
latitude: -36.24484561954707,
@ -116,10 +120,11 @@ describe("<LocationShareMenu />", () => {
return store;
};
const getComponent = (props = {}) =>
mount(<LocationShareMenu {...defaultProps} {...props} />, {
wrappingComponent: MatrixClientContext.Provider,
wrappingComponentProps: { value: mockClient },
const getComponent = (props = {}): RenderResult =>
render(<LocationShareMenu {...defaultProps} {...props} />, {
wrapper: ({ children }) => (
<MatrixClientContext.Provider value={mockClient}>{children}</MatrixClientContext.Provider>
),
});
beforeEach(async () => {
@ -135,74 +140,74 @@ describe("<LocationShareMenu />", () => {
await makeOwnBeaconStore();
});
const getShareTypeOption = (component: ReactWrapper, shareType: LocationShareType) =>
findByTagAndTestId(component, `share-location-option-${shareType}`, "button");
const getBackButton = (getByLabelText: RenderResult["getByLabelText"]) => getByLabelText("Back");
const getBackButton = (component: ReactWrapper) =>
findByTagAndTestId(component, "share-dialog-buttons-back", "button");
const getCancelButton = (getByLabelText: RenderResult["getByLabelText"]) => getByLabelText("Close");
const getCancelButton = (component: ReactWrapper) =>
findByTagAndTestId(component, "share-dialog-buttons-cancel", "button");
const setLocationGeolocate = () => {
// get the callback LocationShareMenu registered for geolocate
expect(mocked(mockGeolocate.on)).toHaveBeenCalledWith("geolocate", expect.any(Function));
const [, onGeolocateCallback] = mocked(mockGeolocate.on).mock.calls.find(([event]) => event === "geolocate");
const getSubmitButton = (component: ReactWrapper) =>
findByTagAndTestId(component, "location-picker-submit-button", "button");
const setLocation = (component: ReactWrapper) => {
// set the location
const locationPickerInstance = component.find("LocationPicker").instance();
act(() => {
// @ts-ignore
locationPickerInstance.onGeolocate(position);
// make sure button gets enabled
component.setProps({});
});
onGeolocateCallback(position);
};
const setShareType = (component: ReactWrapper, shareType: LocationShareType) =>
act(() => {
getShareTypeOption(component, shareType).at(0).simulate("click");
component.setProps({});
});
const setLocationClick = () => {
// get the callback LocationShareMenu registered for geolocate
expect(mocked(mockMap.on)).toHaveBeenCalledWith("click", expect.any(Function));
const [, onMapClickCallback] = mocked(mockMap.on).mock.calls.find(([event]) => event === "click");
const event = {
lngLat: { lng: position.coords.longitude, lat: position.coords.latitude },
} as unknown as maplibregl.MapMouseEvent;
// set the location
onMapClickCallback(event);
};
const shareTypeLabels: Record<LocationShareType, string> = {
[LocationShareType.Own]: "My current location",
[LocationShareType.Live]: "My live location",
[LocationShareType.Pin]: "Drop a Pin",
};
const setShareType = (getByText: RenderResult["getByText"], shareType: LocationShareType) => {
fireEvent.click(getByText(shareTypeLabels[shareType]));
};
describe("when only Own share type is enabled", () => {
beforeEach(() => enableSettings([]));
it("renders own and live location options", () => {
const component = getComponent();
expect(getShareTypeOption(component, LocationShareType.Own).length).toBe(1);
expect(getShareTypeOption(component, LocationShareType.Live).length).toBe(1);
const { getByText } = getComponent();
expect(getByText(shareTypeLabels[LocationShareType.Own])).toBeInTheDocument();
expect(getByText(shareTypeLabels[LocationShareType.Live])).toBeInTheDocument();
});
it("renders back button from location picker screen", () => {
const component = getComponent();
setShareType(component, LocationShareType.Own);
const { getByText, getByLabelText } = getComponent();
setShareType(getByText, LocationShareType.Own);
expect(getBackButton(component).length).toBe(1);
expect(getBackButton(getByLabelText)).toBeInTheDocument();
});
it("clicking cancel button from location picker closes dialog", () => {
const onFinished = jest.fn();
const component = getComponent({ onFinished });
const { getByLabelText } = getComponent({ onFinished });
act(() => {
getCancelButton(component).at(0).simulate("click");
});
fireEvent.click(getCancelButton(getByLabelText));
expect(onFinished).toHaveBeenCalled();
});
it("creates static own location share event on submission", () => {
const onFinished = jest.fn();
const component = getComponent({ onFinished });
const { getByText } = getComponent({ onFinished });
setShareType(component, LocationShareType.Own);
setShareType(getByText, LocationShareType.Own);
setLocation(component);
setLocationGeolocate();
act(() => {
getSubmitButton(component).at(0).simulate("click");
component.setProps({});
});
fireEvent.click(getByText("Share location"));
expect(onFinished).toHaveBeenCalled();
const [messageRoomId, relation, messageBody] = mockClient.sendMessage.mock.calls[0];
@ -220,68 +225,60 @@ describe("<LocationShareMenu />", () => {
describe("with pin drop share type enabled", () => {
it("renders share type switch with own and pin drop options", () => {
const component = getComponent();
expect(component.find("LocationPicker").length).toBe(0);
const { getByText } = getComponent();
expect(document.querySelector(".mx_LocationPicker")).not.toBeInTheDocument();
expect(getShareTypeOption(component, LocationShareType.Own).length).toBe(1);
expect(getShareTypeOption(component, LocationShareType.Pin).length).toBe(1);
expect(getByText(shareTypeLabels[LocationShareType.Own])).toBeInTheDocument();
expect(getByText(shareTypeLabels[LocationShareType.Pin])).toBeInTheDocument();
});
it("does not render back button on share type screen", () => {
const component = getComponent();
expect(getBackButton(component).length).toBe(0);
const { queryByLabelText } = getComponent();
expect(queryByLabelText("Back")).not.toBeInTheDocument();
});
it("clicking cancel button from share type screen closes dialog", () => {
const onFinished = jest.fn();
const component = getComponent({ onFinished });
const { getByLabelText } = getComponent({ onFinished });
act(() => {
getCancelButton(component).at(0).simulate("click");
});
fireEvent.click(getCancelButton(getByLabelText));
expect(onFinished).toHaveBeenCalled();
});
it("selecting own location share type advances to location picker", () => {
const component = getComponent();
const { getByText } = getComponent();
setShareType(component, LocationShareType.Own);
setShareType(getByText, LocationShareType.Own);
expect(component.find("LocationPicker").length).toBe(1);
expect(document.querySelector(".mx_LocationPicker")).toBeInTheDocument();
});
it("clicking back button from location picker screen goes back to share screen", () => {
const onFinished = jest.fn();
const component = getComponent({ onFinished });
const { getByText, getByLabelText } = getComponent({ onFinished });
// advance to location picker
setShareType(component, LocationShareType.Own);
setShareType(getByText, LocationShareType.Own);
expect(component.find("LocationPicker").length).toBe(1);
expect(document.querySelector(".mx_LocationPicker")).toBeInTheDocument();
act(() => {
getBackButton(component).at(0).simulate("click");
component.setProps({});
});
fireEvent.click(getBackButton(getByLabelText));
// back to share type
expect(component.find("ShareType").length).toBe(1);
expect(getByText("What location type do you want to share?")).toBeInTheDocument();
});
it("creates pin drop location share event on submission", () => {
const onFinished = jest.fn();
const component = getComponent({ onFinished });
const { getByText } = getComponent({ onFinished });
// advance to location picker
setShareType(component, LocationShareType.Pin);
setShareType(getByText, LocationShareType.Pin);
setLocation(component);
setLocationClick();
act(() => {
getSubmitButton(component).at(0).simulate("click");
component.setProps({});
});
fireEvent.click(getByText("Share location"));
expect(onFinished).toHaveBeenCalled();
const [messageRoomId, relation, messageBody] = mockClient.sendMessage.mock.calls[0];
@ -300,53 +297,41 @@ describe("<LocationShareMenu />", () => {
describe("with live location disabled", () => {
beforeEach(() => enableSettings([]));
const getToggle = (component: ReactWrapper) =>
findByTestId(component, "enable-live-share-toggle").find('[role="switch"]').at(0);
const getSubmitEnableButton = (component: ReactWrapper) =>
findByTestId(component, "enable-live-share-submit").at(0);
it("goes to labs flag screen after live options is clicked", () => {
const onFinished = jest.fn();
const component = getComponent({ onFinished });
const { getByText, getByTestId } = getComponent({ onFinished });
setShareType(component, LocationShareType.Live);
setShareType(getByText, LocationShareType.Live);
expect(findByTestId(component, "location-picker-enable-live-share")).toMatchSnapshot();
expect(getByTestId("location-picker-enable-live-share")).toMatchSnapshot();
});
it("disables OK button when labs flag is not enabled", () => {
const component = getComponent();
const { getByText } = getComponent();
setShareType(component, LocationShareType.Live);
setShareType(getByText, LocationShareType.Live);
expect(getSubmitEnableButton(component).props()["disabled"]).toBeTruthy();
expect(getByText("OK").hasAttribute("disabled")).toBeTruthy();
});
it("enables OK button when labs flag is toggled to enabled", () => {
const component = getComponent();
const { getByText, getByLabelText } = getComponent();
setShareType(component, LocationShareType.Live);
setShareType(getByText, LocationShareType.Live);
act(() => {
getToggle(component).simulate("click");
component.setProps({});
});
expect(getSubmitEnableButton(component).props()["disabled"]).toBeFalsy();
fireEvent.click(getByLabelText("Enable live location sharing"));
expect(getByText("OK").hasAttribute("disabled")).toBeFalsy();
});
it("enables live share setting on ok button submit", () => {
const component = getComponent();
const { getByText, getByLabelText } = getComponent();
setShareType(component, LocationShareType.Live);
setShareType(getByText, LocationShareType.Live);
act(() => {
getToggle(component).simulate("click");
component.setProps({});
});
fireEvent.click(getByLabelText("Enable live location sharing"));
act(() => {
getSubmitEnableButton(component).simulate("click");
});
fireEvent.click(getByText("OK"));
expect(SettingsStore.setValue).toHaveBeenCalledWith(
"feature_location_share_live",
@ -365,12 +350,12 @@ describe("<LocationShareMenu />", () => {
}, 1000);
});
mocked(SettingsStore.getValue).mockReturnValue(false);
const component = getComponent();
const { getByText, getByLabelText } = getComponent();
setShareType(component, LocationShareType.Live);
setShareType(getByText, LocationShareType.Live);
// we're on enable live share screen
expect(findByTestId(component, "location-picker-enable-live-share").length).toBeTruthy();
expect(getByLabelText("Enable live location sharing")).toBeInTheDocument();
act(() => {
mocked(SettingsStore.getValue).mockReturnValue(true);
@ -378,10 +363,8 @@ describe("<LocationShareMenu />", () => {
jest.runAllTimers();
});
component.setProps({});
// advanced to location picker
expect(component.find("LocationPicker").length).toBeTruthy();
expect(document.querySelector(".mx_LocationPicker")).toBeInTheDocument();
});
});
@ -393,23 +376,20 @@ describe("<LocationShareMenu />", () => {
rel_type: RelationType.Thread,
event_id: "12345",
};
const component = getComponent({ relation });
const { queryByText } = getComponent({ relation });
expect(getShareTypeOption(component, LocationShareType.Live).length).toBeFalsy();
expect(queryByText(shareTypeLabels[LocationShareType.Live])).not.toBeInTheDocument();
});
it("creates beacon info event on submission", async () => {
const onFinished = jest.fn();
const component = getComponent({ onFinished });
const { getByText } = getComponent({ onFinished });
// advance to location picker
setShareType(component, LocationShareType.Live);
setLocation(component);
setShareType(getByText, LocationShareType.Live);
setLocationGeolocate();
act(() => {
getSubmitButton(component).at(0).simulate("click");
component.setProps({});
});
fireEvent.click(getByText("Share location"));
// flush stopping existing beacons promises
await flushPromisesWithFakeTimers();
@ -435,16 +415,13 @@ describe("<LocationShareMenu />", () => {
const logSpy = jest.spyOn(logger, "error").mockReturnValue(undefined);
const error = new Error("oh no");
mockClient.unstable_createLiveBeacon.mockRejectedValue(error);
const component = getComponent();
const { getByText } = getComponent();
// advance to location picker
setShareType(component, LocationShareType.Live);
setLocation(component);
setShareType(getByText, LocationShareType.Live);
setLocationGeolocate();
act(() => {
getSubmitButton(component).at(0).simulate("click");
component.setProps({});
});
fireEvent.click(getByText("Share location"));
await flushPromisesWithFakeTimers();
await flushPromisesWithFakeTimers();
@ -467,16 +444,13 @@ describe("<LocationShareMenu />", () => {
const logSpy = jest.spyOn(logger, "error").mockReturnValue(undefined);
const error = { errcode: "M_FORBIDDEN" } as unknown as Error;
mockClient.unstable_createLiveBeacon.mockRejectedValue(error);
const component = getComponent();
const { getByText } = getComponent();
// advance to location picker
setShareType(component, LocationShareType.Live);
setLocation(component);
setShareType(getByText, LocationShareType.Live);
setLocationGeolocate();
act(() => {
getSubmitButton(component).at(0).simulate("click");
component.setProps({});
});
fireEvent.click(getByText("Share location"));
await flushPromisesWithFakeTimers();
await flushPromisesWithFakeTimers();

View File

@ -15,8 +15,7 @@ limitations under the License.
*/
import React from "react";
// eslint-disable-next-line deprecate/import
import { mount } from "enzyme";
import { render, RenderResult } from "@testing-library/react";
import { RoomMember } from "matrix-js-sdk/src/matrix";
import { LocationAssetType } from "matrix-js-sdk/src/@types/location";
@ -39,11 +38,11 @@ describe("<LocationViewDialog />", () => {
mxEvent: defaultEvent,
onFinished: jest.fn(),
};
const getComponent = (props = {}) => mount(<LocationViewDialog {...defaultProps} {...props} />);
const getComponent = (props = {}): RenderResult => render(<LocationViewDialog {...defaultProps} {...props} />);
it("renders map correctly", () => {
const component = getComponent();
expect(component.find("Map")).toMatchSnapshot();
const { container } = getComponent();
expect(container.querySelector(".mx_Map")).toMatchSnapshot();
});
it("renders marker correctly for self share", () => {
@ -51,7 +50,7 @@ describe("<LocationViewDialog />", () => {
const member = new RoomMember(roomId, userId);
// @ts-ignore cheat assignment to property
selfShareEvent.sender = member;
const component = getComponent({ mxEvent: selfShareEvent });
expect(component.find("SmartMarker").prop("roomMember")).toEqual(member);
const { container } = getComponent({ mxEvent: selfShareEvent });
expect(container.querySelector(".mx_BaseAvatar_image").getAttribute("title")).toEqual(userId);
});
});

View File

@ -15,8 +15,7 @@ limitations under the License.
*/
import React from "react";
// eslint-disable-next-line deprecate/import
import { mount } from "enzyme";
import { render } from "@testing-library/react";
import { mocked } from "jest-mock";
import * as maplibregl from "maplibre-gl";
@ -35,17 +34,15 @@ describe("<SmartMarker />", () => {
map: mockMap,
geoUri: "geo:43.2,54.6",
};
const getComponent = (props = {}) => mount(<SmartMarker {...defaultProps} {...props} />);
const getComponent = (props = {}): JSX.Element => <SmartMarker {...defaultProps} {...props} />;
beforeEach(() => {
jest.clearAllMocks();
});
it("creates a marker on mount", () => {
const component = getComponent();
expect(component).toMatchSnapshot();
component.setProps({});
const { container } = render(getComponent());
expect(container).toMatchSnapshot();
// marker added only once
expect(maplibregl.Marker).toHaveBeenCalledTimes(1);
@ -56,10 +53,10 @@ describe("<SmartMarker />", () => {
});
it("updates marker position on change", () => {
const component = getComponent({ geoUri: "geo:40,50" });
const { rerender } = render(getComponent({ geoUri: "geo:40,50" }));
component.setProps({ geoUri: "geo:41,51" });
component.setProps({ geoUri: "geo:42,52" });
rerender(getComponent({ geoUri: "geo:41,51" }));
rerender(getComponent({ geoUri: "geo:42,52" }));
// marker added only once
expect(maplibregl.Marker).toHaveBeenCalledTimes(1);
@ -70,12 +67,10 @@ describe("<SmartMarker />", () => {
});
it("removes marker on unmount", () => {
const component = getComponent();
expect(component).toMatchSnapshot();
const { unmount, container } = render(getComponent());
expect(container).toMatchSnapshot();
component.setProps({});
component.unmount();
unmount();
expect(mockMarker.remove).toHaveBeenCalled();
});
});

View File

@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LocationPicker <LocationPicker /> for Live location share type updates selected duration 1`] = `
<div
data-test-id="live-duration-option-3600000"
>
Share for 1h
</div>
`;

View File

@ -2,116 +2,53 @@
exports[`<LocationShareMenu /> with live location disabled goes to labs flag screen after live options is clicked 1`] = `
<div
className="mx_EnableLiveShare"
data-test-id="location-picker-enable-live-share"
class="mx_EnableLiveShare"
data-testid="location-picker-enable-live-share"
>
<StyledLiveBeaconIcon
className="mx_EnableLiveShare_icon"
<div
class="mx_StyledLiveBeaconIcon mx_EnableLiveShare_icon"
/>
<h3
class="mx_Heading_h3 mx_EnableLiveShare_heading"
>
<div
className="mx_StyledLiveBeaconIcon mx_EnableLiveShare_icon"
/>
</StyledLiveBeaconIcon>
<Heading
className="mx_EnableLiveShare_heading"
size="h3"
>
<h3
className="mx_Heading_h3 mx_EnableLiveShare_heading"
>
Live location sharing
</h3>
</Heading>
Live location sharing
</h3>
<p
className="mx_EnableLiveShare_description"
class="mx_EnableLiveShare_description"
>
Please note: this is a labs feature using a temporary implementation. This means you will not be able to delete your location history, and advanced users will be able to see your location history even after you stop sharing your live location with this room.
</p>
<LabelledToggleSwitch
data-test-id="enable-live-share-toggle"
label="Enable live location sharing"
onChange={[Function]}
value={false}
<div
class="mx_SettingsFlag"
data-testid="enable-live-share-toggle"
>
<span
class="mx_SettingsFlag_label"
>
Enable live location sharing
</span>
<div
className="mx_SettingsFlag"
aria-checked="false"
aria-disabled="false"
aria-label="Enable live location sharing"
class="mx_AccessibleButton mx_ToggleSwitch mx_ToggleSwitch_enabled"
role="switch"
tabindex="0"
>
<span
className="mx_SettingsFlag_label"
>
Enable live location sharing
</span>
<_default
checked={false}
onChange={[Function]}
title="Enable live location sharing"
>
<AccessibleTooltipButton
aria-checked={false}
aria-disabled={false}
className="mx_ToggleSwitch mx_ToggleSwitch_enabled"
onClick={[Function]}
role="switch"
title="Enable live location sharing"
>
<AccessibleButton
aria-checked={false}
aria-disabled={false}
aria-label="Enable live location sharing"
className="mx_ToggleSwitch mx_ToggleSwitch_enabled"
element="div"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseLeave={[Function]}
onMouseOver={[Function]}
role="switch"
tabIndex={0}
>
<div
aria-checked={false}
aria-disabled={false}
aria-label="Enable live location sharing"
className="mx_AccessibleButton mx_ToggleSwitch mx_ToggleSwitch_enabled"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
onMouseLeave={[Function]}
onMouseOver={[Function]}
role="switch"
tabIndex={0}
>
<div
className="mx_ToggleSwitch_ball"
/>
</div>
</AccessibleButton>
</AccessibleTooltipButton>
</_default>
<div
class="mx_ToggleSwitch_ball"
/>
</div>
</LabelledToggleSwitch>
<AccessibleButton
className="mx_EnableLiveShare_button"
data-test-id="enable-live-share-submit"
disabled={true}
element="button"
kind="primary"
onClick={[Function]}
</div>
<button
aria-disabled="true"
class="mx_AccessibleButton mx_EnableLiveShare_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary mx_AccessibleButton_disabled"
data-testid="enable-live-share-submit"
disabled=""
role="button"
tabIndex={0}
tabindex="0"
>
<button
aria-disabled={true}
className="mx_AccessibleButton mx_EnableLiveShare_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary mx_AccessibleButton_disabled"
data-test-id="enable-live-share-submit"
disabled={true}
role="button"
tabIndex={0}
>
OK
</button>
</AccessibleButton>
OK
</button>
</div>
`;

View File

@ -1,219 +1,49 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<LocationViewDialog /> renders map correctly 1`] = `
<Map
allowGeolocate={true}
centerGeoUri="geo:51.5076,-0.1276"
className="mx_LocationViewDialog_map"
id="mx_LocationViewDialog_$2"
interactive={true}
onError={[Function]}
<div
class="mx_Map mx_LocationViewDialog_map"
id="mx_Map_mx_LocationViewDialog_$2"
>
<div
className="mx_Map mx_LocationViewDialog_map"
id="mx_Map_mx_LocationViewDialog_$2"
onClick={[Function]}
>
<SmartMarker
geoUri="geo:51.5076,-0.1276"
<span>
<div
class="mx_Marker mx_Marker_defaultColor"
id="mx_LocationViewDialog_$2-marker"
map={
MockMap {
"_events": {
"error": [Function],
},
"_eventsCount": 1,
"_maxListeners": undefined,
"addControl": [MockFunction] {
"calls": [
[
MockAttributionControl {},
"top-right",
],
[
MockGeolocateControl {
"_events": {
"error": [Function],
},
"_eventsCount": 1,
"_maxListeners": undefined,
"trigger": [MockFunction],
Symbol(kCapture): false,
},
],
],
"results": [
{
"type": "return",
"value": undefined,
},
{
"type": "return",
"value": undefined,
},
],
},
"fitBounds": [MockFunction],
"removeControl": [MockFunction],
"setCenter": [MockFunction] {
"calls": [
[
{
"lat": 51.5076,
"lon": -0.1276,
},
],
],
"results": [
{
"type": "return",
"value": undefined,
},
],
},
"setStyle": [MockFunction],
"zoomIn": [MockFunction],
"zoomOut": [MockFunction],
Symbol(kCapture): false,
}
}
>
<span>
<ForwardRef
id="mx_LocationViewDialog_$2-marker"
>
<div
className="mx_Marker mx_Marker_defaultColor"
id="mx_LocationViewDialog_$2-marker"
>
<OptionalTooltip>
<div
className="mx_Marker_border"
>
<div
className="mx_Marker_icon"
/>
</div>
</OptionalTooltip>
</div>
</ForwardRef>
</span>
</SmartMarker>
<ZoomButtons
map={
MockMap {
"_events": {
"error": [Function],
},
"_eventsCount": 1,
"_maxListeners": undefined,
"addControl": [MockFunction] {
"calls": [
[
MockAttributionControl {},
"top-right",
],
[
MockGeolocateControl {
"_events": {
"error": [Function],
},
"_eventsCount": 1,
"_maxListeners": undefined,
"trigger": [MockFunction],
Symbol(kCapture): false,
},
],
],
"results": [
{
"type": "return",
"value": undefined,
},
{
"type": "return",
"value": undefined,
},
],
},
"fitBounds": [MockFunction],
"removeControl": [MockFunction],
"setCenter": [MockFunction] {
"calls": [
[
{
"lat": 51.5076,
"lon": -0.1276,
},
],
],
"results": [
{
"type": "return",
"value": undefined,
},
],
},
"setStyle": [MockFunction],
"zoomIn": [MockFunction],
"zoomOut": [MockFunction],
Symbol(kCapture): false,
}
}
>
<div
className="mx_ZoomButtons"
class="mx_Marker_border"
>
<AccessibleButton
className="mx_ZoomButtons_button"
data-testid="map-zoom-in-button"
element="div"
onClick={[Function]}
role="button"
tabIndex={0}
title="Zoom in"
>
<div
className="mx_AccessibleButton mx_ZoomButtons_button"
data-testid="map-zoom-in-button"
onClick={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
role="button"
tabIndex={0}
title="Zoom in"
>
<div
className="mx_ZoomButtons_icon"
/>
</div>
</AccessibleButton>
<AccessibleButton
className="mx_ZoomButtons_button"
data-testid="map-zoom-out-button"
element="div"
onClick={[Function]}
role="button"
tabIndex={0}
title="Zoom out"
>
<div
className="mx_AccessibleButton mx_ZoomButtons_button"
data-testid="map-zoom-out-button"
onClick={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
role="button"
tabIndex={0}
title="Zoom out"
>
<div
className="mx_ZoomButtons_icon"
/>
</div>
</AccessibleButton>
<div
class="mx_Marker_icon"
/>
</div>
</ZoomButtons>
</div>
</span>
<div
class="mx_ZoomButtons"
>
<div
class="mx_AccessibleButton mx_ZoomButtons_button"
data-testid="map-zoom-in-button"
role="button"
tabindex="0"
title="Zoom in"
>
<div
class="mx_ZoomButtons_icon"
/>
</div>
<div
class="mx_AccessibleButton mx_ZoomButtons_button"
data-testid="map-zoom-out-button"
role="button"
tabindex="0"
title="Zoom out"
>
<div
class="mx_ZoomButtons_icon"
/>
</div>
</div>
</Map>
</div>
`;

View File

@ -4,7 +4,7 @@ exports[`<MapError /> applies class when isMinimised is truthy 1`] = `
<div>
<div
class="mx_MapError test mx_MapError_isMinimised"
data-test-id="map-rendering-error"
data-testid="map-rendering-error"
>
<div
class="mx_MapError_icon"
@ -34,7 +34,7 @@ exports[`<MapError /> renders correctly for MapStyleUrlNotConfigured 1`] = `
<div>
<div
class="mx_MapError test"
data-test-id="map-rendering-error"
data-testid="map-rendering-error"
>
<div
class="mx_MapError_icon"
@ -64,7 +64,7 @@ exports[`<MapError /> renders correctly for MapStyleUrlNotReachable 1`] = `
<div>
<div
class="mx_MapError test"
data-test-id="map-rendering-error"
data-testid="map-rendering-error"
>
<div
class="mx_MapError_icon"

View File

@ -1,79 +1,37 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<SmartMarker /> creates a marker on mount 1`] = `
<SmartMarker
geoUri="geo:43.2,54.6"
map={
MockMap {
"_events": {},
"_eventsCount": 0,
"_maxListeners": undefined,
"addControl": [MockFunction],
"fitBounds": [MockFunction],
"removeControl": [MockFunction],
"setCenter": [MockFunction],
"setStyle": [MockFunction],
"zoomIn": [MockFunction],
"zoomOut": [MockFunction],
Symbol(kCapture): false,
}
}
>
<div>
<span>
<ForwardRef>
<div
class="mx_Marker mx_Marker_defaultColor"
>
<div
className="mx_Marker mx_Marker_defaultColor"
class="mx_Marker_border"
>
<OptionalTooltip>
<div
className="mx_Marker_border"
>
<div
className="mx_Marker_icon"
/>
</div>
</OptionalTooltip>
<div
class="mx_Marker_icon"
/>
</div>
</ForwardRef>
</div>
</span>
</SmartMarker>
</div>
`;
exports[`<SmartMarker /> removes marker on unmount 1`] = `
<SmartMarker
geoUri="geo:43.2,54.6"
map={
MockMap {
"_events": {},
"_eventsCount": 0,
"_maxListeners": undefined,
"addControl": [MockFunction],
"fitBounds": [MockFunction],
"removeControl": [MockFunction],
"setCenter": [MockFunction],
"setStyle": [MockFunction],
"zoomIn": [MockFunction],
"zoomOut": [MockFunction],
Symbol(kCapture): false,
}
}
>
<div>
<span>
<ForwardRef>
<div
class="mx_Marker mx_Marker_defaultColor"
>
<div
className="mx_Marker mx_Marker_defaultColor"
class="mx_Marker_border"
>
<OptionalTooltip>
<div
className="mx_Marker_border"
>
<div
className="mx_Marker_icon"
/>
</div>
</OptionalTooltip>
<div
class="mx_Marker_icon"
/>
</div>
</ForwardRef>
</div>
</span>
</SmartMarker>
</div>
`;

View File

@ -9,7 +9,7 @@ exports[`<MBeaconBody /> when map display is not configured renders maps unavail
>
<div
className="mx_MapError mx_MBeaconBody_mapError mx_MBeaconBody_mapErrorInteractive mx_MapError_isMinimised"
data-test-id="map-rendering-error"
data-testid="map-rendering-error"
onClick={[Function]}
>
<div