memos/web/tests/column-grid.test.tsx
johnnyjoygh 620db61f7c chore(web): unify compact truncation into a single ClampedSection
Compact cards previously had two truncation systems taped together: a
text-only clamp inside MemoContent (144px, no re-measure on image load,
fade tinted to the wrong surface) and a whole-tile cap in ColumnGrid
(hard clip mid-image, no affordance), later joined by a content-shape
rule choosing an owner per card — which could still stack two Show-more
buttons and silently broke footnote navigation in clamped cards.

Now there is exactly one mechanism: ClampedSection measures its content
and folds anything taller than 420px to a 360px preview with a fade and
a Show more/less toggle. MemoBody wraps the whole body in it (reactions
stay outside, never hidden); ColumnGrid is pure packing again and never
clips; MemoContent is a stateless renderer whose `compact` prop only
informs footnote-link behavior; MemoPreview uses a static CSS bound in
place of its previously inert toggle.

Deltas: text-only compact previews grow from ~6 rows to the same 360px
image cards get, and pinned memos clamp like any card (pinned means
ordering and a badge, not size).
2026-07-07 21:01:19 +08:00

44 lines
1.6 KiB
TypeScript

import { render } from "@testing-library/react";
import { describe, expect, it } 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("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);
});
});