import { describe, expect, it } from "@jest/globals"; import { RouterLinkStub, shallowMount } from "@vue/test-utils"; import MetricRow from "../../../frontend/src/components/MetricRow.vue"; import ServiceGrid from "../../../frontend/src/components/ServiceGrid.vue"; import StatsGrid from "../../../frontend/src/components/StatsGrid.vue"; import { fallbackHardware } from "../../../frontend/src/data/sample.js"; describe("shared dashboard components", () => { it("renders metric cards", () => { const wrapper = shallowMount(MetricRow, { props: { items: [ { label: "Nodes", value: "26", note: "atlas + oceanus" }, { label: "Storage", value: "80 TB", note: "Longhorn" }, ], }, }); expect(wrapper.text()).toContain("Nodes"); expect(wrapper.text()).toContain("26"); expect(wrapper.text()).toContain("Longhorn"); }); it("summarizes node state in the stats grid", () => { const wrapper = shallowMount(StatsGrid, { props: { hardware: fallbackHardware() }, }); expect(wrapper.text()).toContain("Control plane"); expect(wrapper.text()).toContain("3"); expect(wrapper.text()).toContain("offline"); expect(wrapper.text()).toContain("titan-16"); }); it("hides the attention card when every worker is healthy", () => { const wrapper = shallowMount(StatsGrid, { props: { hardware: { clusters: [ { name: "atlas", nodes: [{ name: "titan-0a", role: "control-plane", status: "ready" }], }, ], specialty: [], }, }, }); expect(wrapper.text()).not.toContain("Attention"); }); it("distinguishes internal and external service links", () => { const wrapper = shallowMount(ServiceGrid, { global: { stubs: { RouterLink: RouterLinkStub, }, }, props: { services: [ { name: "Atlas AI", category: "ai", summary: "Chat", link: "/ai/chat", icon: "🤖" }, { name: "Nextcloud", category: "productivity", summary: "Files", link: "https://cloud.example.dev", icon: "☁️" }, { name: "Bad Link", category: "broken", summary: "invalid", link: "not a url", icon: "❓" }, ], }, }); expect(wrapper.text()).toContain("Atlas AI"); expect(wrapper.text()).toContain("cloud.example.dev"); expect(wrapper.text()).toContain("not a url"); expect(wrapper.findComponent(RouterLinkStub).exists()).toBe(true); }); it("falls back to default service rendering when data is sparse", () => { const wrapper = shallowMount(ServiceGrid, { global: { stubs: { RouterLink: RouterLinkStub, }, }, props: { services: [ { name: "Muted Service", category: "dev", summary: "planned", link: "", status: "planned" }, { name: "Plain Service", category: "dev", summary: "fallback icon", link: "/apps" }, ], }, }); expect(wrapper.text()).toContain("Muted Service"); expect(wrapper.text()).toContain("fallback icon"); expect(wrapper.findAll(".service").length).toBe(2); expect(wrapper.findComponent(RouterLinkStub).exists()).toBe(true); }); it("renders empty and partial hardware states safely", () => { const wrapper = shallowMount(StatsGrid, { props: { hardware: { clusters: [{ name: "atlas", nodes: [{ name: "solo", role: "worker", status: "ready" }] }], specialty: [{ name: "standalone", role: "Spare node", status: "ready" }], }, }, }); expect(wrapper.text()).toContain("1 nodes total"); expect(wrapper.text()).toContain("0"); expect(wrapper.text()).toContain("standalone"); }); it("falls back cleanly when no hardware prop is provided", () => { const wrapper = shallowMount(StatsGrid, { props: {}, }); expect(wrapper.text()).toContain("0 nodes total"); expect(wrapper.text()).not.toContain("Attention"); }); });