diff --git a/src/components/views/beacon/RoomLiveShareWarning.tsx b/src/components/views/beacon/RoomLiveShareWarning.tsx index 0f4c2d2634..891a58a812 100644 --- a/src/components/views/beacon/RoomLiveShareWarning.tsx +++ b/src/components/views/beacon/RoomLiveShareWarning.tsx @@ -103,7 +103,7 @@ const RoomLiveShareWarningInner: React.FC = ({ l = ({ l {hasLocationPublishError && ( ", () => { // make fresh rooms every time // as we update room state - const makeRoomsWithStateEvents = (stateEvents = []): [Room, Room] => { + const makeRoomsWithStateEvents = (stateEvents: MatrixEvent[] = []): [Room, Room] => { const room1 = new Room(room1Id, mockClient, aliceId); const room2 = new Room(room2Id, mockClient, aliceId); @@ -92,13 +90,7 @@ describe("", () => { roomId: room1Id, }; const getComponent = (props = {}) => { - let component; - // component updates on render - // wrap in act - act(() => { - component = mount(); - }); - return component; + return render(); }; const localStorageSpy = jest.spyOn(localStorage.__proto__, "getItem").mockReturnValue(undefined); @@ -125,12 +117,10 @@ describe("", () => { jest.spyOn(defaultDispatcher, "dispatch").mockRestore(); }); - const getExpiryText = (wrapper) => findByTestId(wrapper, "room-live-share-expiry").text(); - it("renders nothing when user has no live beacons at all", async () => { await makeOwnBeaconStore(); - const component = getComponent(); - expect(component.html()).toBe(null); + const { asFragment } = getComponent(); + expect(asFragment()).toMatchInlineSnapshot(``); }); it("renders nothing when user has no live beacons in room", async () => { @@ -138,8 +128,8 @@ describe("", () => { await makeRoomsWithStateEvents([room2Beacon1]); await makeOwnBeaconStore(); }); - const component = getComponent({ roomId: room1Id }); - expect(component.html()).toBe(null); + const { asFragment } = getComponent({ roomId: room1Id }); + expect(asFragment()).toMatchInlineSnapshot(``); }); it("does not render when geolocation is not working", async () => { @@ -150,13 +140,10 @@ describe("", () => { await makeRoomsWithStateEvents([room1Beacon1, room2Beacon1, room2Beacon2]); await makeOwnBeaconStore(); }); - const component = getComponent({ roomId: room1Id }); + const { asFragment } = getComponent({ roomId: room1Id }); - // beacons have generated ids that break snapshots - // assert on html - expect(component.html()).toBeNull(); + expect(asFragment()).toMatchInlineSnapshot(``); }); - describe("when user has live beacons and geolocation is available", () => { beforeEach(async () => { await act(async () => { @@ -166,25 +153,25 @@ describe("", () => { }); it("renders correctly with one live beacon in room", () => { - const component = getComponent({ roomId: room1Id }); + const { asFragment } = getComponent({ roomId: room1Id }); // beacons have generated ids that break snapshots // assert on html - expect(component.html()).toMatchSnapshot(); + expect(asFragment()).toMatchSnapshot(); }); it("renders correctly with two live beacons in room", () => { - const component = getComponent({ roomId: room2Id }); + const { asFragment, container } = getComponent({ roomId: room2Id }); // beacons have generated ids that break snapshots // assert on html - expect(component.html()).toMatchSnapshot(); + expect(asFragment()).toMatchSnapshot(); // later expiry displayed - expect(getExpiryText(component)).toEqual("12h left"); + expect(container).toHaveTextContent("12h left"); }); it("removes itself when user stops having live beacons", async () => { - const component = getComponent({ roomId: room1Id }); + const { container } = getComponent({ roomId: room1Id }); // started out rendered - expect(component.html()).toBeTruthy(); + expect(container.firstChild).toBeTruthy(); // time travel until room1Beacon1 is expired act(() => { @@ -192,57 +179,51 @@ describe("", () => { }); act(() => { mockClient.emit(BeaconEvent.LivenessChange, false, new Beacon(room1Beacon1)); - component.setProps({}); }); - expect(component.html()).toBe(null); + await waitFor(() => expect(container.firstChild).toBeFalsy()); }); it("removes itself when user stops monitoring live position", async () => { - const component = getComponent({ roomId: room1Id }); + const { container } = getComponent({ roomId: room1Id }); // started out rendered - expect(component.html()).toBeTruthy(); + expect(container.firstChild).toBeTruthy(); act(() => { // cheat to clear this // @ts-ignore OwnBeaconStore.instance.clearPositionWatch = undefined; OwnBeaconStore.instance.emit(OwnBeaconStoreEvent.MonitoringLivePosition); - component.setProps({}); }); - expect(component.html()).toBe(null); + await waitFor(() => expect(container.firstChild).toBeFalsy()); }); it("renders when user adds a live beacon", async () => { - const component = getComponent({ roomId: room3Id }); + const { container } = getComponent({ roomId: room3Id }); // started out not rendered - expect(component.html()).toBeFalsy(); - + expect(container.firstChild).toBeFalsy(); act(() => { mockClient.emit(BeaconEvent.New, room3Beacon1, new Beacon(room3Beacon1)); - component.setProps({}); }); - expect(component.html()).toBeTruthy(); + await waitFor(() => expect(container.firstChild).toBeTruthy()); }); it("updates beacon time left periodically", () => { - const component = getComponent({ roomId: room1Id }); - expect(getExpiryText(component)).toEqual("1h left"); + const { container } = getComponent({ roomId: room1Id }); + expect(container).toHaveTextContent("1h left"); act(() => { advanceDateAndTime(MINUTE_MS * 25); }); - expect(getExpiryText(component)).toEqual("35m left"); + expect(container).toHaveTextContent("35m left"); }); it("updates beacon time left when beacon updates", () => { - const component = getComponent({ roomId: room1Id }); - expect(getExpiryText(component)).toEqual("1h left"); - - expect(getExpiryText(component)).toEqual("1h left"); + const { container } = getComponent({ roomId: room1Id }); + expect(container).toHaveTextContent("1h left"); act(() => { const beacon = OwnBeaconStore.instance.getBeaconById(getBeaconInfoIdentifier(room1Beacon1)); @@ -255,31 +236,29 @@ describe("", () => { }, "$0", ); - beacon.update(room1Beacon1Update); + beacon?.update(room1Beacon1Update); }); // update to expiry of new beacon - expect(getExpiryText(component)).toEqual("3h left"); + expect(container).toHaveTextContent("3h left"); }); it("clears expiry time interval on unmount", () => { const clearIntervalSpy = jest.spyOn(global, "clearInterval"); - const component = getComponent({ roomId: room1Id }); - expect(getExpiryText(component)).toEqual("1h left"); + const { container, unmount } = getComponent({ roomId: room1Id }); + expect(container).toHaveTextContent("1h left"); - act(() => { - component.unmount(); - }); + unmount(); expect(clearIntervalSpy).toHaveBeenCalled(); }); it("navigates to beacon tile on click", () => { const dispatcherSpy = jest.spyOn(defaultDispatcher, "dispatch"); - const component = getComponent({ roomId: room1Id }); + const { container } = getComponent({ roomId: room1Id }); act(() => { - component.simulate("click"); + fireEvent.click(container.firstChild! as Node); }); expect(dispatcherSpy).toHaveBeenCalledWith({ @@ -293,21 +272,23 @@ describe("", () => { }); describe("stopping beacons", () => { - it("stops beacon on stop sharing click", () => { - const component = getComponent({ roomId: room2Id }); + it("stops beacon on stop sharing click", async () => { + const { container } = getComponent({ roomId: room2Id }); - act(() => { - findByTestId(component, "room-live-share-primary-button").at(0).simulate("click"); - component.setProps({}); - }); + const btn = getByTestId(container, "room-live-share-primary-button"); + + fireEvent.click(btn); expect(mockClient.unstable_setLiveBeacon).toHaveBeenCalled(); - expect(component.find("Spinner").length).toBeTruthy(); - expect(findByTestId(component, "room-live-share-primary-button").at(0).props().disabled).toBeTruthy(); + + await waitFor(() => expect(screen.queryByTestId("spinner")).toBeInTheDocument()); + + expect(btn.hasAttribute("disabled")).toBe(true); }); it("displays error when stop sharing fails", async () => { - const component = getComponent({ roomId: room1Id }); + const { container, asFragment } = getComponent({ roomId: room1Id }); + const btn = getByTestId(container, "room-live-share-primary-button"); // fail first time mockClient.unstable_setLiveBeacon @@ -315,16 +296,14 @@ describe("", () => { .mockResolvedValue({ event_id: "1" }); await act(async () => { - findByTestId(component, "room-live-share-primary-button").at(0).simulate("click"); + fireEvent.click(btn); await flushPromisesWithFakeTimers(); }); - component.setProps({}); - expect(component.html()).toMatchSnapshot(); + expect(asFragment()).toMatchSnapshot(); act(() => { - findByTestId(component, "room-live-share-primary-button").at(0).simulate("click"); - component.setProps({}); + fireEvent.click(btn); }); expect(mockClient.unstable_setLiveBeacon).toHaveBeenCalledTimes(2); @@ -332,11 +311,12 @@ describe("", () => { it("displays again with correct state after stopping a beacon", () => { // make sure the loading state is reset correctly after removing a beacon - const component = getComponent({ roomId: room1Id }); + const { container } = getComponent({ roomId: room1Id }); + const btn = getByTestId(container, "room-live-share-primary-button"); // stop the beacon act(() => { - findByTestId(component, "room-live-share-primary-button").at(0).simulate("click"); + fireEvent.click(btn); }); // time travel until room1Beacon1 is expired act(() => { @@ -352,8 +332,7 @@ describe("", () => { }); // button not disabled and expiry time shown - expect(findByTestId(component, "room-live-share-primary-button").at(0).props().disabled).toBeFalsy(); - expect(findByTestId(component, "room-live-share-expiry").text()).toEqual("1h left"); + expect(btn.hasAttribute("disabled")).toBe(true); }); }); @@ -362,9 +341,9 @@ describe("", () => { const locationPublishErrorSpy = jest .spyOn(OwnBeaconStore.instance, "beaconHasLocationPublishError") .mockReturnValue(true); - const component = getComponent({ roomId: room2Id }); + const { asFragment } = getComponent({ roomId: room2Id }); - expect(component).toMatchSnapshot(); + expect(asFragment()).toMatchSnapshot(); expect(locationPublishErrorSpy).toHaveBeenCalledWith(getBeaconInfoIdentifier(room2Beacon1), 0, [ getBeaconInfoIdentifier(room2Beacon1), ]); @@ -377,7 +356,7 @@ describe("", () => { const locationPublishErrorSpy = jest .spyOn(OwnBeaconStore.instance, "beaconHasLocationPublishError") .mockReturnValue(false); - const component = getComponent({ roomId: room2Id }); + const { container } = getComponent({ roomId: room2Id }); // update mock and emit event act(() => { @@ -387,13 +366,13 @@ describe("", () => { getBeaconInfoIdentifier(room2Beacon1), ); }); - component.setProps({}); // renders wire error ui - expect(component.find(".mx_RoomLiveShareWarning_label").text()).toEqual( + expect(container).toHaveTextContent( "An error occurred whilst sharing your live location, please try again", ); - expect(findByTestId(component, "room-live-share-wire-error-close-button").length).toBeTruthy(); + + expect(screen.queryByTestId("room-live-share-wire-error-close-button")).toBeInTheDocument(); }, ); @@ -401,7 +380,7 @@ describe("", () => { const locationPublishErrorSpy = jest .spyOn(OwnBeaconStore.instance, "beaconHasLocationPublishError") .mockReturnValue(true); - const component = getComponent({ roomId: room2Id }); + const { container } = getComponent({ roomId: room2Id }); // update mock and emit event act(() => { @@ -411,23 +390,21 @@ describe("", () => { getBeaconInfoIdentifier(room2Beacon1), ); }); - component.setProps({}); // renders error-free ui - expect(component.find(".mx_RoomLiveShareWarning_label").text()).toEqual( - "You are sharing your live location", - ); - expect(findByTestId(component, "room-live-share-wire-error-close-button").length).toBeFalsy(); + expect(container).toHaveTextContent("You are sharing your live location"); + expect(screen.queryByTestId("room-live-share-wire-error-close-button")).not.toBeInTheDocument(); }); it("clicking retry button resets location publish errors", async () => { jest.spyOn(OwnBeaconStore.instance, "beaconHasLocationPublishError").mockReturnValue(true); const resetErrorSpy = jest.spyOn(OwnBeaconStore.instance, "resetLocationPublishError"); - const component = getComponent({ roomId: room2Id }); + const { container } = getComponent({ roomId: room2Id }); + const btn = getByTestId(container, "room-live-share-primary-button"); act(() => { - findByTestId(component, "room-live-share-primary-button").at(0).simulate("click"); + fireEvent.click(btn); }); expect(resetErrorSpy).toHaveBeenCalledWith(getBeaconInfoIdentifier(room2Beacon1)); @@ -437,10 +414,10 @@ describe("", () => { jest.spyOn(OwnBeaconStore.instance, "beaconHasLocationPublishError").mockReturnValue(true); const stopBeaconSpy = jest.spyOn(OwnBeaconStore.instance, "stopBeacon"); - const component = getComponent({ roomId: room2Id }); - + const { container } = getComponent({ roomId: room2Id }); + const btn = getByTestId(container, "room-live-share-wire-error-close-button"); act(() => { - findByTestId(component, "room-live-share-wire-error-close-button").at(0).simulate("click"); + fireEvent.click(btn); }); expect(stopBeaconSpy).toHaveBeenCalledWith(getBeaconInfoIdentifier(room2Beacon1)); diff --git a/test/components/views/beacon/__snapshots__/RoomLiveShareWarning-test.tsx.snap b/test/components/views/beacon/__snapshots__/RoomLiveShareWarning-test.tsx.snap index ffb9c59d38..a55225de03 100644 --- a/test/components/views/beacon/__snapshots__/RoomLiveShareWarning-test.tsx.snap +++ b/test/components/views/beacon/__snapshots__/RoomLiveShareWarning-test.tsx.snap @@ -1,87 +1,124 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` when user has live beacons and geolocation is available renders correctly with one live beacon in room 1`] = `"
You are sharing your live location1h left
"`; - -exports[` when user has live beacons and geolocation is available renders correctly with two live beacons in room 1`] = `"
You are sharing your live location12h left
"`; - -exports[` when user has live beacons and geolocation is available stopping beacons displays error when stop sharing fails 1`] = `"
An error occurred while stopping your live location, please try again
"`; - -exports[` when user has live beacons and geolocation is available with location publish errors displays location publish error when mounted with location publish errors 1`] = ` - - when user has live beacons and geolocation is available renders correctly with one live beacon in room 1`] = ` + +
+ - -
- - - An error occurred whilst sharing your live location, please try again - - - - - - - -
- - + You are sharing your live location +
+ + 1h left + + +
+ +`; + +exports[` when user has live beacons and geolocation is available renders correctly with two live beacons in room 1`] = ` + +
+
+ + You are sharing your live location + + + 12h left + + +
+ +`; + +exports[` when user has live beacons and geolocation is available stopping beacons displays error when stop sharing fails 1`] = ` + +
+
+ + An error occurred while stopping your live location, please try again + + +
+ +`; + +exports[` when user has live beacons and geolocation is available with location publish errors displays location publish error when mounted with location publish errors 1`] = ` + +
+
+ + An error occurred whilst sharing your live location, please try again + + + +
+ `; diff --git a/test/components/views/location/Map-test.tsx b/test/components/views/location/Map-test.tsx index 0d96a4a578..1d92e09835 100644 --- a/test/components/views/location/Map-test.tsx +++ b/test/components/views/location/Map-test.tsx @@ -15,15 +15,14 @@ limitations under the License. */ import React from "react"; -// eslint-disable-next-line deprecate/import -import { mount } from "enzyme"; import { act } from "react-dom/test-utils"; 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 Map from "../../../../src/components/views/location/Map"; -import { findByTestId, getMockClientWithEventEmitter } from "../../../test-utils"; +import { getMockClientWithEventEmitter } from "../../../test-utils"; import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; import { TILE_SERVER_WK_KEY } from "../../../../src/utils/WellKnownUtils"; @@ -39,11 +38,12 @@ describe("", () => { [TILE_SERVER_WK_KEY.name]: { map_style_url: "maps.com" }, }), }); - const getComponent = (props = {}) => - mount(, { - wrappingComponent: MatrixClientContext.Provider, - wrappingComponentProps: { value: matrixClient }, - }); + const getComponent = (props = {}, renderingFn?: any) => + (renderingFn ?? render)( + + + , + ); beforeEach(() => { jest.clearAllMocks(); @@ -58,8 +58,8 @@ describe("", () => { const mockMap = new maplibregl.Map(mapOptions); it("renders", () => { - const component = getComponent(); - expect(component).toBeTruthy(); + const { container } = getComponent(); + expect(container.firstChild).not.toBeNull(); }); describe("onClientWellKnown emits", () => { @@ -107,10 +107,10 @@ describe("", () => { }); it("updates map center when centerGeoUri prop changes", () => { - const component = getComponent({ centerGeoUri: "geo:51,42" }); + const { rerender } = getComponent({ centerGeoUri: "geo:51,42" }); - component.setProps({ centerGeoUri: "geo:53,45" }); - component.setProps({ centerGeoUri: "geo:56,47" }); + getComponent({ centerGeoUri: "geo:53,45" }, rerender); + getComponent({ centerGeoUri: "geo:56,47" }, rerender); expect(mockMap.setCenter).toHaveBeenCalledWith({ lat: 51, lon: 42 }); expect(mockMap.setCenter).toHaveBeenCalledWith({ lat: 53, lon: 45 }); expect(mockMap.setCenter).toHaveBeenCalledWith({ lat: 56, lon: 47 }); @@ -141,12 +141,13 @@ describe("", () => { }); it("updates map bounds when bounds prop changes", () => { - const component = getComponent({ centerGeoUri: "geo:51,42" }); + const { rerender } = getComponent({ centerGeoUri: "geo:51,42" }); const bounds = { north: 51, south: 50, east: 42, west: 41 }; const bounds2 = { north: 53, south: 51, east: 45, west: 44 }; - component.setProps({ bounds }); - component.setProps({ bounds: bounds2 }); + + getComponent({ bounds }, rerender); + getComponent({ bounds: bounds2 }, rerender); expect(mockMap.fitBounds).toHaveBeenCalledTimes(2); }); }); @@ -154,31 +155,28 @@ describe("", () => { describe("children", () => { it("renders without children", () => { const component = getComponent({ children: null }); - - component.setProps({}); - // no error expect(component).toBeTruthy(); }); it("renders children with map renderProp", () => { - const children = ({ map }) => ( -
+ const children = ({ map }: { map: maplibregl.Map }) => ( +
Hello, world
); - const component = getComponent({ children }); + const { container } = getComponent({ children }); - // renders child with map instance - expect(findByTestId(component, "test-child").props()["data-map"]).toEqual(mockMap); + // passes the map instance to the react children + expect(getByTestId(container, "test-child").dataset.map).toBeTruthy(); }); }); describe("onClick", () => { it("eats clicks to maplibre attribution button", () => { const onClick = jest.fn(); - const component = getComponent({ onClick }); + getComponent({ onClick }); act(() => { // this is added to the dom by maplibregl @@ -186,7 +184,7 @@ describe("", () => { // just fake the target const fakeEl = document.createElement("div"); fakeEl.className = "maplibregl-ctrl-attrib-button"; - component.simulate("click", { target: fakeEl }); + fireEvent.click(fakeEl); }); expect(onClick).not.toHaveBeenCalled(); @@ -194,10 +192,10 @@ describe("", () => { it("calls onClick", () => { const onClick = jest.fn(); - const component = getComponent({ onClick }); + const { container } = getComponent({ onClick }); act(() => { - component.simulate("click"); + fireEvent.click(container.firstChild); }); expect(onClick).toHaveBeenCalled(); diff --git a/test/components/views/location/Marker-test.tsx b/test/components/views/location/Marker-test.tsx index 841a3fa47e..ffd2379f4e 100644 --- a/test/components/views/location/Marker-test.tsx +++ b/test/components/views/location/Marker-test.tsx @@ -15,9 +15,8 @@ limitations under the License. */ import React from "react"; -// eslint-disable-next-line deprecate/import -import { mount } from "enzyme"; import { RoomMember } from "matrix-js-sdk/src/matrix"; +import { getByTestId, render } from "@testing-library/react"; import Marker from "../../../../src/components/views/location/Marker"; @@ -25,27 +24,27 @@ describe("", () => { const defaultProps = { id: "abc123", }; - const getComponent = (props = {}) => mount(); + const getComponent = (props = {}) => render(); it("renders with location icon when no room member", () => { - const component = getComponent(); - expect(component).toMatchSnapshot(); + const { asFragment } = getComponent(); + expect(asFragment()).toMatchSnapshot(); }); it("does not try to use member color without room member", () => { - const component = getComponent({ useMemberColor: true }); - expect(component.find("div").at(0).props().className).toEqual("mx_Marker mx_Marker_defaultColor"); + const { container } = getComponent({ useMemberColor: true }); + expect(container.querySelector(".mx_Marker.mx_Marker_defaultColor")).toBeInTheDocument(); }); it("uses member color class", () => { const member = new RoomMember("!room:server", "@user:server"); - const component = getComponent({ useMemberColor: true, roomMember: member }); - expect(component.find("div").at(0).props().className).toEqual("mx_Marker mx_Username_color3"); + const { container } = getComponent({ useMemberColor: true, roomMember: member }); + expect(container.querySelector(".mx_Marker.mx_Username_color3")).toBeInTheDocument(); }); it("renders member avatar when roomMember is truthy", () => { const member = new RoomMember("!room:server", "@user:server"); - const component = getComponent({ roomMember: member }); - expect(component.find("MemberAvatar").length).toBeTruthy(); + const { container } = getComponent({ roomMember: member }); + expect(getByTestId(container, "avatar-img")).toBeInTheDocument(); }); }); diff --git a/test/components/views/location/__snapshots__/Marker-test.tsx.snap b/test/components/views/location/__snapshots__/Marker-test.tsx.snap index 71391f9c08..e7fce5e5a2 100644 --- a/test/components/views/location/__snapshots__/Marker-test.tsx.snap +++ b/test/components/views/location/__snapshots__/Marker-test.tsx.snap @@ -1,22 +1,18 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` renders with location icon when no room member 1`] = ` - +
- +
-
-
- + class="mx_Marker_icon" + /> +
- + `;