From 7e40e3697f25d561b2df1ce663b12590e9a98a01 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Mon, 28 Jul 2025 17:32:53 +0100 Subject: [PATCH] MatrixChat test robustness fixes (#30413) * MatrixChat-test: clean up better in `afterEach` Make the MatrixChat tests behave better by letting them finish their work in an `act` in afterEach. Otherwise we can end up mounting new components during cleanup, which run tasks in the background * MatrixChat-test: clean up dispatcher test This test was kicking off a dispatcher job which would then open a UserDeviceSettings dialog once the test had finished. That would then throw exceptions because some of the mock environment had been torn down. We're just testing that it opens the right dialog, so better to intercept `createDialog`. Aso add an `act` to reduce warnings, and replace a `flushPromises` with a `waitFor` to make the test more robust. --- .../components/structures/MatrixChat-test.tsx | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/test/unit-tests/components/structures/MatrixChat-test.tsx b/test/unit-tests/components/structures/MatrixChat-test.tsx index c813143142..c00d26750c 100644 --- a/test/unit-tests/components/structures/MatrixChat-test.tsx +++ b/test/unit-tests/components/structures/MatrixChat-test.tsx @@ -71,6 +71,8 @@ import { SetupEncryptionStore } from "../../../../src/stores/SetupEncryptionStor import { ShareFormat } from "../../../../src/dispatcher/payloads/SharePayload.ts"; import { clearStorage } from "../../../../src/Lifecycle"; import RoomListStore from "../../../../src/stores/room-list/RoomListStore.ts"; +import UserSettingsDialog from "../../../../src/components/views/dialogs/UserSettingsDialog.tsx"; +import { SdkContextClass } from "../../../../src/contexts/SDKContext.ts"; jest.mock("matrix-js-sdk/src/oidc/authorize", () => ({ completeAuthorizationCodeGrant: jest.fn(), @@ -268,6 +270,10 @@ describe("", () => { // (must be sync otherwise the next test will start before it happens) act(() => defaultDispatcher.dispatch({ action: Action.OnLoggedOut }, true)); + // that will cause the Login to kick off an update in the background, which we need to allow to finish within + // an `act` to avoid warnings + await flushPromises(); + localStorage.clear(); }); @@ -640,22 +646,29 @@ describe("", () => { }); describe("onAction()", () => { - beforeEach(() => { - jest.spyOn(defaultDispatcher, "dispatch").mockClear(); - jest.spyOn(defaultDispatcher, "fire").mockClear(); + afterEach(() => { + jest.restoreAllMocks(); }); - it("should open user device settings", async () => { + + it("ViewUserDeviceSettings should open user device settings", async () => { await getComponentAndWaitForReady(); - defaultDispatcher.dispatch({ - action: Action.ViewUserDeviceSettings, - }); + const createDialog = jest.spyOn(Modal, "createDialog").mockReturnValue({} as any); - await flushPromises(); + await act(async () => { + defaultDispatcher.dispatch({ + action: Action.ViewUserDeviceSettings, + }); - expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({ - action: Action.ViewUserSettings, - initialTabId: UserTab.SessionManager, + await waitFor(() => + expect(createDialog).toHaveBeenCalledWith( + UserSettingsDialog, + { initialTabId: UserTab.SessionManager, sdkContext: expect.any(SdkContextClass) }, + /*className=*/ undefined, + /*isPriority=*/ false, + /*isStatic=*/ true, + ), + ); }); }); @@ -674,10 +687,6 @@ describe("", () => { jest.spyOn(ReleaseAnnouncementStore.instance, "getReleaseAnnouncement").mockReturnValue(null); }); - afterEach(() => { - jest.restoreAllMocks(); - }); - describe("forget_room", () => { it("should dispatch after_forget_room action on successful forget", async () => { await clearAllModals();