Files
pleno-vue/tests/unit/release-manager-workspace.spec.js
T

113 lines
4.1 KiB
JavaScript

// @vitest-environment jsdom
import { mount } from "@vue/test-utils";
import { describe, expect, it, vi } from "vitest";
import ReleaseContextBar from "@/components/release/ReleaseContextBar.vue";
import { normalizeReleasePanel, routeSlugForReleaseChannel } from "@/components/release/useReleaseManagerContext.js";
import { releaseEntityFacts, releaseEntityTooltipText } from "@/components/release/releaseEntityFacts.js";
const global = {
stubs: {
"b-button": {
props: ["disabled", "loading"],
emits: ["click"],
template: "<button :disabled='disabled' @click='$emit(\"click\", $event)'><slot /></button>",
},
"b-tag": {
template: "<span><slot /></span>",
},
"b-tooltip": {
template: "<span><slot name='content' /><slot /></span>",
},
},
};
describe("release manager workspace primitives", () => {
it("normalizes route panels and stable channel route slugs", () => {
expect(normalizeReleasePanel("bundles")).toBe("deployments");
expect(normalizeReleasePanel("replay")).toBe("operations");
expect(normalizeReleasePanel("failover")).toBe("data-services");
expect(normalizeReleasePanel("missing")).toBe("overview");
expect(routeSlugForReleaseChannel({ slug: "stable" })).toBe("master");
expect(routeSlugForReleaseChannel({ slug: "canary" })).toBe("canary");
});
it("builds concrete data-service tooltip facts", () => {
const facts = releaseEntityFacts({
type: "data service",
entity: {
kind: "database",
mode: "production_shared",
target: {
instance_label: "node-3",
deployment_status: "running",
version: "10.11",
replication: {
label: "mariadb-primary",
host: "db-1.truckwash.internal",
port: 3306,
status: "ok",
role: "primary",
lag_seconds: 0,
last_checked_at: "2026-05-21T10:00:00Z",
uptime_seconds: 86400,
},
},
},
});
const text = releaseEntityTooltipText(facts);
expect(text).toContain("Node: node-3");
expect(text).toContain("Online state: running");
expect(text).toContain("Hostname: db-1.truckwash.internal");
expect(text).toContain("Port: 3306");
expect(text).toContain("Replication role: primary");
expect(text).toContain("Last check: 2026-05-21T10:00:00Z");
});
it("emits global context changes and endpoint actions", async () => {
const wrapper = mount(ReleaseContextBar, {
props: {
channels: [
{ id: 1, slug: "stable", name: "Stable", default_channel: true },
{ id: 2, slug: "canary", name: "Canary" },
],
selectedChannelSlug: "stable",
selectedApp: "all",
selectedBranch: "master",
branchOptions: ["master", "canary"],
branchStatus: { frontend: { state: "available" }, api: { state: "available" } },
canDeploy: true,
},
global,
});
await wrapper.get('[data-testid="release-context-channel"]').setValue("canary");
await wrapper.get('[data-testid="release-context-app"]').setValue("api");
await wrapper.get('[data-testid="release-context-branch"]').setValue("canary");
await wrapper.get('[data-testid="release-context-test"]').trigger("click");
expect(wrapper.emitted("update:channel")?.[0]).toEqual(["canary"]);
expect(wrapper.emitted("update:app")?.[0]).toEqual(["api"]);
expect(wrapper.emitted("update:branch")?.[0]).toEqual(["canary"]);
expect(wrapper.emitted("test")).toHaveLength(1);
expect(wrapper.text()).toContain("/master/api");
});
it("shows missing branch context as a warning", () => {
const wrapper = mount(ReleaseContextBar, {
props: {
channels: [{ id: 3, slug: "internal", name: "Internal" }],
selectedChannelSlug: "internal",
selectedApp: "frontend",
selectedBranch: "internal",
branchStatus: { frontend: { state: "missing" } },
},
global,
});
expect(wrapper.get('[data-testid="release-context-branch-warning"]').text()).toContain("internal is missing");
});
});