mirror of
https://github.com/vector-im/element-web.git
synced 2026-05-04 19:56:45 +02:00
Room list: assign room to section when section is created (#33240)
* feat(rls): return section tag when created * feat(vm): assign section tag to room when section created * test: update exisiting tests * test(e2e): check that room is in section
This commit is contained in:
parent
bb4a7e9613
commit
546083bca9
@ -40,6 +40,22 @@ test.describe("Room list custom sections", () => {
|
||||
await expect(dialog).not.toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts a room is nested under a specific section using the treegrid aria-level hierarchy.
|
||||
* Section header rows sit at aria-level=1; room rows nested within a section sit at aria-level=2.
|
||||
* Verifies that the closest preceding aria-level=1 row is the expected section header.
|
||||
*/
|
||||
async function assertRoomInSection(page: Page, sectionName: string, roomName: string): Promise<void> {
|
||||
const roomList = getRoomList(page);
|
||||
const roomRow = roomList.getByRole("row", { name: `Open room ${roomName}` });
|
||||
// Room row must be at aria-level=2 (i.e. inside a section)
|
||||
await expect(roomRow).toHaveAttribute("aria-level", "2");
|
||||
// The closest preceding aria-level=1 row must be the expected section header.
|
||||
// XPath preceding:: axis returns nodes before the context in document order; [1] picks the nearest one.
|
||||
const closestSectionHeader = roomRow.locator(`xpath=preceding::*[@role="row" and @aria-level="1"][1]`);
|
||||
await expect(closestSectionHeader).toContainText(sectionName);
|
||||
}
|
||||
|
||||
test.beforeEach(async ({ page, app, user }) => {
|
||||
// The notification toast is displayed above the search section
|
||||
await app.closeNotificationToast();
|
||||
@ -97,6 +113,9 @@ test.describe("Room list custom sections", () => {
|
||||
|
||||
// The custom section should be created
|
||||
await expect(getSectionHeader(page, "Projects")).toBeVisible();
|
||||
|
||||
// Room should be moved to the new section
|
||||
await assertRoomInSection(page, "Projects", "my room");
|
||||
});
|
||||
|
||||
test("should cancel section creation when dialog is dismissed", async ({ page, app }) => {
|
||||
@ -177,22 +196,6 @@ test.describe("Room list custom sections", () => {
|
||||
});
|
||||
|
||||
test.describe("Adding a room to a custom section", () => {
|
||||
/**
|
||||
* Asserts a room is nested under a specific section using the treegrid aria-level hierarchy.
|
||||
* Section header rows sit at aria-level=1; room rows nested within a section sit at aria-level=2.
|
||||
* Verifies that the closest preceding aria-level=1 row is the expected section header.
|
||||
*/
|
||||
async function assertRoomInSection(page: Page, sectionName: string, roomName: string): Promise<void> {
|
||||
const roomList = getRoomList(page);
|
||||
const roomRow = roomList.getByRole("row", { name: `Open room ${roomName}` });
|
||||
// Room row must be at aria-level=2 (i.e. inside a section)
|
||||
await expect(roomRow).toHaveAttribute("aria-level", "2");
|
||||
// The closest preceding aria-level=1 row must be the expected section header.
|
||||
// XPath preceding:: axis returns nodes before the context in document order; [1] picks the nearest one.
|
||||
const closestSectionHeader = roomRow.locator(`xpath=preceding::*[@role="row" and @aria-level="1"][1]`);
|
||||
await expect(closestSectionHeader).toContainText(sectionName);
|
||||
}
|
||||
|
||||
test("should add a room to a custom section via the More Options menu", async ({ page, app }) => {
|
||||
await app.client.createRoom({ name: "my room" });
|
||||
await createCustomSection(page, "Work");
|
||||
|
||||
@ -491,10 +491,11 @@ export class RoomListStoreV3Class extends AsyncStoreWithClient<EmptyObject> {
|
||||
* Create a new section.
|
||||
* Emits {@link SECTION_CREATED_EVENT} if the section was successfully created.
|
||||
*/
|
||||
public async createSection(): Promise<void> {
|
||||
public async createSection(): Promise<string | undefined> {
|
||||
const tag = await createSection();
|
||||
if (!tag) return;
|
||||
this.emit(SECTION_CREATED_EVENT, tag);
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -400,8 +400,12 @@ export class RoomListItemViewModel
|
||||
echoChamber.notificationVolume = elementNotifState;
|
||||
};
|
||||
|
||||
public onCreateSection = (): void => {
|
||||
RoomListStoreV3.instance.createSection();
|
||||
public onCreateSection = async (): Promise<void> => {
|
||||
const newTag = await RoomListStoreV3.instance.createSection();
|
||||
// Add the room to the section
|
||||
if (newTag) {
|
||||
tagRoom(this.props.room, newTag);
|
||||
}
|
||||
};
|
||||
|
||||
public onToggleSection = (tag: string): void => {
|
||||
|
||||
@ -1021,11 +1021,10 @@ describe("RoomListStoreV3", () => {
|
||||
await store.start();
|
||||
|
||||
const sectionCreatedListener = jest.fn();
|
||||
const listsUpdateListener = jest.fn();
|
||||
store.on(SECTION_CREATED_EVENT, sectionCreatedListener);
|
||||
store.on(LISTS_UPDATE_EVENT, listsUpdateListener);
|
||||
|
||||
await store.createSection();
|
||||
const tag = await store.createSection();
|
||||
expect(tag).toBe("element.io.section.test-tag");
|
||||
|
||||
expect(sectionCreatedListener).toHaveBeenCalledWith("element.io.section.test-tag");
|
||||
});
|
||||
|
||||
@ -23,14 +23,15 @@ describe("createSection", () => {
|
||||
it.each([
|
||||
[false, "", undefined],
|
||||
[true, "", undefined],
|
||||
])("returns undefined when shouldCreate=%s and name='%s'", async (shouldCreate, name, expected) => {
|
||||
[true, "My Section", expect.stringMatching(/^element\.io\.section\./)],
|
||||
])("returns %s when shouldCreate=%s and name='%s'", async (shouldCreate, name, expected) => {
|
||||
jest.spyOn(Modal, "createDialog").mockReturnValue({
|
||||
finished: Promise.resolve([shouldCreate, name]),
|
||||
close: jest.fn(),
|
||||
} as any);
|
||||
|
||||
const result = await createSection();
|
||||
expect(result).toBe(expected);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it("returns the new tag when section is created", async () => {
|
||||
|
||||
@ -315,7 +315,9 @@ describe("RoomListHeaderViewModel", () => {
|
||||
});
|
||||
|
||||
it("should call createSection on RoomListStoreV3 when createSection is called", () => {
|
||||
const createSectionSpy = jest.spyOn(RoomListStoreV3.instance, "createSection").mockResolvedValue();
|
||||
const createSectionSpy = jest
|
||||
.spyOn(RoomListStoreV3.instance, "createSection")
|
||||
.mockResolvedValue("element.io.section.work");
|
||||
vm = new RoomListHeaderViewModel({ matrixClient, spaceStore: SpaceStore.instance });
|
||||
vm.createSection();
|
||||
expect(createSectionSpy).toHaveBeenCalled();
|
||||
|
||||
@ -15,6 +15,7 @@ import {
|
||||
type RoomMember,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { CallType } from "matrix-js-sdk/src/webrtc/call";
|
||||
import { waitFor } from "jest-matrix-react";
|
||||
|
||||
import { createTestClient, flushPromises } from "../../test-utils";
|
||||
import { RoomNotificationState } from "../../../src/stores/notifications/RoomNotificationState";
|
||||
@ -591,11 +592,17 @@ describe("RoomListItemViewModel", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should call createSection on RoomListStoreV3 when onCreateSection is called", () => {
|
||||
const createSectionSpy = jest.spyOn(RoomListStoreV3.instance, "createSection").mockResolvedValue();
|
||||
it("should call createSection on RoomListStoreV3 when onCreateSection is called", async () => {
|
||||
const createSectionSpy = jest
|
||||
.spyOn(RoomListStoreV3.instance, "createSection")
|
||||
.mockResolvedValue("element.io.section.work");
|
||||
const tagRoomSpy = jest.spyOn(tagRoomModule, "tagRoom").mockImplementation(() => {});
|
||||
|
||||
viewModel = new RoomListItemViewModel({ room, client: matrixClient });
|
||||
viewModel.onCreateSection();
|
||||
expect(createSectionSpy).toHaveBeenCalled();
|
||||
|
||||
await waitFor(() => expect(tagRoomSpy).toHaveBeenCalledWith(room, "element.io.section.work"));
|
||||
});
|
||||
|
||||
it("should call tagRoom when onToggleSection is called", () => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user