mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
fix(insights): surface mood-insights read failures instead of silent degradation
The mood-insights regions returned nothing on a failed read by documented intent, degrading to the line chart. Enforce the honest-error standard here too: on error the main region paints a QueryErrorRow with retry, once, mirroring how the loading skeleton is scoped to that one region so the three regions do not stack identical rows. Test watched the silent empty first.
This commit is contained in:
1 parent
1229d54d30
commit
6485aae787
2 files changed
+64
-1
No files matched your search
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* The mood-insights regions used to render nothing on a failed read, by
|
||||
* documented intent ("degrades gracefully to the line chart"). The maintainer
|
||||
* decision is to enforce §6 here like everywhere else: a failed read is not an
|
||||
* empty page. The shared query is forced into its error state; the main "rest"
|
||||
* region has to surface a `query-error-row` with retry (mirroring the loading
|
||||
* convention, which also only paints in the "rest" region).
|
||||
*/
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
|
||||
vi.mock("@/hooks/use-auth", () => ({
|
||||
useAuth: () => ({
|
||||
user: { id: "u1" },
|
||||
isLoading: false,
|
||||
isAuthenticated: true,
|
||||
error: null,
|
||||
refetch: () => {},
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("@tanstack/react-query", () => ({
|
||||
useQuery: () => ({
|
||||
data: undefined,
|
||||
isLoading: false,
|
||||
isError: true,
|
||||
refetch: vi.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
import { I18nProvider } from "@/lib/i18n/context";
|
||||
import { MoodInsightsSections } from "../mood-insights-sections";
|
||||
|
||||
function render(region: "heatmap" | "assessment" | "rest") {
|
||||
return renderToStaticMarkup(
|
||||
<I18nProvider initialLocale="en">
|
||||
<MoodInsightsSections region={region} />
|
||||
</I18nProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
describe("<MoodInsightsSections> — a read failure is honest, not empty", () => {
|
||||
it("surfaces a query-error row with retry in the rest region", () => {
|
||||
const html = render("rest");
|
||||
expect(html).toContain('data-slot="query-error-row"');
|
||||
expect(html).toContain('data-slot="query-error-row-retry"');
|
||||
});
|
||||
|
||||
it("stays quiet in the heatmap/assessment regions to avoid stacking rows", () => {
|
||||
expect(render("heatmap")).toBe("");
|
||||
expect(render("assessment")).toBe("");
|
||||
});
|
||||
});
|
||||
@@ -7,6 +7,7 @@ import { CalendarDays, Sparkles } from "lucide-react";
|
||||
|
||||
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||
import { TileHeader } from "@/components/insights/tile-header";
|
||||
import { QueryErrorRow } from "@/components/ui/query-error-row";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
@@ -100,7 +101,7 @@ export function MoodInsightsSections({
|
||||
const { isAuthenticated } = useAuth();
|
||||
const { t } = useTranslations();
|
||||
|
||||
const { data, isLoading } = useQuery({
|
||||
const { data, isLoading, isError, refetch } = useQuery({
|
||||
queryKey: queryKeys.moodInsights(),
|
||||
queryFn: async () => {
|
||||
return apiGet<MoodInsightsResponse>("/api/mood/insights");
|
||||
@@ -118,6 +119,15 @@ export function MoodInsightsSections({
|
||||
) : null;
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
// §6 — a failed read is not an empty page. Surface it once, in the main
|
||||
// "rest" region (mirroring the loading convention above), rather than
|
||||
// stacking an identical row in all three regions down the page.
|
||||
return region === "rest" ? (
|
||||
<QueryErrorRow onRetry={() => refetch()} />
|
||||
) : null;
|
||||
}
|
||||
|
||||
if (!data || data.summary.totalEntries === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user