Merge branch 'develop' into langleyd/room-list-view-to-shared-components-split

This commit is contained in:
David Langley 2026-01-30 10:31:55 +00:00 committed by GitHub
commit 0f05706446
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 516 additions and 166 deletions

1
.github/CODEOWNERS vendored
View File

@ -16,6 +16,7 @@
/src/components/views/dialogs/devtools/Crypto.tsx @element-hq/element-crypto-web-reviewers
/playwright/e2e/crypto/ @element-hq/element-crypto-web-reviewers
/playwright/e2e/settings/encryption-user-tab/ @element-hq/element-crypto-web-reviewers
/packages/shared-components/src/crypto/ @element-hq/element-crypto-web-reviewers
/src/models/Call.ts @element-hq/element-call-reviewers

View File

@ -90,7 +90,6 @@
"@matrix-org/analytics-events": "^0.31.0",
"@matrix-org/emojibase-bindings": "^1.5.0",
"@matrix-org/react-sdk-module-api": "^2.4.0",
"@matrix-org/spec": "^1.7.0",
"@sentry/browser": "^10.0.0",
"@types/png-chunks-extract": "^1.0.2",
"@vector-im/compound-design-tokens": "6.9.0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -50,6 +50,7 @@
},
"dependencies": {
"@element-hq/element-web-module-api": "^1.8.0",
"@matrix-org/spec": "^1.7.0",
"@vector-im/compound-design-tokens": "^6.4.3",
"classnames": "^2.5.1",
"counterpart": "^0.18.6",

View File

@ -0,0 +1,33 @@
/*
* Copyright 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
.container {
display: flex;
flex-wrap: wrap;
gap: var(--cpd-space-2x);
justify-content: space-evenly;
}
.segment {
display: inline-block;
margin-bottom: var(--cpd-space-4x);
text-align: center;
/* Allow maximum 4 per line, accounting for 8px gap */
min-width: calc(25% - 8px);
}
.emoji {
/* Use the Twemoji font for consistency with other clients */
font-family: Twemoji, var(--cpd-font-family-sans);
font-size: var(--cpd-font-size-heading-xl);
}
.label {
font-weight: var(--cpd-font-weight-regular);
font-size: var(--cpd-font-size-body-lg);
color: var(--cpd-color-text-secondary);
}

View File

@ -0,0 +1,48 @@
/*
Copyright 2026 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { type Meta, type StoryObj } from "@storybook/react-vite";
import { SasEmoji } from "./SasEmoji";
const meta = {
title: "Crypto/SasEmoji",
component: SasEmoji,
tags: ["autodocs"],
args: {
emoji: ["🍕", "🌽", "🚀", "🔒", "🔧", "🍓", "⌛"],
},
parameters: {
design: {
type: "figma",
url: "https://www.figma.com/design/XLWIAB5n8yObYvU0INKPK1/Verification-by-Emoji?node-id=1-2935&t=NrV9JnuItrAyyh53-4",
},
},
} satisfies Meta<typeof SasEmoji>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {};
export const WorstCaseAlbanian: Story = {
globals: {
language: "sq",
},
args: {
emoji: ["🎅", "🎅", "🎅", "🎅", "🎅", "🎅", "🎅"],
},
};
export const WorstCaseGerman: Story = {
globals: {
language: "de",
},
args: {
emoji: ["🔧", "🔧", "🔧", "🔧", "🔧", "🔧", "🔧"],
},
};

View File

@ -0,0 +1,19 @@
/*
Copyright 2026 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import React from "react";
import { describe, it, expect } from "vitest";
import { render } from "@test-utils";
import { SasEmoji } from "./SasEmoji";
describe("<SasEmoji/>", () => {
it("should match snapshot", () => {
const { asFragment } = render(<SasEmoji emoji={["🦋", "🍄", "⚽", "🌏", "🦄", "🚀", "🔧"]} />);
expect(asFragment()).toMatchSnapshot();
});
});

View File

@ -0,0 +1,43 @@
/*
* Copyright 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
import React, { type JSX } from "react";
import classNames from "classnames";
import { type SasEmoji, tEmoji } from "./SasEmojiTranslate.ts";
import styles from "./SasEmoji.module.css";
import { useI18n } from "../../utils/i18nContext.ts";
export type Props = {
/**
* The emoji to render
*/
emoji: [SasEmoji, SasEmoji, SasEmoji, SasEmoji, SasEmoji, SasEmoji, SasEmoji];
/**
* Optional className to apply to the container
*/
className?: string;
};
/**
* Renders the 7 emoji used for SAS verification.
* The component is responsive so can be rendered in any context, dialog, side panel.
*/
export function SasEmoji({ emoji, className }: Props): JSX.Element {
const { language } = useI18n();
const emojiBlocks = emoji.map((emoji, i) => (
<div className={styles.segment} key={i}>
<div className={styles.emoji} aria-hidden={true}>
{emoji}
</div>
<div className={styles.label}>{tEmoji(emoji, language)}</div>
</div>
));
return <div className={classNames(styles.container, className)}>{emojiBlocks}</div>;
}

View File

@ -0,0 +1,26 @@
/*
Copyright 2026 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { describe, it, expect } from "vitest";
import { tEmoji, type SasEmoji } from "./SasEmojiTranslate.ts";
describe("tEmoji", () => {
it.each([
["🐶", "en-GB", "Dog"],
["🐶", "en", "Dog"],
["🐶", "de-DE", "Hund"],
["🐶", "pt", "Cachorro"],
["🔧", "de-DE", "Schraubenschlüssel"],
["🎅", "sq", "Babagjyshi i Vitit të Ri"],
] as [emoji: SasEmoji, locale: string, expectation: string][])(
"should handle locale %s",
(emoji, locale, expectation) => {
expect(tEmoji(emoji, locale)).toEqual(expectation);
},
);
});

View File

@ -0,0 +1,122 @@
/*
* Copyright 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
import SasEmojiJson from "@matrix-org/spec/sas-emoji.json";
import { getNormalizedLanguageKeys } from "matrix-web-i18n";
// Type as specified in https://spec.matrix.org/v1.17/client-server-api/#sas-method-emoji
export type SasEmoji =
| "🐶"
| "🐱"
| "🦁"
| "🐎"
| "🦄"
| "🐷"
| "🐘"
| "🐰"
| "🐼"
| "🐓"
| "🐧"
| "🐢"
| "🐟"
| "🐙"
| "🦋"
| "🌷"
| "🌳"
| "🌵"
| "🍄"
| "🌏"
| "🌙"
| "☁"
| "🔥"
| "🍌"
| "🍎"
| "🍓"
| "🌽"
| "🍕"
| "🎂"
| "❤"
| "😀"
| "🤖"
| "🎩"
| "👓"
| "🔧"
| "🎅"
| "👍"
| "☂"
| "⌛"
| "⏰"
| "🎁"
| "💡"
| "📕"
| "✏"
| "📎"
| "✂"
| "🔒"
| "🔑"
| "🔨"
| "☎"
| "🏁"
| "🚂"
| "🚲"
| "✈"
| "🚀"
| "🏆"
| "⚽"
| "🎸"
| "🎺"
| "🔔"
| "⚓"
| "🎧"
| "📁"
| "📌";
const SasEmojiMap = new Map<
SasEmoji,
[
description: string,
translations: {
[normalizedLanguageKey: string]: string;
},
]
>(
SasEmojiJson.map(({ emoji, description, translated_descriptions: translations }) => [
emoji as SasEmoji,
[
description,
// Normalize the translation keys
Object.keys(translations).reduce<Record<string, string>>((o, k) => {
for (const key of getNormalizedLanguageKeys(k)) {
o[key] = translations[k as keyof typeof translations]!;
}
return o;
}, {}),
],
]),
);
/**
* Translate given SAS emoji into the target locale
* @param emoji - the SAS emoji to translate
* @param locale - the BCP 47 locale to translate to, will fall back to English as the base locale for Matrix SAS Emoji.
*/
export function tEmoji(emoji: SasEmoji, locale: string): string {
const mapping = SasEmojiMap.get(emoji);
if (!mapping) {
throw new Error(`Emoji mapping not found for emoji ${emoji}`);
}
const [description, translations] = mapping;
for (const key of getNormalizedLanguageKeys(locale)) {
if (translations[key]) {
return translations[key];
}
}
return description;
}

View File

@ -0,0 +1,115 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`<SasEmoji/> > should match snapshot 1`] = `
<DocumentFragment>
<div
class="container"
>
<div
class="segment"
>
<div
aria-hidden="true"
class="emoji"
>
🦋
</div>
<div
class="label"
>
Butterfly
</div>
</div>
<div
class="segment"
>
<div
aria-hidden="true"
class="emoji"
>
🍄
</div>
<div
class="label"
>
Mushroom
</div>
</div>
<div
class="segment"
>
<div
aria-hidden="true"
class="emoji"
>
</div>
<div
class="label"
>
Ball
</div>
</div>
<div
class="segment"
>
<div
aria-hidden="true"
class="emoji"
>
🌏
</div>
<div
class="label"
>
Globe
</div>
</div>
<div
class="segment"
>
<div
aria-hidden="true"
class="emoji"
>
🦄
</div>
<div
class="label"
>
Unicorn
</div>
</div>
<div
class="segment"
>
<div
aria-hidden="true"
class="emoji"
>
🚀
</div>
<div
class="label"
>
Rocket
</div>
</div>
<div
class="segment"
>
<div
aria-hidden="true"
class="emoji"
>
🔧
</div>
<div
class="label"
>
Spanner
</div>
</div>
</div>
</DocumentFragment>
`;

View File

@ -0,0 +1,8 @@
/*
* Copyright 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
export { SasEmoji } from "./SasEmoji.tsx";

View File

@ -43,12 +43,15 @@
}
},
"room_list": {
"appearance": "Megjelenítés",
"open_space_menu": "Tér menü megnyitása",
"room_options": "Szobabeállítások",
"show_message_previews": "Üzenetelőnézetek megjelenítése",
"sort": "Rendezés",
"sort_type": {
"activity": "Tevékenység",
"atoz": "AZ"
"atoz": "AZ",
"unread_first": "Olvasatlan elöl"
},
"space_menu": {
"home": "Kezdő tér",

View File

@ -12,6 +12,7 @@ export * from "./audio/PlayPauseButton";
export * from "./audio/SeekBar";
export * from "./avatar/AvatarWithDetails";
export * from "./composer/Banner";
export * from "./crypto/SasEmoji";
export * from "./event-tiles/TextualEventView";
export * from "./message-body/MediaBody";
export * from "./pill-input/Pill";

View File

@ -667,6 +667,11 @@
dependencies:
"@babel/runtime" "^7.17.9"
"@matrix-org/spec@^1.7.0":
version "1.16.0"
resolved "https://registry.yarnpkg.com/@matrix-org/spec/-/spec-1.16.0.tgz#c88f4ed521e4c0bd3a4c108bcaf13f25173a0fdc"
integrity sha512-xUKHkwGXXISMCfTrx6JW6uGEK5O8IeZVOjBm7FX1h/ihpK6l50nlSIMRYdtz4V6q3pvOVBOCft4hPYTJVeTZDA==
"@mdx-js/react@^3.0.0":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-3.1.1.tgz#24bda7fffceb2fe256f954482123cda1be5f5fef"

View File

@ -290,7 +290,7 @@ export async function doTwoWaySasVerification(page: Page, verifier: JSHandle<Ver
// on the bot side, wait for the emojis, confirm they match, and return them
const emojis = await handleSasVerification(verifier);
const emojiBlocks = page.locator(".mx_VerificationShowSas_emojiSas_block");
const emojiBlocks = page.locator(".mx_VerificationShowSas_emojiSas > div");
await expect(emojiBlocks).toHaveCount(emojis.length);
// then, check that our application shows an emoji panel with the same emojis.

View File

@ -10,7 +10,7 @@ import {
type StartedPostgreSqlContainer,
} from "@element-hq/element-web-playwright-common/lib/testcontainers";
const TAG = "main@sha256:a3d8276ff5878ce109f184fd2f0e27fc50e1cb4ec409ad5217022074b19a7fd9";
const TAG = "main@sha256:d0d03f9067c7977807131a9c739c9ed9f081063d1a1c21bee66204e40c44aa50";
/**
* MatrixAuthenticationServiceContainer which freezes the docker digest to

View File

@ -20,40 +20,9 @@ Please see LICENSE files in the repository root for full details.
}
.mx_VerificationShowSas_emojiSas {
text-align: center;
display: flex;
flex-wrap: wrap;
justify-content: center;
margin: 25px 0;
}
.mx_VerificationShowSas_emojiSas_block {
display: inline-block;
margin-bottom: 16px;
position: relative;
width: 52px;
}
.mx_Dialog .mx_VerificationShowSas_emojiSas_block,
.mx_AuthPage_modal .mx_VerificationShowSas_emojiSas_block {
width: 60px;
}
.mx_VerificationShowSas_emojiSas_emoji {
font-size: $font-32px;
/* Use the Twemoji font for consistency with other clients */
font-family: Twemoji, var(--cpd-font-family-sans);
}
.mx_VerificationShowSas_emojiSas_label {
font-size: $font-12px;
word-break: break-word;
}
.mx_VerificationShowSas_emojiSas_break {
flex-basis: 100%;
}
.mx_VerificationShowSas_buttonRow {
text-align: center;
display: flex;

View File

@ -22,7 +22,7 @@ import { HistoryVisibility, JoinRule, type Room } from "matrix-js-sdk/src/matrix
import { type ViewRoomOpts } from "@matrix-org/react-sdk-module-api/lib/lifecycles/RoomViewLifecycle";
import { Flex, Box } from "@element-hq/web-shared-components";
import { CallType } from "matrix-js-sdk/src/webrtc/call";
import { HistoryIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { HistoryIcon, UserProfileSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { useRoomName } from "../../../../hooks/useRoomName.ts";
import { RightPanelPhases } from "../../../../stores/right-panel/RightPanelStorePhases.ts";
@ -391,6 +391,40 @@ function RoomHeaderButtons({
);
}
/** Create an icon to warn the user about shared history visibility, in encrypted rooms.
*
* Note that we use the same icon as in the room summary card and elsewhere, to aid user recognition.
*/
function historyVisibilityIcon(historyVisibility: HistoryVisibility): JSX.Element | null {
if (historyVisibility === HistoryVisibility.Shared) {
return (
<Tooltip label={_t("room|header|shared_history_tooltip")} placement="right">
<HistoryIcon
width="16px"
height="16px"
className="mx_RoomHeader_icon"
color="var(--cpd-color-icon-info-primary)"
aria-label={_t("room|header|shared_history_tooltip")}
/>
</Tooltip>
);
} else if (historyVisibility === HistoryVisibility.WorldReadable) {
return (
<Tooltip label={_t("room|header|world_readable_history_tooltip")} placement="right">
<UserProfileSolidIcon
width="16px"
height="16px"
className="mx_RoomHeader_icon"
color="var(--cpd-color-icon-info-primary)"
aria-label={_t("room|header|world_readable_history_tooltip")}
/>
</Tooltip>
);
} else {
return null;
}
}
export default function RoomHeader({
room,
additionalButtons,
@ -490,20 +524,7 @@ export default function RoomHeader({
</Tooltip>
)}
{isRoomEncrypted &&
historySharingEnabled &&
(historyVisibility === HistoryVisibility.Shared ||
historyVisibility === HistoryVisibility.WorldReadable) && (
<Tooltip label={_t("room|header|shared_history_tooltip")} placement="right">
<HistoryIcon
width="16px"
height="16px"
className="mx_RoomHeader_icon"
color="var(--cpd-color-icon-info-primary)"
aria-label={_t("room|header|shared_history_tooltip")}
/>
</Tooltip>
)}
{isRoomEncrypted && historySharingEnabled && historyVisibilityIcon(historyVisibility)}
</Text>
</Box>
</button>

View File

@ -6,12 +6,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.
*/
import React from "react";
import React, { type ComponentProps } from "react";
import { type Device } from "matrix-js-sdk/src/matrix";
import { type GeneratedSas, type EmojiMapping } from "matrix-js-sdk/src/crypto-api";
import SasEmoji from "@matrix-org/spec/sas-emoji.json";
import { type GeneratedSas } from "matrix-js-sdk/src/crypto-api";
import { SasEmoji } from "@element-hq/web-shared-components";
import { _t, getNormalizedLanguageKeys, getUserLanguage } from "../../../languageHandler";
import { _t } from "../../../languageHandler";
import { PendingActionSpinner } from "../right_panel/EncryptionInfo";
import AccessibleButton from "../elements/AccessibleButton";
@ -34,52 +34,6 @@ interface IState {
cancelling?: boolean;
}
const SasEmojiMap = new Map<
string, // lowercase
{
description: string;
translations: {
[normalizedLanguageKey: string]: string;
};
}
>(
SasEmoji.map(({ description, translated_descriptions: translations }) => [
description.toLowerCase(),
{
description,
// Normalize the translation keys
translations: Object.keys(translations).reduce<Record<string, string>>((o, k) => {
for (const key of getNormalizedLanguageKeys(k)) {
o[key] = translations[k as keyof typeof translations]!;
}
return o;
}, {}),
},
]),
);
/**
* Translate given EmojiMapping into the target locale
* @param mapping - the given EmojiMapping to translate
* @param locale - the BCP 47 locale to translate to, will fall back to English as the base locale for Matrix SAS Emoji.
*/
export function tEmoji(mapping: EmojiMapping, locale: string): string {
const name = mapping[1];
const emoji = SasEmojiMap.get(name.toLowerCase());
if (!emoji) {
console.warn("Emoji not found for translation", name);
return name;
}
for (const key of getNormalizedLanguageKeys(locale)) {
if (!!emoji.translations[key]) {
return emoji.translations[key];
}
}
return emoji.description;
}
export default class VerificationShowSas extends React.Component<IProps, IState> {
public constructor(props: IProps) {
super(props);
@ -100,25 +54,14 @@ export default class VerificationShowSas extends React.Component<IProps, IState>
};
public render(): React.ReactNode {
const locale = getUserLanguage();
let sasDisplay;
let sasCaption;
if (this.props.sas.emoji) {
const emojiBlocks = this.props.sas.emoji.map((emoji, i) => (
<div className="mx_VerificationShowSas_emojiSas_block" key={i}>
<div className="mx_VerificationShowSas_emojiSas_emoji" aria-hidden={true}>
{emoji[0]}
</div>
<div className="mx_VerificationShowSas_emojiSas_label">{tEmoji(emoji, locale)}</div>
</div>
));
sasDisplay = (
<div className="mx_VerificationShowSas_emojiSas">
{emojiBlocks.slice(0, 4)}
<div className="mx_VerificationShowSas_emojiSas_break" />
{emojiBlocks.slice(4)}
</div>
<SasEmoji
className="mx_VerificationShowSas_emojiSas"
emoji={this.props.sas.emoji.map((e) => e[0]) as ComponentProps<typeof SasEmoji>["emoji"]}
/>
);
sasCaption = this.props.isSelf
? _t("encryption|verification|confirm_the_emojis")

View File

@ -2020,7 +2020,8 @@
"other": "%(count)s people asking to join"
},
"room_is_public": "This room is public",
"shared_history_tooltip": "New members see history"
"shared_history_tooltip": "New members see history",
"world_readable_history_tooltip": "Anyone can see history"
},
"header_avatar_open_settings_label": "Open room settings",
"header_face_pile_tooltip": "People",

View File

@ -2017,7 +2017,8 @@
"Csatlakozást kér": "one",
"%(count)s csatlakozást kérő ember": "other"
},
"room_is_public": "Ez egy nyilvános szoba"
"room_is_public": "Ez egy nyilvános szoba",
"shared_history_tooltip": "Az új tagok látják az előzményeket"
},
"header_avatar_open_settings_label": "Szobabeállítások megnyitása",
"header_face_pile_tooltip": "Taglista váltása",

View File

@ -1,23 +0,0 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2023 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { type EmojiMapping } from "matrix-js-sdk/src/crypto-api";
import { tEmoji } from "../../../../src/components/views/verification/VerificationShowSas";
describe("tEmoji", () => {
it.each([
["en-GB", "Dog"],
["en", "Dog"],
["de-DE", "Hund"],
["pt", "Cachorro"],
])("should handle locale %s", (locale, expectation) => {
const emoji: EmojiMapping = ["🐶", "Dog"];
expect(tEmoji(emoji, locale)).toEqual(expectation);
});
});

View File

@ -34,7 +34,7 @@ describe("IncomingSasDialog", () => {
it("should show some emojis once keys are exchanged", () => {
const mockVerifier = makeMockVerifier();
const { container } = renderComponent(mockVerifier);
const { getAllByText } = renderComponent(mockVerifier);
// fire the ShowSas event
const sasEvent = makeMockSasCallbacks();
@ -42,11 +42,8 @@ describe("IncomingSasDialog", () => {
mockVerifier.emit(VerifierEvent.ShowSas, sasEvent);
});
const emojis = container.getElementsByClassName("mx_VerificationShowSas_emojiSas_block");
expect(emojis.length).toEqual(7);
for (const emoji of emojis) {
expect(emoji).toHaveTextContent("🦄Unicorn");
}
expect(getAllByText("🦄")).toHaveLength(7);
expect(getAllByText("Unicorn")).toHaveLength(7);
});
});

View File

@ -456,41 +456,38 @@ exports[`VerificationRequestDialog When other device accepted emoji, displays em
Confirm that the emojis below match those shown on your other device.
</p>
<div
class="mx_VerificationShowSas_emojiSas"
class="_container_1lqqy_8 mx_VerificationShowSas_emojiSas"
>
<div
class="mx_VerificationShowSas_emojiSas_block"
class="_segment_1lqqy_15"
>
<div
aria-hidden="true"
class="mx_VerificationShowSas_emojiSas_emoji"
class="_emoji_1lqqy_23"
>
🐶
</div>
<div
class="mx_VerificationShowSas_emojiSas_label"
class="_label_1lqqy_29"
>
Dog
</div>
</div>
<div
class="mx_VerificationShowSas_emojiSas_block"
class="_segment_1lqqy_15"
>
<div
aria-hidden="true"
class="mx_VerificationShowSas_emojiSas_emoji"
class="_emoji_1lqqy_23"
>
🐱
</div>
<div
class="mx_VerificationShowSas_emojiSas_label"
class="_label_1lqqy_29"
>
Cat
</div>
</div>
<div
class="mx_VerificationShowSas_emojiSas_break"
/>
</div>
<p />
<div

View File

@ -105,7 +105,7 @@ describe("<VerificationPanel />", () => {
});
it("should show some emojis once keys are exchanged", () => {
const { container } = renderComponent({
const { getAllByText } = renderComponent({
request: mockRequest,
phase: Phase.Started,
});
@ -117,11 +117,8 @@ describe("<VerificationPanel />", () => {
mockVerifier.emit(VerifierEvent.ShowSas, sasEvent);
});
const emojis = container.getElementsByClassName("mx_VerificationShowSas_emojiSas_block");
expect(emojis.length).toEqual(7);
for (const emoji of emojis) {
expect(emoji).toHaveTextContent("🦄Unicorn");
}
expect(getAllByText("🦄")).toHaveLength(7);
expect(getAllByText("Unicorn")).toHaveLength(7);
});
describe("'Verify own device' flow", () => {

View File

@ -744,6 +744,29 @@ describe("RoomHeader", () => {
expect(queryByLabelText(document.body, "New members see history")).not.toBeInTheDocument();
});
it("shows a user icon if the room is encrypted and has world readable history", async () => {
mocked(client.getCrypto()!).isEncryptionEnabledInRoom.mockResolvedValue(true);
await room.addLiveEvents(
[
new MatrixEvent({
type: "m.room.history_visibility",
content: { history_visibility: "world_readable" },
sender: MatrixClientPeg.get()!.getSafeUserId(),
state_key: "",
room_id: room.roomId,
}),
],
{ addToState: true },
);
const featureEnabled = true;
jest.spyOn(SettingsStore, "getValue").mockImplementation(
(flag) => flag === "feature_share_history_on_invite" && featureEnabled,
);
render(<RoomHeader room={room} />, getWrapper());
await waitFor(() => getByLabelText(document.body, "Anyone can see history"));
});
describe("dm", () => {
beforeEach(() => {
// Make the mocked room a DM

View File

@ -56,7 +56,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
style="--cpd-icon-button-size: 100%;"
>
<svg
aria-labelledby="_r_134_"
aria-labelledby="_r_13s_"
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
@ -83,7 +83,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
style="--cpd-icon-button-size: 100%;"
>
<svg
aria-labelledby="_r_139_"
aria-labelledby="_r_141_"
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
@ -98,7 +98,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
</button>
<button
aria-label="Threads"
aria-labelledby="_r_13e_"
aria-labelledby="_r_146_"
class="_icon-button_1215g_8"
data-kind="primary"
role="button"
@ -125,7 +125,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
</button>
<button
aria-label="Room info"
aria-labelledby="_r_13j_"
aria-labelledby="_r_14b_"
class="_icon-button_1215g_8"
data-kind="primary"
role="button"