Migrate more tests to vitest (#34355)
* Remove doubled-up I18n Provider. ModalManager already provides this. * Reconfigure svgr into a vite-friendly `?react` resource query * Move InviteDialog test to vitest * Move RoomHeader tests to Vitest * Share serializer between Jest & Vitest * Attempt to stabilise InviteDialog test * Fix async leaks * Migrate more tests to vitest * Migrate MatrixChat test to vitest * Deflake * Iterate * Iterate * Iterate
This commit is contained in:
@@ -9,5 +9,7 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
import { vi } from "vitest";
|
import { vi } from "vitest";
|
||||||
|
|
||||||
export default function workerFactory(options) {
|
export default function workerFactory(options) {
|
||||||
return vi.fn;
|
return {
|
||||||
|
postMessage: vi.fn(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ export class DecryptionFailureTracker {
|
|||||||
/**
|
/**
|
||||||
* Clear state and stop checking for and tracking failures.
|
* Clear state and stop checking for and tracking failures.
|
||||||
*/
|
*/
|
||||||
private stop(): void {
|
public stop(): void {
|
||||||
if (this.checkInterval) clearInterval(this.checkInterval);
|
if (this.checkInterval) clearInterval(this.checkInterval);
|
||||||
if (this.trackInterval) clearInterval(this.trackInterval);
|
if (this.trackInterval) clearInterval(this.trackInterval);
|
||||||
|
|
||||||
|
|||||||
@@ -955,8 +955,8 @@ export async function logout(): Promise<void> {
|
|||||||
homeserverUrl: client.getHomeserverUrl(),
|
homeserverUrl: client.getHomeserverUrl(),
|
||||||
deviceId: client.getDeviceId()!,
|
deviceId: client.getDeviceId()!,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch {
|
||||||
console.error("@@", e);
|
// This is fine
|
||||||
}
|
}
|
||||||
|
|
||||||
PosthogAnalytics.instance.logout();
|
PosthogAnalytics.instance.logout();
|
||||||
|
|||||||
+280
-241
File diff suppressed because it is too large
Load Diff
@@ -524,6 +524,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||||||
UIStore.destroy();
|
UIStore.destroy();
|
||||||
this.stores.resizeNotifier.removeListener("middlePanelResized", this.dispatchTimelineResize);
|
this.stores.resizeNotifier.removeListener("middlePanelResized", this.dispatchTimelineResize);
|
||||||
window.removeEventListener("resize", this.onWindowResized);
|
window.removeEventListener("resize", this.onWindowResized);
|
||||||
|
|
||||||
|
DecryptionFailureTracker.instance.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private onWindowResized = (): void => {
|
private onWindowResized = (): void => {
|
||||||
@@ -1577,6 +1579,15 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||||||
this.firstSyncComplete = false;
|
this.firstSyncComplete = false;
|
||||||
const cli = MatrixClientPeg.safeGet();
|
const cli = MatrixClientPeg.safeGet();
|
||||||
|
|
||||||
|
// If the client has already completed its initial sync — e.g. this is a repeat WillStartClient for a client
|
||||||
|
// that is already running — it won't emit another `Prepared`, so resolve firstSyncPromise straight away
|
||||||
|
// rather than waiting for an event that will never come.
|
||||||
|
// This is mostly an issue under test.
|
||||||
|
if (cli.getSyncState() === SyncState.Prepared) {
|
||||||
|
this.firstSyncComplete = true;
|
||||||
|
this.firstSyncPromise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
// Allow the JS SDK to reap timeline events. This reduces the amount of
|
// Allow the JS SDK to reap timeline events. This reduces the amount of
|
||||||
// memory consumed as the JS SDK stores multiple distinct copies of room
|
// memory consumed as the JS SDK stores multiple distinct copies of room
|
||||||
// state (each of which can be 10s of MBs) for each DISJOINT timeline. This is
|
// state (each of which can be 10s of MBs) for each DISJOINT timeline. This is
|
||||||
|
|||||||
+21
-17
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`<MatrixChat /> Multi-tab lockout shows the lockout page when a second tab opens after a session is restored 1`] = `
|
exports[`<MatrixChat /> > Multi-tab lockout > shows the lockout page when a second tab opens > after a session is restored 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<main
|
<main
|
||||||
class="mx_SessionLockStolenView mx_SplashPage"
|
class="mx_SessionLockStolenView mx_SplashPage"
|
||||||
@@ -15,7 +15,7 @@ exports[`<MatrixChat /> Multi-tab lockout shows the lockout page when a second t
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<MatrixChat /> Multi-tab lockout shows the lockout page when a second tab opens during crypto init 1`] = `
|
exports[`<MatrixChat /> > Multi-tab lockout > shows the lockout page when a second tab opens > during crypto init 1`] = `
|
||||||
<body
|
<body
|
||||||
style="--emoji-font-family: Twemoji;"
|
style="--emoji-font-family: Twemoji;"
|
||||||
>
|
>
|
||||||
@@ -34,7 +34,7 @@ exports[`<MatrixChat /> Multi-tab lockout shows the lockout page when a second t
|
|||||||
</body>
|
</body>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<MatrixChat /> Multi-tab lockout shows the lockout page when a second tab opens while we are checking the sync store 1`] = `
|
exports[`<MatrixChat /> > Multi-tab lockout > shows the lockout page when a second tab opens > while we are checking the sync store 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<main
|
<main
|
||||||
class="mx_SessionLockStolenView mx_SplashPage"
|
class="mx_SessionLockStolenView mx_SplashPage"
|
||||||
@@ -49,7 +49,7 @@ exports[`<MatrixChat /> Multi-tab lockout shows the lockout page when a second t
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<MatrixChat /> Multi-tab lockout shows the lockout page when a second tab opens while we were waiting for the lock ourselves 1`] = `
|
exports[`<MatrixChat /> > Multi-tab lockout > shows the lockout page when a second tab opens > while we were waiting for the lock ourselves 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<main
|
<main
|
||||||
class="mx_SessionLockStolenView mx_SplashPage"
|
class="mx_SessionLockStolenView mx_SplashPage"
|
||||||
@@ -64,7 +64,7 @@ exports[`<MatrixChat /> Multi-tab lockout shows the lockout page when a second t
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<MatrixChat /> Multi-tab lockout waits for other tab to stop during startup 1`] = `
|
exports[`<MatrixChat /> > Multi-tab lockout > waits for other tab to stop during startup 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="mx_ConfirmSessionLockTheftView"
|
class="mx_ConfirmSessionLockTheftView"
|
||||||
@@ -87,7 +87,7 @@ exports[`<MatrixChat /> Multi-tab lockout waits for other tab to stop during sta
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<MatrixChat /> Multi-tab lockout waits for other tab to stop during startup 2`] = `
|
exports[`<MatrixChat /> > Multi-tab lockout > waits for other tab to stop during startup 2`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="mx_MatrixChat_splash"
|
class="mx_MatrixChat_splash"
|
||||||
@@ -118,14 +118,15 @@ exports[`<MatrixChat /> Multi-tab lockout waits for other tab to stop during sta
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<MatrixChat /> Multi-tab lockout waits for other tab to stop during startup 3`] = `
|
exports[`<MatrixChat /> > Multi-tab lockout > waits for other tab to stop during startup 3`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="mx_AuthPage"
|
class="mx_AuthPage"
|
||||||
|
style="background: url("themes/element/img/backgrounds/lake.jpg") center center / cover fixed;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="mx_AuthPage_modal"
|
class="mx_AuthPage_modal"
|
||||||
style="position: relative;"
|
style="position: relative; background: ;"
|
||||||
>
|
>
|
||||||
<main
|
<main
|
||||||
aria-live="polite"
|
aria-live="polite"
|
||||||
@@ -269,7 +270,7 @@ exports[`<MatrixChat /> Multi-tab lockout waits for other tab to stop during sta
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<MatrixChat /> qr login should fire ViewQrLogin action on 'qr_login' route 1`] = `
|
exports[`<MatrixChat /> > qr login > should fire ViewQrLogin action on 'qr_login' route 1`] = `
|
||||||
<div
|
<div
|
||||||
aria-label="Sign in with QR code"
|
aria-label="Sign in with QR code"
|
||||||
class=""
|
class=""
|
||||||
@@ -323,7 +324,7 @@ exports[`<MatrixChat /> qr login should fire ViewQrLogin action on 'qr_login' ro
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<MatrixChat /> qr login should open QrLoginDialog on ViewQrLogin action 1`] = `
|
exports[`<MatrixChat /> > qr login > should open QrLoginDialog on ViewQrLogin action 1`] = `
|
||||||
<div
|
<div
|
||||||
aria-label="Sign in with QR code"
|
aria-label="Sign in with QR code"
|
||||||
class=""
|
class=""
|
||||||
@@ -377,7 +378,7 @@ exports[`<MatrixChat /> qr login should open QrLoginDialog on ViewQrLogin action
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<MatrixChat /> should render spinner while app is loading 1`] = `
|
exports[`<MatrixChat /> > should render spinner while app is loading 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="mx_MatrixChat_splash"
|
class="mx_MatrixChat_splash"
|
||||||
@@ -408,18 +409,19 @@ exports[`<MatrixChat /> should render spinner while app is loading 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<MatrixChat /> with a soft-logged-out session should show the soft-logout page 1`] = `
|
exports[`<MatrixChat /> > with a soft-logged-out session > should show the soft-logout page 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="mx_AuthPage"
|
class="mx_AuthPage"
|
||||||
|
style="background: url("themes/element/img/backgrounds/lake.jpg") center center / cover fixed;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="mx_AuthPage_modal mx_AuthPage_modal_withBlur"
|
class="mx_AuthPage_modal mx_AuthPage_modal_withBlur"
|
||||||
style="position: relative;"
|
style="position: relative; background: ;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="mx_AuthPage_modalBlur"
|
class="mx_AuthPage_modalBlur"
|
||||||
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px; filter: blur(40px);"
|
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px; filter: blur(40px); background: url("themes/element/img/backgrounds/lake.jpg") center center / cover fixed;"
|
||||||
/>
|
/>
|
||||||
<main
|
<main
|
||||||
aria-live="polite"
|
aria-live="polite"
|
||||||
@@ -575,7 +577,7 @@ exports[`<MatrixChat /> with a soft-logged-out session should show the soft-logo
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<MatrixChat /> with an existing session onAction() room actions leave_room for a room should launch a confirmation modal 1`] = `
|
exports[`<MatrixChat /> > with an existing session > onAction() > room actions > leave_room > for a room > should launch a confirmation modal 1`] = `
|
||||||
<div
|
<div
|
||||||
aria-describedby="mx_Dialog_content"
|
aria-describedby="mx_Dialog_content"
|
||||||
aria-labelledby="mx_BaseDialog_title"
|
aria-labelledby="mx_BaseDialog_title"
|
||||||
@@ -625,6 +627,7 @@ exports[`<MatrixChat /> with an existing session onAction() room actions leave_r
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
aria-describedby="react-use-id-1"
|
||||||
aria-label="Close dialog"
|
aria-label="Close dialog"
|
||||||
class="mx_AccessibleButton mx_Dialog_cancelButton"
|
class="mx_AccessibleButton mx_Dialog_cancelButton"
|
||||||
role="button"
|
role="button"
|
||||||
@@ -645,7 +648,7 @@ exports[`<MatrixChat /> with an existing session onAction() room actions leave_r
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<MatrixChat /> with an existing session onAction() room actions leave_room for a space should launch a confirmation modal 1`] = `
|
exports[`<MatrixChat /> > with an existing session > onAction() > room actions > leave_room > for a space > should launch a confirmation modal 1`] = `
|
||||||
<div
|
<div
|
||||||
aria-describedby="mx_Dialog_content"
|
aria-describedby="mx_Dialog_content"
|
||||||
aria-labelledby="mx_BaseDialog_title"
|
aria-labelledby="mx_BaseDialog_title"
|
||||||
@@ -695,6 +698,7 @@ exports[`<MatrixChat /> with an existing session onAction() room actions leave_r
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
aria-describedby="react-use-id-1"
|
||||||
aria-label="Close dialog"
|
aria-label="Close dialog"
|
||||||
class="mx_AccessibleButton mx_Dialog_cancelButton"
|
class="mx_AccessibleButton mx_Dialog_cancelButton"
|
||||||
role="button"
|
role="button"
|
||||||
+22
-20
@@ -5,15 +5,17 @@ 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.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
// @vitest-environment happy-dom
|
||||||
import { act, render, screen } from "jest-matrix-react";
|
|
||||||
import { mocked } from "jest-mock";
|
|
||||||
import EventEmitter from "events";
|
|
||||||
|
|
||||||
import CompleteSecurity from "../../../../../src/components/structures/auth/CompleteSecurity";
|
import { vi, describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||||
import { stubClient } from "../../../../test-utils";
|
import React from "react";
|
||||||
import { Phase, SetupEncryptionStore } from "../../../../../src/stores/SetupEncryptionStore";
|
import { act, render, screen } from "test-utils-rtl";
|
||||||
import SdkConfig from "../../../../../src/SdkConfig";
|
import EventEmitter from "events";
|
||||||
|
import { stubClient } from "test-utils";
|
||||||
|
|
||||||
|
import CompleteSecurity from "./CompleteSecurity";
|
||||||
|
import { Phase, SetupEncryptionStore } from "../../../stores/SetupEncryptionStore";
|
||||||
|
import SdkConfig from "../../../SdkConfig";
|
||||||
|
|
||||||
class MockSetupEncryptionStore extends EventEmitter {
|
class MockSetupEncryptionStore extends EventEmitter {
|
||||||
public phase: Phase = Phase.Intro;
|
public phase: Phase = Phase.Intro;
|
||||||
@@ -21,8 +23,8 @@ class MockSetupEncryptionStore extends EventEmitter {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public start: () => void = jest.fn();
|
public start: () => void = vi.fn();
|
||||||
public stop: () => void = jest.fn();
|
public stop: () => void = vi.fn();
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("CompleteSecurity", () => {
|
describe("CompleteSecurity", () => {
|
||||||
@@ -35,16 +37,16 @@ describe("CompleteSecurity", () => {
|
|||||||
});
|
});
|
||||||
const userIdToDevices = new Map();
|
const userIdToDevices = new Map();
|
||||||
userIdToDevices.set("USER_ID", deviceIdToDevice);
|
userIdToDevices.set("USER_ID", deviceIdToDevice);
|
||||||
mocked(client.getCrypto()!.getUserDeviceInfo).mockResolvedValue(userIdToDevices);
|
vi.mocked(client.getCrypto()!.getUserDeviceInfo).mockResolvedValue(userIdToDevices);
|
||||||
|
|
||||||
const mockSetupEncryptionStore = new MockSetupEncryptionStore();
|
const mockSetupEncryptionStore = new MockSetupEncryptionStore();
|
||||||
jest.spyOn(SetupEncryptionStore, "sharedInstance").mockReturnValue(
|
vi.spyOn(SetupEncryptionStore, "sharedInstance").mockReturnValue(
|
||||||
mockSetupEncryptionStore as SetupEncryptionStore,
|
mockSetupEncryptionStore as SetupEncryptionStore,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Renders with a cancel button by default", () => {
|
it("Renders with a cancel button by default", () => {
|
||||||
@@ -54,7 +56,7 @@ describe("CompleteSecurity", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("Renders with a cancel button if forceVerification false", () => {
|
it("Renders with a cancel button if forceVerification false", () => {
|
||||||
jest.spyOn(SdkConfig, "get").mockImplementation((key: string) => {
|
vi.spyOn(SdkConfig, "get").mockImplementation((key: string) => {
|
||||||
if (key === "forceVerification") {
|
if (key === "forceVerification") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -66,7 +68,7 @@ describe("CompleteSecurity", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("Renders without a cancel button if forceVerification true", () => {
|
it("Renders without a cancel button if forceVerification true", () => {
|
||||||
jest.spyOn(SdkConfig, "get").mockImplementation((key: string) => {
|
vi.spyOn(SdkConfig, "get").mockImplementation((key: string) => {
|
||||||
if (key === "force_verification") {
|
if (key === "force_verification") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -80,7 +82,7 @@ describe("CompleteSecurity", () => {
|
|||||||
it("Renders a warning if user hits Reset", async () => {
|
it("Renders a warning if user hits Reset", async () => {
|
||||||
// Given a store and a dialog based on it
|
// Given a store and a dialog based on it
|
||||||
const store = new SetupEncryptionStore();
|
const store = new SetupEncryptionStore();
|
||||||
jest.spyOn(SetupEncryptionStore, "sharedInstance").mockReturnValue(store);
|
vi.spyOn(SetupEncryptionStore, "sharedInstance").mockReturnValue(store);
|
||||||
const panel = await act(() => render(<CompleteSecurity onFinished={() => {}} />));
|
const panel = await act(() => render(<CompleteSecurity onFinished={() => {}} />));
|
||||||
|
|
||||||
// No recovery methods are available, so only the "Can't confirm?" button should be visible
|
// No recovery methods are available, so only the "Can't confirm?" button should be visible
|
||||||
@@ -99,12 +101,12 @@ describe("CompleteSecurity", () => {
|
|||||||
it("Allows verifying with another device if one is available", async () => {
|
it("Allows verifying with another device if one is available", async () => {
|
||||||
// Given a store and a dialog based on it
|
// Given a store and a dialog based on it
|
||||||
const store = new SetupEncryptionStore();
|
const store = new SetupEncryptionStore();
|
||||||
jest.spyOn(store, "fetchKeyInfo").mockImplementation(async () => {
|
vi.spyOn(store, "fetchKeyInfo").mockImplementation(async () => {
|
||||||
store.hasDevicesToVerifyAgainst = true;
|
store.hasDevicesToVerifyAgainst = true;
|
||||||
store.phase = Phase.Intro;
|
store.phase = Phase.Intro;
|
||||||
store.emit("update");
|
store.emit("update");
|
||||||
});
|
});
|
||||||
jest.spyOn(SetupEncryptionStore, "sharedInstance").mockReturnValue(store);
|
vi.spyOn(SetupEncryptionStore, "sharedInstance").mockReturnValue(store);
|
||||||
const panel = await act(() => render(<CompleteSecurity onFinished={() => {}} />));
|
const panel = await act(() => render(<CompleteSecurity onFinished={() => {}} />));
|
||||||
|
|
||||||
// The snapshot should have "Use another device" and "Can't confirm?"
|
// The snapshot should have "Use another device" and "Can't confirm?"
|
||||||
@@ -124,12 +126,12 @@ describe("CompleteSecurity", () => {
|
|||||||
it("Allows verifying with recovery key if one is available", async () => {
|
it("Allows verifying with recovery key if one is available", async () => {
|
||||||
// Given a store and a dialog based on it
|
// Given a store and a dialog based on it
|
||||||
const store = new SetupEncryptionStore();
|
const store = new SetupEncryptionStore();
|
||||||
jest.spyOn(store, "fetchKeyInfo").mockImplementation(async () => {
|
vi.spyOn(store, "fetchKeyInfo").mockImplementation(async () => {
|
||||||
store.keyInfo = {} as any;
|
store.keyInfo = {} as any;
|
||||||
store.phase = Phase.Intro;
|
store.phase = Phase.Intro;
|
||||||
store.emit("update");
|
store.emit("update");
|
||||||
});
|
});
|
||||||
jest.spyOn(SetupEncryptionStore, "sharedInstance").mockReturnValue(store);
|
vi.spyOn(SetupEncryptionStore, "sharedInstance").mockReturnValue(store);
|
||||||
const panel = await act(() => render(<CompleteSecurity onFinished={() => {}} />));
|
const panel = await act(() => render(<CompleteSecurity onFinished={() => {}} />));
|
||||||
|
|
||||||
// The snapshot should have "Use recovery key" and "Can't confirm?"
|
// The snapshot should have "Use recovery key" and "Can't confirm?"
|
||||||
+13
-11
@@ -5,28 +5,30 @@ 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.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// @vitest-environment happy-dom
|
||||||
|
|
||||||
|
import { vi, describe, it, expect, afterEach } from "vitest";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { render } from "jest-matrix-react";
|
import { render } from "test-utils-rtl";
|
||||||
import { mocked } from "jest-mock";
|
|
||||||
|
|
||||||
import E2eSetup from "../../../../../src/components/structures/auth/E2eSetup.tsx";
|
import E2eSetup from "./E2eSetup.tsx";
|
||||||
import { InitialCryptoSetupStore } from "../../../../../src/stores/InitialCryptoSetupStore.ts";
|
import { InitialCryptoSetupStore } from "../../../stores/InitialCryptoSetupStore.ts";
|
||||||
|
|
||||||
afterEach(() => jest.restoreAllMocks());
|
afterEach(() => vi.restoreAllMocks());
|
||||||
|
|
||||||
describe("LeftPanel", () => {
|
describe("LeftPanel", () => {
|
||||||
it("should call `onCancelled` when the user clicks the cancel button", () => {
|
it("should call `onCancelled` when the user clicks the cancel button", () => {
|
||||||
const mockInitialCryptoSetupStore = {
|
const mockInitialCryptoSetupStore = {
|
||||||
getStatus: jest.fn(),
|
getStatus: vi.fn(),
|
||||||
on: jest.fn(),
|
on: vi.fn(),
|
||||||
off: jest.fn(),
|
off: vi.fn(),
|
||||||
};
|
};
|
||||||
jest.spyOn(InitialCryptoSetupStore, "sharedInstance").mockReturnValue(mockInitialCryptoSetupStore as any);
|
vi.spyOn(InitialCryptoSetupStore, "sharedInstance").mockReturnValue(mockInitialCryptoSetupStore as any);
|
||||||
|
|
||||||
// We need the setup process to have failed, for the dialog to present a cancel button.
|
// We need the setup process to have failed, for the dialog to present a cancel button.
|
||||||
mocked(mockInitialCryptoSetupStore.getStatus).mockReturnValue("error");
|
vi.mocked(mockInitialCryptoSetupStore.getStatus).mockReturnValue("error");
|
||||||
|
|
||||||
const onCancelled = jest.fn();
|
const onCancelled = vi.fn();
|
||||||
const { getByRole } = render(<E2eSetup onCancelled={onCancelled} />);
|
const { getByRole } = render(<E2eSetup onCancelled={onCancelled} />);
|
||||||
|
|
||||||
getByRole("button", { name: "Cancel" }).click();
|
getByRole("button", { name: "Cancel" }).click();
|
||||||
+29
-33
@@ -6,20 +6,22 @@ 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.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// @vitest-environment happy-dom
|
||||||
|
|
||||||
|
import { vi, describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { mocked } from "jest-mock";
|
import { render, type RenderResult, screen, waitFor, cleanup } from "test-utils-rtl";
|
||||||
import { render, type RenderResult, screen, waitFor, cleanup } from "jest-matrix-react";
|
|
||||||
import userEvent from "@testing-library/user-event";
|
import userEvent from "@testing-library/user-event";
|
||||||
import { type MatrixClient, createClient } from "matrix-js-sdk/src/matrix";
|
import { type MatrixClient, createClient } from "matrix-js-sdk/src/matrix";
|
||||||
|
import { clearAllModals, filterConsole, stubClient, waitEnoughCyclesForModal } from "test-utils";
|
||||||
|
|
||||||
import ForgotPassword from "../../../../../src/components/structures/auth/ForgotPassword";
|
import ForgotPassword from "./ForgotPassword";
|
||||||
import { type ValidatedServerConfig } from "../../../../../src/utils/ValidatedServerConfig";
|
import { type ValidatedServerConfig } from "../../../utils/ValidatedServerConfig";
|
||||||
import { clearAllModals, filterConsole, stubClient, waitEnoughCyclesForModal } from "../../../../test-utils";
|
import AutoDiscoveryUtils from "../../../utils/AutoDiscoveryUtils";
|
||||||
import AutoDiscoveryUtils from "../../../../../src/utils/AutoDiscoveryUtils";
|
|
||||||
|
|
||||||
jest.mock("matrix-js-sdk/src/matrix", () => ({
|
vi.mock("matrix-js-sdk/src/matrix", async () => ({
|
||||||
...jest.requireActual("matrix-js-sdk/src/matrix"),
|
...(await vi.importActual("matrix-js-sdk/src/matrix")),
|
||||||
createClient: jest.fn(),
|
createClient: vi.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe("<ForgotPassword>", () => {
|
describe("<ForgotPassword>", () => {
|
||||||
@@ -54,15 +56,15 @@ describe("<ForgotPassword>", () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
client = stubClient();
|
client = stubClient();
|
||||||
mocked(createClient).mockReturnValue(client);
|
vi.mocked(createClient).mockReturnValue(client);
|
||||||
|
|
||||||
serverConfig = { hsName: "example.com" } as ValidatedServerConfig;
|
serverConfig = { hsName: "example.com" } as ValidatedServerConfig;
|
||||||
|
|
||||||
onComplete = jest.fn();
|
onComplete = vi.fn();
|
||||||
onLoginClick = jest.fn();
|
onLoginClick = vi.fn();
|
||||||
|
|
||||||
jest.spyOn(AutoDiscoveryUtils, "validateServerConfigWithStaticUrls").mockResolvedValue(serverConfig);
|
vi.spyOn(AutoDiscoveryUtils, "validateServerConfigWithStaticUrls").mockResolvedValue(serverConfig);
|
||||||
jest.spyOn(AutoDiscoveryUtils, "authComponentStateForError");
|
vi.spyOn(AutoDiscoveryUtils, "authComponentStateForError");
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
@@ -120,9 +122,9 @@ describe("<ForgotPassword>", () => {
|
|||||||
|
|
||||||
describe("and submitting an unknown email", () => {
|
describe("and submitting an unknown email", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
mocked(AutoDiscoveryUtils.validateServerConfigWithStaticUrls).mockResolvedValue(serverConfig);
|
vi.mocked(AutoDiscoveryUtils.validateServerConfigWithStaticUrls).mockResolvedValue(serverConfig);
|
||||||
await typeIntoField("Email address", testEmail);
|
await typeIntoField("Email address", testEmail);
|
||||||
mocked(client).requestPasswordEmailToken.mockRejectedValue({
|
vi.mocked(client).requestPasswordEmailToken.mockRejectedValue({
|
||||||
errcode: "M_THREEPID_NOT_FOUND",
|
errcode: "M_THREEPID_NOT_FOUND",
|
||||||
});
|
});
|
||||||
await click(screen.getByText("Send email"));
|
await click(screen.getByText("Send email"));
|
||||||
@@ -136,7 +138,7 @@ describe("<ForgotPassword>", () => {
|
|||||||
describe("and a connection error occurs", () => {
|
describe("and a connection error occurs", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await typeIntoField("Email address", testEmail);
|
await typeIntoField("Email address", testEmail);
|
||||||
mocked(client).requestPasswordEmailToken.mockRejectedValue({
|
vi.mocked(client).requestPasswordEmailToken.mockRejectedValue({
|
||||||
name: "ConnectionError",
|
name: "ConnectionError",
|
||||||
});
|
});
|
||||||
await click(screen.getByText("Send email"));
|
await click(screen.getByText("Send email"));
|
||||||
@@ -154,8 +156,8 @@ describe("<ForgotPassword>", () => {
|
|||||||
describe("and the server liveness check fails", () => {
|
describe("and the server liveness check fails", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await typeIntoField("Email address", testEmail);
|
await typeIntoField("Email address", testEmail);
|
||||||
mocked(AutoDiscoveryUtils.validateServerConfigWithStaticUrls).mockRejectedValue({});
|
vi.mocked(AutoDiscoveryUtils.validateServerConfigWithStaticUrls).mockRejectedValue({});
|
||||||
mocked(AutoDiscoveryUtils.authComponentStateForError).mockReturnValue({
|
vi.mocked(AutoDiscoveryUtils.authComponentStateForError).mockReturnValue({
|
||||||
serverErrorIsFatal: true,
|
serverErrorIsFatal: true,
|
||||||
serverIsAlive: false,
|
serverIsAlive: false,
|
||||||
serverDeadError: "server down",
|
serverDeadError: "server down",
|
||||||
@@ -171,7 +173,7 @@ describe("<ForgotPassword>", () => {
|
|||||||
describe("and submitting an known email", () => {
|
describe("and submitting an known email", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await typeIntoField("Email address", testEmail);
|
await typeIntoField("Email address", testEmail);
|
||||||
mocked(client).requestPasswordEmailToken.mockResolvedValue({
|
vi.mocked(client).requestPasswordEmailToken.mockResolvedValue({
|
||||||
sid: testSid,
|
sid: testSid,
|
||||||
});
|
});
|
||||||
await click(screen.getByText("Send email"));
|
await click(screen.getByText("Send email"));
|
||||||
@@ -238,14 +240,14 @@ describe("<ForgotPassword>", () => {
|
|||||||
|
|
||||||
describe("and entering a new password", () => {
|
describe("and entering a new password", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
mocked(client.setPassword).mockRejectedValue({ httpStatus: 401 });
|
vi.mocked(client.setPassword).mockRejectedValue({ httpStatus: 401 });
|
||||||
await typeIntoField("New Password", testPassword);
|
await typeIntoField("New Password", testPassword);
|
||||||
await typeIntoField("Confirm new password", testPassword);
|
await typeIntoField("Confirm new password", testPassword);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("and submitting it running into rate limiting", () => {
|
describe("and submitting it running into rate limiting", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
mocked(client.setPassword).mockRejectedValue({
|
vi.mocked(client.setPassword).mockRejectedValue({
|
||||||
message: "rate limit reached",
|
message: "rate limit reached",
|
||||||
httpStatus: 429,
|
httpStatus: 429,
|
||||||
data: {
|
data: {
|
||||||
@@ -265,7 +267,7 @@ describe("<ForgotPassword>", () => {
|
|||||||
describe("and confirm the email link and submitting the new password", () => {
|
describe("and confirm the email link and submitting the new password", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
// fake link confirmed by resolving client.setPassword instead of raising an error
|
// fake link confirmed by resolving client.setPassword instead of raising an error
|
||||||
mocked(client.setPassword).mockResolvedValue({});
|
vi.mocked(client.setPassword).mockResolvedValue({});
|
||||||
await click(screen.getByText("Reset password"));
|
await click(screen.getByText("Reset password"));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -314,9 +316,7 @@ describe("<ForgotPassword>", () => {
|
|||||||
describe("and dismissing the dialog by clicking the background", () => {
|
describe("and dismissing the dialog by clicking the background", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await userEvent.click(await screen.findByTestId("dialog-background"), { delay: null });
|
await userEvent.click(await screen.findByTestId("dialog-background"), { delay: null });
|
||||||
await waitEnoughCyclesForModal({
|
await waitEnoughCyclesForModal();
|
||||||
useFakeTimers: true,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
itShouldCloseTheDialogAndShowThePasswordInput();
|
itShouldCloseTheDialogAndShowThePasswordInput();
|
||||||
@@ -325,9 +325,7 @@ describe("<ForgotPassword>", () => {
|
|||||||
describe("and dismissing the dialog", () => {
|
describe("and dismissing the dialog", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await click(await screen.findByLabelText("Close dialog"));
|
await click(await screen.findByLabelText("Close dialog"));
|
||||||
await waitEnoughCyclesForModal({
|
await waitEnoughCyclesForModal();
|
||||||
useFakeTimers: true,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
itShouldCloseTheDialogAndShowThePasswordInput();
|
itShouldCloseTheDialogAndShowThePasswordInput();
|
||||||
@@ -336,9 +334,7 @@ describe("<ForgotPassword>", () => {
|
|||||||
describe("and clicking »Re-enter email address«", () => {
|
describe("and clicking »Re-enter email address«", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await click(await screen.findByText("Re-enter email address"));
|
await click(await screen.findByText("Re-enter email address"));
|
||||||
await waitEnoughCyclesForModal({
|
await waitEnoughCyclesForModal();
|
||||||
useFakeTimers: true,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should close the dialog and go back to the email input", async () => {
|
it("should close the dialog and go back to the email input", async () => {
|
||||||
@@ -352,7 +348,7 @@ describe("<ForgotPassword>", () => {
|
|||||||
|
|
||||||
describe("and validating the link from the mail", () => {
|
describe("and validating the link from the mail", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
mocked(client.setPassword).mockResolvedValue({});
|
vi.mocked(client.setPassword).mockResolvedValue({});
|
||||||
await click(screen.getByText("Reset password"));
|
await click(screen.getByText("Reset password"));
|
||||||
// flush promises for the modal to disappear
|
// flush promises for the modal to disappear
|
||||||
await waitEnoughCyclesForModal();
|
await waitEnoughCyclesForModal();
|
||||||
+23
-22
@@ -5,10 +5,12 @@ 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.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// @vitest-environment happy-dom
|
||||||
|
|
||||||
|
import { vi, describe, it, expect, beforeEach, afterEach, type MockedObject } from "vitest";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { fireEvent, render, screen, waitForElementToBeRemoved } from "jest-matrix-react";
|
import { fireEvent, render, screen, waitForElementToBeRemoved } from "test-utils-rtl";
|
||||||
import { mocked, type MockedObject } from "jest-mock-vitest-adapter";
|
import fetchMock from "@fetch-mock/vitest";
|
||||||
import fetchMock from "@fetch-mock/jest";
|
|
||||||
import {
|
import {
|
||||||
OAUTH_AWARE_PREFERRED_FLOW_FIELD,
|
OAUTH_AWARE_PREFERRED_FLOW_FIELD,
|
||||||
IdentityProviderBrand,
|
IdentityProviderBrand,
|
||||||
@@ -17,16 +19,16 @@ import {
|
|||||||
} from "matrix-js-sdk/src/matrix";
|
} from "matrix-js-sdk/src/matrix";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import * as Matrix from "matrix-js-sdk/src/matrix";
|
import * as Matrix from "matrix-js-sdk/src/matrix";
|
||||||
|
import { mkServerConfig, mockPlatformPeg, unmockPlatformPeg } from "test-utils";
|
||||||
|
import { makeDelegatedAuthMetadata } from "test-utils/auth";
|
||||||
|
|
||||||
import SdkConfig from "../../../../../src/SdkConfig";
|
import SdkConfig from "../../../SdkConfig";
|
||||||
import { mkServerConfig, mockPlatformPeg, unmockPlatformPeg } from "../../../../test-utils";
|
import Login from "./Login";
|
||||||
import Login from "../../../../../src/components/structures/auth/Login";
|
import type BasePlatform from "../../../BasePlatform";
|
||||||
import type BasePlatform from "../../../../../src/BasePlatform";
|
import * as registerClientUtils from "../../../utils/oauth/registerClient";
|
||||||
import * as registerClientUtils from "../../../../../src/utils/oauth/registerClient";
|
import { ModuleApi } from "../../../modules/Api.ts";
|
||||||
import { makeDelegatedAuthMetadata } from "../../../../test-utils/auth";
|
|
||||||
import { ModuleApi } from "../../../../../src/modules/Api.ts";
|
|
||||||
|
|
||||||
jest.useRealTimers();
|
vi.useRealTimers();
|
||||||
|
|
||||||
const oauthStaticClientsConfig = {
|
const oauthStaticClientsConfig = {
|
||||||
"https://staticallyregisteredissuer.org/": {
|
"https://staticallyregisteredissuer.org/": {
|
||||||
@@ -37,9 +39,9 @@ const oauthStaticClientsConfig = {
|
|||||||
describe("Login", function () {
|
describe("Login", function () {
|
||||||
let platform: MockedObject<BasePlatform>;
|
let platform: MockedObject<BasePlatform>;
|
||||||
|
|
||||||
const mockClient = mocked({
|
const mockClient = vi.mocked({
|
||||||
login: jest.fn().mockResolvedValue({}),
|
login: vi.fn().mockResolvedValue({}),
|
||||||
loginFlows: jest.fn(),
|
loginFlows: vi.fn(),
|
||||||
} as unknown as Matrix.MatrixClient);
|
} as unknown as Matrix.MatrixClient);
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
@@ -54,7 +56,7 @@ describe("Login", function () {
|
|||||||
user_id: "@user:server",
|
user_id: "@user:server",
|
||||||
});
|
});
|
||||||
mockClient.loginFlows.mockClear().mockResolvedValue({ flows: [{ type: "m.login.password" }] });
|
mockClient.loginFlows.mockClear().mockResolvedValue({ flows: [{ type: "m.login.password" }] });
|
||||||
jest.spyOn(Matrix, "createClient").mockImplementation((opts) => {
|
vi.spyOn(Matrix, "createClient").mockImplementation((opts) => {
|
||||||
mockClient.idBaseUrl = opts.idBaseUrl;
|
mockClient.idBaseUrl = opts.idBaseUrl;
|
||||||
mockClient.baseUrl = opts.baseUrl;
|
mockClient.baseUrl = opts.baseUrl;
|
||||||
return mockClient;
|
return mockClient;
|
||||||
@@ -64,7 +66,7 @@ describe("Login", function () {
|
|||||||
versions: ["v1.1"],
|
versions: ["v1.1"],
|
||||||
});
|
});
|
||||||
platform = mockPlatformPeg({
|
platform = mockPlatformPeg({
|
||||||
startSingleSignOn: jest.fn(),
|
startSingleSignOn: vi.fn(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -106,7 +108,7 @@ describe("Login", function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should show register button", async () => {
|
it("should show register button", async () => {
|
||||||
const onRegisterClick = jest.fn();
|
const onRegisterClick = vi.fn();
|
||||||
const { getByText } = render(
|
const { getByText } = render(
|
||||||
<Login
|
<Login
|
||||||
serverConfig={mkServerConfig("https://matrix.org", "https://vector.im")}
|
serverConfig={mkServerConfig("https://matrix.org", "https://vector.im")}
|
||||||
@@ -320,8 +322,7 @@ describe("Login", function () {
|
|||||||
|
|
||||||
for (const idp of idpsWithIcons) {
|
for (const idp of idpsWithIcons) {
|
||||||
const ssoButton = getByTestId(`idp-${idp.id}`);
|
const ssoButton = getByTestId(`idp-${idp.id}`);
|
||||||
expect(ssoButton).toBeTruthy();
|
expect(ssoButton).toHaveAccessibleName(`Continue with Provider ${idp.brand}`);
|
||||||
expect(ssoButton.childNodes[0]).toHaveAccessibleName(idp.brand);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ssoButtons = container.querySelectorAll(".mx_SSOButton");
|
const ssoButtons = container.querySelectorAll(".mx_SSOButton");
|
||||||
@@ -399,16 +400,16 @@ describe("Login", function () {
|
|||||||
const issuer = "https://test.com/";
|
const issuer = "https://test.com/";
|
||||||
const delegatedAuth = makeDelegatedAuthMetadata(issuer);
|
const delegatedAuth = makeDelegatedAuthMetadata(issuer);
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(logger, "error");
|
vi.spyOn(logger, "error");
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.spyOn(logger, "error").mockRestore();
|
vi.spyOn(logger, "error").mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should attempt to register oauth client", async () => {
|
it("should attempt to register oauth client", async () => {
|
||||||
// dont mock, spy so we can check config values were correctly passed
|
// dont mock, spy so we can check config values were correctly passed
|
||||||
jest.spyOn(registerClientUtils, "getOAuthClientId");
|
vi.spyOn(registerClientUtils, "getOAuthClientId");
|
||||||
fetchMock.post(delegatedAuth.registration_endpoint!, { status: 500 });
|
fetchMock.post(delegatedAuth.registration_endpoint!, { status: 500 });
|
||||||
getComponent(hsUrl, isUrl, delegatedAuth);
|
getComponent(hsUrl, isUrl, delegatedAuth);
|
||||||
|
|
||||||
+6
-3
@@ -6,13 +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.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { act, render, type RenderResult } from "jest-matrix-react";
|
// @vitest-environment happy-dom
|
||||||
|
|
||||||
|
import { vi, describe, it, expect, beforeEach } from "vitest";
|
||||||
|
import { act, render, type RenderResult } from "test-utils-rtl";
|
||||||
import React, { type ComponentProps } from "react";
|
import React, { type ComponentProps } from "react";
|
||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
import { CryptoEvent } from "matrix-js-sdk/src/crypto-api";
|
import { CryptoEvent } from "matrix-js-sdk/src/crypto-api";
|
||||||
import { sleep } from "matrix-js-sdk/src/utils";
|
import { sleep } from "matrix-js-sdk/src/utils";
|
||||||
|
|
||||||
import { LoginSplashView } from "../../../../../src/components/structures/auth/LoginSplashView";
|
import { LoginSplashView } from "./LoginSplashView";
|
||||||
import type { MatrixClient } from "matrix-js-sdk/src/matrix";
|
import type { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
describe("<LoginSplashView />", () => {
|
describe("<LoginSplashView />", () => {
|
||||||
@@ -42,7 +45,7 @@ describe("<LoginSplashView />", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("Calls onLogoutClick", () => {
|
it("Calls onLogoutClick", () => {
|
||||||
const onLogoutClick = jest.fn();
|
const onLogoutClick = vi.fn();
|
||||||
const rendered = getComponent({ onLogoutClick });
|
const rendered = getComponent({ onLogoutClick });
|
||||||
expect(onLogoutClick).not.toHaveBeenCalled();
|
expect(onLogoutClick).not.toHaveBeenCalled();
|
||||||
rendered.getByRole("button", { name: "Logout" }).click();
|
rendered.getByRole("button", { name: "Logout" }).click();
|
||||||
+24
-27
@@ -7,30 +7,27 @@ 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.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// @vitest-environment happy-dom
|
||||||
|
|
||||||
|
import { vi, describe, it, expect, beforeEach, afterEach, type MockedObject } from "vitest";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { fireEvent, render, screen, waitFor, waitForElementToBeRemoved } from "jest-matrix-react";
|
import { fireEvent, render, screen, waitFor, waitForElementToBeRemoved } from "test-utils-rtl";
|
||||||
import { createClient, type MatrixClient, MatrixError, type ValidatedAuthMetadata } from "matrix-js-sdk/src/matrix";
|
import { createClient, type MatrixClient, MatrixError, type ValidatedAuthMetadata } from "matrix-js-sdk/src/matrix";
|
||||||
import { mocked, type MockedObject } from "jest-mock-vitest-adapter";
|
import fetchMock from "@fetch-mock/vitest";
|
||||||
import fetchMock from "@fetch-mock/jest";
|
import { getMockClientWithEventEmitter, mkServerConfig, mockPlatformPeg, unmockPlatformPeg } from "test-utils";
|
||||||
|
import { makeDelegatedAuthMetadata } from "test-utils/auth";
|
||||||
|
|
||||||
import SdkConfig, { DEFAULTS } from "../../../../../src/SdkConfig";
|
import SdkConfig, { DEFAULTS } from "../../../SdkConfig";
|
||||||
import {
|
import Registration from "./Registration";
|
||||||
getMockClientWithEventEmitter,
|
import { startOAuthLogin } from "../../../utils/oauth/authorize";
|
||||||
mkServerConfig,
|
|
||||||
mockPlatformPeg,
|
|
||||||
unmockPlatformPeg,
|
|
||||||
} from "../../../../test-utils";
|
|
||||||
import Registration from "../../../../../src/components/structures/auth/Registration";
|
|
||||||
import { makeDelegatedAuthMetadata } from "../../../../test-utils/auth";
|
|
||||||
import { startOAuthLogin } from "../../../../../src/utils/oauth/authorize";
|
|
||||||
|
|
||||||
jest.mock("../../../../../src/utils/oauth/authorize", () => ({
|
vi.mock("../../../utils/oauth/authorize", () => ({
|
||||||
startOAuthLogin: jest.fn(),
|
startOAuthLogin: vi.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock("matrix-js-sdk/src/matrix", () => ({
|
vi.mock("matrix-js-sdk/src/matrix", async () => ({
|
||||||
...jest.requireActual("matrix-js-sdk/src/matrix"),
|
...(await vi.importActual("matrix-js-sdk/src/matrix")),
|
||||||
createClient: jest.fn(),
|
createClient: vi.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/** The matrix versions our mock server claims to support */
|
/** The matrix versions our mock server claims to support */
|
||||||
@@ -45,9 +42,9 @@ describe("Registration", function () {
|
|||||||
disable_custom_urls: true,
|
disable_custom_urls: true,
|
||||||
});
|
});
|
||||||
mockClient = getMockClientWithEventEmitter({
|
mockClient = getMockClientWithEventEmitter({
|
||||||
registerRequest: jest.fn(),
|
registerRequest: vi.fn(),
|
||||||
loginFlows: jest.fn(),
|
loginFlows: vi.fn(),
|
||||||
getVersions: jest.fn().mockResolvedValue({ versions: SERVER_SUPPORTED_MATRIX_VERSIONS }),
|
getVersions: vi.fn().mockResolvedValue({ versions: SERVER_SUPPORTED_MATRIX_VERSIONS }),
|
||||||
});
|
});
|
||||||
mockClient.registerRequest.mockRejectedValueOnce(
|
mockClient.registerRequest.mockRejectedValueOnce(
|
||||||
new MatrixError(
|
new MatrixError(
|
||||||
@@ -58,7 +55,7 @@ describe("Registration", function () {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
mockClient.loginFlows.mockResolvedValue({ flows: [{ type: "m.login.password" }] });
|
mockClient.loginFlows.mockResolvedValue({ flows: [{ type: "m.login.password" }] });
|
||||||
mocked(createClient).mockImplementation((opts) => {
|
vi.mocked(createClient).mockImplementation((opts) => {
|
||||||
mockClient.idBaseUrl = opts.idBaseUrl;
|
mockClient.idBaseUrl = opts.idBaseUrl;
|
||||||
mockClient.baseUrl = opts.baseUrl;
|
mockClient.baseUrl = opts.baseUrl;
|
||||||
return mockClient;
|
return mockClient;
|
||||||
@@ -69,21 +66,21 @@ describe("Registration", function () {
|
|||||||
versions: SERVER_SUPPORTED_MATRIX_VERSIONS,
|
versions: SERVER_SUPPORTED_MATRIX_VERSIONS,
|
||||||
});
|
});
|
||||||
mockPlatformPeg({
|
mockPlatformPeg({
|
||||||
startSingleSignOn: jest.fn(),
|
startSingleSignOn: vi.fn(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function () {
|
||||||
jest.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
SdkConfig.reset(); // we touch the config, so clean up
|
SdkConfig.reset(); // we touch the config, so clean up
|
||||||
unmockPlatformPeg();
|
unmockPlatformPeg();
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
defaultDeviceDisplayName: "test-device-display-name",
|
defaultDeviceDisplayName: "test-device-display-name",
|
||||||
onLoggedIn: jest.fn(),
|
onLoggedIn: vi.fn(),
|
||||||
onLoginClick: jest.fn(),
|
onLoginClick: vi.fn(),
|
||||||
onServerConfigChange: jest.fn(),
|
onServerConfigChange: vi.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultHsUrl = "https://matrix.org";
|
const defaultHsUrl = "https://matrix.org";
|
||||||
+7
-5
@@ -1,13 +1,14 @@
|
|||||||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`CompleteSecurity Allows verifying with another device if one is available 1`] = `
|
exports[`CompleteSecurity > Allows verifying with another device if one is available 1`] = `
|
||||||
<DocumentFragment>
|
<DocumentFragment>
|
||||||
<div
|
<div
|
||||||
class="mx_AuthPage"
|
class="mx_AuthPage"
|
||||||
|
style="background: url("themes/element/img/backgrounds/lake.jpg") center center / cover fixed;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="mx_AuthPage_modal"
|
class="mx_AuthPage_modal"
|
||||||
style="position: relative;"
|
style="position: relative; background: ;"
|
||||||
>
|
>
|
||||||
<main
|
<main
|
||||||
aria-live="polite"
|
aria-live="polite"
|
||||||
@@ -193,14 +194,15 @@ exports[`CompleteSecurity Allows verifying with another device if one is availab
|
|||||||
</DocumentFragment>
|
</DocumentFragment>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`CompleteSecurity Allows verifying with recovery key if one is available 1`] = `
|
exports[`CompleteSecurity > Allows verifying with recovery key if one is available 1`] = `
|
||||||
<DocumentFragment>
|
<DocumentFragment>
|
||||||
<div
|
<div
|
||||||
class="mx_AuthPage"
|
class="mx_AuthPage"
|
||||||
|
style="background: url("themes/element/img/backgrounds/lake.jpg") center center / cover fixed;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="mx_AuthPage_modal"
|
class="mx_AuthPage_modal"
|
||||||
style="position: relative;"
|
style="position: relative; background: ;"
|
||||||
>
|
>
|
||||||
<main
|
<main
|
||||||
aria-live="polite"
|
aria-live="polite"
|
||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`<LoginSplashView /> Renders a spinner 1`] = `
|
exports[`<LoginSplashView /> > Renders a spinner 1`] = `
|
||||||
<DocumentFragment>
|
<DocumentFragment>
|
||||||
<div
|
<div
|
||||||
class="mx_MatrixChat_splash"
|
class="mx_MatrixChat_splash"
|
||||||
@@ -42,7 +42,7 @@ exports[`<LoginSplashView /> Renders a spinner 1`] = `
|
|||||||
</DocumentFragment>
|
</DocumentFragment>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<LoginSplashView /> Renders an error message 1`] = `
|
exports[`<LoginSplashView /> > Renders an error message 1`] = `
|
||||||
<DocumentFragment>
|
<DocumentFragment>
|
||||||
<div
|
<div
|
||||||
class="mx_MatrixChat_splash"
|
class="mx_MatrixChat_splash"
|
||||||
@@ -8,7 +8,8 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
|
|
||||||
import fetchMock from "@fetch-mock/vitest";
|
import fetchMock from "@fetch-mock/vitest";
|
||||||
import { merge } from "lodash";
|
import { merge } from "lodash";
|
||||||
import { setMissingEntryGenerator, setLanguage } from "@element-hq/web-shared-components";
|
import { setMissingEntryGenerator, setLanguage, I18nApi } from "@element-hq/web-shared-components";
|
||||||
|
import type { ModuleApiType } from "../modules/Api.ts";
|
||||||
|
|
||||||
import enElementWeb from "../i18n/strings/en_EN.json";
|
import enElementWeb from "../i18n/strings/en_EN.json";
|
||||||
import deElementWeb from "../i18n/strings/de_DE.json";
|
import deElementWeb from "../i18n/strings/de_DE.json";
|
||||||
@@ -64,3 +65,6 @@ setupLanguageMock();
|
|||||||
|
|
||||||
setLanguage("en");
|
setLanguage("en");
|
||||||
setMissingEntryGenerator((key) => key.split("|", 2)[1]);
|
setMissingEntryGenerator((key) => key.split("|", 2)[1]);
|
||||||
|
|
||||||
|
// Set up a stub module API (so the i18n API exists)
|
||||||
|
window.mxModuleApi = { i18n: new I18nApi() } as ModuleApiType;
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ import SdkConfig, { DEFAULTS } from "../SdkConfig";
|
|||||||
import "./setupGlobals.ts";
|
import "./setupGlobals.ts";
|
||||||
import { setupLanguageMock } from "./setupLanguage.ts";
|
import { setupLanguageMock } from "./setupLanguage.ts";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
var IS_REACT_ACT_ENVIRONMENT: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
||||||
|
|
||||||
manageFetchMockGlobally();
|
manageFetchMockGlobally();
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ 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.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { vi, expect as viExpect, beforeAll as viBeforeAll, afterAll as viAfterAll } from "vitest";
|
import { vi } from "vitest";
|
||||||
|
import * as vitest from "vitest";
|
||||||
import { mocked as jestMocked } from "jest-mock";
|
import { mocked as jestMocked } from "jest-mock";
|
||||||
|
|
||||||
export const isJest = typeof jest !== "undefined";
|
export const isJest = typeof jest !== "undefined";
|
||||||
@@ -25,9 +26,17 @@ const adapter = {
|
|||||||
const mocked = adapter.mocked;
|
const mocked = adapter.mocked;
|
||||||
export { adapter as vi, mocked };
|
export { adapter as vi, mocked };
|
||||||
|
|
||||||
const _expect = isJest ? (expect as unknown as typeof viExpect) : viExpect;
|
const _expect = isJest ? (expect as unknown as typeof vitest.expect) : vitest.expect;
|
||||||
const _beforeAll = isJest ? (beforeAll as unknown as typeof viBeforeAll) : viBeforeAll;
|
const _beforeAll = isJest ? (beforeAll as unknown as typeof vitest.beforeAll) : vitest.beforeAll;
|
||||||
const _afterAll = isJest ? (afterAll as unknown as typeof viAfterAll) : viAfterAll;
|
const _afterAll = isJest ? (afterAll as unknown as typeof vitest.afterAll) : vitest.afterAll;
|
||||||
export { _expect as expect, _beforeAll as beforeAll, _afterAll as afterAll };
|
const _beforeEach = isJest ? (beforeEach as unknown as typeof vitest.beforeEach) : vitest.beforeEach;
|
||||||
|
const _afterEach = isJest ? (afterEach as unknown as typeof vitest.afterEach) : vitest.afterEach;
|
||||||
|
export {
|
||||||
|
_expect as expect,
|
||||||
|
_beforeAll as beforeAll,
|
||||||
|
_afterAll as afterAll,
|
||||||
|
_beforeEach as beforeEach,
|
||||||
|
_afterEach as afterEach,
|
||||||
|
};
|
||||||
|
|
||||||
export { type Mocked, type MockedObject } from "vitest";
|
export { type Mocked, type MockedObject } from "vitest";
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { type ActionPayload } from "../../src/dispatcher/payloads";
|
|||||||
import defaultDispatcher from "../../src/dispatcher/dispatcher";
|
import defaultDispatcher from "../../src/dispatcher/dispatcher";
|
||||||
import { type DispatcherAction } from "../../src/dispatcher/actions";
|
import { type DispatcherAction } from "../../src/dispatcher/actions";
|
||||||
import Modal from "../../src/Modal";
|
import Modal from "../../src/Modal";
|
||||||
import { vi } from "../setup/adapter.ts";
|
import { vi, beforeEach, afterEach } from "../setup/adapter.ts";
|
||||||
|
|
||||||
export const emitPromise = (e: EventEmitter, k: string | symbol) => new Promise((r) => e.once(k, r));
|
export const emitPromise = (e: EventEmitter, k: string | symbol) => new Promise((r) => e.once(k, r));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user