diff --git a/package.json b/package.json index 489f789089..c891bc0dca 100644 --- a/package.json +++ b/package.json @@ -164,10 +164,10 @@ "@casualbot/jest-sonar-reporter": "2.2.7", "@peculiar/webcrypto": "^1.4.3", "@playwright/test": "^1.40.1", - "@testing-library/dom": "^9.0.0", - "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14", - "@testing-library/user-event": "^14.4.3", + "@testing-library/dom": "^10.4.0", + "@testing-library/jest-dom": "^6.4.8", + "@testing-library/react": "^16.0.0", + "@testing-library/user-event": "^14.5.2", "@types/commonmark": "^0.27.4", "@types/content-type": "^1.1.5", "@types/counterpart": "^0.18.1", diff --git a/src/settings/handlers/AbstractLocalStorageSettingsHandler.ts b/src/settings/handlers/AbstractLocalStorageSettingsHandler.ts index bcc72055f4..9a5d41d33a 100644 --- a/src/settings/handlers/AbstractLocalStorageSettingsHandler.ts +++ b/src/settings/handlers/AbstractLocalStorageSettingsHandler.ts @@ -108,4 +108,9 @@ export default abstract class AbstractLocalStorageSettingsHandler extends Settin public isSupported(): boolean { return localStorage !== undefined && localStorage !== null; } + + public reset(): void { + AbstractLocalStorageSettingsHandler.clear(); + AbstractLocalStorageSettingsHandler.clear(); + } } diff --git a/test/components/views/dialogs/RoomSettingsDialog-test.tsx b/test/components/views/dialogs/RoomSettingsDialog-test.tsx index d028d43a93..4d53e714c7 100644 --- a/test/components/views/dialogs/RoomSettingsDialog-test.tsx +++ b/test/components/views/dialogs/RoomSettingsDialog-test.tsx @@ -15,7 +15,7 @@ limitations under the License. */ import React from "react"; -import { fireEvent, render, screen } from "@testing-library/react"; +import { fireEvent, render, screen, waitFor } from "@testing-library/react"; import { EventTimeline, EventType, @@ -129,7 +129,7 @@ describe("", () => { expect(screen.getByTestId("settings-tab-ROOM_PEOPLE_TAB")).toBeInTheDocument(); }); - it("re-renders on room join rule changes", () => { + it("re-renders on room join rule changes", async () => { jest.spyOn(SettingsStore, "getValue").mockImplementation( (setting) => setting === "feature_ask_to_join", ); @@ -142,7 +142,9 @@ describe("", () => { room.getLiveTimeline().getState(EventTimeline.FORWARDS)!, null, ); - expect(screen.queryByTestId("settings-tab-ROOM_PEOPLE_TAB")).not.toBeInTheDocument(); + await waitFor(() => + expect(screen.queryByTestId("settings-tab-ROOM_PEOPLE_TAB")).not.toBeInTheDocument(), + ); }); }); diff --git a/test/components/views/dialogs/SpotlightDialog-test.tsx b/test/components/views/dialogs/SpotlightDialog-test.tsx index 86367b2811..00584f3b4f 100644 --- a/test/components/views/dialogs/SpotlightDialog-test.tsx +++ b/test/components/views/dialogs/SpotlightDialog-test.tsx @@ -32,7 +32,7 @@ import { fireEvent, render, screen, waitFor } from "@testing-library/react"; import SpotlightDialog from "../../../../src/components/views/dialogs/spotlight/SpotlightDialog"; import { Filter } from "../../../../src/components/views/dialogs/spotlight/Filter"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; -import { LocalRoom, LOCAL_ROOM_ID_PREFIX } from "../../../../src/models/LocalRoom"; +import { LOCAL_ROOM_ID_PREFIX, LocalRoom } from "../../../../src/models/LocalRoom"; import { DirectoryMember, startDmOnFirstMessage } from "../../../../src/utils/direct-messages"; import DMRoomMap from "../../../../src/utils/DMRoomMap"; import { flushPromisesWithFakeTimers, mkRoom, stubClient } from "../../../test-utils"; @@ -157,6 +157,9 @@ describe("Spotlight Dialog", () => { let mockedClient: MatrixClient; beforeEach(() => { + SdkConfig.reset(); + localStorage.clear(); + SettingsStore.reset(); mockedClient = mockClient({ rooms: [testPublicRoom], users: [testPerson] }); testRoom = mkRoom(mockedClient, "!test23:example.com"); mocked(testRoom.getMyMembership).mockReturnValue(KnownMembership.Join); @@ -235,14 +238,8 @@ describe("Spotlight Dialog", () => { }); describe("when MSC3946 dynamic room predecessors is enabled", () => { - beforeEach(() => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName, roomId, excludeDefault) => { - if (settingName === "feature_dynamic_room_predecessors") { - return true; - } else { - return []; // SpotlightSearch.recentSearches - } - }); + beforeEach(async () => { + await SettingsStore.setValue("feature_dynamic_room_predecessors", null, SettingLevel.DEVICE, true); }); afterEach(() => { @@ -552,13 +549,9 @@ describe("Spotlight Dialog", () => { guest_can_join: false, }; - beforeEach(() => { + beforeEach(async () => { mockedClient = mockClient({ rooms: [nsfwNameRoom, nsfwTopicRoom, potatoRoom], users: [testPerson] }); - SettingsStore.setValue("SpotlightSearch.showNsfwPublicRooms", null, SettingLevel.DEVICE, false); - }); - - afterAll(() => { - SettingsStore.setValue("SpotlightSearch.showNsfwPublicRooms", null, SettingLevel.DEVICE, false); + await SettingsStore.setValue("SpotlightSearch.showNsfwPublicRooms", null, SettingLevel.DEVICE, false); }); it("does not display rooms with nsfw keywords in results when showNsfwPublicRooms is falsy", async () => { @@ -576,7 +569,7 @@ describe("Spotlight Dialog", () => { }); it("displays rooms with nsfw keywords in results when showNsfwPublicRooms is truthy", async () => { - SettingsStore.setValue("SpotlightSearch.showNsfwPublicRooms", null, SettingLevel.DEVICE, true); + await SettingsStore.setValue("SpotlightSearch.showNsfwPublicRooms", null, SettingLevel.DEVICE, true); render( null} />); // search is debounced @@ -624,9 +617,7 @@ describe("Spotlight Dialog", () => { describe("when disabling feature", () => { beforeEach(async () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => - setting === "feature_ask_to_join" ? false : [], - ); + await SettingsStore.setValue("feature_ask_to_join", null, SettingLevel.DEVICE, false); render( {}} />); @@ -634,7 +625,7 @@ describe("Spotlight Dialog", () => { jest.advanceTimersByTime(200); await flushPromisesWithFakeTimers(); - fireEvent.click(screen.getByRole("button", { name: "View" })); + fireEvent.click(await screen.findByRole("button", { name: "View" })); }); it("should not skip to auto join", async () => { @@ -648,18 +639,12 @@ describe("Spotlight Dialog", () => { describe("when enabling feature", () => { beforeEach(async () => { - jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => - setting === "feature_ask_to_join" ? true : [], - ); + await SettingsStore.setValue("feature_ask_to_join", null, SettingLevel.DEVICE, true); jest.spyOn(mockedClient, "getRoom").mockReturnValue(null); render( {}} />); - // search is debounced - jest.advanceTimersByTime(200); - await flushPromisesWithFakeTimers(); - - fireEvent.click(screen.getByRole("button", { name: "Ask to join" })); + await waitFor(() => fireEvent.click(screen.getByRole("button", { name: "Ask to join" }))); }); it("should skip to auto join", async () => { diff --git a/test/components/views/messages/MLocationBody-test.tsx b/test/components/views/messages/MLocationBody-test.tsx index 9f156eac94..55c4f89e54 100644 --- a/test/components/views/messages/MLocationBody-test.tsx +++ b/test/components/views/messages/MLocationBody-test.tsx @@ -19,6 +19,7 @@ import { fireEvent, render, waitFor } from "@testing-library/react"; import { LocationAssetType, ClientEvent, RoomMember, SyncState } from "matrix-js-sdk/src/matrix"; import * as maplibregl from "maplibre-gl"; import { logger } from "matrix-js-sdk/src/logger"; +import { sleep } from "matrix-js-sdk/src/utils"; import MLocationBody from "../../../../src/components/views/messages/MLocationBody"; import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; @@ -64,9 +65,11 @@ describe("MLocationBody", () => { }); const component = getComponent(); - // simulate error initialising map in maplibregl - // @ts-ignore - mockMap.emit("error", { status: 404 }); + sleep(10).then(() => { + // simulate error initialising map in maplibregl + // @ts-ignore + mockMap.emit("error", { status: 404 }); + }); return component; }; @@ -100,9 +103,10 @@ describe("MLocationBody", () => { expect(component.container.querySelector(".mx_EventTile_body")).toMatchSnapshot(); }); - it("displays correct fallback content when map_style_url is misconfigured", () => { + it("displays correct fallback content when map_style_url is misconfigured", async () => { const component = getMapErrorComponent(); - expect(component.container.querySelector(".mx_EventTile_body")).toMatchSnapshot(); + await waitFor(() => expect(component.container.querySelector(".mx_EventTile_body")).toBeTruthy()); + await waitFor(() => expect(component.container.querySelector(".mx_EventTile_body")).toMatchSnapshot()); }); it("should clear the error on reconnect", () => { diff --git a/test/components/views/messages/MPollEndBody-test.tsx b/test/components/views/messages/MPollEndBody-test.tsx index 2410e2e108..d2ec63e421 100644 --- a/test/components/views/messages/MPollEndBody-test.tsx +++ b/test/components/views/messages/MPollEndBody-test.tsx @@ -15,7 +15,7 @@ limitations under the License. */ import React from "react"; -import { render, waitForElementToBeRemoved } from "@testing-library/react"; +import { render, waitFor, waitForElementToBeRemoved } from "@testing-library/react"; import { EventTimeline, MatrixEvent, Room, M_TEXT } from "matrix-js-sdk/src/matrix"; import { logger } from "matrix-js-sdk/src/logger"; @@ -129,13 +129,12 @@ describe("", () => { describe("when poll start event does not exist in current timeline", () => { it("fetches the related poll start event and displays a poll tile", async () => { await setupRoomWithEventsTimeline(pollEndEvent); - const { container, getByTestId, queryByRole } = getComponent(); + const { container, getByTestId, queryByRole, getByRole } = getComponent(); // while fetching event, only icon is shown expect(container).toMatchSnapshot(); - // flush the fetch event promise - await flushPromises(); + await waitFor(() => expect(getByRole("progressbar")).toBeInTheDocument()); await waitForElementToBeRemoved(() => queryByRole("progressbar")); expect(mockClient.fetchRoomEvent).toHaveBeenCalledWith(roomId, pollStartEvent.getId()); diff --git a/test/components/views/right_panel/PinnedMessagesCard-test.tsx b/test/components/views/right_panel/PinnedMessagesCard-test.tsx index d773b51fb9..c8f5fed6b9 100644 --- a/test/components/views/right_panel/PinnedMessagesCard-test.tsx +++ b/test/components/views/right_panel/PinnedMessagesCard-test.tsx @@ -88,19 +88,17 @@ describe("", () => { const mountPins = async (room: Room): Promise => { let pins!: RenderResult; - await act(async () => { - pins = render( - - - , - ); - // Wait a tick for state updates - await sleep(0); - }); + pins = render( + + + , + ); + // Wait a tick for state updates + await sleep(0); return pins; }; @@ -156,7 +154,7 @@ describe("", () => { const localPins = [pin1]; const nonLocalPins = [pin2]; const room = mkRoom(localPins, nonLocalPins); - const pins = await mountPins(room); + const pins = await act(() => mountPins(room)); expect(pins.container.querySelectorAll(".mx_PinnedEventTile")).toHaveLength(2); // Unpin the first message @@ -224,7 +222,7 @@ describe("", () => { events: [messageEvent], }); - const pins = await mountPins(mkRoom([], [pin1])); + const pins = await act(() => mountPins(mkRoom([], [pin1]))); const pinTile = pins.container.querySelectorAll(".mx_PinnedEventTile"); expect(pinTile.length).toBe(1); expect(pinTile[0].querySelector(".mx_EventTile_body")!).toHaveTextContent("First pinned message, edited"); @@ -299,7 +297,7 @@ describe("", () => { jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true); const sendStateEvent = jest.spyOn(cli, "sendStateEvent"); - const pins = await mountPins(room); + const pins = await act(() => mountPins(room)); const pinTile = pins.container.querySelectorAll(".mx_PinnedEventTile"); expect(pinTile).toHaveLength(1); @@ -313,7 +311,7 @@ describe("", () => { it("should show spinner whilst loading", async () => { const room = mkRoom([], [pin1]); mountPins(room); - const spinner = await screen.findByTestId("spinner"); + const spinner = await screen.getByTestId("spinner"); await waitForElementToBeRemoved(spinner); }); }); diff --git a/test/components/views/rooms/MemberList-test.tsx b/test/components/views/rooms/MemberList-test.tsx index 87806e5a85..f611fa00d3 100644 --- a/test/components/views/rooms/MemberList-test.tsx +++ b/test/components/views/rooms/MemberList-test.tsx @@ -16,7 +16,7 @@ limitations under the License. */ import React from "react"; -import { act, fireEvent, render, RenderResult, screen } from "@testing-library/react"; +import { act, fireEvent, render, RenderResult, screen, waitFor } from "@testing-library/react"; import { Room, MatrixClient, RoomState, RoomMember, User, MatrixEvent } from "matrix-js-sdk/src/matrix"; import { KnownMembership } from "matrix-js-sdk/src/types"; import { mocked, MockedObject } from "jest-mock"; @@ -30,6 +30,7 @@ import { filterConsole, flushPromises, getMockClientWithEventEmitter, + mockClientMethodsRooms, mockClientMethodsUser, } from "../../../test-utils"; import { shouldShowComponent } from "../../../../src/customisations/helpers/UIComponents"; @@ -358,6 +359,7 @@ describe("MemberList", () => { mocked(shouldShowComponent).mockReturnValue(true); client = getMockClientWithEventEmitter({ ...mockClientMethodsUser(), + ...mockClientMethodsRooms(), getRoom: jest.fn(), hasLazyLoadMembersEnabled: jest.fn(), }); diff --git a/test/components/views/settings/discovery/EmailAddresses-test.tsx b/test/components/views/settings/discovery/EmailAddresses-test.tsx index 547f802873..a0430898a6 100644 --- a/test/components/views/settings/discovery/EmailAddresses-test.tsx +++ b/test/components/views/settings/discovery/EmailAddresses-test.tsx @@ -15,7 +15,7 @@ limitations under the License. */ import React from "react"; -import { fireEvent, render, screen } from "@testing-library/react"; +import { fireEvent, render, screen, waitFor } from "@testing-library/react"; import { IThreepid, ThreepidMedium, IRequestTokenResponse, MatrixError } from "matrix-js-sdk/src/matrix"; import { TranslationKey, UserFriendlyError } from "../../../../../src/languageHandler"; @@ -104,6 +104,7 @@ describe("", () => { "https://fake-url/", ), ); + await waitFor(() => expect(screen.getByText("Complete")).not.toHaveAttribute("aria-disabled", "true")); fireEvent.click(screen.getByText("Complete")); // Expect error dialog/modal to be shown. We have to wait for the UI to transition. @@ -120,6 +121,7 @@ describe("", () => { it("Shows error dialog when share completion fails (UserFriendlyError)", async () => { const fakeErrorText = "Fake UserFriendlyError error in test" as TranslationKey; mockClient.bindThreePid.mockRejectedValue(new UserFriendlyError(fakeErrorText)); + await waitFor(() => expect(screen.getByText("Complete")).not.toHaveAttribute("aria-disabled", "true")); fireEvent.click(screen.getByText("Complete")); // Expect error dialog/modal to be shown. We have to wait for the UI to transition. @@ -132,6 +134,7 @@ describe("", () => { it("Shows error dialog when share completion fails (generic error)", async () => { const fakeErrorText = "Fake plain error in test"; mockClient.bindThreePid.mockRejectedValue(new Error(fakeErrorText)); + await waitFor(() => expect(screen.getByText("Complete")).not.toHaveAttribute("aria-disabled", "true")); fireEvent.click(screen.getByText("Complete")); // Expect error dialog/modal to be shown. We have to wait for the UI to transition. diff --git a/test/voice-broadcast/components/molecules/VoiceBroadcastPreRecordingPip-test.tsx b/test/voice-broadcast/components/molecules/VoiceBroadcastPreRecordingPip-test.tsx index a15efc86bc..2756f44086 100644 --- a/test/voice-broadcast/components/molecules/VoiceBroadcastPreRecordingPip-test.tsx +++ b/test/voice-broadcast/components/molecules/VoiceBroadcastPreRecordingPip-test.tsx @@ -109,10 +109,8 @@ describe("VoiceBroadcastPreRecordingPip", () => { describe("and double clicking »Go live«", () => { beforeEach(async () => { - await act(async () => { - await userEvent.click(screen.getByText("Go live")); - await userEvent.click(screen.getByText("Go live")); - }); + await userEvent.click(screen.getByText("Go live")); + await userEvent.click(screen.getByText("Go live")); }); it("should call start once", () => { diff --git a/yarn.lock b/yarn.lock index 5da2161d97..e483428e8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2369,21 +2369,21 @@ dependencies: "@sinonjs/commons" "^3.0.0" -"@testing-library/dom@^9.0.0": - version "9.3.4" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-9.3.4.tgz#50696ec28376926fec0a1bf87d9dbac5e27f60ce" - integrity sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ== +"@testing-library/dom@^10.4.0": + version "10.4.0" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-10.4.0.tgz#82a9d9462f11d240ecadbf406607c6ceeeff43a8" + integrity sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ== dependencies: "@babel/code-frame" "^7.10.4" "@babel/runtime" "^7.12.5" "@types/aria-query" "^5.0.1" - aria-query "5.1.3" + aria-query "5.3.0" chalk "^4.1.0" dom-accessibility-api "^0.5.9" lz-string "^1.5.0" pretty-format "^27.0.2" -"@testing-library/jest-dom@^6.0.0": +"@testing-library/jest-dom@^6.4.8": version "6.4.8" resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.4.8.tgz#9c435742b20c6183d4e7034f2b329d562c079daa" integrity sha512-JD0G+Zc38f5MBHA4NgxQMR5XtO5Jx9g86jqturNTt2WUfRmLDIY7iKkWHDCCTiDuFMre6nxAD5wHw9W5kI4rGw== @@ -2397,16 +2397,14 @@ lodash "^4.17.21" redent "^3.0.0" -"@testing-library/react@^14": - version "14.3.1" - resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-14.3.1.tgz#29513fc3770d6fb75245c4e1245c470e4ffdd830" - integrity sha512-H99XjUhWQw0lTgyMN05W3xQG1Nh4lq574D8keFf1dDoNTJgp66VbJozRaczoF+wsiaPJNt/TcnfpLGufGxSrZQ== +"@testing-library/react@^16.0.0": + version "16.0.0" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-16.0.0.tgz#0a1e0c7a3de25841c3591b8cb7fb0cf0c0a27321" + integrity sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ== dependencies: "@babel/runtime" "^7.12.5" - "@testing-library/dom" "^9.0.0" - "@types/react-dom" "^18.0.0" -"@testing-library/user-event@^14.4.3": +"@testing-library/user-event@^14.5.2": version "14.5.2" resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.5.2.tgz#db7257d727c891905947bd1c1a99da20e03c2ebd" integrity sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ== @@ -2745,7 +2743,7 @@ dependencies: "@types/react" "*" -"@types/react-dom@18.3.0", "@types/react-dom@^18.0.0": +"@types/react-dom@18.3.0": version "18.3.0" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== @@ -3191,20 +3189,20 @@ aria-hidden@^1.1.1: dependencies: tslib "^2.0.0" -aria-query@5.1.3, aria-query@~5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" - integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== - dependencies: - deep-equal "^2.0.5" - -aria-query@^5.0.0: +aria-query@5.3.0, aria-query@^5.0.0: version "5.3.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== dependencies: dequal "^2.0.3" +aria-query@~5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" + integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== + dependencies: + deep-equal "^2.0.5" + array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f"