memos/web/tests/column-grid.test.tsx
johnnyjoygh 55d8e6ad42 chore(web): compact user profile header and in-place views on profiles
The user page at /u/:username now opens with a compact identity block
(40px
avatar, name, handle, clamped bio) instead of a hero header with a share
button, and the list beneath it follows the user's column setting like
Explore does. In grid mode the header spans every column via a new
ColumnGrid
header slot, exposed through PagedMemoList.renderHeader. Loading shows a
skeleton after the standard delay, not-found renders a body instead of a
toast fired from render, and visitors get an explicit empty message.

Saved views now apply on profile routes too. A single profile-route
matcher
in lib/memo-views replaces five separate spellings,
isMemoCollectionRoute
names the routes where views, calendar days and tags narrow the list in
place, and the sidebar shows the Views section on every such route for
signed-in users. The never-taken navigation-target branch in the
collection
sidebar is removed along with its props.
2026-09-05 00:22:05 +08:00

87 lines
3.6 KiB
TypeScript

import { DirectionProvider } from "@base-ui/react/direction-provider";
import { render } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import ColumnGrid from "@/components/ColumnGrid";
// jsdom has no layout engine (offsetHeight/clientWidth are 0) and no ResizeObserver,
// both of which ColumnGrid guards for — so these assert render structure, not positioning.
interface Item {
id: string;
}
const item = (id: string): Item => ({ id });
const getKey = (i: Item) => i.id;
describe("<ColumnGrid>", () => {
it("renders one card per item", () => {
const { container } = render(
<ColumnGrid items={[item("a"), item("b"), item("c")]} getKey={getKey} renderItem={(i) => <div data-testid="card">{i.id}</div>} />,
);
expect(container.querySelectorAll('[data-testid="card"]')).toHaveLength(3);
});
it("renders the leading node as the first tile, before the items", () => {
const { container, getByTestId } = render(
<ColumnGrid
items={[item("a")]}
getKey={getKey}
renderItem={(i) => <div data-testid={`card-${i.id}`}>{i.id}</div>}
leading={<div data-testid="composer" />}
/>,
);
expect(getByTestId("composer")).toBeInTheDocument();
// The grid is the container's only child; its first wrapper holds the leading node.
const grid = container.firstElementChild as HTMLElement;
expect(grid.children[0].querySelector('[data-testid="composer"]')).not.toBeNull();
});
it("spans the header across the packed columns and starts every column below it", () => {
// 532px fits two 260px columns with a 12px gap; every measured height is 100px.
const clientWidth = vi.spyOn(HTMLElement.prototype, "clientWidth", "get").mockReturnValue(532);
const offsetHeight = vi.spyOn(HTMLElement.prototype, "offsetHeight", "get").mockReturnValue(100);
const { getByTestId } = render(
<ColumnGrid
items={[item("a"), item("b")]}
getKey={getKey}
renderItem={(i) => <div data-testid={`card-${i.id}`}>{i.id}</div>}
header={<div data-testid="identity" />}
/>,
);
const header = getByTestId("identity").parentElement as HTMLElement;
expect(header.style.width).toBe("532px");
expect(header.style.left).toBe("0px");
// Header height plus one grid gap: both columns begin on the same line beneath it.
expect(getByTestId("card-a").parentElement?.style.transform).toContain("translate3d(0px, 112px");
expect(getByTestId("card-b").parentElement?.style.transform).toContain("translate3d(272px, 112px");
clientWidth.mockRestore();
offsetHeight.mockRestore();
});
it("renders nothing for an empty list", () => {
const { container } = render(<ColumnGrid items={[]} getKey={getKey} renderItem={() => <div data-testid="card" />} />);
expect(container.querySelectorAll('[data-testid="card"]')).toHaveLength(0);
});
it("places the first packed column at inline start in RTL", () => {
const clientWidth = vi.spyOn(HTMLElement.prototype, "clientWidth", "get").mockReturnValue(532);
const offsetHeight = vi.spyOn(HTMLElement.prototype, "offsetHeight", "get").mockReturnValue(100);
const { getByTestId } = render(
<DirectionProvider direction="rtl">
<ColumnGrid items={[item("a"), item("b")]} getKey={getKey} renderItem={(i) => <div data-testid={`card-${i.id}`}>{i.id}</div>} />
</DirectionProvider>,
);
expect(getByTestId("card-a").parentElement?.style.transform).toContain("translate3d(272px");
expect(getByTestId("card-b").parentElement?.style.transform).toContain("translate3d(0px");
clientWidth.mockRestore();
offsetHeight.mockRestore();
});
});