|
1 | 1 | /** |
2 | 2 | * Dashboard API helper tests |
3 | 3 | * |
4 | | - * Tests for periodToSeconds and computeOptimalInterval from |
5 | | - * src/lib/api/dashboards.ts. |
| 4 | + * Tests for periodToSeconds, computeOptimalInterval, and queryAllWidgets |
| 5 | + * from src/lib/api/dashboards.ts. |
6 | 6 | */ |
7 | 7 |
|
8 | 8 | import { describe, expect, test } from "bun:test"; |
9 | 9 | import { |
10 | 10 | computeOptimalInterval, |
11 | 11 | periodToSeconds, |
| 12 | + queryAllWidgets, |
12 | 13 | } from "../../../src/lib/api/dashboards.js"; |
13 | | -import type { DashboardWidget } from "../../../src/types/dashboard.js"; |
| 14 | +import type { |
| 15 | + DashboardDetail, |
| 16 | + DashboardWidget, |
| 17 | +} from "../../../src/types/dashboard.js"; |
14 | 18 |
|
15 | 19 | // --------------------------------------------------------------------------- |
16 | 20 | // periodToSeconds |
@@ -138,3 +142,73 @@ describe("computeOptimalInterval", () => { |
138 | 142 | expect(result).toBe("1m"); |
139 | 143 | }); |
140 | 144 | }); |
| 145 | + |
| 146 | +// --------------------------------------------------------------------------- |
| 147 | +// queryAllWidgets — text widget handling |
| 148 | +// --------------------------------------------------------------------------- |
| 149 | + |
| 150 | +/** |
| 151 | + * Build a minimal DashboardDetail with the given widgets. |
| 152 | + * |
| 153 | + * Text widgets carry markdown in `description` (a passthrough field not in |
| 154 | + * the typed schema), so widgets are cast via `as any`. |
| 155 | + */ |
| 156 | +function makeDashboard(widgets: Record<string, unknown>[]): DashboardDetail { |
| 157 | + return { id: "1", title: "Test Dashboard", widgets } as DashboardDetail; |
| 158 | +} |
| 159 | + |
| 160 | +describe("queryAllWidgets", () => { |
| 161 | + // Text widgets return immediately — no API call, no mocking needed. |
| 162 | + // regionUrl and orgSlug are unused for text widgets. |
| 163 | + const UNUSED_URL = "https://unused.example.com"; |
| 164 | + const UNUSED_ORG = "unused-org"; |
| 165 | + |
| 166 | + test("returns TextResult for text widget with description", async () => { |
| 167 | + const dashboard = makeDashboard([ |
| 168 | + { title: "Notes", displayType: "text", description: "# Hello\n**bold**" }, |
| 169 | + ]); |
| 170 | + |
| 171 | + const results = await queryAllWidgets(UNUSED_URL, UNUSED_ORG, dashboard); |
| 172 | + |
| 173 | + expect(results.size).toBe(1); |
| 174 | + expect(results.get(0)).toEqual({ |
| 175 | + type: "text", |
| 176 | + content: "# Hello\n**bold**", |
| 177 | + }); |
| 178 | + }); |
| 179 | + |
| 180 | + test("returns TextResult with empty content when description is missing", async () => { |
| 181 | + const dashboard = makeDashboard([ |
| 182 | + { title: "Empty Notes", displayType: "text" }, |
| 183 | + ]); |
| 184 | + |
| 185 | + const results = await queryAllWidgets(UNUSED_URL, UNUSED_ORG, dashboard); |
| 186 | + |
| 187 | + expect(results.get(0)).toEqual({ type: "text", content: "" }); |
| 188 | + }); |
| 189 | + |
| 190 | + test("returns TextResult with empty content for non-string description", async () => { |
| 191 | + const dashboard = makeDashboard([ |
| 192 | + { title: "Bad Description", displayType: "text", description: 42 }, |
| 193 | + ]); |
| 194 | + |
| 195 | + const results = await queryAllWidgets(UNUSED_URL, UNUSED_ORG, dashboard); |
| 196 | + |
| 197 | + expect(results.get(0)).toEqual({ type: "text", content: "" }); |
| 198 | + }); |
| 199 | + |
| 200 | + test("handles multiple text widgets in a single dashboard", async () => { |
| 201 | + const dashboard = makeDashboard([ |
| 202 | + { title: "Notes 1", displayType: "text", description: "First" }, |
| 203 | + { title: "Notes 2", displayType: "text", description: "Second" }, |
| 204 | + { title: "Notes 3", displayType: "text", description: "Third" }, |
| 205 | + ]); |
| 206 | + |
| 207 | + const results = await queryAllWidgets(UNUSED_URL, UNUSED_ORG, dashboard); |
| 208 | + |
| 209 | + expect(results.size).toBe(3); |
| 210 | + expect(results.get(0)).toEqual({ type: "text", content: "First" }); |
| 211 | + expect(results.get(1)).toEqual({ type: "text", content: "Second" }); |
| 212 | + expect(results.get(2)).toEqual({ type: "text", content: "Third" }); |
| 213 | + }); |
| 214 | +}); |
0 commit comments