mirror of
https://github.com/Novaloop-AG/healthchat-web.git
synced 2026-11-04 10:32:44 +00:00
Merge remote-tracking branch 'origin/develop' into dbkr/refactor_createcrosssigningdialog
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { render, screen } from "jest-matrix-react";
|
||||
import { waitFor } from "@testing-library/dom";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { act } from "@testing-library/react-hooks/dom";
|
||||
|
||||
import NewRecoveryMethodDialog from "../../../../../src/async-components/views/dialogs/security/NewRecoveryMethodDialog";
|
||||
import { createTestClient } from "../../../../test-utils";
|
||||
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext.tsx";
|
||||
import dis from "../../../../../src/dispatcher/dispatcher.ts";
|
||||
import { Action } from "../../../../../src/dispatcher/actions.ts";
|
||||
import Modal from "../../../../../src/Modal.tsx";
|
||||
|
||||
describe("<NewRecoveryMethodDialog />", () => {
|
||||
let matrixClient: MatrixClient;
|
||||
beforeEach(() => {
|
||||
matrixClient = createTestClient();
|
||||
jest.spyOn(dis, "fire");
|
||||
jest.spyOn(Modal, "createDialog");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
function renderComponent(onFinished: () => void = jest.fn()) {
|
||||
return render(
|
||||
<MatrixClientContext.Provider value={matrixClient}>
|
||||
<NewRecoveryMethodDialog onFinished={onFinished} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
}
|
||||
|
||||
test("when cancel is clicked", async () => {
|
||||
const onFinished = jest.fn();
|
||||
act(() => {
|
||||
renderComponent(onFinished);
|
||||
});
|
||||
|
||||
await userEvent.click(screen.getByRole("button", { name: "Go to Settings" }));
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
expect(dis.fire).toHaveBeenCalledWith(Action.ViewUserSettings);
|
||||
});
|
||||
|
||||
test("when key backup is enabled", async () => {
|
||||
jest.spyOn(matrixClient.getCrypto()!, "getActiveSessionBackupVersion").mockResolvedValue("version");
|
||||
|
||||
const onFinished = jest.fn();
|
||||
|
||||
await act(async () => {
|
||||
const { asFragment } = renderComponent(onFinished);
|
||||
await waitFor(() =>
|
||||
expect(
|
||||
screen.getByText("This session is encrypting history using the new recovery method."),
|
||||
).toBeInTheDocument(),
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
await userEvent.click(screen.getByRole("button", { name: "Set up Secure Messages" }));
|
||||
expect(onFinished).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("when key backup is disabled", async () => {
|
||||
const onFinished = jest.fn();
|
||||
|
||||
const { asFragment } = renderComponent(onFinished);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
|
||||
await userEvent.click(screen.getByRole("button", { name: "Set up Secure Messages" }));
|
||||
await waitFor(() => expect(Modal.createDialog).toHaveBeenCalled());
|
||||
});
|
||||
});
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<NewRecoveryMethodDialog /> when key backup is disabled 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
data-focus-guard="true"
|
||||
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
|
||||
tabindex="0"
|
||||
/>
|
||||
<div
|
||||
aria-labelledby="mx_BaseDialog_title"
|
||||
class="mx_KeyBackupFailedDialog mx_Dialog_fixedWidth"
|
||||
data-focus-lock-disabled="false"
|
||||
role="dialog"
|
||||
>
|
||||
<div
|
||||
class="mx_Dialog_header"
|
||||
>
|
||||
<h1
|
||||
class="mx_Heading_h3 mx_Dialog_title"
|
||||
id="mx_BaseDialog_title"
|
||||
>
|
||||
<span
|
||||
class="mx_KeyBackupFailedDialog_title"
|
||||
>
|
||||
New Recovery Method
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
<p>
|
||||
A new Security Phrase and key for Secure Messages have been detected.
|
||||
</p>
|
||||
<strong
|
||||
class="warning"
|
||||
>
|
||||
If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.
|
||||
</strong>
|
||||
<div
|
||||
class="mx_Dialog_buttons"
|
||||
>
|
||||
<span
|
||||
class="mx_Dialog_buttons_row"
|
||||
>
|
||||
<button
|
||||
data-testid="dialog-cancel-button"
|
||||
type="button"
|
||||
>
|
||||
Go to Settings
|
||||
</button>
|
||||
<button
|
||||
class="mx_Dialog_primary"
|
||||
data-testid="dialog-primary-button"
|
||||
type="button"
|
||||
>
|
||||
Set up Secure Messages
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
aria-label="Close dialog"
|
||||
class="mx_AccessibleButton mx_Dialog_cancelButton"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
data-focus-guard="true"
|
||||
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
|
||||
tabindex="0"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`<NewRecoveryMethodDialog /> when key backup is enabled 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
data-focus-guard="true"
|
||||
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
|
||||
tabindex="0"
|
||||
/>
|
||||
<div
|
||||
aria-labelledby="mx_BaseDialog_title"
|
||||
class="mx_KeyBackupFailedDialog mx_Dialog_fixedWidth"
|
||||
data-focus-lock-disabled="false"
|
||||
role="dialog"
|
||||
>
|
||||
<div
|
||||
class="mx_Dialog_header"
|
||||
>
|
||||
<h1
|
||||
class="mx_Heading_h3 mx_Dialog_title"
|
||||
id="mx_BaseDialog_title"
|
||||
>
|
||||
<span
|
||||
class="mx_KeyBackupFailedDialog_title"
|
||||
>
|
||||
New Recovery Method
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
<p>
|
||||
A new Security Phrase and key for Secure Messages have been detected.
|
||||
</p>
|
||||
<p>
|
||||
This session is encrypting history using the new recovery method.
|
||||
</p>
|
||||
<strong
|
||||
class="warning"
|
||||
>
|
||||
If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.
|
||||
</strong>
|
||||
<div
|
||||
class="mx_Dialog_buttons"
|
||||
>
|
||||
<span
|
||||
class="mx_Dialog_buttons_row"
|
||||
>
|
||||
<button
|
||||
data-testid="dialog-cancel-button"
|
||||
type="button"
|
||||
>
|
||||
Go to Settings
|
||||
</button>
|
||||
<button
|
||||
class="mx_Dialog_primary"
|
||||
data-testid="dialog-primary-button"
|
||||
type="button"
|
||||
>
|
||||
Set up Secure Messages
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
aria-label="Close dialog"
|
||||
class="mx_AccessibleButton mx_Dialog_cancelButton"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
data-focus-guard="true"
|
||||
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
|
||||
tabindex="0"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
@@ -22,7 +22,7 @@ import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { OidcError } from "matrix-js-sdk/src/oidc/error";
|
||||
import { BearerTokenResponse } from "matrix-js-sdk/src/oidc/validate";
|
||||
import { defer, IDeferred, sleep } from "matrix-js-sdk/src/utils";
|
||||
import { UserVerificationStatus } from "matrix-js-sdk/src/crypto-api";
|
||||
import { CryptoEvent, UserVerificationStatus } from "matrix-js-sdk/src/crypto-api";
|
||||
|
||||
import MatrixChat from "../../../../src/components/structures/MatrixChat";
|
||||
import * as StorageAccess from "../../../../src/utils/StorageAccess";
|
||||
@@ -137,6 +137,7 @@ describe("<MatrixChat />", () => {
|
||||
userHasCrossSigningKeys: jest.fn(),
|
||||
// This needs to not finish immediately because we need to test the screen appears
|
||||
bootstrapCrossSigning: jest.fn().mockImplementation(() => bootstrapDeferred.promise),
|
||||
getActiveSessionBackupVersion: jest.fn().mockResolvedValue(null),
|
||||
}),
|
||||
secretStorage: {
|
||||
isStored: jest.fn().mockReturnValue(null),
|
||||
@@ -1515,4 +1516,22 @@ describe("<MatrixChat />", () => {
|
||||
expect(screen.getByTestId("mobile-register")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when key backup failed", () => {
|
||||
it("should show the new recovery method dialog", async () => {
|
||||
jest.mock("../../../../src/async-components/views/dialogs/security/NewRecoveryMethodDialog", () => ({
|
||||
__esModule: true,
|
||||
default: () => <span>mocked dialog</span>,
|
||||
}));
|
||||
jest.spyOn(mockClient.getCrypto()!, "getActiveSessionBackupVersion").mockResolvedValue("version");
|
||||
|
||||
getComponent({});
|
||||
defaultDispatcher.dispatch({
|
||||
action: "will_start_client",
|
||||
});
|
||||
await flushPromises();
|
||||
mockClient.emit(CryptoEvent.KeyBackupFailed, "error code");
|
||||
await waitFor(() => expect(screen.getByText("mocked dialog")).toBeInTheDocument());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,7 +10,10 @@ import React from "react";
|
||||
import fetchMock from "fetch-mock-jest";
|
||||
import { render, screen, waitForElementToBeRemoved } from "jest-matrix-react";
|
||||
|
||||
import ChangelogDialog from "../../../../../src/components/views/dialogs/ChangelogDialog";
|
||||
import ChangelogDialog, {
|
||||
DevelopVersionString,
|
||||
parseVersion,
|
||||
} from "../../../../../src/components/views/dialogs/ChangelogDialog";
|
||||
|
||||
describe("<ChangelogDialog />", () => {
|
||||
it("should fetch github proxy url for each repo with old and new version strings", async () => {
|
||||
@@ -64,8 +67,8 @@ describe("<ChangelogDialog />", () => {
|
||||
files: [],
|
||||
});
|
||||
|
||||
const newVersion = "newsha1-js-newsha3";
|
||||
const oldVersion = "oldsha1-js-oldsha3";
|
||||
const newVersion = "newsha1-js-newsha3" as DevelopVersionString;
|
||||
const oldVersion = "oldsha1-js-oldsha3" as DevelopVersionString;
|
||||
const { asFragment } = render(
|
||||
<ChangelogDialog newVersion={newVersion} version={oldVersion} onFinished={jest.fn()} />,
|
||||
);
|
||||
@@ -78,3 +81,24 @@ describe("<ChangelogDialog />", () => {
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseVersion", () => {
|
||||
it("should return null for old-style version strings", () => {
|
||||
expect(parseVersion("aaaabbbb-react-ccccdddd-js-eeeeffff")).toBeNull();
|
||||
});
|
||||
|
||||
it("should return null for invalid version strings", () => {
|
||||
expect(parseVersion("aaaabbbb-react-ccccdddd")).toBeNull();
|
||||
});
|
||||
|
||||
it("should return null for release version strings", () => {
|
||||
expect(parseVersion("v1.22.33")).toBeNull();
|
||||
});
|
||||
|
||||
it("should return mapping for develop version string", () => {
|
||||
expect(parseVersion("aaaabbbb-js-eeeeffff")).toEqual({
|
||||
"element-hq/element-web": "aaaabbbb",
|
||||
"matrix-org/matrix-js-sdk": "eeeeffff",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,19 +7,24 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import {
|
||||
EventTimeline,
|
||||
EventTimelineSet,
|
||||
EventType,
|
||||
IRoomEvent,
|
||||
MatrixClient,
|
||||
MatrixEvent,
|
||||
MsgType,
|
||||
Relations,
|
||||
RelationType,
|
||||
Room,
|
||||
RoomMember,
|
||||
RoomState,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import fetchMock from "fetch-mock-jest";
|
||||
import escapeHtml from "escape-html";
|
||||
import { RelationsContainer } from "matrix-js-sdk/src/models/relations-container";
|
||||
|
||||
import { filterConsole, mkStubRoom, REPEATABLE_DATE, stubClient } from "../../../test-utils";
|
||||
import { filterConsole, mkReaction, mkStubRoom, REPEATABLE_DATE, stubClient } from "../../../test-utils";
|
||||
import { ExportType, IExportOptions } from "../../../../src/utils/exportUtils/exportUtils";
|
||||
import SdkConfig from "../../../../src/SdkConfig";
|
||||
import HTMLExporter from "../../../../src/utils/exportUtils/HtmlExport";
|
||||
@@ -123,6 +128,35 @@ describe("HTMLExport", () => {
|
||||
fetchMock.get(media.srcHttp!, body);
|
||||
}
|
||||
|
||||
function mockReactionForMessage(message: IRoomEvent): MatrixEvent {
|
||||
const firstMessage = new MatrixEvent(message);
|
||||
const reaction = mkReaction(firstMessage);
|
||||
|
||||
const relationsContainer = {
|
||||
getRelations: jest.fn(),
|
||||
getChildEventsForEvent: jest.fn(),
|
||||
} as unknown as RelationsContainer;
|
||||
const relations = new Relations(RelationType.Annotation, EventType.Reaction, client);
|
||||
relations.addEvent(reaction);
|
||||
relationsContainer.getChildEventsForEvent = jest
|
||||
.fn()
|
||||
.mockImplementation(
|
||||
(eventId: string, relationType: RelationType | string, eventType: EventType | string) => {
|
||||
if (eventId === firstMessage.getId()) {
|
||||
return relations;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const timelineSet = {
|
||||
relations: relationsContainer,
|
||||
getLiveTimeline: () => timeline,
|
||||
} as unknown as EventTimelineSet;
|
||||
const timeline = new EventTimeline(timelineSet);
|
||||
room.getUnfilteredTimelineSet = jest.fn().mockReturnValue(timelineSet);
|
||||
return reaction;
|
||||
}
|
||||
|
||||
it("should throw when created with invalid config for LastNMessages", async () => {
|
||||
expect(
|
||||
() =>
|
||||
@@ -167,6 +201,7 @@ describe("HTMLExport", () => {
|
||||
body: `Message #${i}`,
|
||||
},
|
||||
}));
|
||||
mockReactionForMessage(events[0]);
|
||||
mockMessages(...events);
|
||||
|
||||
const exporter = new HTMLExporter(
|
||||
@@ -587,4 +622,24 @@ describe("HTMLExport", () => {
|
||||
expect(await file.text()).toContain("testing testing");
|
||||
expect(client.createMessagesRequest).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should include reactions", async () => {
|
||||
const reaction = mockReactionForMessage(EVENT_MESSAGE);
|
||||
mockMessages(EVENT_MESSAGE);
|
||||
const exporter = new HTMLExporter(
|
||||
room,
|
||||
ExportType.LastNMessages,
|
||||
{
|
||||
attachmentsIncluded: false,
|
||||
maxSize: 1_024 * 1_024,
|
||||
numberOfMessages: 40,
|
||||
},
|
||||
() => {},
|
||||
);
|
||||
|
||||
await exporter.export();
|
||||
|
||||
const file = getMessageFile(exporter);
|
||||
expect(await file.text()).toContain(reaction.getContent()["m.relates_to"]?.key);
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user