Fix React hydration issues (#32958)

* Add more playwright axe tests to settings dialogs

* Add utility to jest setupTests to detect React hydration errors

* Iterate jest utility

* Fix axe issue heading-order

* Fix div-in-p issues

* Fix setupTests.ts

* Fix heading order

* Make types happier

* Fix hydration issues of thead containing text nodes

* Update tests

* Fix form-in-form React hydration issues

* Fix li-in-li React hydration issues

* Fix checked in form without onChange React hydration issue

* Fix styling bleeding from _common.pcss

* Update snapshots

* Fix more remaining issues

* Remove _common.pcss h2 rule altogether

* Fix test

* Update snapshots

* Iterate

* Iterate

* Update snapshots

* Simplify diff

* Test

* Update screenshots

* Update screenshot
This commit is contained in:
Michael Telatynski
2026-04-16 14:35:40 +01:00
committed by GitHub
parent d7f5546294
commit 30f442208a
62 changed files with 2652 additions and 2579 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 KiB

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

-12
View File
@@ -834,18 +834,6 @@ legend {
} }
} }
@define-mixin ButtonResetDefault {
appearance: none;
background: none;
border: none;
padding: 0;
margin: 0;
font-size: inherit;
font-family: inherit;
line-height: inherit;
cursor: pointer;
}
@define-mixin LegacyCallButton { @define-mixin LegacyCallButton {
box-sizing: border-box; box-sizing: border-box;
font-weight: var(--cpd-font-weight-semibold); font-weight: var(--cpd-font-weight-semibold);
@@ -13,8 +13,7 @@ Please see LICENSE files in the repository root for full details.
top: 0; top: 0;
} }
.mx_ShareDialogButtons_button { button.mx_ShareDialogButtons_button {
@mixin ButtonResetDefault;
height: 24px; height: 24px;
width: 24px; width: 24px;
border-radius: 50%; border-radius: 50%;
@@ -9,6 +9,19 @@ Please see LICENSE files in the repository root for full details.
.mx_AccessibleButton { .mx_AccessibleButton {
cursor: pointer; cursor: pointer;
&:where(button) {
/* Clear default button styling */
appearance: none;
background: none;
border: none;
padding: 0;
margin: 0;
font-size: inherit;
font-family: inherit;
line-height: inherit;
box-sizing: content-box;
}
&.mx_AccessibleButton_disabled { &.mx_AccessibleButton_disabled {
cursor: not-allowed; cursor: not-allowed;
@@ -28,7 +28,6 @@ Please see LICENSE files in the repository root for full details.
/* using em here to adapt to the local font size */ /* using em here to adapt to the local font size */
width: 1em; width: 1em;
height: 1em; height: 1em;
cursor: pointer;
padding-left: 12px; padding-left: 12px;
padding-right: 10px; padding-right: 10px;
display: block; display: block;
@@ -12,12 +12,6 @@ Please see LICENSE files in the repository root for full details.
gap: 32px; gap: 32px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
> form {
gap: 32px;
display: flex;
flex-direction: column;
}
} }
.mx_SettingsSubsection_description { .mx_SettingsSubsection_description {
@@ -14,12 +14,13 @@ Please see LICENSE files in the repository root for full details.
color: $links; color: $links;
} }
form:not(.mx_EncryptionUserSettingsTab form) { form {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: $spacing-8; gap: var(--cpd-space-3x);
flex-grow: 1; flex-grow: 1;
} }
// never want full width buttons // never want full width buttons
// event when other content is 100% width // event when other content is 100% width
.mx_AccessibleButton { .mx_AccessibleButton {
@@ -184,6 +184,10 @@ const Tile: React.FC<ITileProps> = ({
aria-labelledby={checkboxLabelId} aria-labelledby={checkboxLabelId}
checked={!!selected} checked={!!selected}
tabIndex={-1} tabIndex={-1}
onChange={(e) => {
e.stopPropagation();
onToggleClick();
}}
/> />
); );
} else { } else {
@@ -311,9 +315,9 @@ const Tile: React.FC<ITileProps> = ({
}; };
childSection = ( childSection = (
<div className="mx_SpaceHierarchy_subspace_children" onKeyDown={onChildrenKeyDown} role="group"> <ul className="mx_SpaceHierarchy_subspace_children" onKeyDown={onChildrenKeyDown} role="group">
{children} {children}
</div> </ul>
); );
} }
@@ -12,7 +12,7 @@ import React, { type JSX, type ReactNode } from "react";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { sleep } from "matrix-js-sdk/src/utils"; import { sleep } from "matrix-js-sdk/src/utils";
import { LockSolidIcon, CheckIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { LockSolidIcon, CheckIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { Button } from "@vector-im/compound-web"; import { Button, Form } from "@vector-im/compound-web";
import { _t, _td } from "../../../languageHandler"; import { _t, _td } from "../../../languageHandler";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
@@ -380,7 +380,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
<> <>
<LockSolidIcon className="mx_AuthBody_lockIcon" /> <LockSolidIcon className="mx_AuthBody_lockIcon" />
<h1>{_t("auth|reset_password_title")}</h1> <h1>{_t("auth|reset_password_title")}</h1>
<form onSubmit={this.onSubmitForm}> <Form.Root onSubmit={this.onSubmitForm}>
<fieldset disabled={this.state.phase === Phase.ResettingPassword}> <fieldset disabled={this.state.phase === Phase.ResettingPassword}>
<div className="mx_AuthBody_fieldRow"> <div className="mx_AuthBody_fieldRow">
<PassphraseField <PassphraseField
@@ -413,6 +413,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
<StyledCheckbox <StyledCheckbox
onChange={() => this.setState({ logoutDevices: !this.state.logoutDevices })} onChange={() => this.setState({ logoutDevices: !this.state.logoutDevices })}
checked={this.state.logoutDevices} checked={this.state.logoutDevices}
formWrap={false}
> >
{_t("auth|reset_password|sign_out_other_devices")} {_t("auth|reset_password|sign_out_other_devices")}
</StyledCheckbox> </StyledCheckbox>
@@ -422,7 +423,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
{submitButtonChild} {submitButtonChild}
</Button> </Button>
</fieldset> </fieldset>
</form> </Form.Root>
</> </>
); );
} }
@@ -459,8 +459,8 @@ export class EmailIdentityAuthEntry extends React.Component<
{ {
a: (text: string) => ( a: (text: string) => (
<Fragment> <Fragment>
<AccessibleButton kind="link_inline" onClick={null} disabled> <AccessibleButton element="a" kind="link_inline" onClick={null} disabled>
{text} <Spinner size={14} /> {text} <Spinner as="span" size={14} />
</AccessibleButton> </AccessibleButton>
</Fragment> </Fragment>
), ),
@@ -475,6 +475,7 @@ export class EmailIdentityAuthEntry extends React.Component<
{ {
a: (text: string) => ( a: (text: string) => (
<AccessibleButton <AccessibleButton
element="a"
kind="link_inline" kind="link_inline"
title={ title={
this.state.requested ? _t("auth|uia|email_resent") : _t("action|resend") this.state.requested ? _t("auth|uia|email_resent") : _t("action|resend")
@@ -104,7 +104,12 @@ export default class WidgetCapabilitiesPromptDialog extends React.PureComponent<
return ( return (
<div className="mx_WidgetCapabilitiesPromptDialog_cap" key={cap + i}> <div className="mx_WidgetCapabilitiesPromptDialog_cap" key={cap + i}>
<StyledCheckbox checked={isChecked} onChange={() => this.onToggle(cap)} description={text.byline}> <StyledCheckbox
checked={isChecked}
onChange={() => this.onToggle(cap)}
description={text.byline}
formWrap={false}
>
{text.primary} {text.primary}
</StyledCheckbox> </StyledCheckbox>
</div> </div>
@@ -110,7 +110,11 @@ function KeyStorage(): JSX.Element {
return ( return (
<table aria-label={_t("devtools|crypto|key_storage")}> <table aria-label={_t("devtools|crypto|key_storage")}>
<thead>{_t("devtools|crypto|key_storage")}</thead> <thead>
<tr>
<th colSpan={2}>{_t("devtools|crypto|key_storage")}</th>
</tr>
</thead>
<tbody> <tbody>
<tr> <tr>
<th scope="row">{_t("devtools|crypto|key_backup_latest_version")}</th> <th scope="row">{_t("devtools|crypto|key_backup_latest_version")}</th>
@@ -212,7 +216,11 @@ function CrossSigning(): JSX.Element {
return ( return (
<table aria-label={_t("devtools|crypto|cross_signing")}> <table aria-label={_t("devtools|crypto|cross_signing")}>
<thead>{_t("devtools|crypto|cross_signing")}</thead> <thead>
<tr>
<th colSpan={2}>{_t("devtools|crypto|cross_signing")}</th>
</tr>
</thead>
<tbody> <tbody>
<tr> <tr>
<th scope="row">{_t("devtools|crypto|cross_signing_status")}</th> <th scope="row">{_t("devtools|crypto|cross_signing_status")}</th>
@@ -303,7 +311,11 @@ function Session(): JSX.Element {
return ( return (
<table aria-label={_t("devtools|crypto|session")}> <table aria-label={_t("devtools|crypto|session")}>
<thead>{_t("devtools|crypto|session")}</thead> <thead>
<tr>
<th colSpan={2}>{_t("devtools|crypto|session")}</th>
</tr>
</thead>
<tbody> <tbody>
<tr> <tr>
<th scope="row">{_t("devtools|crypto|device_id")}</th> <th scope="row">{_t("devtools|crypto|device_id")}</th>
@@ -152,46 +152,49 @@ const AccessibleButton = function AccessibleButton<T extends ElementType = typeo
} else { } else {
newProps.onClick = onClick ?? undefined; newProps.onClick = onClick ?? undefined;
} }
// We need to consume enter onKeyDown and space onKeyUp
// otherwise we are risking also activating other keyboard focusable elements
// that might receive focus as a result of the AccessibleButtonClick action
// It's because we are using html buttons at a few places e.g. inside dialogs
// And divs which we report as role button to assistive technologies.
// Browsers handle space and enter key presses differently and we are only adjusting to the
// inconsistencies here
newProps.onKeyDown = (e: KeyboardEvent<never>) => {
const action = getKeyBindingsManager().getAccessibilityAction(e);
switch (action) { if (element !== "button") {
case KeyBindingAction.Enter: // We need to consume enter onKeyDown and space onKeyUp
e.stopPropagation(); // otherwise we are risking also activating other keyboard focusable elements
e.preventDefault(); // that might receive focus as a result of the AccessibleButtonClick action
return onClick?.(e); // It's because we are using html buttons at a few places e.g. inside dialogs
case KeyBindingAction.Space: // And divs which we report as role button to assistive technologies.
e.stopPropagation(); // Browsers handle space and enter key presses differently and we are only adjusting to the
e.preventDefault(); // inconsistencies here
break; newProps.onKeyDown = (e: KeyboardEvent<never>) => {
default: const action = getKeyBindingsManager().getAccessibilityAction(e);
onKeyDown?.(e);
}
};
newProps.onKeyUp = (e: KeyboardEvent<never>) => {
const action = getKeyBindingsManager().getAccessibilityAction(e);
switch (action) { switch (action) {
case KeyBindingAction.Enter: case KeyBindingAction.Enter:
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
break; return onClick?.(e);
case KeyBindingAction.Space: case KeyBindingAction.Space:
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
return onClick?.(e); break;
default: default:
onKeyUp?.(e); onKeyDown?.(e);
break; }
} };
}; newProps.onKeyUp = (e: KeyboardEvent<never>) => {
const action = getKeyBindingsManager().getAccessibilityAction(e);
switch (action) {
case KeyBindingAction.Enter:
e.stopPropagation();
e.preventDefault();
break;
case KeyBindingAction.Space:
e.stopPropagation();
e.preventDefault();
return onClick?.(e);
default:
onKeyUp?.(e);
break;
}
};
}
} }
// Pass through the ref - used for keyboard shortcut access to some buttons // Pass through the ref - used for keyboard shortcut access to some buttons
@@ -44,6 +44,7 @@ export const CopyTextButton: React.FC<Pick<IProps, "getTextToCopy" | "className"
return ( return (
<AccessibleButton <AccessibleButton
element="button"
title={tooltip ?? _t("action|copy")} title={tooltip ?? _t("action|copy")}
onClick={onCopyClickInternal} onClick={onCopyClickInternal}
className={className} className={className}
@@ -62,12 +63,12 @@ const CopyableText: React.FC<IProps> = ({ children, getTextToCopy, border = true
}); });
return ( return (
<div className={combinedClassName} {...props}> <span className={combinedClassName} {...props}>
{children} {children}
<CopyTextButton getTextToCopy={getTextToCopy} className="mx_CopyableText_copyButton"> <CopyTextButton getTextToCopy={getTextToCopy} className="mx_CopyableText_copyButton">
<CopyIcon /> <CopyIcon />
</CopyTextButton> </CopyTextButton>
</div> </span>
); );
}; };
@@ -13,7 +13,7 @@ import Modal from "../../../Modal";
import InfoDialog from "../dialogs/InfoDialog"; import InfoDialog from "../dialogs/InfoDialog";
import AccessibleButton, { type ButtonProps } from "./AccessibleButton"; import AccessibleButton, { type ButtonProps } from "./AccessibleButton";
type Props = Omit<ButtonProps<"div">, "element" | "kind" | "onClick" | "className"> & { type Props = Omit<ButtonProps<"button">, "element" | "kind" | "onClick" | "className"> & {
title: string; title: string;
description: string | React.ReactNode; description: string | React.ReactNode;
}; };
@@ -29,7 +29,13 @@ const LearnMore: React.FC<Props> = ({ title, description, ...rest }) => {
}; };
return ( return (
<AccessibleButton {...rest} kind="link_inline" onClick={onClick} className="mx_LearnMore_button"> <AccessibleButton
{...rest}
element="button"
kind="link_inline"
onClick={onClick}
className="mx_LearnMore_button"
>
{_t("action|learn_more")} {_t("action|learn_more")}
</AccessibleButton> </AccessibleButton>
); );
@@ -15,6 +15,11 @@ interface IProps {
size?: number; size?: number;
message?: string; message?: string;
onFinished: any; // XXX: Spinner pretends to be a dialog so it must accept an onFinished, but it never calls it onFinished: any; // XXX: Spinner pretends to be a dialog so it must accept an onFinished, but it never calls it
/**
* Whether to render the content in a div or span.
* @default "div"
*/
as?: "span" | "div";
} }
export default class Spinner extends React.PureComponent<IProps> { export default class Spinner extends React.PureComponent<IProps> {
@@ -23,16 +28,16 @@ export default class Spinner extends React.PureComponent<IProps> {
}; };
public render(): React.ReactNode { public render(): React.ReactNode {
const { size, message } = this.props; const { size, message, as: Component = "div" } = this.props;
return ( return (
<div className="mx_Spinner"> <Component className="mx_Spinner">
{message && ( {message && (
<React.Fragment> <React.Fragment>
<div className="mx_Spinner_Msg">{message}</div>&nbsp; <div className="mx_Spinner_Msg">{message}</div>&nbsp;
</React.Fragment> </React.Fragment>
)} )}
<InlineSpinner size={size} aria-label={_t("common|loading")} role="progressbar" data-testid="spinner" /> <InlineSpinner size={size} aria-label={_t("common|loading")} role="progressbar" data-testid="spinner" />
</div> </Component>
); );
} }
} }
@@ -14,6 +14,7 @@ interface IProps extends React.InputHTMLAttributes<HTMLInputElement> {
inputRef?: Ref<HTMLInputElement>; inputRef?: Ref<HTMLInputElement>;
id?: string; id?: string;
description?: ReactNode; description?: ReactNode;
formWrap?: boolean;
} }
const StyledCheckbox: React.FC<IProps> = ({ const StyledCheckbox: React.FC<IProps> = ({
@@ -22,30 +23,36 @@ const StyledCheckbox: React.FC<IProps> = ({
className, className,
inputRef, inputRef,
description, description,
formWrap = true,
...otherProps ...otherProps
}) => { }) => {
const id = initialId || "checkbox_" + secureRandomString(10); const id = initialId || "checkbox_" + secureRandomString(10);
const name = useId(); const name = useId();
const descriptionId = useId(); const descriptionId = useId();
return (
<Form.Root> const field = (
<InlineField <InlineField
className={className} className={className}
name={name} name={name}
control={ control={
<CheckboxInput <CheckboxInput
ref={inputRef} ref={inputRef}
aria-describedby={description ? descriptionId : undefined} aria-describedby={description ? descriptionId : undefined}
id={id} id={id}
{...otherProps} {...otherProps}
/> />
} }
> >
{label && <Label htmlFor={id}>{label}</Label>} {label && <Label htmlFor={id}>{label}</Label>}
{description && <HelpMessage id={descriptionId}>{description}</HelpMessage>} {description && <HelpMessage id={descriptionId}>{description}</HelpMessage>}
</InlineField> </InlineField>
</Form.Root>
); );
if (formWrap) {
return <Form.Root>{field}</Form.Root>;
}
return field;
}; };
export default StyledCheckbox; export default StyledCheckbox;
@@ -255,7 +255,7 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
} else { } else {
body = ( body = (
<p> <p>
<Spinner /> <Spinner as="span" />
</p> </p>
); );
} }
@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
import React, { type ChangeEventHandler } from "react"; import React, { type ChangeEventHandler } from "react";
import { JoinRule, Visibility } from "matrix-js-sdk/src/matrix"; import { JoinRule, Visibility } from "matrix-js-sdk/src/matrix";
import { SettingsToggleInput } from "@vector-im/compound-web"; import { Form, SettingsToggleInput } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
@@ -16,6 +16,7 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
import DirectoryCustomisations from "../../../customisations/Directory"; import DirectoryCustomisations from "../../../customisations/Directory";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import ErrorDialog from "../dialogs/ErrorDialog"; import ErrorDialog from "../dialogs/ErrorDialog";
import { onSubmitPreventDefault } from "../../../utils/form.ts";
interface IProps { interface IProps {
roomId: string; roomId: string;
@@ -90,16 +91,18 @@ export default class RoomPublishSetting extends React.PureComponent<IProps, ISta
const enabled = canSetCanonicalAlias && (isRoomPublishable || this.state.isRoomPublished); const enabled = canSetCanonicalAlias && (isRoomPublishable || this.state.isRoomPublished);
return ( return (
<SettingsToggleInput <Form.Root onSubmit={onSubmitPreventDefault}>
name="room-publish" <SettingsToggleInput
checked={this.state.isRoomPublished} name="room-publish"
onChange={this.onRoomPublishChange} checked={this.state.isRoomPublished}
disabled={!enabled || this.state.busy} onChange={this.onRoomPublishChange}
disabledMessage={disabledMessage} disabled={!enabled || this.state.busy}
label={_t("room_settings|general|publish_toggle", { disabledMessage={disabledMessage}
domain: client.getDomain(), label={_t("room_settings|general|publish_toggle", {
})} domain: client.getDomain(),
/> })}
/>
</Form.Root>
); );
} }
} }
@@ -220,7 +220,12 @@ export default class EventIndexPanel extends React.Component<EmptyObject, IState
: _t("error|unknown")} : _t("error|unknown")}
</code> </code>
<p> <p>
<AccessibleButton key="delete" kind="danger" onClick={this.confirmEventStoreReset}> <AccessibleButton
element="button"
key="delete"
kind="danger"
onClick={this.confirmEventStoreReset}
>
{_t("action|reset")} {_t("action|reset")}
</AccessibleButton> </AccessibleButton>
</p> </p>
@@ -52,6 +52,7 @@ import { SettingsSubsectionHeading } from "./shared/SettingsSubsectionHeading";
import { SettingsSubsection } from "./shared/SettingsSubsection"; import { SettingsSubsection } from "./shared/SettingsSubsection";
import { doesRoomHaveUnreadMessages } from "../../../Unread"; import { doesRoomHaveUnreadMessages } from "../../../Unread";
import SettingsFlag from "../elements/SettingsFlag"; import SettingsFlag from "../elements/SettingsFlag";
import { onSubmitPreventDefault } from "../../../utils/form.ts";
// TODO: this "view" component still has far too much application logic in it, // TODO: this "view" component still has far too much application logic in it,
// which should be factored out to other files. // which should be factored out to other files.
@@ -651,7 +652,7 @@ export default class Notifications extends React.PureComponent<EmptyObject, ISta
// If all the rules are inhibited, don't show anything. // If all the rules are inhibited, don't show anything.
if (this.isInhibited) { if (this.isInhibited) {
return masterSwitch; return <Form.Root onSubmit={onSubmitPreventDefault}>{masterSwitch}</Form.Root>;
} }
const emailSwitches = (this.state.threepids || []) const emailSwitches = (this.state.threepids || [])
@@ -669,19 +670,21 @@ export default class Notifications extends React.PureComponent<EmptyObject, ISta
return ( return (
<SettingsSubsection> <SettingsSubsection>
{masterSwitch} <Form.Root onSubmit={onSubmitPreventDefault}>
{masterSwitch}
<SettingsFlag name="deviceNotificationsEnabled" level={SettingLevel.DEVICE} /> <SettingsFlag name="deviceNotificationsEnabled" level={SettingLevel.DEVICE} />
{this.state.deviceNotificationsEnabled && ( {this.state.deviceNotificationsEnabled && (
<> <>
<SettingsFlag name="notificationsEnabled" level={SettingLevel.DEVICE} /> <SettingsFlag name="notificationsEnabled" level={SettingLevel.DEVICE} />
<SettingsFlag name="notificationBodyEnabled" level={SettingLevel.DEVICE} /> <SettingsFlag name="notificationBodyEnabled" level={SettingLevel.DEVICE} />
<SettingsFlag name="audioNotificationsEnabled" level={SettingLevel.DEVICE} /> <SettingsFlag name="audioNotificationsEnabled" level={SettingLevel.DEVICE} />
</> </>
)} )}
{emailSwitches} {emailSwitches}
</Form.Root>
</SettingsSubsection> </SettingsSubsection>
); );
} }
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/ */
import React, { type JSX, useState } from "react"; import React, { type JSX, useState } from "react";
import { SettingsToggleInput } from "@vector-im/compound-web"; import { Form, SettingsToggleInput } from "@vector-im/compound-web";
import NewAndImprovedIcon from "../../../../../res/img/element-icons/new-and-improved.svg"; import NewAndImprovedIcon from "../../../../../res/img/element-icons/new-and-improved.svg";
import { useMatrixClientContext } from "../../../../contexts/MatrixClientContext"; import { useMatrixClientContext } from "../../../../contexts/MatrixClientContext";
@@ -33,6 +33,7 @@ import { SettingsSubsection } from "../shared/SettingsSubsection";
import { NotificationPusherSettings } from "./NotificationPusherSettings"; import { NotificationPusherSettings } from "./NotificationPusherSettings";
import SettingsFlag from "../../elements/SettingsFlag"; import SettingsFlag from "../../elements/SettingsFlag";
import { SettingsSubsectionHeading } from "../shared/SettingsSubsectionHeading"; import { SettingsSubsectionHeading } from "../shared/SettingsSubsectionHeading";
import { onSubmitPreventDefault } from "../../../../utils/form.ts";
enum NotificationDefaultLevels { enum NotificationDefaultLevels {
AllMessages = "all_messages", AllMessages = "all_messages",
@@ -111,7 +112,7 @@ export default function NotificationSettings2(): JSX.Element {
</SettingsBanner> </SettingsBanner>
)} )}
<SettingsSection> <SettingsSection>
<div className="mx_SettingsSubsection_content mx_NotificationSettings2_flags"> <Form.Root className="mx_SettingsSubsection_content" onSubmit={onSubmitPreventDefault}>
<SettingsToggleInput <SettingsToggleInput
name="enable_notifications_account" name="enable_notifications_account"
label={_t("settings|notifications|enable_notifications_account")} label={_t("settings|notifications|enable_notifications_account")}
@@ -131,7 +132,7 @@ export default function NotificationSettings2(): JSX.Element {
level={SettingLevel.DEVICE} level={SettingLevel.DEVICE}
/> />
<SettingsFlag name="audioNotificationsEnabled" level={SettingLevel.DEVICE} /> <SettingsFlag name="audioNotificationsEnabled" level={SettingLevel.DEVICE} />
</div> </Form.Root>
<SettingsSubsection <SettingsSubsection
heading={ heading={
<SettingsSubsectionHeading <SettingsSubsectionHeading
@@ -346,8 +347,10 @@ export default function NotificationSettings2(): JSX.Element {
placeholder={_t("notifications|keyword_new")} placeholder={_t("notifications|keyword_new")}
/> />
<SettingsFlag name="Notifications.showbold" level={SettingLevel.DEVICE} /> <Form.Root onSubmit={onSubmitPreventDefault}>
<SettingsFlag name="Notifications.tac_only_notifications" level={SettingLevel.DEVICE} /> <SettingsFlag name="Notifications.showbold" level={SettingLevel.DEVICE} />
<SettingsFlag name="Notifications.tac_only_notifications" level={SettingLevel.DEVICE} />
</Form.Root>
</SettingsSubsection> </SettingsSubsection>
<NotificationPusherSettings /> <NotificationPusherSettings />
<SettingsSubsection heading={_t("settings|notifications|quick_actions_section")}> <SettingsSubsection heading={_t("settings|notifications|quick_actions_section")}>
@@ -8,7 +8,6 @@ Please see LICENSE files in the repository root for full details.
import React, { type ContextType } from "react"; import React, { type ContextType } from "react";
import { type Room } from "matrix-js-sdk/src/matrix"; import { type Room } from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types"; import { KnownMembership } from "matrix-js-sdk/src/types";
import { Form } from "@vector-im/compound-web";
import { _t } from "../../../../../languageHandler"; import { _t } from "../../../../../languageHandler";
import RoomProfileSettings from "../../../room_settings/RoomProfileSettings"; import RoomProfileSettings from "../../../room_settings/RoomProfileSettings";
@@ -72,32 +71,25 @@ export default class GeneralRoomSettingsTab extends React.Component<IProps, ISta
return ( return (
<SettingsTab data-testid="General"> <SettingsTab data-testid="General">
<Form.Root <SettingsSection heading={_t("common|general")}>
onSubmit={(evt) => { <RoomProfileSettings roomId={room.roomId} />
evt.preventDefault(); </SettingsSection>
evt.stopPropagation();
}}
>
<SettingsSection heading={_t("common|general")}>
<RoomProfileSettings roomId={room.roomId} />
</SettingsSection>
<SettingsSection heading={_t("room_settings|general|aliases_section")}> <SettingsSection heading={_t("room_settings|general|aliases_section")}>
<AliasSettings <AliasSettings
roomId={room.roomId} roomId={room.roomId}
canSetCanonicalAlias={canSetCanonical} canSetCanonicalAlias={canSetCanonical}
canSetAliases={canSetAliases} canSetAliases={canSetAliases}
canonicalAliasEvent={canonicalAliasEv} canonicalAliasEvent={canonicalAliasEv}
/> />
</SettingsSection> </SettingsSection>
<SettingsSection heading={_t("room_settings|general|other_section")}> <SettingsSection heading={_t("room_settings|general|other_section")}>
<SettingsSubsection heading={_t("common|moderation_and_safety")} legacy={false}> <SettingsSubsection heading={_t("common|moderation_and_safety")} legacy={false}>
<MediaPreviewAccountSettings roomId={room.roomId} /> <MediaPreviewAccountSettings roomId={room.roomId} />
</SettingsSubsection> </SettingsSubsection>
{leaveSection} {leaveSection}
</SettingsSection> </SettingsSection>
</Form.Root>
</SettingsTab> </SettingsTab>
); );
} }
@@ -137,6 +137,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
{ {
a: (sub) => ( a: (sub) => (
<AccessibleButton <AccessibleButton
element="a"
kind="link_inline" kind="link_inline"
onClick={() => { onClick={() => {
dialog.close(); dialog.close();
@@ -334,6 +335,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
{_t("room_settings|security|encrypted_room_public_confirm_description_2", undefined, { {_t("room_settings|security|encrypted_room_public_confirm_description_2", undefined, {
a: (sub) => ( a: (sub) => (
<AccessibleButton <AccessibleButton
element="a"
kind="link_inline" kind="link_inline"
onClick={(): void => { onClick={(): void => {
dialog.close(); dialog.close();
@@ -7,7 +7,6 @@ Please see LICENSE files in the repository root for full details.
*/ */
import React from "react"; import React from "react";
import { Form } from "@vector-im/compound-web";
import { Features } from "../../../../../settings/Settings"; import { Features } from "../../../../../settings/Settings";
import SettingsStore from "../../../../../settings/SettingsStore"; import SettingsStore from "../../../../../settings/SettingsStore";
@@ -22,20 +21,13 @@ export default class NotificationUserSettingsTab extends React.Component {
return ( return (
<SettingsTab> <SettingsTab>
<Form.Root {newNotificationSettingsEnabled ? (
onSubmit={(evt) => { <NotificationSettings2 />
evt.preventDefault(); ) : (
evt.stopPropagation(); <SettingsSection>
}} <Notifications />
> </SettingsSection>
{newNotificationSettingsEnabled ? ( )}
<NotificationSettings2 />
) : (
<SettingsSection>
<Notifications />
</SettingsSection>
)}
</Form.Root>
</SettingsTab> </SettingsTab>
); );
} }
@@ -184,14 +184,7 @@ const SpaceSettingsVisibilityTab: React.FC<IProps> = ({ matrixClient: cli, space
</Form.Root> </Form.Root>
</SettingsFieldset> </SettingsFieldset>
<Form.Root {addressesSection}
onSubmit={(evt) => {
evt.preventDefault();
evt.stopPropagation();
}}
>
{addressesSection}
</Form.Root>
</SettingsSection> </SettingsSection>
</SettingsTab> </SettingsTab>
); );
+17
View File
@@ -0,0 +1,17 @@
/*
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 type React from "react";
/**
* onSubmit handler which calls preventDefault and stopPropagation on the event
* @param e submit event
*/
export function onSubmitPreventDefault(e: SubmitEvent | React.SubmitEvent): void {
e.preventDefault();
e.stopPropagation();
}
+25
View File
@@ -66,3 +66,28 @@ if (env["GITHUB_ACTIONS"] !== undefined) {
require("./setup/setupManualMocks"); // must be first require("./setup/setupManualMocks"); // must be first
require("./setup/setupLanguage"); require("./setup/setupLanguage");
require("./setup/setupConfig"); require("./setup/setupConfig");
// Utility to check for React errors during the tests
// Fails tests on errors like the following:
// In HTML, <div> cannot be a descendant of <p>.
// In HTML, <form> cannot be a descendant of <form>.
// In HTML, text nodes cannot be a child of <thead>.
// This will cause a hydration error.
// You provided a `checked` prop to a form field without an `onChange` handler.
let errors: any[] = [];
beforeEach(() => {
errors = [];
const originalError = console.error;
jest.spyOn(console, "error").mockImplementation((...args) => {
if (/validateDOMNesting|Hydration failed|hydration error|prop to a form field without an/i.test(args[0])) {
errors.push(args[0]);
}
originalError.call(console, ...args);
});
});
afterEach(() => {
mocked(console.error).mockRestore?.();
if (errors.length > 0) {
throw new Error("Test failed due to React hydration errors in the console.");
}
});
@@ -378,114 +378,115 @@ exports[`SpaceHierarchy <SpaceHierarchy /> renders 1`] = `
</svg> </svg>
</div> </div>
</div> </div>
<div <ul
class="mx_SpaceHierarchy_subspace_children" class="mx_SpaceHierarchy_subspace_children"
role="group" role="group"
/>
</li>
<li
aria-labelledby="_r_k_"
class="mx_SpaceHierarchy_roomTileWrapper"
role="treeitem"
>
<div
class="mx_AccessibleButton mx_SpaceHierarchy_roomTile"
role="button"
tabindex="-1"
> >
<div <li
class="mx_SpaceHierarchy_roomTile_item" aria-labelledby="_r_k_"
class="mx_SpaceHierarchy_roomTileWrapper"
role="treeitem"
> >
<div <div
class="mx_SpaceHierarchy_roomTile_avatar" class="mx_AccessibleButton mx_SpaceHierarchy_roomTile"
>
<span
class="_avatar_7h2br_8 mx_BaseAvatar _avatar-imageless_7h2br_55"
data-color="2"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 20px;"
>
N
</span>
</div>
<div
class="mx_SpaceHierarchy_roomTile_name"
>
<span
id="_r_k_"
>
Nested room
</span>
</div>
<div
class="mx_SpaceHierarchy_roomTile_info"
>
3 members
</div>
</div>
<div
class="mx_SpaceHierarchy_actions"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
role="button" role="button"
tabindex="-1" tabindex="-1"
> >
Join <div
</div> class="mx_SpaceHierarchy_roomTile_item"
<span
aria-labelledby="_r_l_"
tabindex="0"
>
<form
class="_root_19upo_16"
> >
<div <div
class="_inline-field_19upo_32" class="mx_SpaceHierarchy_roomTile_avatar"
> >
<div <span
class="_inline-field-control_19upo_44" class="_avatar_7h2br_8 mx_BaseAvatar _avatar-imageless_7h2br_55"
data-color="2"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 20px;"
>
N
</span>
</div>
<div
class="mx_SpaceHierarchy_roomTile_name"
>
<span
id="_r_k_"
>
Nested room
</span>
</div>
<div
class="mx_SpaceHierarchy_roomTile_info"
>
3 members
</div>
</div>
<div
class="mx_SpaceHierarchy_actions"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
role="button"
tabindex="-1"
>
Join
</div>
<span
aria-labelledby="_r_l_"
tabindex="0"
>
<form
class="_root_19upo_16"
> >
<div <div
class="_container_153f2_10" class="_inline-field_19upo_32"
> >
<input
aria-labelledby="_r_k_"
class="_input_153f2_18"
disabled=""
id="checkbox_RD7nyrA2oh"
role="presentation"
tabindex="-1"
type="checkbox"
/>
<div <div
class="_ui_153f2_19" class="_inline-field-control_19upo_44"
> >
<svg <div
aria-hidden="true" class="_container_153f2_10"
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
> >
<path <input
d="M9.55 17.575q-.2 0-.375-.062a.9.9 0 0 1-.325-.213L4.55 13q-.274-.274-.262-.713.012-.437.287-.712a.95.95 0 0 1 .7-.275q.425 0 .7.275L9.55 15.15l8.475-8.475q.274-.275.713-.275.437 0 .712.275.275.274.275.713 0 .437-.275.712l-9.2 9.2q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063" aria-labelledby="_r_k_"
class="_input_153f2_18"
disabled=""
id="checkbox_RD7nyrA2oh"
role="presentation"
tabindex="-1"
type="checkbox"
/> />
</svg> <div
class="_ui_153f2_19"
>
<svg
aria-hidden="true"
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.55 17.575q-.2 0-.375-.062a.9.9 0 0 1-.325-.213L4.55 13q-.274-.274-.262-.713.012-.437.287-.712a.95.95 0 0 1 .7-.275q.425 0 .7.275L9.55 15.15l8.475-8.475q.274-.275.713-.275.437 0 .712.275.275.274.275.713 0 .437-.275.712l-9.2 9.2q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</div>
</div>
</div> </div>
<div
class="_inline-field-body_19upo_38"
/>
</div> </div>
</div> </form>
<div </span>
class="_inline-field-body_19upo_38" </div>
/> </div>
</div> </li>
</form> </ul>
</span>
</div>
</div>
</li> </li>
<li <li
aria-labelledby="_r_t_" aria-labelledby="_r_t_"
@@ -967,7 +968,7 @@ exports[`SpaceHierarchy <SpaceHierarchy /> should not render cycles 1`] = `
</svg> </svg>
</div> </div>
</div> </div>
<div <ul
class="mx_SpaceHierarchy_subspace_children" class="mx_SpaceHierarchy_subspace_children"
role="group" role="group"
/> />
@@ -19,14 +19,14 @@ exports[`<EmailIdentityAuthEntry/> should render 1`] = `
> >
<span> <span>
Did not receive it? Did not receive it?
<div <a
aria-label="Resend" aria-label="Resend"
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Resend it Resend it
</div> </a>
</span> </span>
</p> </p>
</div> </div>
@@ -54,10 +54,10 @@ exports[`<BeaconListItem /> when a beacon is live and has locations renders beac
/> />
</svg> </svg>
</a> </a>
<div <span
class="mx_CopyableText mx_ShareLatestLocation_copy" class="mx_CopyableText mx_ShareLatestLocation_copy"
> >
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -77,8 +77,8 @@ exports[`<BeaconListItem /> when a beacon is live and has locations renders beac
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</div> </div>
</div> </div>
<span <span
@@ -94,10 +94,10 @@ exports[`<DialogSidebar /> renders sidebar correctly with beacons 1`] = `
/> />
</svg> </svg>
</a> </a>
<div <span
class="mx_CopyableText mx_ShareLatestLocation_copy" class="mx_CopyableText mx_ShareLatestLocation_copy"
> >
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -117,8 +117,8 @@ exports[`<DialogSidebar /> renders sidebar correctly with beacons 1`] = `
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</div> </div>
</div> </div>
<span <span
@@ -25,10 +25,10 @@ exports[`<ShareLatestLocation /> renders share buttons when there is a location
/> />
</svg> </svg>
</a> </a>
<div <span
class="mx_CopyableText mx_ShareLatestLocation_copy" class="mx_CopyableText mx_ShareLatestLocation_copy"
> >
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -48,7 +48,7 @@ exports[`<ShareLatestLocation /> renders share buttons when there is a location
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</DocumentFragment> </DocumentFragment>
`; `;
@@ -29,11 +29,11 @@ exports[`DevtoolsDialog renders the devtools dialog 1`] = `
> >
Toolbox Toolbox
</div> </div>
<div <span
class="mx_CopyableText mx_DevTools_label_right" class="mx_CopyableText mx_DevTools_label_right"
> >
Room ID: !id Room ID: !id
<div <button
aria-describedby="_r_2_" aria-describedby="_r_2_"
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
@@ -54,8 +54,8 @@ exports[`DevtoolsDialog renders the devtools dialog 1`] = `
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
<div <div
class="mx_DevTools_label_bottom" class="mx_DevTools_label_bottom"
/> />
@@ -5,7 +5,13 @@ exports[`<Crypto /> <CrossSigning /> should display when the cross-signing data
aria-label="Cross-signing" aria-label="Cross-signing"
> >
<thead> <thead>
Cross-signing <tr>
<th
colspan="2"
>
Cross-signing
</th>
</tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
@@ -77,7 +83,13 @@ exports[`<Crypto /> <CrossSigning /> should display when the cross-signing data
aria-label="Cross-signing" aria-label="Cross-signing"
> >
<thead> <thead>
Cross-signing <tr>
<th
colspan="2"
>
Cross-signing
</th>
</tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
@@ -149,7 +161,13 @@ exports[`<Crypto /> <KeyStorage /> should display when the key storage data are
aria-label="Key Storage" aria-label="Key Storage"
> >
<thead> <thead>
Key Storage <tr>
<th
colspan="2"
>
Key Storage
</th>
</tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
@@ -221,7 +239,13 @@ exports[`<Crypto /> <KeyStorage /> should display when the key storage data are
aria-label="Key Storage" aria-label="Key Storage"
> >
<thead> <thead>
Key Storage <tr>
<th
colspan="2"
>
Key Storage
</th>
</tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
@@ -7,11 +7,11 @@ exports[`<Users /> should render a single device - signed by owner 1`] = `
> >
<ul> <ul>
<li> <li>
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
User ID: @alice:example.com User ID: @alice:example.com
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -31,15 +31,15 @@ exports[`<Users /> should render a single device - signed by owner 1`] = `
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</li> </li>
<li> <li>
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
Device ID: SIGNED Device ID: SIGNED
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -59,8 +59,8 @@ exports[`<Users /> should render a single device - signed by owner 1`] = `
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</li> </li>
<li> <li>
Displayname: Displayname:
@@ -95,11 +95,11 @@ exports[`<Users /> should render a single device - signed by owner 1`] = `
Device keys Device keys
<ul> <ul>
<li> <li>
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
ed25519: an_ed25519_public_key ed25519: an_ed25519_public_key
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -119,15 +119,15 @@ exports[`<Users /> should render a single device - signed by owner 1`] = `
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</li> </li>
<li> <li>
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
curve25519: a_curve25519_public_key curve25519: a_curve25519_public_key
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -147,8 +147,8 @@ exports[`<Users /> should render a single device - signed by owner 1`] = `
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</li> </li>
</ul> </ul>
</li> </li>
@@ -171,11 +171,11 @@ exports[`<Users /> should render a single device - unsigned 1`] = `
> >
<ul> <ul>
<li> <li>
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
User ID: @alice:example.com User ID: @alice:example.com
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -195,15 +195,15 @@ exports[`<Users /> should render a single device - unsigned 1`] = `
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</li> </li>
<li> <li>
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
Device ID: UNSIGNED Device ID: UNSIGNED
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -223,8 +223,8 @@ exports[`<Users /> should render a single device - unsigned 1`] = `
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</li> </li>
<li> <li>
Displayname: Displayname:
@@ -259,11 +259,11 @@ exports[`<Users /> should render a single device - unsigned 1`] = `
Device keys Device keys
<ul> <ul>
<li> <li>
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
ed25519: an_ed25519_public_key ed25519: an_ed25519_public_key
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -283,15 +283,15 @@ exports[`<Users /> should render a single device - unsigned 1`] = `
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</li> </li>
<li> <li>
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
curve25519: a_curve25519_public_key curve25519: a_curve25519_public_key
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -311,8 +311,8 @@ exports[`<Users /> should render a single device - unsigned 1`] = `
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</li> </li>
</ul> </ul>
</li> </li>
@@ -335,11 +335,11 @@ exports[`<Users /> should render a single device - verified by cross-signing 1`]
> >
<ul> <ul>
<li> <li>
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
User ID: @alice:example.com User ID: @alice:example.com
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -359,15 +359,15 @@ exports[`<Users /> should render a single device - verified by cross-signing 1`]
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</li> </li>
<li> <li>
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
Device ID: VERIFIED Device ID: VERIFIED
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -387,8 +387,8 @@ exports[`<Users /> should render a single device - verified by cross-signing 1`]
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</li> </li>
<li> <li>
Displayname: Displayname:
@@ -425,11 +425,11 @@ exports[`<Users /> should render a single device - verified by cross-signing 1`]
Device keys Device keys
<ul> <ul>
<li> <li>
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
ed25519: an_ed25519_public_key ed25519: an_ed25519_public_key
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -449,15 +449,15 @@ exports[`<Users /> should render a single device - verified by cross-signing 1`]
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</li> </li>
<li> <li>
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
curve25519: a_curve25519_public_key curve25519: a_curve25519_public_key
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -477,8 +477,8 @@ exports[`<Users /> should render a single device - verified by cross-signing 1`]
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</li> </li>
</ul> </ul>
</li> </li>
@@ -501,11 +501,11 @@ exports[`<Users /> should render a single user 1`] = `
> >
<ul> <ul>
<li> <li>
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
User ID: @alice:example.com User ID: @alice:example.com
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -525,8 +525,8 @@ exports[`<Users /> should render a single user 1`] = `
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</li> </li>
<li> <li>
Membership: join Membership: join
@@ -2,13 +2,13 @@
exports[`<LearnMore /> renders button 1`] = ` exports[`<LearnMore /> renders button 1`] = `
<div> <div>
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
data-testid="testid" data-testid="testid"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</div> </div>
`; `;
@@ -59,7 +59,7 @@ exports[`<TextualBody /> renders formatted m.text correctly linkification is not
</code> </code>
</div> </div>
</pre> </pre>
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_EventTile_button mx_EventTile_copyButton" class="mx_AccessibleButton mx_EventTile_button mx_EventTile_copyButton"
role="button" role="button"
@@ -79,7 +79,7 @@ exports[`<TextualBody /> renders formatted m.text correctly linkification is not
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </div>
@@ -278,7 +278,7 @@ exports[`<TextualBody /> renders formatted m.text correctly pills do not appear
</code> </code>
</div> </div>
</pre> </pre>
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_EventTile_button mx_EventTile_copyButton" class="mx_AccessibleButton mx_EventTile_button mx_EventTile_copyButton"
role="button" role="button"
@@ -298,7 +298,7 @@ exports[`<TextualBody /> renders formatted m.text correctly pills do not appear
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </div>
@@ -482,7 +482,7 @@ num_sqrt = num **
/> />
</svg> </svg>
</span> </span>
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_EventTile_button mx_EventTile_copyButton mx_EventTile_buttonBottom" class="mx_AccessibleButton mx_EventTile_button mx_EventTile_copyButton mx_EventTile_buttonBottom"
role="button" role="button"
@@ -502,7 +502,7 @@ num_sqrt = num **
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </div>
@@ -99,11 +99,11 @@ exports[`<UserInfo /> with crypto enabled renders <BasicUserInfo /> 1`] = `
<p <p
class="_typography_6v6n8_153 _font-body-sm-semibold_6v6n8_36 mx_UserInfo_profile_mxid" class="_typography_6v6n8_153 _font-body-sm-semibold_6v6n8_36 mx_UserInfo_profile_mxid"
> >
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
customUserIdentifier customUserIdentifier
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -123,8 +123,8 @@ exports[`<UserInfo /> with crypto enabled renders <BasicUserInfo /> 1`] = `
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</p> </p>
</div> </div>
<div <div
@@ -401,11 +401,11 @@ exports[`<UserInfo /> with crypto enabled should render a deactivate button for
<p <p
class="_typography_6v6n8_153 _font-body-sm-semibold_6v6n8_36 mx_UserInfo_profile_mxid" class="_typography_6v6n8_153 _font-body-sm-semibold_6v6n8_36 mx_UserInfo_profile_mxid"
> >
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
customUserIdentifier customUserIdentifier
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -425,8 +425,8 @@ exports[`<UserInfo /> with crypto enabled should render a deactivate button for
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</p> </p>
</div> </div>
<div <div
@@ -48,11 +48,11 @@ exports[`<UserInfoHeaderView /> renders custom user identifiers in the header 1`
<p <p
class="_typography_6v6n8_153 _font-body-sm-semibold_6v6n8_36 mx_UserInfo_profile_mxid" class="_typography_6v6n8_153 _font-body-sm-semibold_6v6n8_36 mx_UserInfo_profile_mxid"
> >
<div <span
class="mx_CopyableText" class="mx_CopyableText"
> >
customUserIdentifier customUserIdentifier
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -72,8 +72,8 @@ exports[`<UserInfoHeaderView /> renders custom user identifiers in the header 1`
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</p> </p>
</div> </div>
<div <div
@@ -37,7 +37,6 @@ import {
import { mocked } from "jest-mock"; import { mocked } from "jest-mock";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
import { PushProcessor } from "matrix-js-sdk/src/pushprocessor"; import { PushProcessor } from "matrix-js-sdk/src/pushprocessor";
import { Form } from "@vector-im/compound-web";
import Notifications from "../../../../../src/components/views/settings/Notifications"; import Notifications from "../../../../../src/components/views/settings/Notifications";
import SettingsStore from "../../../../../src/settings/SettingsStore"; import SettingsStore from "../../../../../src/settings/SettingsStore";
@@ -249,12 +248,7 @@ const pushRules: IPushRules = {
const flushPromises = async () => await new Promise((resolve) => window.setTimeout(resolve)); const flushPromises = async () => await new Promise((resolve) => window.setTimeout(resolve));
describe("<Notifications />", () => { describe("<Notifications />", () => {
const getComponent = () => const getComponent = () => render(<Notifications />);
render(
<Form.Root>
<Notifications />
</Form.Root>,
);
// get component, wait for async data and force a render // get component, wait for async data and force a render
const getComponentAndWait = async () => { const getComponentAndWait = async () => {
@@ -42,74 +42,74 @@ exports[`<Notifications /> main notification switches renders only enable notifi
</span> </span>
</div> </div>
</div> </div>
<form </form>
class="_root_19upo_16" <form
class="_root_19upo_16"
>
<div
class="_inline-field_19upo_32"
> >
<div <div
class="_inline-field_19upo_32" class="_inline-field-control_19upo_44"
> >
<div <div
class="_inline-field-control_19upo_44" class="_container_udcm8_10"
> >
<input
checked=""
class="_input_udcm8_24"
id="mx_SettingsFlag_testid_0"
role="switch"
type="checkbox"
/>
<div <div
class="_container_udcm8_10" class="_ui_udcm8_34"
> />
<input
checked=""
class="_input_udcm8_24"
id="mx_SettingsFlag_testid_0"
role="switch"
type="checkbox"
/>
<div
class="_ui_udcm8_34"
/>
</div>
</div>
<div
class="_inline-field-body_19upo_38"
>
<label
class="_label_19upo_59"
for="mx_SettingsFlag_testid_0"
>
Show all activity in the room list (dots or number of unread messages)
</label>
</div> </div>
</div> </div>
<div <div
class="_inline-field_19upo_32" class="_inline-field-body_19upo_38"
>
<label
class="_label_19upo_59"
for="mx_SettingsFlag_testid_0"
>
Show all activity in the room list (dots or number of unread messages)
</label>
</div>
</div>
<div
class="_inline-field_19upo_32"
>
<div
class="_inline-field-control_19upo_44"
> >
<div <div
class="_inline-field-control_19upo_44" class="_container_udcm8_10"
> >
<input
checked=""
class="_input_udcm8_24"
id="mx_SettingsFlag_testid_1"
role="switch"
type="checkbox"
/>
<div <div
class="_container_udcm8_10" class="_ui_udcm8_34"
> />
<input
checked=""
class="_input_udcm8_24"
id="mx_SettingsFlag_testid_1"
role="switch"
type="checkbox"
/>
<div
class="_ui_udcm8_34"
/>
</div>
</div>
<div
class="_inline-field-body_19upo_38"
>
<label
class="_label_19upo_59"
for="mx_SettingsFlag_testid_1"
>
Only show notifications in the thread activity centre
</label>
</div> </div>
</div> </div>
</form> <div
class="_inline-field-body_19upo_38"
>
<label
class="_label_19upo_59"
for="mx_SettingsFlag_testid_1"
>
Only show notifications in the thread activity centre
</label>
</div>
</div>
</form> </form>
</div> </div>
`; `;
@@ -57,13 +57,13 @@ HTMLCollection [
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
Verify your current session for enhanced secure messaging. Verify your current session for enhanced secure messaging.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
<div <div
class="mx_DeviceSecurityCard_actions" class="mx_DeviceSecurityCard_actions"
@@ -334,13 +334,13 @@ exports[`<CurrentDeviceSection /> renders device and correct security card when
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
Verify your current session for enhanced secure messaging. Verify your current session for enhanced secure messaging.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
<div <div
class="mx_DeviceSecurityCard_actions" class="mx_DeviceSecurityCard_actions"
@@ -521,13 +521,13 @@ exports[`<CurrentDeviceSection /> renders device and correct security card when
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
Verify your current session for enhanced secure messaging. Verify your current session for enhanced secure messaging.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
<div <div
class="mx_DeviceSecurityCard_actions" class="mx_DeviceSecurityCard_actions"
@@ -37,13 +37,13 @@ exports[`<DeviceDetailHeading /> displays name edit form on rename button click
id="device-rename-description-123" id="device-rename-description-123"
> >
Please be aware that session names are also visible to people you communicate with. Please be aware that session names are also visible to people you communicate with.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</span> </span>
</div> </div>
<div <div
@@ -59,13 +59,13 @@ exports[`<DeviceDetails /> renders a verified device 1`] = `
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
This session is ready for secure messaging. This session is ready for secure messaging.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
</div> </div>
</div> </div>
@@ -175,13 +175,13 @@ exports[`<DeviceDetails /> renders device with metadata 1`] = `
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
Verify or remove this session for best security and reliability. Verify or remove this session for best security and reliability.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
</div> </div>
</div> </div>
@@ -391,13 +391,13 @@ exports[`<DeviceDetails /> renders device without metadata 1`] = `
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
Verify or remove this session for best security and reliability. Verify or remove this session for best security and reliability.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
</div> </div>
</div> </div>
@@ -34,13 +34,13 @@ exports[`<DeviceVerificationStatusCard /> renders a verified device 1`] = `
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
This session is ready for secure messaging. This session is ready for secure messaging.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
</div> </div>
</div> </div>
@@ -79,13 +79,13 @@ exports[`<DeviceVerificationStatusCard /> renders an unverifiable device 1`] = `
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
This session doesn't support encryption and thus can't be verified. This session doesn't support encryption and thus can't be verified.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
</div> </div>
</div> </div>
@@ -124,13 +124,13 @@ exports[`<DeviceVerificationStatusCard /> renders an unverified device 1`] = `
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
Verify or remove this session for best security and reliability. Verify or remove this session for best security and reliability.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
<div <div
class="mx_DeviceSecurityCard_actions" class="mx_DeviceSecurityCard_actions"
@@ -39,13 +39,13 @@ HTMLCollection [
> >
<span> <span>
Consider removing old sessions (90 days or older) you don't use anymore. Consider removing old sessions (90 days or older) you don't use anymore.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</span> </span>
</p> </p>
</div> </div>
@@ -90,13 +90,13 @@ HTMLCollection [
> >
<span> <span>
Verify your sessions for enhanced secure messaging or remove from those you don't recognize or use anymore. Verify your sessions for enhanced secure messaging or remove from those you don't recognize or use anymore.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</span> </span>
</p> </p>
</div> </div>
@@ -143,13 +143,13 @@ HTMLCollection [
> >
<span> <span>
For best security, remove any session that you don't recognize or use anymore. For best security, remove any session that you don't recognize or use anymore.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</span> </span>
</p> </p>
</div> </div>
@@ -57,13 +57,13 @@ exports[`<SecurityRecommendations /> renders both cards when user has both unver
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
Verify your sessions for enhanced secure messaging or remove from those you don't recognize or use anymore. Verify your sessions for enhanced secure messaging or remove from those you don't recognize or use anymore.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
<div <div
class="mx_DeviceSecurityCard_actions" class="mx_DeviceSecurityCard_actions"
@@ -105,13 +105,13 @@ exports[`<SecurityRecommendations /> renders both cards when user has both unver
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
Consider removing old sessions (90 days or older) you don't use anymore. Consider removing old sessions (90 days or older) you don't use anymore.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
<div <div
class="mx_DeviceSecurityCard_actions" class="mx_DeviceSecurityCard_actions"
@@ -189,13 +189,13 @@ exports[`<SecurityRecommendations /> renders inactive devices section when user
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
Verify your sessions for enhanced secure messaging or remove from those you don't recognize or use anymore. Verify your sessions for enhanced secure messaging or remove from those you don't recognize or use anymore.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
<div <div
class="mx_DeviceSecurityCard_actions" class="mx_DeviceSecurityCard_actions"
@@ -237,13 +237,13 @@ exports[`<SecurityRecommendations /> renders inactive devices section when user
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
Consider removing old sessions (90 days or older) you don't use anymore. Consider removing old sessions (90 days or older) you don't use anymore.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
<div <div
class="mx_DeviceSecurityCard_actions" class="mx_DeviceSecurityCard_actions"
@@ -321,13 +321,13 @@ exports[`<SecurityRecommendations /> renders unverified devices section when use
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
Verify your sessions for enhanced secure messaging or remove from those you don't recognize or use anymore. Verify your sessions for enhanced secure messaging or remove from those you don't recognize or use anymore.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
<div <div
class="mx_DeviceSecurityCard_actions" class="mx_DeviceSecurityCard_actions"
@@ -369,13 +369,13 @@ exports[`<SecurityRecommendations /> renders unverified devices section when use
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
Consider removing old sessions (90 days or older) you don't use anymore. Consider removing old sessions (90 days or older) you don't use anymore.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
<div <div
class="mx_DeviceSecurityCard_actions" class="mx_DeviceSecurityCard_actions"
@@ -18,7 +18,6 @@ import {
RuleId, RuleId,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import React from "react"; import React from "react";
import { Form } from "@vector-im/compound-web";
import NotificationSettings2 from "../../../../../../src/components/views/settings/notifications/NotificationSettings2"; import NotificationSettings2 from "../../../../../../src/components/views/settings/notifications/NotificationSettings2";
import MatrixClientContext from "../../../../../../src/contexts/MatrixClientContext"; import MatrixClientContext from "../../../../../../src/contexts/MatrixClientContext";
@@ -94,9 +93,7 @@ describe("<Notifications />", () => {
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -109,9 +106,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(async () => { await act(async () => {
@@ -172,9 +167,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -190,9 +183,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -230,9 +221,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -267,9 +256,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -298,9 +285,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -325,9 +310,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -349,9 +332,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -379,9 +360,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -405,9 +384,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -429,9 +406,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -459,9 +434,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -485,9 +458,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -514,9 +485,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -535,9 +504,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -648,9 +615,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -709,9 +674,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const screen = render( const screen = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await act(waitForUpdate); await act(waitForUpdate);
@@ -731,9 +694,7 @@ describe("<Notifications />", () => {
const { container } = render( const { container } = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await waitForUpdate(); await waitForUpdate();
@@ -760,9 +721,7 @@ describe("<Notifications />", () => {
const user = userEvent.setup(); const user = userEvent.setup();
const { container } = render( const { container } = render(
<MatrixClientContext.Provider value={cli}> <MatrixClientContext.Provider value={cli}>
<Form.Root> <NotificationSettings2 />
<NotificationSettings2 />
</Form.Root>
</MatrixClientContext.Provider>, </MatrixClientContext.Provider>,
); );
await waitForUpdate(); await waitForUpdate();
@@ -38,11 +38,11 @@ exports[`AdvancedRoomSettingsTab should render as expected 1`] = `
<span> <span>
Internal room ID Internal room ID
</span> </span>
<div <span
class="mx_CopyableText mx_CopyableText_border" class="mx_CopyableText mx_CopyableText_border"
> >
!room:example.com !room:example.com
<div <button
aria-label="Copy" aria-label="Copy"
class="mx_AccessibleButton mx_CopyableText_copyButton" class="mx_AccessibleButton mx_CopyableText_copyButton"
role="button" role="button"
@@ -62,8 +62,8 @@ exports[`AdvancedRoomSettingsTab should render as expected 1`] = `
d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z" d="M8 10a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-9a2 2 0 0 1-2-2zm2 0v9h9v-9z"
/> />
</svg> </svg>
</div> </button>
</div> </span>
</div> </div>
</div> </div>
</div> </div>
@@ -186,7 +186,7 @@ exports[`<SecurityRoomSettingsTab /> join rule warns when trying to make an encr
<span> <span>
To avoid these issues, create a To avoid these issues, create a
<div <a
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
@@ -194,7 +194,7 @@ exports[`<SecurityRoomSettingsTab /> join rule warns when trying to make an encr
new public room new public room
</div> </a>
for the conversation you plan to have. for the conversation you plan to have.
</span> </span>
@@ -32,13 +32,13 @@ HTMLCollection [
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
This session doesn't support encryption and thus can't be verified. This session doesn't support encryption and thus can't be verified.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
</div> </div>
</div>, </div>,
@@ -238,13 +238,13 @@ exports[`<SessionManagerTab /> current session section renders current session s
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
Your current session is ready for secure messaging. Your current session is ready for secure messaging.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
</div> </div>
</div> </div>
@@ -411,13 +411,13 @@ exports[`<SessionManagerTab /> current session section renders current session s
class="mx_DeviceSecurityCard_description" class="mx_DeviceSecurityCard_description"
> >
Verify your current session for enhanced secure messaging. Verify your current session for enhanced secure messaging.
<div <button
class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
role="button" role="button"
tabindex="0" tabindex="0"
> >
Learn more Learn more
</div> </button>
</p> </p>
<div <div
class="mx_DeviceSecurityCard_actions" class="mx_DeviceSecurityCard_actions"
@@ -167,75 +167,75 @@ exports[`<SpaceSettingsVisibilityTab /> for a public space renders addresses sec
</form> </form>
</div> </div>
</fieldset> </fieldset>
<form <div
class="_root_19upo_16" class="mx_SettingsSection"
> >
<div <h3
class="mx_SettingsSection" class="mx_Heading_h4"
> >
<h3 Address
class="mx_Heading_h4" </h3>
<div
class="mx_SettingsSection_subSections"
>
<fieldset
class="mx_SettingsFieldset"
data-testid="published-address-fieldset"
> >
Address <legend
</h3> class="mx_SettingsFieldset_legend"
<div >
class="mx_SettingsSection_subSections" Published Addresses
> </legend>
<fieldset <div
class="mx_SettingsFieldset" class="mx_SettingsFieldset_description"
data-testid="published-address-fieldset"
> >
<legend
class="mx_SettingsFieldset_legend"
>
Published Addresses
</legend>
<div <div
class="mx_SettingsFieldset_description" class="mx_SettingsSubsection_text"
> >
<div Published addresses can be used by anyone on any server to join your space. To publish an address, it needs to be set as a local address first.
class="mx_SettingsSubsection_text"
>
Published addresses can be used by anyone on any server to join your space. To publish an address, it needs to be set as a local address first.
</div>
</div> </div>
</div>
<div
class="mx_SettingsFieldset_content"
>
<div <div
class="mx_SettingsFieldset_content" class="mx_Field mx_Field_select"
> >
<div <select
class="mx_Field mx_Field_select" disabled=""
id="canonicalAlias"
label="Main address"
placeholder="Main address"
type="text"
> >
<select <option
disabled="" value=""
id="canonicalAlias"
label="Main address"
placeholder="Main address"
type="text"
> >
<option not specified
value="" </option>
> </select>
not specified <label
</option> for="canonicalAlias"
</select> >
<label Main address
for="canonicalAlias" </label>
> <svg
Main address class="mx_Field_select_chevron"
</label> fill="currentColor"
<svg height="1em"
class="mx_Field_select_chevron" viewBox="0 0 24 24"
fill="currentColor" width="1em"
height="1em" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" >
width="1em" <path
xmlns="http://www.w3.org/2000/svg" d="M12 14.95q-.2 0-.375-.062a.9.9 0 0 1-.325-.213l-4.6-4.6a.95.95 0 0 1-.275-.7q0-.425.275-.7a.95.95 0 0 1 .7-.275q.425 0 .7.275l3.9 3.9 3.9-3.9a.95.95 0 0 1 .7-.275q.425 0 .7.275a.95.95 0 0 1 .275.7.95.95 0 0 1-.275.7l-4.6 4.6q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
> />
<path </svg>
d="M12 14.95q-.2 0-.375-.062a.9.9 0 0 1-.325-.213l-4.6-4.6a.95.95 0 0 1-.275-.7q0-.425.275-.7a.95.95 0 0 1 .7-.275q.425 0 .7.275l3.9 3.9 3.9-3.9a.95.95 0 0 1 .7-.275q.425 0 .7.275a.95.95 0 0 1 .275.7.95.95 0 0 1-.275.7l-4.6 4.6q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063" </div>
/> <form
</svg> class="_root_19upo_16"
</div> >
<div <div
class="_inline-field_19upo_32" class="_inline-field_19upo_32"
> >
@@ -274,59 +274,65 @@ exports[`<SpaceSettingsVisibilityTab /> for a public space renders addresses sec
</span> </span>
</div> </div>
</div> </div>
<datalist </form>
id="mx_AliasSettings_altRecommendations" <datalist
/> id="mx_AliasSettings_altRecommendations"
/>
<div
class="mx_EditableItemList"
id="roomAltAliases"
>
<div
class="mx_EditableItemList_label"
>
No other published addresses yet, add one below
</div>
<ul />
<div />
</div>
</div>
</fieldset>
<fieldset
class="mx_SettingsFieldset"
data-testid="local-address-fieldset"
>
<legend
class="mx_SettingsFieldset_legend"
>
Local Addresses
</legend>
<div
class="mx_SettingsFieldset_description"
>
<div
class="mx_SettingsSubsection_text"
>
Set addresses for this space so users can find this space through your homeserver (matrix.org)
</div>
</div>
<div
class="mx_SettingsFieldset_content"
>
<details>
<summary
class="mx_AliasSettings_localAddresses"
>
Show more
</summary>
<div <div
class="mx_EditableItemList" class="mx_EditableItemList"
id="roomAltAliases" id="roomAliases"
> >
<div <div
class="mx_EditableItemList_label" class="mx_EditableItemList_label"
> >
No other published addresses yet, add one below This space has no local addresses
</div> </div>
<ul /> <form
<div /> autocomplete="off"
</div> class="mx_EditableItemList_newItem"
</div> novalidate=""
</fieldset>
<fieldset
class="mx_SettingsFieldset"
data-testid="local-address-fieldset"
>
<legend
class="mx_SettingsFieldset_legend"
>
Local Addresses
</legend>
<div
class="mx_SettingsFieldset_description"
>
<div
class="mx_SettingsSubsection_text"
>
Set addresses for this space so users can find this space through your homeserver (matrix.org)
</div>
</div>
<div
class="mx_SettingsFieldset_content"
>
<details>
<summary
class="mx_AliasSettings_localAddresses"
> >
Show more
</summary>
<div
class="mx_EditableItemList"
id="roomAliases"
>
<div
class="mx_EditableItemList_label"
>
This space has no local addresses
</div>
<div <div
class="mx_Field mx_Field_input mx_RoomAliasField mx_Field_labelAlwaysTopLeft" class="mx_Field mx_Field_input mx_RoomAliasField mx_Field_labelAlwaysTopLeft"
> >
@@ -368,13 +374,13 @@ exports[`<SpaceSettingsVisibilityTab /> for a public space renders addresses sec
> >
Add Add
</div> </div>
</div> </form>
</details> </div>
</div> </details>
</fieldset> </div>
</div> </fieldset>
</div> </div>
</form> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -528,9 +534,6 @@ exports[`<SpaceSettingsVisibilityTab /> renders container 1`] = `
</form> </form>
</div> </div>
</fieldset> </fieldset>
<form
class="_root_19upo_16"
/>
</div> </div>
</div> </div>
</div> </div>
@@ -0,0 +1,18 @@
/*
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 { onSubmitPreventDefault } from "../../../src/utils/form.ts";
describe("onSubmitPreventDefault", () => {
it("should preventDefault", () => {
const event = new SubmitEvent("submit");
const spy = jest.spyOn(event, "preventDefault");
onSubmitPreventDefault(event);
expect(spy).toHaveBeenCalled();
});
});