Room list: persist section state (expanded/collapsed) (#34351)

* Add new setting to store section state

* Store section state in device settings

* Wire up section header view model and new section functions

* Update room list vm tests

* Add e2e test on section state persistence

* Use more intuitive syntax for SectionExpansionState

* Formatting

* Fix chats section staying expanded

* Add CHAT section case in e2e test
This commit is contained in:
Florian Duros
2026-07-29 13:56:40 +00:00
committed by GitHub
parent 1683525c5b
commit 7f8c4cef80
8 changed files with 267 additions and 29 deletions
@@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details.
*/
import { rejectToast } from "@element-hq/element-web-playwright-common";
import { rejectToast, rejectToastIfExists } from "@element-hq/element-web-playwright-common";
import { expect, test } from "../../../element-web-test";
import { SettingLevel } from "../../../../src/settings/SettingLevel";
@@ -229,6 +229,63 @@ test.describe("Room list sections", () => {
});
});
test.describe("Section collapse state persistence", () => {
test.beforeEach(async ({ app }) => {
// A favourite room (so we get a Favourites section) and a regular room in Chats,
// giving us two independent sections whose expansion state we can assert.
const favouriteId = await app.client.createRoom({ name: "favourite room" });
await app.client.evaluate(async (client, roomId) => {
await client.setRoomTag(roomId, "m.favourite");
}, favouriteId);
await app.client.createRoom({ name: "regular room" });
});
test("persists the collapsed/expanded state across reloads", async ({ page }) => {
const roomList = getRoomList(page);
const favouritesHeader = getSectionHeader(page, "Favourites");
const chatsHeader = getSectionHeader(page, "Chats");
const favRoom = roomList.getByRole("row", { name: "Open room favourite room" });
const regularRoom = roomList.getByRole("row", { name: "Open room regular room" });
// Collapse both the Favourites and Chats sections
await expect(favouritesHeader).toHaveAttribute("aria-expanded", "true");
await favouritesHeader.click();
await expect(favouritesHeader).toHaveAttribute("aria-expanded", "false");
await expect(favRoom).not.toBeVisible();
await expect(chatsHeader).toHaveAttribute("aria-expanded", "true");
await chatsHeader.click();
await expect(chatsHeader).toHaveAttribute("aria-expanded", "false");
await expect(regularRoom).not.toBeVisible();
// Reload the page: the collapsed state is persisted at the device level and should survive
await page.reload();
await rejectToastIfExists(page, "Verify this device");
await rejectToastIfExists(page, "Notifications");
// Both sections are still collapsed and their rooms stay hidden
await expect(getSectionHeader(page, "Favourites")).toHaveAttribute("aria-expanded", "false");
await expect(getRoomList(page).getByRole("row", { name: "Open room favourite room" })).not.toBeVisible();
await expect(getSectionHeader(page, "Chats")).toHaveAttribute("aria-expanded", "false");
await expect(getRoomList(page).getByRole("row", { name: "Open room regular room" })).not.toBeVisible();
// Expand them again and reload: the expanded state is likewise persisted
await getSectionHeader(page, "Favourites").click();
await expect(getSectionHeader(page, "Favourites")).toHaveAttribute("aria-expanded", "true");
await getSectionHeader(page, "Chats").click();
await expect(getSectionHeader(page, "Chats")).toHaveAttribute("aria-expanded", "true");
await page.reload();
await rejectToastIfExists(page, "Verify this device");
await rejectToastIfExists(page, "Notifications");
await expect(getSectionHeader(page, "Favourites")).toHaveAttribute("aria-expanded", "true");
await expect(getRoomList(page).getByRole("row", { name: "Open room favourite room" })).toBeVisible();
await expect(getSectionHeader(page, "Chats")).toHaveAttribute("aria-expanded", "true");
await expect(getRoomList(page).getByRole("row", { name: "Open room regular room" })).toBeVisible();
});
});
test.describe("Rooms placement in sections", () => {
test("should move a room between sections when tags change", async ({ page, app }) => {
await app.client.createRoom({ name: "my room" });