Promote "Share encrypted history" from labs (#33281)

* Promote "Share encrypted history" from labs

* fix lint

* Update labs.md

* update snapshots

* Update unit tests

* update playwright screenshot
This commit is contained in:
Richard van der Hoff
2026-04-23 16:04:09 +00:00
committed by GitHub
parent c02b970d35
commit c4638d1773
14 changed files with 72 additions and 107 deletions
@@ -212,7 +212,7 @@ exports[`RoomView for a local room in state ERROR should match the snapshot 1`]
</div>
</div>
<div
aria-labelledby="_r_1c3_"
aria-labelledby="_r_1cl_"
class="_banner_n7ud0_8"
data-type="critical"
role="status"
@@ -238,7 +238,7 @@ exports[`RoomView for a local room in state ERROR should match the snapshot 1`]
>
<p
class="_typography_6v6n8_153 _font-body-md-medium_6v6n8_60 _title_1xryk_24"
id="_r_1c3_"
id="_r_1cl_"
>
Could not start a chat with this user
</p>
@@ -417,7 +417,7 @@ exports[`RoomView for a local room in state NEW should match the snapshot 1`] =
>
<svg
aria-label="Messages in this room are not end-to-end encrypted"
aria-labelledby="_r_197_"
aria-labelledby="_r_19j_"
class="mx_E2EIcon mx_MessageComposer_e2eIcon"
color="var(--cpd-color-icon-info-primary)"
fill="currentColor"
@@ -693,6 +693,24 @@ exports[`RoomView for a local room in state NEW that is encrypted should match t
>
@user:example.com
</span>
<svg
aria-label="New members see history"
aria-labelledby="_r_1cf_"
class="mx_RoomHeader_icon"
color="var(--cpd-color-icon-info-primary)"
fill="currentColor"
height="16px"
viewBox="0 0 24 24"
width="16px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M18.93 8A8 8 0 1 1 4 12a1 1 0 1 0-2 0c0 5.523 4.477 10 10 10s10-4.477 10-10a10 10 0 0 0-.832-4A10 10 0 0 0 12 2a9.99 9.99 0 0 0-8 3.999V4a1 1 0 0 0-2 0v4a1 1 0 0 0 1 1h4a1 1 0 0 0 0-2H5.755A7.99 7.99 0 0 1 12 4a8 8 0 0 1 6.93 4"
/>
<path
d="M13 8a1 1 0 1 0-2 0v4a1 1 0 0 0 .293.707l2.83 2.83a1 1 0 0 0 1.414-1.414L13 11.586z"
/>
</svg>
</div>
</div>
</button>
@@ -2838,6 +2856,24 @@ exports[`RoomView should not display the timeline when the room encryption is lo
>
!roomviewshouldnotdisplaythetimelinewhentheroomencryptionisloading:example.org
</span>
<svg
aria-label="New members see history"
aria-labelledby="_r_gc_"
class="mx_RoomHeader_icon"
color="var(--cpd-color-icon-info-primary)"
fill="currentColor"
height="16px"
viewBox="0 0 24 24"
width="16px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M18.93 8A8 8 0 1 1 4 12a1 1 0 1 0-2 0c0 5.523 4.477 10 10 10s10-4.477 10-10a10 10 0 0 0-.832-4A10 10 0 0 0 12 2a9.99 9.99 0 0 0-8 3.999V4a1 1 0 0 0-2 0v4a1 1 0 0 0 1 1h4a1 1 0 0 0 0-2H5.755A7.99 7.99 0 0 1 12 4a8 8 0 0 1 6.93 4"
/>
<path
d="M13 8a1 1 0 1 0-2 0v4a1 1 0 0 0 .293.707l2.83 2.83a1 1 0 0 0 1.414-1.414L13 11.586z"
/>
</svg>
</div>
</div>
</button>
@@ -3023,7 +3059,7 @@ exports[`RoomView should not display the timeline when the room encryption is lo
tabindex="0"
>
<div
aria-labelledby="_r_gc_"
aria-labelledby="_r_gh_"
class="mx_E2EIcon mx_MessageComposer_e2eIcon"
data-testid="e2e-icon"
style="width: 12px; height: 12px;"
@@ -3358,7 +3394,7 @@ exports[`RoomView video rooms should render joined video room view 1`] = `
</button>
<button
aria-label="Chat"
aria-labelledby="_r_kg_"
aria-labelledby="_r_ks_"
class="_icon-button_1215g_8"
data-kind="primary"
role="button"
@@ -3385,7 +3421,7 @@ exports[`RoomView video rooms should render joined video room view 1`] = `
</button>
<button
aria-label="Threads"
aria-labelledby="_r_kl_"
aria-labelledby="_r_l1_"
class="_icon-button_1215g_8"
data-kind="primary"
role="button"
@@ -3412,7 +3448,7 @@ exports[`RoomView video rooms should render joined video room view 1`] = `
</button>
<button
aria-label="Room info"
aria-labelledby="_r_kq_"
aria-labelledby="_r_l6_"
class="_icon-button_1215g_8"
data-kind="primary"
role="button"
@@ -3442,7 +3478,7 @@ exports[`RoomView video rooms should render joined video room view 1`] = `
>
<div
aria-label="0 members"
aria-labelledby="_r_kv_"
aria-labelledby="_r_lb_"
class="mx_AccessibleButton mx_FacePile"
role="button"
tabindex="0"
@@ -3527,7 +3563,7 @@ exports[`RoomView video rooms should render joined video room view 1`] = `
</p>
</div>
<button
aria-labelledby="_r_l8_"
aria-labelledby="_r_lk_"
class="_icon-button_1215g_8"
data-kind="secondary"
data-testid="base-card-close-button"
@@ -3587,7 +3623,7 @@ exports[`RoomView video rooms should render joined video room view 1`] = `
>
<svg
aria-label="Messages in this room are not end-to-end encrypted"
aria-labelledby="_r_ld_"
aria-labelledby="_r_lp_"
class="mx_E2EIcon mx_MessageComposer_e2eIcon"
color="var(--cpd-color-icon-info-primary)"
fill="currentColor"
@@ -60,7 +60,6 @@ import WidgetStore, { type IApp } from "../../../../../../src/stores/WidgetStore
import { UIFeature } from "../../../../../../src/settings/UIFeature";
import { SettingLevel } from "../../../../../../src/settings/SettingLevel";
import { ElementCallMemberEventType } from "../../../../../../src/call-types";
import { defaultWatchManager } from "../../../../../../src/settings/Settings.tsx";
jest.mock("../../../../../../src/utils/ShieldUtils");
jest.mock("../../../../../../src/hooks/right-panel/useCurrentPhase", () => ({
@@ -723,25 +722,9 @@ describe("RoomHeader", () => {
],
{ addToState: true },
);
let 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, "New members see history"));
// Disable the labs flag and check the icon disappears
featureEnabled = false;
act(() =>
defaultWatchManager.notifyUpdate(
"feature_share_history_on_invite",
null,
SettingLevel.DEVICE,
featureEnabled,
),
);
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 () => {
@@ -758,10 +741,6 @@ describe("RoomHeader", () => {
],
{ 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"));
@@ -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_13s_"
aria-labelledby="_r_14k_"
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_141_"
aria-labelledby="_r_14p_"
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_146_"
aria-labelledby="_r_14u_"
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_14b_"
aria-labelledby="_r_153_"
class="_icon-button_1215g_8"
data-kind="primary"
role="button"
@@ -24,7 +24,7 @@ describe("/invite", () => {
await command.run(client, roomId, null, args).promise;
expect(client.invite).toHaveBeenCalledWith(roomId, "@u:s.co", {});
expect(client.invite).toHaveBeenCalledWith(roomId, "@u:s.co", { shareEncryptedHistory: true });
});
it("should provide the invite reason if we supply it", async () => {
@@ -35,6 +35,9 @@ describe("/invite", () => {
await command.run(client, roomId, null, args).promise;
expect(client.invite).toHaveBeenCalledWith(roomId, "@u:s.co", { reason: "They are a very nice person" });
expect(client.invite).toHaveBeenCalledWith(roomId, "@u:s.co", {
reason: "They are a very nice person",
shareEncryptedHistory: true,
});
});
});
@@ -213,7 +213,7 @@ describe("RoomViewStore", function () {
dis.dispatch({ action: Action.ViewRoom, room_id: roomId });
dis.dispatch({ action: Action.JoinRoom });
await untilDispatch(Action.JoinRoomReady, dis);
expect(mockClient.joinRoom).toHaveBeenCalledWith(roomId, { viaServers: [] });
expect(mockClient.joinRoom).toHaveBeenCalledWith(roomId, { acceptSharedHistory: true, viaServers: [] });
expect(roomViewStore.isJoining()).toBe(true);
});
@@ -229,14 +229,14 @@ describe("RoomViewStore", function () {
}),
);
await untilDispatch(Action.JoinRoomReady, dis);
expect(mockClient.joinRoom).toHaveBeenCalledWith(alias, { viaServers: ["server1"] });
expect(mockClient.joinRoom).toHaveBeenCalledWith(alias, { acceptSharedHistory: true, viaServers: ["server1"] });
expect(roomViewStore.isJoining()).toBe(true);
});
it("can auto-join a room", async () => {
dis.dispatch({ action: Action.ViewRoom, room_id: roomId, auto_join: true });
await untilDispatch(Action.JoinRoomReady, dis);
expect(mockClient.joinRoom).toHaveBeenCalledWith(roomId, { viaServers: [] });
expect(mockClient.joinRoom).toHaveBeenCalledWith(roomId, { acceptSharedHistory: true, viaServers: [] });
expect(roomViewStore.isJoining()).toBe(true);
});
@@ -282,7 +282,7 @@ describe("RoomViewStore", function () {
await untilDispatch(Action.JoinRoomReady, dis);
expect(roomViewStore.isJoining()).toBeTruthy();
expect(mockClient.joinRoom).toHaveBeenCalledWith(alias, { viaServers: [] });
expect(mockClient.joinRoom).toHaveBeenCalledWith(alias, { acceptSharedHistory: true, viaServers: [] });
});
it("emits ViewRoomError if the alias lookup fails", async () => {
@@ -548,11 +548,7 @@ describe("RoomViewStore", function () {
expect(mocked(dis.dispatch).mock.calls[2][0]).toEqual({ action: "prompt_ask_to_join" });
});
it("sets 'acceptSharedHistory' if that option is enabled", async () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName, roomId, value) => {
return settingName === "feature_share_history_on_invite"; // this is enabled, everything else is disabled.
});
it("sets 'acceptSharedHistory'", async () => {
dis.dispatch({ action: Action.ViewRoom, room_id: roomId });
dis.dispatch({ action: Action.JoinRoom });
await untilDispatch(Action.JoinRoomReady, dis);
@@ -120,9 +120,9 @@ describe("MultiInviter", () => {
const result = await inviter.invite([MXID1, MXID2, MXID3]);
expect(client.invite).toHaveBeenCalledTimes(3);
expect(client.invite).toHaveBeenNthCalledWith(1, ROOMID, MXID1, {});
expect(client.invite).toHaveBeenNthCalledWith(2, ROOMID, MXID2, {});
expect(client.invite).toHaveBeenNthCalledWith(3, ROOMID, MXID3, {});
expect(client.invite).toHaveBeenNthCalledWith(1, ROOMID, MXID1, { shareEncryptedHistory: true });
expect(client.invite).toHaveBeenNthCalledWith(2, ROOMID, MXID2, { shareEncryptedHistory: true });
expect(client.invite).toHaveBeenNthCalledWith(3, ROOMID, MXID3, { shareEncryptedHistory: true });
expectAllInvitedResult(result);
});
@@ -138,9 +138,9 @@ describe("MultiInviter", () => {
const result = await inviter.invite([MXID1, MXID2, MXID3]);
expect(client.invite).toHaveBeenCalledTimes(3);
expect(client.invite).toHaveBeenNthCalledWith(1, ROOMID, MXID1, {});
expect(client.invite).toHaveBeenNthCalledWith(2, ROOMID, MXID2, {});
expect(client.invite).toHaveBeenNthCalledWith(3, ROOMID, MXID3, {});
expect(client.invite).toHaveBeenNthCalledWith(1, ROOMID, MXID1, { shareEncryptedHistory: true });
expect(client.invite).toHaveBeenNthCalledWith(2, ROOMID, MXID2, { shareEncryptedHistory: true });
expect(client.invite).toHaveBeenNthCalledWith(3, ROOMID, MXID3, { shareEncryptedHistory: true });
expectAllInvitedResult(result);
});
@@ -153,7 +153,7 @@ describe("MultiInviter", () => {
const result = await inviter.invite([MXID1, MXID2, MXID3]);
expect(client.invite).toHaveBeenCalledTimes(1);
expect(client.invite).toHaveBeenNthCalledWith(1, ROOMID, MXID1, {});
expect(client.invite).toHaveBeenNthCalledWith(1, ROOMID, MXID1, { shareEncryptedHistory: true });
// The resolved state is 'invited' for all users.
// With the above client expectations, the test ensures that only the first user is invited.
@@ -255,15 +255,5 @@ describe("MultiInviter", () => {
`"This space is unfederated. You cannot invite people from external servers."`,
);
});
it("should set shareEncryptedHistory if that setting is enabled", async () => {
mocked(SettingsStore.getValue).mockImplementation((settingName, roomId, value) => {
return settingName === "feature_share_history_on_invite"; // this is enabled, everything else is disabled.
});
await inviter.invite([MXID1]);
expect(client.invite).toHaveBeenCalledTimes(1);
expect(client.invite).toHaveBeenNthCalledWith(1, ROOMID, MXID1, { shareEncryptedHistory: true });
});
});
});