121 lines
4.0 KiB
JavaScript
121 lines
4.0 KiB
JavaScript
import { RouterLinkStub, shallowMount } from "../../../frontend/node_modules/@vue/test-utils/dist/vue-test-utils.esm-bundler.mjs";
|
|
import { describe, expect, it } from "../../../frontend/node_modules/vitest/dist/index.js";
|
|
|
|
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");
|
|
});
|
|
});
|