From b719f531ddeb955d423c539e141c498e3559da17 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 20 Jul 2026 14:07:35 +0100 Subject: [PATCH] Migrate more tests to vitest (#34349) --- .../CreateCrossSigning.test.ts} | 34 ++-- .../DecryptionFailureTracker.test.ts} | 30 +-- .../DeviceListener.test.ts} | 182 +++++++++--------- .../utils/FormattingUtils.test.tsx} | 13 +- .../utils/MessageDiffUtils.test.ts} | 7 +- .../FormattingUtils.test.tsx.snap} | 8 +- .../MessageDiffUtils.test.ts.snap} | 34 ++-- .../createVoiceMessageContent.test.ts.snap} | 4 +- .../utils/createVoiceMessageContent.test.ts} | 3 +- .../MatrixSchemePermalinkConstructor.test.ts} | 6 +- .../MatrixToPermalinkConstructor.test.ts} | 6 +- .../utils/permalinks/Permalinks.test.ts} | 35 ++-- .../utils/threepids.test.ts} | 14 +- .../utils/userStatus.test.ts} | 31 +-- .../vector/rageshakesetup.test.ts} | 24 +-- .../timeline/DateSeparatorViewModel.test.ts} | 76 ++++---- .../DisambiguatedProfileViewModel.test.ts} | 18 +- .../body/AudioPlayerViewModel.test.ts} | 14 +- .../structures/ResizerViewModel.test.ts} | 33 ++-- .../test/unit-tests/audio/MockedPlayback.ts | 9 +- 20 files changed, 310 insertions(+), 271 deletions(-) rename apps/web/{test/CreateCrossSigning-test.ts => src/CreateCrossSigning.test.ts} (69%) rename apps/web/{test/unit-tests/DecryptionFailureTracker-test.ts => src/DecryptionFailureTracker.test.ts} (97%) rename apps/web/{test/unit-tests/DeviceListener-test.ts => src/DeviceListener.test.ts} (91%) rename apps/web/{test/unit-tests/utils/FormattingUtils-test.tsx => src/utils/FormattingUtils.test.tsx} (89%) rename apps/web/{test/unit-tests/utils/MessageDiffUtils-test.ts => src/utils/MessageDiffUtils.test.ts} (94%) rename apps/web/{test/unit-tests/utils/__snapshots__/FormattingUtils-test.tsx.snap => src/utils/__snapshots__/FormattingUtils.test.tsx.snap} (68%) rename apps/web/{test/unit-tests/utils/__snapshots__/MessageDiffUtils-test.ts.snap => src/utils/__snapshots__/MessageDiffUtils.test.ts.snap} (87%) rename apps/web/{test/unit-tests/utils/__snapshots__/createVoiceMessageContent-test.ts.snap => src/utils/__snapshots__/createVoiceMessageContent.test.ts.snap} (79%) rename apps/web/{test/unit-tests/utils/createVoiceMessageContent-test.ts => src/utils/createVoiceMessageContent.test.ts} (85%) rename apps/web/{test/unit-tests/utils/permalinks/MatrixSchemePermalinkConstructor-test.ts => src/utils/permalinks/MatrixSchemePermalinkConstructor.test.ts} (77%) rename apps/web/{test/unit-tests/utils/permalinks/MatrixToPermalinkConstructor-test.ts => src/utils/permalinks/MatrixToPermalinkConstructor.test.ts} (91%) rename apps/web/{test/unit-tests/utils/permalinks/Permalinks-test.ts => src/utils/permalinks/Permalinks.test.ts} (94%) rename apps/web/{test/unit-tests/utils/threepids-test.ts => src/utils/threepids.test.ts} (94%) rename apps/web/{test/unit-tests/utils/userStatus-test.ts => src/utils/userStatus.test.ts} (81%) rename apps/web/{test/unit-tests/vector/rageshakesetup-test.ts => src/vector/rageshakesetup.test.ts} (77%) rename apps/web/{test/viewmodels/timeline/DateSeparatorViewModel-test.ts => src/viewmodels/room/timeline/DateSeparatorViewModel.test.ts} (82%) rename apps/web/{test/viewmodels/profile/DisambiguatedProfileViewModel-test.ts => src/viewmodels/room/timeline/event-tile/DisambiguatedProfileViewModel.test.ts} (92%) rename apps/web/{test/viewmodels/audio/AudioPlayerViewModel-test.ts => src/viewmodels/room/timeline/event-tile/body/AudioPlayerViewModel.test.ts} (87%) rename apps/web/{test/viewmodels/structures/ResizerViewModel-test.ts => src/viewmodels/structures/ResizerViewModel.test.ts} (85%) diff --git a/apps/web/test/CreateCrossSigning-test.ts b/apps/web/src/CreateCrossSigning.test.ts similarity index 69% rename from apps/web/test/CreateCrossSigning-test.ts rename to apps/web/src/CreateCrossSigning.test.ts index 09bb3b5a63..111bad0800 100644 --- a/apps/web/test/CreateCrossSigning-test.ts +++ b/apps/web/src/CreateCrossSigning.test.ts @@ -6,12 +6,16 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { HTTPError, type MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix"; -import { mocked } from "jest-mock"; +// @vitest-environment happy-dom -import { createCrossSigning } from "../src/CreateCrossSigning"; -import { createTestClient } from "./test-utils"; -import Modal from "../src/Modal"; +import { vi, describe, it, expect, beforeEach } from "vitest"; +import { HTTPError, type MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix"; +import { createTestClient } from "test-utils"; + +import { createCrossSigning } from "./CreateCrossSigning"; +import Modal from "./Modal"; + +vi.mock("./Modal"); describe("CreateCrossSigning", () => { let client: MatrixClient; @@ -29,7 +33,7 @@ describe("CreateCrossSigning", () => { }); it("should upload", async () => { - client.uploadDeviceSigningKeys = jest.fn().mockRejectedValueOnce( + client.uploadDeviceSigningKeys = vi.fn().mockRejectedValueOnce( new MatrixError({ flows: [ { @@ -41,20 +45,20 @@ describe("CreateCrossSigning", () => { await createCrossSigning(client); - const { authUploadDeviceSigningKeys } = mocked(client.getCrypto()!).bootstrapCrossSigning.mock.calls[0][0]; + const { authUploadDeviceSigningKeys } = vi.mocked(client.getCrypto()!).bootstrapCrossSigning.mock.calls[0][0]; - const makeRequest = jest.fn(); + const makeRequest = vi.fn(); await authUploadDeviceSigningKeys!(makeRequest); expect(makeRequest).toHaveBeenCalledWith(null); }); it("should prompt user if upload failed with UIA", async () => { - const createDialog = jest.spyOn(Modal, "createDialog").mockReturnValue({ + const createDialog = vi.spyOn(Modal, "createDialog").mockReturnValue({ finished: Promise.resolve([true]), - close: jest.fn(), + close: vi.fn(), }); - client.uploadDeviceSigningKeys = jest.fn().mockRejectedValueOnce( + client.uploadDeviceSigningKeys = vi.fn().mockRejectedValueOnce( new MatrixError({ flows: [ { @@ -66,9 +70,9 @@ describe("CreateCrossSigning", () => { await createCrossSigning(client); - const { authUploadDeviceSigningKeys } = mocked(client.getCrypto()!).bootstrapCrossSigning.mock.calls[0][0]; + const { authUploadDeviceSigningKeys } = vi.mocked(client.getCrypto()!).bootstrapCrossSigning.mock.calls[0][0]; - const makeRequest = jest.fn().mockRejectedValue( + const makeRequest = vi.fn().mockRejectedValue( new MatrixError({ flows: [ { @@ -85,10 +89,10 @@ describe("CreateCrossSigning", () => { it("should throw error if server fails with something other than UIA", async () => { await createCrossSigning(client); - const { authUploadDeviceSigningKeys } = mocked(client.getCrypto()!).bootstrapCrossSigning.mock.calls[0][0]; + const { authUploadDeviceSigningKeys } = vi.mocked(client.getCrypto()!).bootstrapCrossSigning.mock.calls[0][0]; const error = new HTTPError("Internal Server Error", 500); - const makeRequest = jest.fn().mockRejectedValue(error); + const makeRequest = vi.fn().mockRejectedValue(error); await expect(authUploadDeviceSigningKeys!(makeRequest)).rejects.toThrow(error); expect(makeRequest).not.toHaveBeenCalledWith(); }); diff --git a/apps/web/test/unit-tests/DecryptionFailureTracker-test.ts b/apps/web/src/DecryptionFailureTracker.test.ts similarity index 97% rename from apps/web/test/unit-tests/DecryptionFailureTracker-test.ts rename to apps/web/src/DecryptionFailureTracker.test.ts index bad06a59c0..c38fd8e614 100644 --- a/apps/web/test/unit-tests/DecryptionFailureTracker-test.ts +++ b/apps/web/src/DecryptionFailureTracker.test.ts @@ -5,7 +5,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { mocked, type Mocked, type MockedObject } from "jest-mock"; +// @vitest-environment happy-dom + +import { vi, describe, it, expect, afterEach, type Mocked, type MockedObject } from "vitest"; import { HttpApiEvent, type MatrixClient, type MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/matrix"; import { decryptExistingEvent, mkDecryptionFailureMatrixEvent } from "matrix-js-sdk/src/testing"; import { @@ -15,10 +17,10 @@ import { CryptoEvent, } from "matrix-js-sdk/src/crypto-api"; import { sleep } from "matrix-js-sdk/src/utils"; +import { stubClient } from "test-utils"; -import { DecryptionFailureTracker, type ErrorProperties } from "../../src/DecryptionFailureTracker"; -import { stubClient } from "../test-utils"; -import * as Lifecycle from "../../src/Lifecycle"; +import { DecryptionFailureTracker, type ErrorProperties } from "./DecryptionFailureTracker"; +import * as Lifecycle from "./Lifecycle"; async function createFailedDecryptionEvent(opts: { sender?: string; code?: DecryptionFailureCode } = {}) { return await mkDecryptionFailureMatrixEvent({ @@ -592,7 +594,7 @@ describe("DecryptionFailureTracker", function () { // Calling .start will start some intervals. This test shouldn't run // long enough for the timers to fire, but we'll use fake timers just // to be safe. - jest.useFakeTimers(); + vi.useFakeTimers(); await tracker.start(client); // If the client fails to decrypt, it should get tracked @@ -616,7 +618,7 @@ describe("DecryptionFailureTracker", function () { expect(errorCount).toEqual(1); - jest.useRealTimers(); + vi.useRealTimers(); }); it("tracks client information", async () => { @@ -657,7 +659,7 @@ describe("DecryptionFailureTracker", function () { const now = Date.now(); eventDecrypted(tracker, federatedDecryption, now); - mocked(client.getCrypto()!.getUserVerificationStatus).mockResolvedValue( + vi.mocked(client.getCrypto()!.getUserVerificationStatus).mockResolvedValue( new UserVerificationStatus(true, true, false), ); client.emit(CryptoEvent.KeysChanged, {}); @@ -677,7 +679,7 @@ describe("DecryptionFailureTracker", function () { // change client params, and make sure the reports the right values client.getDomain.mockReturnValue("example.com"); - mocked(client.getCrypto()!.getVersion).mockReturnValue("Olm 0.0.0"); + vi.mocked(client.getCrypto()!.getVersion).mockReturnValue("Olm 0.0.0"); // @ts-ignore access to private method await tracker.calculateClientProperties(client); @@ -725,19 +727,19 @@ describe("DecryptionFailureTracker", function () { }); function mockClient(): MockedObject { - const client = mocked(stubClient()); + const client = vi.mocked(stubClient()); const mockCrypto = { - getVersion: jest.fn().mockReturnValue("Rust SDK 0.7.0 (61b175b), Vodozemac 0.5.1"), - getUserVerificationStatus: jest.fn().mockResolvedValue(new UserVerificationStatus(false, false, false)), + getVersion: vi.fn().mockReturnValue("Rust SDK 0.7.0 (61b175b), Vodozemac 0.5.1"), + getUserVerificationStatus: vi.fn().mockResolvedValue(new UserVerificationStatus(false, false, false)), } as unknown as Mocked; client.getCrypto.mockReturnValue(mockCrypto); // @ts-ignore - client.stopClient = jest.fn(() => {}); + client.stopClient = vi.fn(() => {}); // @ts-ignore - client.removeAllListeners = jest.fn(() => {}); + client.removeAllListeners = vi.fn(() => {}); - client.store = { destroy: jest.fn(() => {}) } as any; + client.store = { destroy: vi.fn(() => {}) } as any; return client; } diff --git a/apps/web/test/unit-tests/DeviceListener-test.ts b/apps/web/src/DeviceListener.test.ts similarity index 91% rename from apps/web/test/unit-tests/DeviceListener-test.ts rename to apps/web/src/DeviceListener.test.ts index 4aa47a80ac..325d3cd8d6 100644 --- a/apps/web/test/unit-tests/DeviceListener-test.ts +++ b/apps/web/src/DeviceListener.test.ts @@ -6,7 +6,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { type Mocked, mocked } from "jest-mock-vitest-adapter"; +// @vitest-environment happy-dom + +import { vi, describe, it, expect, beforeEach, type Mocked } from "vitest"; import { MatrixEvent, type Room, @@ -24,38 +26,40 @@ import { type SecretStorageStatus, } from "matrix-js-sdk/src/crypto-api"; import { type CryptoSessionStateChange } from "@matrix-org/analytics-events/types/typescript/CryptoSessionStateChange"; +import { getMockClientWithEventEmitter, mockPlatformPeg } from "test-utils"; import { DeviceListener, ACCOUNT_DATA_KEY_M_KEY_BACKUP, ACCOUNT_DATA_KEY_M_KEY_BACKUP_DISABLED_UNSTABLE, RECOVERY_ACCOUNT_DATA_KEY, -} from "../../src/device-listener"; -import { MatrixClientPeg } from "../../src/MatrixClientPeg"; -import * as SetupEncryptionToast from "../../src/toasts/SetupEncryptionToast"; -import * as UnverifiedSessionToast from "../../src/toasts/UnverifiedSessionToast"; -import * as BulkUnverifiedSessionsToast from "../../src/toasts/BulkUnverifiedSessionsToast"; -import { isSecretStorageBeingAccessed } from "../../src/SecurityManager"; -import { Action } from "../../src/dispatcher/actions"; -import SettingsStore from "../../src/settings/SettingsStore"; -import { SettingLevel } from "../../src/settings/SettingLevel"; -import { getMockClientWithEventEmitter, mockPlatformPeg } from "../test-utils"; -import { isBulkUnverifiedDeviceReminderSnoozed } from "../../src/utils/device/snoozeBulkUnverifiedDeviceReminder"; -import { PosthogAnalytics } from "../../src/PosthogAnalytics"; +} from "./device-listener"; +import { MatrixClientPeg } from "./MatrixClientPeg"; +import * as SetupEncryptionToast from "./toasts/SetupEncryptionToast"; +import * as UnverifiedSessionToast from "./toasts/UnverifiedSessionToast"; +import * as BulkUnverifiedSessionsToast from "./toasts/BulkUnverifiedSessionsToast"; +import { isSecretStorageBeingAccessed } from "./SecurityManager"; +import { Action } from "./dispatcher/actions"; +import SettingsStore from "./settings/SettingsStore"; +import { SettingLevel } from "./settings/SettingLevel"; +import { isBulkUnverifiedDeviceReminderSnoozed } from "./utils/device/snoozeBulkUnverifiedDeviceReminder"; +import { PosthogAnalytics } from "./PosthogAnalytics"; -jest.mock("../../src/dispatcher/dispatcher", () => ({ - dispatch: jest.fn(), - register: jest.fn(), - unregister: jest.fn(), +vi.mock("./dispatcher/dispatcher", () => ({ + default: { + dispatch: vi.fn(), + register: vi.fn(), + unregister: vi.fn(), + }, })); -jest.mock("../../src/SecurityManager", () => ({ - isSecretStorageBeingAccessed: jest.fn(), - accessSecretStorage: jest.fn(), +vi.mock("./SecurityManager", () => ({ + isSecretStorageBeingAccessed: vi.fn(), + accessSecretStorage: vi.fn(), })); -jest.mock("../../src/utils/device/snoozeBulkUnverifiedDeviceReminder", () => ({ - isBulkUnverifiedDeviceReminderSnoozed: jest.fn(), +vi.mock("./utils/device/snoozeBulkUnverifiedDeviceReminder", () => ({ + isBulkUnverifiedDeviceReminderSnoozed: vi.fn(), })); const userId = "@user:server"; @@ -79,36 +83,36 @@ describe("DeviceListener", () => { let mockCrypto: Mocked; beforeEach(() => { - jest.resetAllMocks(); + vi.resetAllMocks(); // don't litter the console with logs - jest.spyOn(console, "debug").mockImplementation(() => {}); - jest.spyOn(console, "info").mockImplementation(() => {}); - jest.spyOn(console, "warn").mockImplementation(() => {}); - jest.spyOn(console, "error").mockImplementation(() => {}); + vi.spyOn(console, "debug").mockImplementation(() => {}); + vi.spyOn(console, "info").mockImplementation(() => {}); + vi.spyOn(console, "warn").mockImplementation(() => {}); + vi.spyOn(console, "error").mockImplementation(() => {}); // spy on various toasts' hide and show functions // easier than mocking - jest.spyOn(SetupEncryptionToast, "showToast").mockReturnValue(undefined); - jest.spyOn(SetupEncryptionToast, "hideToast").mockReturnValue(undefined); - jest.spyOn(BulkUnverifiedSessionsToast, "showToast").mockReturnValue(undefined); - jest.spyOn(BulkUnverifiedSessionsToast, "hideToast").mockReturnValue(undefined); - jest.spyOn(UnverifiedSessionToast, "showToast").mockResolvedValue(undefined); - jest.spyOn(UnverifiedSessionToast, "hideToast").mockReturnValue(undefined); + vi.spyOn(SetupEncryptionToast, "showToast").mockReturnValue(undefined); + vi.spyOn(SetupEncryptionToast, "hideToast").mockReturnValue(undefined); + vi.spyOn(BulkUnverifiedSessionsToast, "showToast").mockReturnValue(undefined); + vi.spyOn(BulkUnverifiedSessionsToast, "hideToast").mockReturnValue(undefined); + vi.spyOn(UnverifiedSessionToast, "showToast").mockResolvedValue(undefined); + vi.spyOn(UnverifiedSessionToast, "hideToast").mockReturnValue(undefined); mockPlatformPeg({ - getAppVersion: jest.fn().mockResolvedValue("1.2.3"), + getAppVersion: vi.fn().mockResolvedValue("1.2.3"), }); mockCrypto = { - getDeviceVerificationStatus: jest.fn().mockResolvedValue({ + getDeviceVerificationStatus: vi.fn().mockResolvedValue({ crossSigningVerified: false, }), - getUserDeviceInfo: jest.fn().mockResolvedValue(new Map()), - isCrossSigningReady: jest.fn().mockResolvedValue(true), - getSecretStorageStatus: jest.fn().mockResolvedValue(readySecretStorageStatus), - userHasCrossSigningKeys: jest.fn(), - getActiveSessionBackupVersion: jest.fn(), - getCrossSigningStatus: jest.fn().mockReturnValue({ + getUserDeviceInfo: vi.fn().mockResolvedValue(new Map()), + isCrossSigningReady: vi.fn().mockResolvedValue(true), + getSecretStorageStatus: vi.fn().mockResolvedValue(readySecretStorageStatus), + userHasCrossSigningKeys: vi.fn(), + getActiveSessionBackupVersion: vi.fn(), + getCrossSigningStatus: vi.fn().mockReturnValue({ publicKeysOnDevice: true, privateKeysInSecretStorage: true, privateKeysCachedLocally: { @@ -117,33 +121,33 @@ describe("DeviceListener", () => { userSigningKey: true, }, }), - getSessionBackupPrivateKey: jest.fn(), - isEncryptionEnabledInRoom: jest.fn(), - getKeyBackupInfo: jest.fn().mockResolvedValue(null), + getSessionBackupPrivateKey: vi.fn(), + isEncryptionEnabledInRoom: vi.fn(), + getKeyBackupInfo: vi.fn().mockResolvedValue(null), } as unknown as Mocked; mockClient = getMockClientWithEventEmitter({ - isGuest: jest.fn(), - getUserId: jest.fn().mockReturnValue(userId), - getSafeUserId: jest.fn().mockReturnValue(userId), - getRooms: jest.fn().mockReturnValue([]), - isVersionSupported: jest.fn().mockResolvedValue(true), - isInitialSyncComplete: jest.fn().mockReturnValue(true), - isKeyBackupKeyStored: jest.fn(), - waitForClientWellKnown: jest.fn(), - getClientWellKnown: jest.fn(), - getDeviceId: jest.fn().mockReturnValue(deviceId), - setAccountData: jest.fn(), - getAccountData: jest.fn(), - getAccountDataFromServer: jest.fn(), - deleteAccountData: jest.fn(), - getCrypto: jest.fn().mockReturnValue(mockCrypto), + isGuest: vi.fn(), + getUserId: vi.fn().mockReturnValue(userId), + getSafeUserId: vi.fn().mockReturnValue(userId), + getRooms: vi.fn().mockReturnValue([]), + isVersionSupported: vi.fn().mockResolvedValue(true), + isInitialSyncComplete: vi.fn().mockReturnValue(true), + isKeyBackupKeyStored: vi.fn(), + waitForClientWellKnown: vi.fn(), + getClientWellKnown: vi.fn(), + getDeviceId: vi.fn().mockReturnValue(deviceId), + setAccountData: vi.fn(), + getAccountData: vi.fn(), + getAccountDataFromServer: vi.fn(), + deleteAccountData: vi.fn(), + getCrypto: vi.fn().mockReturnValue(mockCrypto), secretStorage: { - isStored: jest.fn().mockReturnValue(null), + isStored: vi.fn().mockReturnValue(null), }, }); - jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient); - jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); - mocked(isBulkUnverifiedDeviceReminderSnoozed).mockClear().mockReturnValue(false); + vi.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient); + vi.spyOn(SettingsStore, "getValue").mockReturnValue(false); + vi.mocked(isBulkUnverifiedDeviceReminderSnoozed).mockClear().mockReturnValue(false); }); const createAndStart = async (): Promise => { @@ -155,8 +159,8 @@ describe("DeviceListener", () => { describe("client information", () => { it("watches device client information setting", async () => { - const watchSettingSpy = jest.spyOn(SettingsStore, "watchSetting"); - const unwatchSettingSpy = jest.spyOn(SettingsStore, "unwatchSetting"); + const watchSettingSpy = vi.spyOn(SettingsStore, "watchSetting"); + const unwatchSettingSpy = vi.spyOn(SettingsStore, "unwatchSetting"); const deviceListener = await createAndStart(); expect(watchSettingSpy).toHaveBeenCalledWith("deviceClientInformationOptIn", null, expect.any(Function)); @@ -168,7 +172,7 @@ describe("DeviceListener", () => { it("responds to KeyBackupDecryptionKeyCached events", async () => { // Given a Device Listener - const recheck = jest.fn(); + const recheck = vi.fn(); const deviceListener = await createAndStart(); deviceListener.recheck = recheck; @@ -179,7 +183,7 @@ describe("DeviceListener", () => { expect(recheck).toHaveBeenCalled(); // And when we stop our device listener - const removeListener = jest.fn(() => {}); + const removeListener = vi.fn(() => {}); // @ts-ignore overwriting with a mock mockClient.removeListener = removeListener; deviceListener.stop(); @@ -190,7 +194,7 @@ describe("DeviceListener", () => { describe("when device client information feature is enabled", () => { beforeEach(() => { - jest.spyOn(SettingsStore, "getValue").mockImplementation( + vi.spyOn(SettingsStore, "getValue").mockImplementation( (settingName) => settingName === "deviceClientInformationOptIn", ); }); @@ -241,7 +245,7 @@ describe("DeviceListener", () => { }); const emptyClientInfoEvent = new MatrixEvent({ type: `io.element.matrix_client_information.${deviceId}` }); beforeEach(() => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); + vi.spyOn(SettingsStore, "getValue").mockReturnValue(false); mockClient!.getAccountData.mockReturnValue(undefined); }); @@ -280,7 +284,7 @@ describe("DeviceListener", () => { }); it("saves client information after setting is enabled", async () => { - const watchSettingSpy = jest.spyOn(SettingsStore, "watchSetting"); + const watchSettingSpy = vi.spyOn(SettingsStore, "watchSetting"); await createAndStart(); const [settingName, roomId, callback] = watchSettingSpy.mock.calls[0]; @@ -376,7 +380,7 @@ describe("DeviceListener", () => { mockCrypto!.isCrossSigningReady.mockResolvedValue(false); mockCrypto!.getSecretStorageStatus.mockResolvedValue(unreadySecretStorageStatus); mockClient!.getRooms.mockReturnValue(rooms); - jest.spyOn(mockClient.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true); + vi.spyOn(mockClient.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true); }); it("hides setup encryption toast when it is dismissed", async () => { @@ -392,27 +396,27 @@ describe("DeviceListener", () => { const instance = await createAndStart(); expect(SetupEncryptionToast.showToast).toHaveBeenCalledTimes(1); - jest.useFakeTimers({ advanceTimers: true }); + vi.useFakeTimers(); instance.dismissEncryptionSetup(); await flushPromises(); expect(SetupEncryptionToast.hideToast).toHaveBeenCalled(); // 1.5 days after the toast was dismissed, we don't re-show the // toast yet. - jest.advanceTimersByTime(1.5 * 24 * 60 * 60 * 1000); + vi.advanceTimersByTime(1.5 * 24 * 60 * 60 * 1000); expect(SetupEncryptionToast.showToast).toHaveBeenCalledTimes(1); // 2 days after the toast was dismissed, we re-show the toast. - jest.advanceTimersByTime(0.5 * 24 * 60 * 60 * 1000); + vi.advanceTimersByTime(0.5 * 24 * 60 * 60 * 1000); expect(SetupEncryptionToast.showToast).toHaveBeenCalledTimes(2); - jest.useRealTimers(); + vi.useRealTimers(); }); it("doesn't re-show toast if the device is now verified", async () => { const instance = await createAndStart(); expect(SetupEncryptionToast.showToast).toHaveBeenCalledTimes(1); - jest.useFakeTimers({ advanceTimers: true }); + vi.useFakeTimers(); instance.dismissEncryptionSetup(); await flushPromises(); expect(SetupEncryptionToast.hideToast).toHaveBeenCalled(); @@ -427,20 +431,20 @@ describe("DeviceListener", () => { ); instance.recheck(); await flushPromises(); - jest.advanceTimersByTime(2 * 24 * 60 * 60 * 1000); + vi.advanceTimersByTime(2 * 24 * 60 * 60 * 1000); expect(SetupEncryptionToast.showToast).toHaveBeenCalledTimes(1); - jest.useRealTimers(); + vi.useRealTimers(); }); it("does not show any toasts when secret storage is being accessed", async () => { - mocked(isSecretStorageBeingAccessed).mockReturnValue(true); + vi.mocked(isSecretStorageBeingAccessed).mockReturnValue(true); await createAndStart(); expect(SetupEncryptionToast.showToast).not.toHaveBeenCalled(); }); it("shows toasts even when no rooms are encrypted", async () => { - jest.spyOn(mockClient.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(false); + vi.spyOn(mockClient.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(false); await createAndStart(); expect(SetupEncryptionToast.showToast).toHaveBeenCalled(); @@ -609,7 +613,7 @@ describe("DeviceListener", () => { // And we have run the checks once (and we were told to verify) const instance = await createAndStart(); expect(SetupEncryptionToast.showToast).toHaveBeenCalledWith("verify_this_session"); - mocked(SetupEncryptionToast.showToast).mockClear(); + vi.mocked(SetupEncryptionToast.showToast).mockClear(); mockCrypto.getDeviceVerificationStatus.mockClear(); // When we dismiss the dialog telling us to set up encryption @@ -672,7 +676,7 @@ describe("DeviceListener", () => { beforeEach(() => { // Encryption is in use mockClient.getRooms.mockReturnValue([{ roomId: "!room1" }, { roomId: "!room2" }] as unknown as Room[]); - jest.spyOn(mockClient.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true); + vi.spyOn(mockClient.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true); // The device is verified mockCrypto.getDeviceVerificationStatus.mockResolvedValue( @@ -839,7 +843,7 @@ describe("DeviceListener", () => { }); it("hides toast when reminder is snoozed", async () => { - mocked(isBulkUnverifiedDeviceReminderSnoozed).mockReturnValue(true); + vi.mocked(isBulkUnverifiedDeviceReminderSnoozed).mockReturnValue(true); // currentDevice, device2 are verified, device3 is unverified mockCrypto!.getDeviceVerificationStatus.mockImplementation(async (_userId, deviceId) => { switch (deviceId) { @@ -931,12 +935,12 @@ describe("DeviceListener", () => { }); describe("Report verification and recovery state to Analytics", () => { - let setPropertySpy: jest.SpyInstance; - let trackEventSpy: jest.SpyInstance; + let setPropertySpy: Mocked; + let trackEventSpy: Mocked; beforeEach(() => { - setPropertySpy = jest.spyOn(PosthogAnalytics.instance, "setProperty"); - trackEventSpy = jest.spyOn(PosthogAnalytics.instance, "trackEvent"); + setPropertySpy = vi.spyOn(PosthogAnalytics.instance, "setProperty"); + trackEventSpy = vi.spyOn(PosthogAnalytics.instance, "trackEvent"); }); describe("Report crypto verification state to analytics", () => { @@ -1301,7 +1305,7 @@ describe("DeviceListener", () => { mockCrypto!.isCrossSigningReady.mockResolvedValue(true); mockCrypto!.getSecretStorageStatus.mockResolvedValue(unreadySecretStorageStatus); mockClient!.getRooms.mockReturnValue(rooms); - jest.spyOn(mockClient.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true); + vi.spyOn(mockClient.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true); }); it("shows the 'set up recovery' toast if user has not set up 4S", async () => { @@ -1320,7 +1324,7 @@ describe("DeviceListener", () => { }); it("does not show the 'set up recovery' toast if user has no encrypted rooms", async () => { - jest.spyOn(mockClient.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(false); + vi.spyOn(mockClient.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(false); await createAndStart(); expect(SetupEncryptionToast.showToast).not.toHaveBeenCalledWith("set_up_recovery"); diff --git a/apps/web/test/unit-tests/utils/FormattingUtils-test.tsx b/apps/web/src/utils/FormattingUtils.test.tsx similarity index 89% rename from apps/web/test/unit-tests/utils/FormattingUtils-test.tsx rename to apps/web/src/utils/FormattingUtils.test.tsx index 1b5aedda53..b577909032 100644 --- a/apps/web/test/unit-tests/utils/FormattingUtils-test.tsx +++ b/apps/web/src/utils/FormattingUtils.test.tsx @@ -6,12 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ +import { vi, describe, it, expect, beforeEach } from "vitest"; import React from "react"; -import { formatList, formatCount, formatCountLong } from "../../../src/utils/FormattingUtils"; -import SettingsStore from "../../../src/settings/SettingsStore"; +import { formatList, formatCount, formatCountLong } from "./FormattingUtils"; +import SettingsStore from "../settings/SettingsStore"; -jest.mock("../../../src/dispatcher/dispatcher"); +vi.mock("../dispatcher/dispatcher"); describe("FormattingUtils", () => { describe("formatCount", () => { @@ -37,8 +38,8 @@ describe("FormattingUtils", () => { describe("formatList", () => { beforeEach(() => { - jest.resetAllMocks(); - jest.spyOn(SettingsStore, "getValue").mockReturnValue("en-GB"); + vi.resetAllMocks(); + vi.spyOn(SettingsStore, "getValue").mockReturnValue("en-GB"); }); it("should return empty string when given empty list", () => { @@ -54,7 +55,7 @@ describe("FormattingUtils", () => { }); it("should return expected sentence in German without item limit", () => { - jest.spyOn(SettingsStore, "getValue").mockReturnValue("de"); + vi.spyOn(SettingsStore, "getValue").mockReturnValue("de"); expect(formatList(["abc", "def", "ghi"])).toEqual("abc, def und ghi"); }); diff --git a/apps/web/test/unit-tests/utils/MessageDiffUtils-test.ts b/apps/web/src/utils/MessageDiffUtils.test.ts similarity index 94% rename from apps/web/test/unit-tests/utils/MessageDiffUtils-test.ts rename to apps/web/src/utils/MessageDiffUtils.test.ts index 08ac1d5209..c30c6592b9 100644 --- a/apps/web/test/unit-tests/utils/MessageDiffUtils-test.ts +++ b/apps/web/src/utils/MessageDiffUtils.test.ts @@ -6,11 +6,14 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { render } from "jest-matrix-react"; +// @vitest-environment happy-dom + +import { describe, it, expect } from "vitest"; +import { render } from "test-utils-rtl"; import type { IContent } from "matrix-js-sdk/src/matrix"; import type React from "react"; -import { editBodyDiffToHtml } from "../../../src/utils/MessageDiffUtils"; +import { editBodyDiffToHtml } from "./MessageDiffUtils"; describe("editBodyDiffToHtml", () => { function buildContent(message: string): IContent { diff --git a/apps/web/test/unit-tests/utils/__snapshots__/FormattingUtils-test.tsx.snap b/apps/web/src/utils/__snapshots__/FormattingUtils.test.tsx.snap similarity index 68% rename from apps/web/test/unit-tests/utils/__snapshots__/FormattingUtils-test.tsx.snap rename to apps/web/src/utils/__snapshots__/FormattingUtils.test.tsx.snap index 92baf3ce34..7f7cdd3157 100644 --- a/apps/web/test/unit-tests/utils/__snapshots__/FormattingUtils-test.tsx.snap +++ b/apps/web/src/utils/__snapshots__/FormattingUtils.test.tsx.snap @@ -1,6 +1,6 @@ -// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`FormattingUtils formatList should return expected sentence in ReactNode when given 2 React children 1`] = ` +exports[`FormattingUtils > formatList > should return expected sentence in ReactNode when given 2 React children 1`] = ` @@ -18,7 +18,7 @@ exports[`FormattingUtils formatList should return expected sentence in ReactNode `; -exports[`FormattingUtils formatList should return expected sentence in ReactNode when given more React children 1`] = ` +exports[`FormattingUtils > formatList > should return expected sentence in ReactNode when given more React children 1`] = ` @@ -52,7 +52,7 @@ exports[`FormattingUtils formatList should return expected sentence in ReactNode `; -exports[`FormattingUtils formatList should return expected sentence in ReactNode when using itemLimit 1`] = ` +exports[`FormattingUtils > formatList > should return expected sentence in ReactNode when using itemLimit 1`] = ` diff --git a/apps/web/test/unit-tests/utils/__snapshots__/MessageDiffUtils-test.ts.snap b/apps/web/src/utils/__snapshots__/MessageDiffUtils.test.ts.snap similarity index 87% rename from apps/web/test/unit-tests/utils/__snapshots__/MessageDiffUtils-test.ts.snap rename to apps/web/src/utils/__snapshots__/MessageDiffUtils.test.ts.snap index 1c25d3b3a6..51edd183e5 100644 --- a/apps/web/test/unit-tests/utils/__snapshots__/MessageDiffUtils-test.ts.snap +++ b/apps/web/src/utils/__snapshots__/MessageDiffUtils.test.ts.snap @@ -1,6 +1,6 @@ -// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`editBodyDiffToHtml deduplicates diff steps 1`] = ` +exports[`editBodyDiffToHtml > deduplicates diff steps 1`] = `
`; -exports[`editBodyDiffToHtml handles complex transformations 1`] = ` +exports[`editBodyDiffToHtml > handles complex transformations 1`] = `
`; -exports[`editBodyDiffToHtml handles non-html input 1`] = ` +exports[`editBodyDiffToHtml > handles non-html input 1`] = `
`; -exports[`editBodyDiffToHtml renders attribute additions 1`] = ` +exports[`editBodyDiffToHtml > renders attribute additions 1`] = `
`; -exports[`editBodyDiffToHtml renders attribute deletions 1`] = ` +exports[`editBodyDiffToHtml > renders attribute deletions 1`] = `
`; -exports[`editBodyDiffToHtml renders attribute modifications 1`] = ` +exports[`editBodyDiffToHtml > renders attribute modifications 1`] = `
`; -exports[`editBodyDiffToHtml renders block element additions 1`] = ` +exports[`editBodyDiffToHtml > renders block element additions 1`] = `
`; -exports[`editBodyDiffToHtml renders block element deletions 1`] = ` +exports[`editBodyDiffToHtml > renders block element deletions 1`] = `
`; -exports[`editBodyDiffToHtml renders central word changes 1`] = ` +exports[`editBodyDiffToHtml > renders central word changes 1`] = `
`; -exports[`editBodyDiffToHtml renders element replacements 1`] = ` +exports[`editBodyDiffToHtml > renders element replacements 1`] = `
`; -exports[`editBodyDiffToHtml renders handles empty tags 1`] = ` +exports[`editBodyDiffToHtml > renders handles empty tags 1`] = `
`; -exports[`editBodyDiffToHtml renders inline element additions 1`] = ` +exports[`editBodyDiffToHtml > renders inline element additions 1`] = `
`; -exports[`editBodyDiffToHtml renders inline element deletions 1`] = ` +exports[`editBodyDiffToHtml > renders inline element deletions 1`] = `
`; -exports[`editBodyDiffToHtml renders simple word changes 1`] = ` +exports[`editBodyDiffToHtml > renders simple word changes 1`] = `
`; -exports[`editBodyDiffToHtml renders text additions 1`] = ` +exports[`editBodyDiffToHtml > renders text additions 1`] = `
`; -exports[`editBodyDiffToHtml renders text deletions 1`] = ` +exports[`editBodyDiffToHtml > renders text deletions 1`] = `
should create a voice message content 1`] = ` { "body": "Voice message", "file": {}, diff --git a/apps/web/test/unit-tests/utils/createVoiceMessageContent-test.ts b/apps/web/src/utils/createVoiceMessageContent.test.ts similarity index 85% rename from apps/web/test/unit-tests/utils/createVoiceMessageContent-test.ts rename to apps/web/src/utils/createVoiceMessageContent.test.ts index 83f14cbb97..b70a48bf8b 100644 --- a/apps/web/test/unit-tests/utils/createVoiceMessageContent-test.ts +++ b/apps/web/src/utils/createVoiceMessageContent.test.ts @@ -6,9 +6,10 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ +import { describe, it, expect } from "vitest"; import { type EncryptedFile } from "matrix-js-sdk/src/types"; -import { createVoiceMessageContent } from "../../../src/utils/createVoiceMessageContent"; +import { createVoiceMessageContent } from "./createVoiceMessageContent"; describe("createVoiceMessageContent", () => { it("should create a voice message content", () => { diff --git a/apps/web/test/unit-tests/utils/permalinks/MatrixSchemePermalinkConstructor-test.ts b/apps/web/src/utils/permalinks/MatrixSchemePermalinkConstructor.test.ts similarity index 77% rename from apps/web/test/unit-tests/utils/permalinks/MatrixSchemePermalinkConstructor-test.ts rename to apps/web/src/utils/permalinks/MatrixSchemePermalinkConstructor.test.ts index 514ff7bdb7..69100af47b 100644 --- a/apps/web/test/unit-tests/utils/permalinks/MatrixSchemePermalinkConstructor-test.ts +++ b/apps/web/src/utils/permalinks/MatrixSchemePermalinkConstructor.test.ts @@ -6,8 +6,10 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { PermalinkParts } from "../../../../src/utils/permalinks/PermalinkConstructor"; -import MatrixSchemePermalinkConstructor from "../../../../src/utils/permalinks/MatrixSchemePermalinkConstructor"; +import { describe, it, expect } from "vitest"; + +import { PermalinkParts } from "./PermalinkConstructor"; +import MatrixSchemePermalinkConstructor from "./MatrixSchemePermalinkConstructor"; describe("MatrixSchemePermalinkConstructor", () => { const peramlinkConstructor = new MatrixSchemePermalinkConstructor(); diff --git a/apps/web/test/unit-tests/utils/permalinks/MatrixToPermalinkConstructor-test.ts b/apps/web/src/utils/permalinks/MatrixToPermalinkConstructor.test.ts similarity index 91% rename from apps/web/test/unit-tests/utils/permalinks/MatrixToPermalinkConstructor-test.ts rename to apps/web/src/utils/permalinks/MatrixToPermalinkConstructor.test.ts index 92f005d0d9..160e114184 100644 --- a/apps/web/test/unit-tests/utils/permalinks/MatrixToPermalinkConstructor-test.ts +++ b/apps/web/src/utils/permalinks/MatrixToPermalinkConstructor.test.ts @@ -6,8 +6,10 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import MatrixToPermalinkConstructor from "../../../../src/utils/permalinks/MatrixToPermalinkConstructor"; -import { PermalinkParts } from "../../../../src/utils/permalinks/PermalinkConstructor"; +import { describe, it, expect } from "vitest"; + +import MatrixToPermalinkConstructor from "./MatrixToPermalinkConstructor"; +import { PermalinkParts } from "./PermalinkConstructor"; describe("MatrixToPermalinkConstructor", () => { const peramlinkConstructor = new MatrixToPermalinkConstructor(); diff --git a/apps/web/test/unit-tests/utils/permalinks/Permalinks-test.ts b/apps/web/src/utils/permalinks/Permalinks.test.ts similarity index 94% rename from apps/web/test/unit-tests/utils/permalinks/Permalinks-test.ts rename to apps/web/src/utils/permalinks/Permalinks.test.ts index 3e631e87b9..f7d0c2c91d 100644 --- a/apps/web/test/unit-tests/utils/permalinks/Permalinks-test.ts +++ b/apps/web/src/utils/permalinks/Permalinks.test.ts @@ -7,27 +7,24 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ +import { vi, describe, it, expect, afterAll, beforeEach } from "vitest"; +import { getMockClientWithEventEmitter } from "test-utils/client"; + import { type EventEmitter } from "events"; import { Room, RoomMember, EventType, MatrixEvent } from "matrix-js-sdk/src/matrix"; import { KnownMembership } from "matrix-js-sdk/src/types"; -import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; -import { PermalinkParts } from "../../../../src/utils/permalinks/PermalinkConstructor"; -import { - makeRoomPermalink, - makeUserPermalink, - parsePermalink, - RoomPermalinkCreator, -} from "../../../../src/utils/permalinks/Permalinks"; -import { type IConfigOptions } from "../../../../src/IConfigOptions"; -import SdkConfig from "../../../../src/SdkConfig"; -import { getMockClientWithEventEmitter } from "../../../test-utils"; +import { MatrixClientPeg } from "../../MatrixClientPeg"; +import { PermalinkParts } from "./PermalinkConstructor"; +import { makeRoomPermalink, makeUserPermalink, parsePermalink, RoomPermalinkCreator } from "./Permalinks"; +import { type IConfigOptions } from "../../IConfigOptions"; +import SdkConfig from "../../SdkConfig"; describe("Permalinks", function () { const userId = "@test:example.com"; const mockClient = getMockClientWithEventEmitter({ - getUserId: jest.fn().mockReturnValue(userId), - getRoom: jest.fn(), + getUserId: vi.fn().mockReturnValue(userId), + getRoom: vi.fn(), }); mockClient.credentials = { userId }; @@ -72,18 +69,18 @@ describe("Permalinks", function () { const stateEvents = serverACL ? [powerLevels, serverACL] : [powerLevels]; room.currentState.setStateEvents(stateEvents); - jest.spyOn(room, "getCanonicalAlias").mockReturnValue(null); - jest.spyOn(room, "getJoinedMembers").mockReturnValue(members); - jest.spyOn(room, "getMember").mockImplementation((userId) => members.find((m) => m.userId === userId) || null); + vi.spyOn(room, "getCanonicalAlias").mockReturnValue(null); + vi.spyOn(room, "getJoinedMembers").mockReturnValue(members); + vi.spyOn(room, "getMember").mockImplementation((userId) => members.find((m) => m.userId === userId) || null); return room; } beforeEach(function () { - jest.clearAllMocks(); + vi.clearAllMocks(); }); afterAll(() => { - jest.spyOn(MatrixClientPeg, "get").mockRestore(); + vi.spyOn(MatrixClientPeg, "get").mockRestore(); }); it("should not clean up listeners even if start was called multiple times", () => { @@ -416,7 +413,7 @@ describe("Permalinks", function () { it("should use permalink_prefix for permalinks", function () { const sdkConfigGet = SdkConfig.get; - jest.spyOn(SdkConfig, "get").mockImplementation((key: keyof IConfigOptions, altCaseName?: string) => { + vi.spyOn(SdkConfig, "get").mockImplementation((key: keyof IConfigOptions, altCaseName?: string) => { if (key === "permalink_prefix") { return "https://element.fs.tld"; } else return sdkConfigGet(key, altCaseName); diff --git a/apps/web/test/unit-tests/utils/threepids-test.ts b/apps/web/src/utils/threepids.test.ts similarity index 94% rename from apps/web/test/unit-tests/utils/threepids-test.ts rename to apps/web/src/utils/threepids.test.ts index 4cf2a427d1..e4450f1011 100644 --- a/apps/web/test/unit-tests/utils/threepids-test.ts +++ b/apps/web/src/utils/threepids.test.ts @@ -6,12 +6,14 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { type Mocked } from "jest-mock"; -import { type IIdentityServerProvider, type MatrixClient } from "matrix-js-sdk/src/matrix"; +// @vitest-environment happy-dom -import { DirectoryMember, ThreepidMember } from "../../../src/utils/direct-messages"; -import { lookupThreePids, resolveThreePids } from "../../../src/utils/threepids"; -import { stubClient } from "../../test-utils"; +import { vi, describe, it, expect, beforeEach, type Mocked } from "vitest"; +import { type IIdentityServerProvider, type MatrixClient } from "matrix-js-sdk/src/matrix"; +import { stubClient } from "test-utils"; + +import { DirectoryMember, ThreepidMember } from "./direct-messages"; +import { lookupThreePids, resolveThreePids } from "./threepids"; describe("threepids", () => { let client: Mocked; @@ -21,7 +23,7 @@ describe("threepids", () => { beforeEach(() => { client = stubClient() as Mocked; identityServer = { - getAccessToken: jest.fn().mockResolvedValue(accessToken), + getAccessToken: vi.fn().mockResolvedValue(accessToken), } as unknown as Mocked; }); diff --git a/apps/web/test/unit-tests/utils/userStatus-test.ts b/apps/web/src/utils/userStatus.test.ts similarity index 81% rename from apps/web/test/unit-tests/utils/userStatus-test.ts rename to apps/web/src/utils/userStatus.test.ts index 99f150f942..9170b195a5 100644 --- a/apps/web/test/unit-tests/utils/userStatus-test.ts +++ b/apps/web/src/utils/userStatus.test.ts @@ -5,8 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ +// @vitest-environment happy-dom + +import { vi, describe, it, expect, beforeEach } from "vitest"; import { type MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix"; -import { mocked } from "jest-mock"; +import { stubClient } from "test-utils"; import { clearUserStatus, @@ -14,8 +17,7 @@ import { setUserStatus, userStatusFromProfile, userStatusTextWithinMaxLength, -} from "../../../src/utils/userStatus"; -import { stubClient } from "../../test-utils"; +} from "./userStatus"; describe("userStatus utils", () => { describe("userStatusFromProfile", () => { @@ -88,19 +90,22 @@ describe("userStatus utils", () => { beforeEach(() => { client = stubClient(); - client.doesServerSupportExtendedProfiles = jest.fn(); + client.doesServerSupportExtendedProfiles = vi.fn(); }); it("returns undefined if the server does not support extended profiles", async () => { - mocked(client.doesServerSupportExtendedProfiles).mockResolvedValue(false); + vi.mocked(client.doesServerSupportExtendedProfiles).mockResolvedValue(false); await expect(fetchUserStatus(client, "@alice:example.com")).resolves.toBeUndefined(); expect(client.getExtendedProfileProperty).not.toHaveBeenCalled(); }); it("returns the validated status if the server supports extended profiles and has a status set", async () => { - mocked(client.doesServerSupportExtendedProfiles).mockResolvedValue(true); - mocked(client.getExtendedProfileProperty).mockResolvedValue({ emoji: "🐳", text: "Feeling a little blue" }); + vi.mocked(client.doesServerSupportExtendedProfiles).mockResolvedValue(true); + vi.mocked(client.getExtendedProfileProperty).mockResolvedValue({ + emoji: "🐳", + text: "Feeling a little blue", + }); await expect(fetchUserStatus(client, "@alice:example.com")).resolves.toEqual({ emoji: "🐳", @@ -113,15 +118,15 @@ describe("userStatus utils", () => { }); it("returns undefined if the status is invalid", async () => { - mocked(client.doesServerSupportExtendedProfiles).mockResolvedValue(true); - mocked(client.getExtendedProfileProperty).mockResolvedValue({ text: "Feeling a little blue" }); + vi.mocked(client.doesServerSupportExtendedProfiles).mockResolvedValue(true); + vi.mocked(client.getExtendedProfileProperty).mockResolvedValue({ text: "Feeling a little blue" }); await expect(fetchUserStatus(client, "@alice:example.com")).resolves.toBeUndefined(); }); it("returns undefined if the user has no status set", async () => { - mocked(client.doesServerSupportExtendedProfiles).mockResolvedValue(true); - mocked(client.getExtendedProfileProperty).mockRejectedValue( + vi.mocked(client.doesServerSupportExtendedProfiles).mockResolvedValue(true); + vi.mocked(client.getExtendedProfileProperty).mockRejectedValue( new MatrixError({ errcode: "M_NOT_FOUND" }, 404), ); @@ -129,9 +134,9 @@ describe("userStatus utils", () => { }); it("returns undefined and logs a warning if fetching the status fails unexpectedly", async () => { - mocked(client.doesServerSupportExtendedProfiles).mockResolvedValue(true); + vi.mocked(client.doesServerSupportExtendedProfiles).mockResolvedValue(true); const error = new Error("network error"); - mocked(client.getExtendedProfileProperty).mockRejectedValue(error); + vi.mocked(client.getExtendedProfileProperty).mockRejectedValue(error); await expect(fetchUserStatus(client, "@alice:example.com")).resolves.toBeUndefined(); }); diff --git a/apps/web/test/unit-tests/vector/rageshakesetup-test.ts b/apps/web/src/vector/rageshakesetup.test.ts similarity index 77% rename from apps/web/test/unit-tests/vector/rageshakesetup-test.ts rename to apps/web/src/vector/rageshakesetup.test.ts index 81b5064c71..ba2dad2e58 100644 --- a/apps/web/test/unit-tests/vector/rageshakesetup-test.ts +++ b/apps/web/src/vector/rageshakesetup.test.ts @@ -5,13 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import fetchMock from "@fetch-mock/jest"; +// @vitest-environment happy-dom -import type { Mocked } from "jest-mock"; -import type { ConsoleLogger } from "../../../src/rageshake/rageshake"; -import SdkConfig from "../../../src/SdkConfig"; -import "../../../src/vector/rageshakesetup"; -import { BugReportEndpointURLLocal } from "../../../src/IConfigOptions"; +import { vi, describe, it, expect, beforeEach, afterEach, type Mocked } from "vitest"; +import fetchMock from "@fetch-mock/vitest"; + +import type { ConsoleLogger } from "../rageshake/rageshake"; +import SdkConfig from "../SdkConfig"; +import "./rageshakesetup"; +import { BugReportEndpointURLLocal } from "../IConfigOptions"; const RAGESHAKE_URL = "https://logs.example.org/logtome"; @@ -23,9 +25,9 @@ describe("mxSendRageshake", () => { fetchMock.postOnce(RAGESHAKE_URL, { status: 200, body: {} }); const mockConsoleLogger = { - flush: jest.fn(), - consume: jest.fn(), - warn: jest.fn(), + flush: vi.fn(), + consume: vi.fn(), + warn: vi.fn(), } as unknown as Mocked; prevLogger = global.mx_rage_logger; mockConsoleLogger.flush.mockReturnValue("line 1\nline 2\n"); @@ -34,7 +36,7 @@ describe("mxSendRageshake", () => { afterEach(() => { global.mx_rage_logger = prevLogger; - jest.restoreAllMocks(); + vi.restoreAllMocks(); fetchMock.unmockGlobal(); SdkConfig.reset(); }); @@ -57,7 +59,7 @@ describe("mxSendRageshake", () => { it("Provides a rageshake locally", async () => { SdkConfig.put({ bug_report_endpoint_url: BugReportEndpointURLLocal }); - const urlSpy = jest.spyOn(URL, "createObjectURL"); + const urlSpy = vi.spyOn(URL, "createObjectURL"); await window.mxSendRageshake("Hello world"); expect(fetchMock).not.toHaveFetched(RAGESHAKE_URL); expect(urlSpy).toHaveBeenCalledTimes(1); diff --git a/apps/web/test/viewmodels/timeline/DateSeparatorViewModel-test.ts b/apps/web/src/viewmodels/room/timeline/DateSeparatorViewModel.test.ts similarity index 82% rename from apps/web/test/viewmodels/timeline/DateSeparatorViewModel-test.ts rename to apps/web/src/viewmodels/room/timeline/DateSeparatorViewModel.test.ts index 75315ea60b..705ec59cec 100644 --- a/apps/web/test/viewmodels/timeline/DateSeparatorViewModel-test.ts +++ b/apps/web/src/viewmodels/room/timeline/DateSeparatorViewModel.test.ts @@ -5,27 +5,28 @@ * Please see LICENSE files in the repository root for full details. */ +import { vi, describe, it, expect, beforeEach, afterEach } from "vitest"; import React from "react"; -import { mocked } from "jest-mock"; import { ConnectionError, Direction } from "matrix-js-sdk/src/matrix"; +import { flushPromisesWithFakeTimers } from "test-utils/utilities"; -import dispatcher from "../../../src/dispatcher/dispatcher"; -import { Action } from "../../../src/dispatcher/actions"; -import { formatFullDateNoTime } from "../../../src/DateUtils"; -import Modal from "../../../src/Modal"; -import { MatrixClientPeg } from "../../../src/MatrixClientPeg"; -import SettingsStore from "../../../src/settings/SettingsStore"; -import { UIFeature } from "../../../src/settings/UIFeature"; -import { SDKContextClass } from "../../../src/contexts/SDKContextClass"; -import { DateSeparatorViewModel } from "../../../src/viewmodels/room/timeline/DateSeparatorViewModel"; -import { flushPromisesWithFakeTimers } from "../../test-utils/utilities"; +import dispatcher from "../../../dispatcher/dispatcher"; +import { Action } from "../../../dispatcher/actions"; +import { formatFullDateNoTime } from "../../../DateUtils"; +import Modal from "../../../Modal"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; +import SettingsStore from "../../../settings/SettingsStore"; +import { UIFeature } from "../../../settings/UIFeature"; +import { SDKContextClass } from "../../../contexts/SDKContextClass"; +import { DateSeparatorViewModel } from "./DateSeparatorViewModel"; -jest.mock("../../../src/settings/SettingsStore"); -jest.mock("../../../src/contexts/SDKContextClass", () => ({ +vi.mock("../../../Modal"); +vi.mock("../../../settings/SettingsStore"); +vi.mock("../../../contexts/SDKContextClass", () => ({ SDKContextClass: { instance: { roomViewStore: { - getRoomId: jest.fn(), + getRoomId: vi.fn(), }, }, }, @@ -56,7 +57,7 @@ describe("DateSeparatorViewModel", () => { ]; const watchCallbacks = new Map void>(); - const mockTimestampToEvent = jest.fn(); + const mockTimestampToEvent = vi.fn(); const hasTestId = (node: React.ReactNode, testId: string): boolean => { if (!React.isValidElement<{ children?: React.ReactNode }>(node)) return false; @@ -78,35 +79,36 @@ describe("DateSeparatorViewModel", () => { }; beforeEach(() => { - jest.useFakeTimers(); - jest.setSystemTime(nowDate.getTime()); + vi.useFakeTimers(); + vi.setSystemTime(nowDate.getTime()); watchCallbacks.clear(); - mocked(SettingsStore).getValue.mockImplementation((key): any => { + vi.mocked(SettingsStore).getValue.mockImplementation((key): any => { if (String(key) === UIFeature.TimelineEnableRelativeDates) return true; if (key === "feature_jump_to_date") return false; return undefined; }); - mocked(SettingsStore).watchSetting.mockImplementation((settingName, _roomId, cb): any => { + vi.mocked(SettingsStore).watchSetting.mockImplementation((settingName, _roomId, cb): any => { watchCallbacks.set(String(settingName), cb); return `${String(settingName)}-watch-ref`; }); - mocked(SettingsStore).unwatchSetting.mockImplementation(() => {}); + vi.mocked(SettingsStore).unwatchSetting.mockImplementation(() => {}); mockTimestampToEvent.mockReset(); - jest.spyOn(MatrixClientPeg, "safeGet").mockReturnValue({ + vi.spyOn(MatrixClientPeg, "safeGet").mockReturnValue({ timestampToEvent: mockTimestampToEvent, } as any); - jest.spyOn(dispatcher, "dispatch").mockImplementation(() => {}); - jest.spyOn(Modal, "createDialog").mockImplementation(() => ({ close: jest.fn() }) as any); + vi.spyOn(dispatcher, "dispatch").mockImplementation(() => {}); + vi.spyOn(Modal, "createDialog").mockImplementation(() => ({ close: vi.fn() }) as any); - mocked(SDKContextClass.instance.roomViewStore.getRoomId).mockReturnValue(roomId); + vi.mocked(SDKContextClass.instance.roomViewStore.getRoomId).mockReturnValue(roomId); }); afterEach(() => { - jest.restoreAllMocks(); - jest.useRealTimers(); + vi.restoreAllMocks(); + vi.clearAllMocks(); + vi.useRealTimers(); }); it("computes relative label for today", () => { @@ -133,7 +135,7 @@ describe("DateSeparatorViewModel", () => { }); it("exposes jumpToDateMenu when feature is enabled", () => { - mocked(SettingsStore).getValue.mockImplementation((key): any => { + vi.mocked(SettingsStore).getValue.mockImplementation((key): any => { if (String(key) === UIFeature.TimelineEnableRelativeDates) return true; if (key === "feature_jump_to_date") return true; return undefined; @@ -150,7 +152,7 @@ describe("DateSeparatorViewModel", () => { }); it("does not expose jumpToDateMenu when exporting", () => { - mocked(SettingsStore).getValue.mockImplementation((key): any => { + vi.mocked(SettingsStore).getValue.mockImplementation((key): any => { if (String(key) === UIFeature.TimelineEnableRelativeDates) return true; if (key === "feature_jump_to_date") return true; return undefined; @@ -197,7 +199,7 @@ describe("DateSeparatorViewModel", () => { event_id: "$event", origin_server_ts: nowDate.getTime(), }); - mocked(SDKContextClass.instance.roomViewStore.getRoomId).mockReturnValue("!other:example.org"); + vi.mocked(SDKContextClass.instance.roomViewStore.getRoomId).mockReturnValue("!other:example.org"); const vm = createViewModel(); await vm.pickDate(nowDate.getTime() - HOUR_MS); @@ -212,7 +214,7 @@ describe("DateSeparatorViewModel", () => { await vm.pickDate(nowDate.getTime() - HOUR_MS); expect(Modal.createDialog).toHaveBeenCalled(); - const [, params] = mocked(Modal.createDialog).mock.calls.at(-1)!; + const [, params] = vi.mocked(Modal.createDialog).mock.calls.at(-1)!; expect(hasTestId((params as any).description, "jump-to-date-error-submit-debug-logs-button")).toBe(true); }); @@ -223,7 +225,7 @@ describe("DateSeparatorViewModel", () => { await vm.pickDate(nowDate.getTime() - HOUR_MS); expect(Modal.createDialog).toHaveBeenCalled(); - const [, params] = mocked(Modal.createDialog).mock.calls.at(-1)!; + const [, params] = vi.mocked(Modal.createDialog).mock.calls.at(-1)!; expect(hasTestId((params as any).description, "jump-to-date-error-submit-debug-logs-button")).toBe(false); }); @@ -242,7 +244,7 @@ describe("DateSeparatorViewModel", () => { describe("when TimelineEnableRelativeDates is false", () => { beforeEach(() => { - mocked(SettingsStore).getValue.mockImplementation((key): any => { + vi.mocked(SettingsStore).getValue.mockImplementation((key): any => { if (String(key) === UIFeature.TimelineEnableRelativeDates) return false; if (key === "feature_jump_to_date") return false; return undefined; @@ -257,7 +259,7 @@ describe("DateSeparatorViewModel", () => { describe("jump actions", () => { beforeEach(() => { - mocked(SettingsStore).getValue.mockImplementation((key): any => { + vi.mocked(SettingsStore).getValue.mockImplementation((key): any => { if (String(key) === UIFeature.TimelineEnableRelativeDates) return true; if (key === "feature_jump_to_date") return true; return undefined; @@ -303,7 +305,7 @@ describe("DateSeparatorViewModel", () => { }); it("does not jump when room changed before request resolves", async () => { - mocked(SDKContextClass.instance.roomViewStore.getRoomId).mockReturnValue("!some-other-room"); + vi.mocked(SDKContextClass.instance.roomViewStore.getRoomId).mockReturnValue("!some-other-room"); mockTimestampToEvent.mockResolvedValue({ event_id: "$abc", origin_server_ts: 0, @@ -317,7 +319,7 @@ describe("DateSeparatorViewModel", () => { }); it("does not show jump to date error if user switched room", async () => { - mocked(SDKContextClass.instance.roomViewStore.getRoomId).mockReturnValue("!some-other-room"); + vi.mocked(SDKContextClass.instance.roomViewStore.getRoomId).mockReturnValue("!some-other-room"); mockTimestampToEvent.mockRejectedValue(new Error("Fake error in test")); const vm = createViewModel(); @@ -335,7 +337,7 @@ describe("DateSeparatorViewModel", () => { await flushPromisesWithFakeTimers(); expect(Modal.createDialog).toHaveBeenCalled(); - const [, params] = mocked(Modal.createDialog).mock.calls.at(-1)!; + const [, params] = vi.mocked(Modal.createDialog).mock.calls.at(-1)!; expect(hasTestId((params as any).description, "jump-to-date-error-submit-debug-logs-button")).toBe(true); }); @@ -347,7 +349,7 @@ describe("DateSeparatorViewModel", () => { await flushPromisesWithFakeTimers(); expect(Modal.createDialog).toHaveBeenCalled(); - const [, params] = mocked(Modal.createDialog).mock.calls.at(-1)!; + const [, params] = vi.mocked(Modal.createDialog).mock.calls.at(-1)!; expect(hasTestId((params as any).description, "jump-to-date-error-submit-debug-logs-button")).toBe(false); }); }); diff --git a/apps/web/test/viewmodels/profile/DisambiguatedProfileViewModel-test.ts b/apps/web/src/viewmodels/room/timeline/event-tile/DisambiguatedProfileViewModel.test.ts similarity index 92% rename from apps/web/test/viewmodels/profile/DisambiguatedProfileViewModel-test.ts rename to apps/web/src/viewmodels/room/timeline/event-tile/DisambiguatedProfileViewModel.test.ts index 5b8c2070e7..c5027a4e04 100644 --- a/apps/web/test/viewmodels/profile/DisambiguatedProfileViewModel-test.ts +++ b/apps/web/src/viewmodels/room/timeline/event-tile/DisambiguatedProfileViewModel.test.ts @@ -5,7 +5,9 @@ * Please see LICENSE files in the repository root for full details. */ -import { DisambiguatedProfileViewModel } from "../../../src/viewmodels/room/timeline/event-tile/DisambiguatedProfileViewModel"; +import { vi, describe, it, expect } from "vitest"; + +import { DisambiguatedProfileViewModel } from "./DisambiguatedProfileViewModel"; describe("DisambiguatedProfileViewModel", () => { const member = { @@ -53,14 +55,14 @@ describe("DisambiguatedProfileViewModel", () => { }); it("should delegate onClick without emitting a snapshot update", () => { - const onClick = jest.fn(); + const onClick = vi.fn(); const vm = new DisambiguatedProfileViewModel({ member, fallbackName: "Fallback", onClick, }); const prevSnapshot = vm.getSnapshot(); - const subscriber = jest.fn(); + const subscriber = vi.fn(); vm.subscribe(subscriber); vm.onClick?.({} as never); @@ -71,7 +73,7 @@ describe("DisambiguatedProfileViewModel", () => { }); it("should keep onClick bound when extracted as a callback", () => { - const onClick = jest.fn(); + const onClick = vi.fn(); const vm = new DisambiguatedProfileViewModel({ member, fallbackName: "Fallback", @@ -89,7 +91,7 @@ describe("DisambiguatedProfileViewModel", () => { member: null, fallbackName: "Fallback", }); - const subscriber = jest.fn(); + const subscriber = vi.fn(); vm.subscribe(subscriber); vm.setMember("Updated"); @@ -103,7 +105,7 @@ describe("DisambiguatedProfileViewModel", () => { member: null, fallbackName: "Fallback", }); - const subscriber = jest.fn(); + const subscriber = vi.fn(); vm.subscribe(subscriber); vm.setMember("Fallback"); @@ -136,7 +138,7 @@ describe("DisambiguatedProfileViewModel", () => { member: null, fallbackName: "Fallback", }); - const subscriber = jest.fn(); + const subscriber = vi.fn(); vm.subscribe(subscriber); vm.setMember("Fallback", member); @@ -150,7 +152,7 @@ describe("DisambiguatedProfileViewModel", () => { member, fallbackName: "Fallback", }); - const subscriber = jest.fn(); + const subscriber = vi.fn(); vm.subscribe(subscriber); vm.setMember("Fallback", member); diff --git a/apps/web/test/viewmodels/audio/AudioPlayerViewModel-test.ts b/apps/web/src/viewmodels/room/timeline/event-tile/body/AudioPlayerViewModel.test.ts similarity index 87% rename from apps/web/test/viewmodels/audio/AudioPlayerViewModel-test.ts rename to apps/web/src/viewmodels/room/timeline/event-tile/body/AudioPlayerViewModel.test.ts index 5c0b474460..cbb6514a3e 100644 --- a/apps/web/test/viewmodels/audio/AudioPlayerViewModel-test.ts +++ b/apps/web/src/viewmodels/room/timeline/event-tile/body/AudioPlayerViewModel.test.ts @@ -5,12 +5,16 @@ * Please see LICENSE files in the repository root for full details. */ +// @vitest-environment happy-dom + +import { vi, describe, it, expect, beforeEach } from "vitest"; + import { type ChangeEvent, type KeyboardEvent as ReactKeyboardEvent } from "react"; import { waitFor } from "@testing-library/dom"; -import { type Playback, PlaybackState } from "../../../src/audio/Playback"; -import { AudioPlayerViewModel } from "../../../src/viewmodels/room/timeline/event-tile/body/AudioPlayerViewModel"; -import { MockedPlayback } from "../../unit-tests/audio/MockedPlayback"; +import { type Playback, PlaybackState } from "../../../../../audio/Playback"; +import { AudioPlayerViewModel } from "./AudioPlayerViewModel"; +import { MockedPlayback } from "../../../../../../test/unit-tests/audio/MockedPlayback"; describe("AudioPlayerViewModel", () => { let playback: Playback; @@ -45,7 +49,7 @@ describe("AudioPlayerViewModel", () => { }); it("should has error=true when playback.prepare fails", async () => { - jest.spyOn(playback, "prepare").mockRejectedValue(new Error("Failed to prepare playback")); + vi.spyOn(playback, "prepare").mockRejectedValue(new Error("Failed to prepare playback")); const vm = new AudioPlayerViewModel({ playback, mediaName: "mediaName" }); await waitFor(() => expect(vm.getSnapshot().error).toBe(true)); }); @@ -68,7 +72,7 @@ describe("AudioPlayerViewModel", () => { it("does not stop propagation for unhandled key down events", () => { const vm = new AudioPlayerViewModel({ playback, mediaName: "mediaName" }); const event = new KeyboardEvent("keydown", { key: "a" }); - const stopPropagationSpy = jest.spyOn(event, "stopPropagation"); + const stopPropagationSpy = vi.spyOn(event, "stopPropagation"); vm.onKeyDown(event as unknown as ReactKeyboardEvent); diff --git a/apps/web/test/viewmodels/structures/ResizerViewModel-test.ts b/apps/web/src/viewmodels/structures/ResizerViewModel.test.ts similarity index 85% rename from apps/web/test/viewmodels/structures/ResizerViewModel-test.ts rename to apps/web/src/viewmodels/structures/ResizerViewModel.test.ts index f25949528a..97bab42366 100644 --- a/apps/web/test/viewmodels/structures/ResizerViewModel-test.ts +++ b/apps/web/src/viewmodels/structures/ResizerViewModel.test.ts @@ -5,17 +5,22 @@ * Please see LICENSE files in the repository root for full details. */ -import { waitFor } from "jest-matrix-react"; +// @vitest-environment happy-dom + +import { vi, describe, it, expect, afterEach } from "vitest"; + +import { waitFor } from "test-utils-rtl"; import { type PanelImperativeHandle } from "@element-hq/web-shared-components"; -import { ResizerViewModel } from "../../../src/viewmodels/structures/ResizerViewModel"; -import SettingsStore from "../../../src/settings/SettingsStore"; -import { SettingLevel } from "../../../src/settings/SettingLevel"; +import { ResizerViewModel } from "./ResizerViewModel"; +import SettingsStore from "../../settings/SettingsStore"; +import { SettingLevel } from "../../settings/SettingLevel"; -jest.mock("what-input"); +vi.mock("what-input"); describe("LeftPanelResizerViewModel", () => { afterEach(() => { + localStorage.clear(); SettingsStore.reset(); }); @@ -72,8 +77,8 @@ describe("LeftPanelResizerViewModel", () => { const vm = new ResizerViewModel(); SettingsStore.setValue("RoomList.panelSize", null, SettingLevel.DEVICE, 34); const mockHandle = { - resize: jest.fn(), - isCollapsed: jest.fn().mockReturnValue(true), + resize: vi.fn(), + isCollapsed: vi.fn().mockReturnValue(true), } as unknown as PanelImperativeHandle; vm.setPanelHandle(mockHandle); @@ -90,8 +95,8 @@ describe("LeftPanelResizerViewModel", () => { const vm = new ResizerViewModel(); SettingsStore.setValue("RoomList.panelSize", null, SettingLevel.DEVICE, 34); const mockHandle = { - resize: jest.fn(), - isCollapsed: jest.fn().mockReturnValue(true), + resize: vi.fn(), + isCollapsed: vi.fn().mockReturnValue(true), } as unknown as PanelImperativeHandle; vm.setPanelHandle(mockHandle); // Simulate click @@ -103,8 +108,8 @@ describe("LeftPanelResizerViewModel", () => { it("to maximum size of the panel", () => { const vm = new ResizerViewModel(); const mockHandle = { - resize: jest.fn(), - isCollapsed: jest.fn().mockReturnValue(true), + resize: vi.fn(), + isCollapsed: vi.fn().mockReturnValue(true), } as unknown as PanelImperativeHandle; vm.setPanelHandle(mockHandle); // Simulate click @@ -117,8 +122,8 @@ describe("LeftPanelResizerViewModel", () => { it("should collapse panel on click when panel is expanded", () => { const vm = new ResizerViewModel(); const mockHandle = { - collapse: jest.fn(), - isCollapsed: jest.fn().mockReturnValue(false), + collapse: vi.fn(), + isCollapsed: vi.fn().mockReturnValue(false), } as unknown as PanelImperativeHandle; vm.setPanelHandle(mockHandle); @@ -129,7 +134,7 @@ describe("LeftPanelResizerViewModel", () => { it("should resize to nearest whole number", () => { const vm = new ResizerViewModel(); const mockHandle = { - resize: jest.fn(), + resize: vi.fn(), } as unknown as PanelImperativeHandle; vm.setPanelHandle(mockHandle); diff --git a/apps/web/test/unit-tests/audio/MockedPlayback.ts b/apps/web/test/unit-tests/audio/MockedPlayback.ts index da7839748e..5c89bfc0d5 100644 --- a/apps/web/test/unit-tests/audio/MockedPlayback.ts +++ b/apps/web/test/unit-tests/audio/MockedPlayback.ts @@ -9,6 +9,7 @@ import EventEmitter from "events"; import { SimpleObservable } from "matrix-widget-api"; import { PlaybackState } from "../../../src/audio/Playback"; +import { vi } from "../../setup/adapter.ts"; /** * A mocked playback implementation for testing purposes. @@ -51,8 +52,8 @@ export class MockedPlayback extends EventEmitter { return this.waveformObservable; } - public prepare = jest.fn().mockResolvedValue(undefined); - public skipTo = jest.fn(); - public toggle = jest.fn(); - public destroy = jest.fn().mockResolvedValue(undefined); + public prepare = vi.fn().mockResolvedValue(undefined); + public skipTo = vi.fn(); + public toggle = vi.fn(); + public destroy = vi.fn().mockResolvedValue(undefined); }