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
|
// 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;
|
const previousSibling = child.previousElementSibling as HTMLElement | null;
|
||||||
if (previousSibling && child.offsetLeft < previousSibling.offsetLeft) {
|
if (previousSibling && child.offsetLeft <= previousSibling.offsetLeft) {
|
||||||
if (!isWrapping) setWrappingIndex(i);
|
if (!isWrapping) setWrappingIndex(i);
|
||||||
isWrapping = true;
|
isWrapping = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,15 +35,26 @@ describe("<RoomListPrimaryFilters />", () => {
|
|||||||
|
|
||||||
vm = {
|
vm = {
|
||||||
primaryFilters: [
|
primaryFilters: [
|
||||||
{ name: "People", active: false, toggle: filterToggleMocks[0], key: FilterKey.PeopleFilter },
|
{ name: "People", active: true, toggle: filterToggleMocks[0], key: FilterKey.PeopleFilter },
|
||||||
{ name: "Rooms", active: true, toggle: filterToggleMocks[1], key: FilterKey.RoomsFilter },
|
{ name: "Rooms", active: false, toggle: filterToggleMocks[1], key: FilterKey.RoomsFilter },
|
||||||
{ name: "Unreads", active: false, toggle: filterToggleMocks[2], key: FilterKey.UnreadFilter },
|
{ name: "Unreads", active: false, toggle: filterToggleMocks[2], key: FilterKey.UnreadFilter },
|
||||||
],
|
],
|
||||||
} as unknown as RoomListViewState;
|
} 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", () => {
|
it("should renders all filters correctly", () => {
|
||||||
const { asFragment } = render(<RoomListPrimaryFilters vm={vm} />);
|
const { asFragment } = render(<RoomListPrimaryFilters vm={vm} />);
|
||||||
|
mockFiltersOffsetLeft();
|
||||||
|
|
||||||
// Check that all filters are rendered
|
// Check that all filters are rendered
|
||||||
expect(screen.getByRole("option", { name: "People" })).toBeInTheDocument();
|
expect(screen.getByRole("option", { name: "People" })).toBeInTheDocument();
|
||||||
@ -51,8 +62,8 @@ describe("<RoomListPrimaryFilters />", () => {
|
|||||||
expect(screen.getByRole("option", { name: "Unreads" })).toBeInTheDocument();
|
expect(screen.getByRole("option", { name: "Unreads" })).toBeInTheDocument();
|
||||||
|
|
||||||
// Check that the active filter is marked as selected
|
// 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", "true");
|
||||||
expect(screen.getByRole("option", { name: "People" })).toHaveAttribute("aria-selected", "false");
|
expect(screen.getByRole("option", { name: "Rooms" })).toHaveAttribute("aria-selected", "false");
|
||||||
expect(screen.getByRole("option", { name: "Unreads" })).toHaveAttribute("aria-selected", "false");
|
expect(screen.getByRole("option", { name: "Unreads" })).toHaveAttribute("aria-selected", "false");
|
||||||
|
|
||||||
expect(asFragment()).toMatchSnapshot();
|
expect(asFragment()).toMatchSnapshot();
|
||||||
@ -61,6 +72,7 @@ describe("<RoomListPrimaryFilters />", () => {
|
|||||||
it("should call toggle function when a filter is clicked", async () => {
|
it("should call toggle function when a filter is clicked", async () => {
|
||||||
const user = userEvent.setup();
|
const user = userEvent.setup();
|
||||||
render(<RoomListPrimaryFilters vm={vm} />);
|
render(<RoomListPrimaryFilters vm={vm} />);
|
||||||
|
mockFiltersOffsetLeft();
|
||||||
|
|
||||||
// Click on an inactive filter
|
// Click on an inactive filter
|
||||||
await user.click(screen.getByRole("option", { name: "People" }));
|
await user.click(screen.getByRole("option", { name: "People" }));
|
||||||
@ -69,24 +81,27 @@ describe("<RoomListPrimaryFilters />", () => {
|
|||||||
expect(filterToggleMocks[0]).toHaveBeenCalledTimes(1);
|
expect(filterToggleMocks[0]).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
function mockFiltersOffsetLeft() {
|
function makeUnreadWrapping() {
|
||||||
jest.spyOn(screen.getByRole("option", { name: "People" }), "offsetLeft", "get").mockReturnValue(0);
|
// Use `getByText` instead of `getByRole` to bypass the aria-hidden
|
||||||
jest.spyOn(screen.getByRole("option", { name: "Rooms" }), "offsetLeft", "get").mockReturnValue(30);
|
jest.spyOn(screen.getByText("People"), "offsetLeft", "get").mockReturnValue(0);
|
||||||
|
jest.spyOn(screen.getByText("Rooms"), "offsetLeft", "get").mockReturnValue(30);
|
||||||
// Unreads is wrapping
|
// 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 () => {
|
it("should hide or display filters if they are wrapping", async () => {
|
||||||
const user = userEvent.setup();
|
const user = userEvent.setup();
|
||||||
render(<RoomListPrimaryFilters vm={vm} />);
|
render(<RoomListPrimaryFilters vm={vm} />);
|
||||||
|
mockFiltersOffsetLeft();
|
||||||
|
|
||||||
// No filter is wrapping, so chevron shouldn't be visible
|
// No filter is wrapping, so chevron shouldn't be visible
|
||||||
expect(screen.queryByRole("button", { name: "Expand filter list" })).toBeNull();
|
expect(screen.queryByRole("button", { name: "Expand filter list" })).toBeNull();
|
||||||
expect(screen.queryByRole("option", { name: "Unreads" })).toBeVisible();
|
expect(screen.queryByRole("option", { name: "Unreads" })).toBeVisible();
|
||||||
|
|
||||||
mockFiltersOffsetLeft();
|
makeUnreadWrapping();
|
||||||
// @ts-ignore
|
|
||||||
act(() => resizeCallback([{ target: screen.getByRole("listbox", { name: "Room list filters" }) }]));
|
|
||||||
|
|
||||||
// The Unreads filter is wrapping, it should not be visible
|
// The Unreads filter is wrapping, it should not be visible
|
||||||
expect(screen.queryByRole("option", { name: "Unreads" })).toBeNull();
|
expect(screen.queryByRole("option", { name: "Unreads" })).toBeNull();
|
||||||
@ -107,9 +122,7 @@ describe("<RoomListPrimaryFilters />", () => {
|
|||||||
|
|
||||||
const user = userEvent.setup();
|
const user = userEvent.setup();
|
||||||
render(<RoomListPrimaryFilters vm={vm} />);
|
render(<RoomListPrimaryFilters vm={vm} />);
|
||||||
mockFiltersOffsetLeft();
|
makeUnreadWrapping();
|
||||||
// @ts-ignore
|
|
||||||
act(() => resizeCallback([{ target: screen.getByRole("listbox", { name: "Room list filters" }) }]));
|
|
||||||
|
|
||||||
// Unread filter should be moved to the first position
|
// Unread filter should be moved to the first position
|
||||||
expect(screen.getByRole("listbox", { name: "Room list filters" }).children[0]).toBe(
|
expect(screen.getByRole("listbox", { name: "Room list filters" }).children[0]).toBe(
|
||||||
@ -122,4 +135,21 @@ describe("<RoomListPrimaryFilters />", () => {
|
|||||||
screen.getByRole("option", { name: "Unreads" }),
|
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
|
<button
|
||||||
aria-hidden="false"
|
aria-hidden="false"
|
||||||
aria-selected="false"
|
aria-selected="true"
|
||||||
class="_chat-filter_5qdp0_8"
|
class="_chat-filter_5qdp0_8"
|
||||||
role="option"
|
role="option"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@ -25,7 +25,7 @@ exports[`<RoomListPrimaryFilters /> should renders all filters correctly 1`] = `
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
aria-hidden="false"
|
aria-hidden="false"
|
||||||
aria-selected="true"
|
aria-selected="false"
|
||||||
class="_chat-filter_5qdp0_8"
|
class="_chat-filter_5qdp0_8"
|
||||||
role="option"
|
role="option"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user