mirror of
https://github.com/vector-im/element-web.git
synced 2025-11-09 20:51:41 +01:00
Avoid flicker of the room list filter on resize (#30787)
* fix: avoid flicker of the room list filter on resize * test: update existing test to render correctly * test: add test to avoid flicker regression
This commit is contained in:
parent
6f41ac58bc
commit
841f12bd46
@ -103,7 +103,7 @@ function useCollapseFilters<T extends HTMLElement>(
|
||||
|
||||
// If the previous element is on the left element of the current one, it means that the filter is wrapping
|
||||
const previousSibling = child.previousElementSibling as HTMLElement | null;
|
||||
if (previousSibling && child.offsetLeft < previousSibling.offsetLeft) {
|
||||
if (previousSibling && child.offsetLeft <= previousSibling.offsetLeft) {
|
||||
if (!isWrapping) setWrappingIndex(i);
|
||||
isWrapping = true;
|
||||
}
|
||||
|
||||
@ -35,15 +35,26 @@ describe("<RoomListPrimaryFilters />", () => {
|
||||
|
||||
vm = {
|
||||
primaryFilters: [
|
||||
{ name: "People", active: false, toggle: filterToggleMocks[0], key: FilterKey.PeopleFilter },
|
||||
{ name: "Rooms", active: true, toggle: filterToggleMocks[1], key: FilterKey.RoomsFilter },
|
||||
{ name: "People", active: true, toggle: filterToggleMocks[0], key: FilterKey.PeopleFilter },
|
||||
{ name: "Rooms", active: false, toggle: filterToggleMocks[1], key: FilterKey.RoomsFilter },
|
||||
{ name: "Unreads", active: false, toggle: filterToggleMocks[2], key: FilterKey.UnreadFilter },
|
||||
],
|
||||
} as unknown as RoomListViewState;
|
||||
});
|
||||
|
||||
function mockFiltersOffsetLeft() {
|
||||
// Use `getByText` instead of `getByRole` to bypass the aria-hidden
|
||||
jest.spyOn(screen.getByText("People"), "offsetLeft", "get").mockReturnValue(0);
|
||||
jest.spyOn(screen.getByText("Rooms"), "offsetLeft", "get").mockReturnValue(30);
|
||||
jest.spyOn(screen.getByText("Unreads"), "offsetLeft", "get").mockReturnValue(60);
|
||||
|
||||
// @ts-ignore
|
||||
act(() => resizeCallback([{ target: screen.getByRole("listbox", { name: "Room list filters" }) }]));
|
||||
}
|
||||
|
||||
it("should renders all filters correctly", () => {
|
||||
const { asFragment } = render(<RoomListPrimaryFilters vm={vm} />);
|
||||
mockFiltersOffsetLeft();
|
||||
|
||||
// Check that all filters are rendered
|
||||
expect(screen.getByRole("option", { name: "People" })).toBeInTheDocument();
|
||||
@ -51,8 +62,8 @@ describe("<RoomListPrimaryFilters />", () => {
|
||||
expect(screen.getByRole("option", { name: "Unreads" })).toBeInTheDocument();
|
||||
|
||||
// Check that the active filter is marked as selected
|
||||
expect(screen.getByRole("option", { name: "Rooms" })).toHaveAttribute("aria-selected", "true");
|
||||
expect(screen.getByRole("option", { name: "People" })).toHaveAttribute("aria-selected", "false");
|
||||
expect(screen.getByRole("option", { name: "People" })).toHaveAttribute("aria-selected", "true");
|
||||
expect(screen.getByRole("option", { name: "Rooms" })).toHaveAttribute("aria-selected", "false");
|
||||
expect(screen.getByRole("option", { name: "Unreads" })).toHaveAttribute("aria-selected", "false");
|
||||
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
@ -61,6 +72,7 @@ describe("<RoomListPrimaryFilters />", () => {
|
||||
it("should call toggle function when a filter is clicked", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<RoomListPrimaryFilters vm={vm} />);
|
||||
mockFiltersOffsetLeft();
|
||||
|
||||
// Click on an inactive filter
|
||||
await user.click(screen.getByRole("option", { name: "People" }));
|
||||
@ -69,24 +81,27 @@ describe("<RoomListPrimaryFilters />", () => {
|
||||
expect(filterToggleMocks[0]).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
function mockFiltersOffsetLeft() {
|
||||
jest.spyOn(screen.getByRole("option", { name: "People" }), "offsetLeft", "get").mockReturnValue(0);
|
||||
jest.spyOn(screen.getByRole("option", { name: "Rooms" }), "offsetLeft", "get").mockReturnValue(30);
|
||||
function makeUnreadWrapping() {
|
||||
// Use `getByText` instead of `getByRole` to bypass the aria-hidden
|
||||
jest.spyOn(screen.getByText("People"), "offsetLeft", "get").mockReturnValue(0);
|
||||
jest.spyOn(screen.getByText("Rooms"), "offsetLeft", "get").mockReturnValue(30);
|
||||
// Unreads is wrapping
|
||||
jest.spyOn(screen.getByRole("option", { name: "Unreads" }), "offsetLeft", "get").mockReturnValue(0);
|
||||
jest.spyOn(screen.getByText("Unreads"), "offsetLeft", "get").mockReturnValue(0);
|
||||
|
||||
// @ts-ignore
|
||||
act(() => resizeCallback([{ target: screen.getByRole("listbox", { name: "Room list filters" }) }]));
|
||||
}
|
||||
|
||||
it("should hide or display filters if they are wrapping", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<RoomListPrimaryFilters vm={vm} />);
|
||||
mockFiltersOffsetLeft();
|
||||
|
||||
// No filter is wrapping, so chevron shouldn't be visible
|
||||
expect(screen.queryByRole("button", { name: "Expand filter list" })).toBeNull();
|
||||
expect(screen.queryByRole("option", { name: "Unreads" })).toBeVisible();
|
||||
|
||||
mockFiltersOffsetLeft();
|
||||
// @ts-ignore
|
||||
act(() => resizeCallback([{ target: screen.getByRole("listbox", { name: "Room list filters" }) }]));
|
||||
makeUnreadWrapping();
|
||||
|
||||
// The Unreads filter is wrapping, it should not be visible
|
||||
expect(screen.queryByRole("option", { name: "Unreads" })).toBeNull();
|
||||
@ -107,9 +122,7 @@ describe("<RoomListPrimaryFilters />", () => {
|
||||
|
||||
const user = userEvent.setup();
|
||||
render(<RoomListPrimaryFilters vm={vm} />);
|
||||
mockFiltersOffsetLeft();
|
||||
// @ts-ignore
|
||||
act(() => resizeCallback([{ target: screen.getByRole("listbox", { name: "Room list filters" }) }]));
|
||||
makeUnreadWrapping();
|
||||
|
||||
// Unread filter should be moved to the first position
|
||||
expect(screen.getByRole("listbox", { name: "Room list filters" }).children[0]).toBe(
|
||||
@ -122,4 +135,21 @@ describe("<RoomListPrimaryFilters />", () => {
|
||||
screen.getByRole("option", { name: "Unreads" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("should hide the filter is the previous is on the same vertical position", async () => {
|
||||
render(<RoomListPrimaryFilters vm={vm} />);
|
||||
mockFiltersOffsetLeft();
|
||||
|
||||
jest.spyOn(screen.getByRole("option", { name: "People" }), "offsetLeft", "get").mockReturnValue(0);
|
||||
// Rooms is wrapping
|
||||
jest.spyOn(screen.getByRole("option", { name: "Rooms" }), "offsetLeft", "get").mockReturnValue(0);
|
||||
|
||||
// @ts-ignore
|
||||
act(() => resizeCallback([{ target: screen.getByRole("listbox", { name: "Room list filters" }) }]));
|
||||
|
||||
// The Unreads filter is wrapping, it should not be visible
|
||||
expect(screen.queryByRole("option", { name: "Rooms" })).toBeNull();
|
||||
// Now filters are wrapping, so chevron should be visible
|
||||
expect(screen.getByRole("button", { name: "Expand filter list" })).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
@ -16,7 +16,7 @@ exports[`<RoomListPrimaryFilters /> should renders all filters correctly 1`] = `
|
||||
>
|
||||
<button
|
||||
aria-hidden="false"
|
||||
aria-selected="false"
|
||||
aria-selected="true"
|
||||
class="_chat-filter_5qdp0_8"
|
||||
role="option"
|
||||
tabindex="0"
|
||||
@ -25,7 +25,7 @@ exports[`<RoomListPrimaryFilters /> should renders all filters correctly 1`] = `
|
||||
</button>
|
||||
<button
|
||||
aria-hidden="false"
|
||||
aria-selected="true"
|
||||
aria-selected="false"
|
||||
class="_chat-filter_5qdp0_8"
|
||||
role="option"
|
||||
tabindex="0"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user