One component now owns the icon / heading / helper / action stack that the dashboard, accounts list, reminders list, and activity tab were each rendering inline. The four duplicated 'flex-col items-center py-12 text-center' Card blocks collapse to one shared surface so the empty experience reads the same wherever the user lands. Covered by 4 SSR tests (icon + title + description, omitted helper, action slot pass-through, centring). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
53 lines
1.9 KiB
TypeScript
53 lines
1.9 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
import { ActivityIcon } from "lucide-react";
|
|
import { EmptyState } from "./empty-state";
|
|
|
|
describe("EmptyState", () => {
|
|
it("renders the icon, title, and description", () => {
|
|
const html = renderToStaticMarkup(
|
|
<EmptyState
|
|
icon={ActivityIcon}
|
|
title="No activity yet."
|
|
description="Reminder fire events will appear here."
|
|
/>,
|
|
);
|
|
expect(html).toContain("No activity yet.");
|
|
expect(html).toContain("Reminder fire events will appear here.");
|
|
// The lucide icon component renders an <svg> with the lucide-activity class.
|
|
expect(html).toMatch(/<svg[^>]*lucide-activity/);
|
|
});
|
|
|
|
it("omits the description when it isn't passed", () => {
|
|
const html = renderToStaticMarkup(
|
|
<EmptyState icon={ActivityIcon} title="No archived runs." />,
|
|
);
|
|
expect(html).toContain("No archived runs.");
|
|
// No second <p> element for the helper text — the only <p> is the title.
|
|
expect((html.match(/<p\b/g) ?? []).length).toBe(1);
|
|
});
|
|
|
|
it("renders the action slot when provided", () => {
|
|
const html = renderToStaticMarkup(
|
|
<EmptyState
|
|
icon={ActivityIcon}
|
|
title="No reminders yet."
|
|
action={<button data-testid="cta">Schedule one</button>}
|
|
/>,
|
|
);
|
|
expect(html).toContain('data-testid="cta"');
|
|
expect(html).toContain("Schedule one");
|
|
});
|
|
|
|
it("centres the layout (icon → text → action stack)", () => {
|
|
const html = renderToStaticMarkup(
|
|
<EmptyState icon={ActivityIcon} title="x" action={<span>cta</span>} />,
|
|
);
|
|
// The CardContent uses flex-col items-center text-center for the
|
|
// canonical empty state layout. Lock that in so future tweaks
|
|
// can't accidentally drop the centring.
|
|
expect(html).toMatch(/flex-col items-center/);
|
|
expect(html).toMatch(/text-center/);
|
|
});
|
|
});
|