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();