Files
pleno-vue/tests/unit/bird-configuration.spec.js
T
Jeppe B c85a82b9ac feat(bird): add Control Plane configuration (#237)
Adds a safe Bird Control Plane configuration surface with read-only health, credential redaction, protected capability switches, canonical workspace support, and focused frontend coverage.

Required CI passed on head cc04117d6b against master 3de5215b5e.
2026-07-29 19:19:17 +02:00

217 lines
7.1 KiB
JavaScript

// @vitest-environment jsdom
import { flushPromises, mount } from "@vue/test-utils";
import { beforeEach, describe, expect, it, vi } from "vitest";
const birdMocks = vi.hoisted(() => ({
getAll: vi.fn(),
getStatus: vi.fn(),
}));
vi.mock("@/components/displays/superuser/configuration/ConfigurationCategory.vue", () => ({
default: {
props: ["title", "subtitle"],
template: '<section class="configuration-category"><h2>{{ title }}</h2><p>{{ subtitle }}</p><slot /></section>',
},
}));
vi.mock("@/components/displays/superuser/configuration/ConfigurationInput.vue", () => ({
default: {
props: ["title", "value"],
template: '<div class="configuration-input">{{ title }}:{{ value }}</div>',
},
}));
vi.mock("@/components/displays/superuser/configuration/ConfigurationSecretKey.vue", () => ({
default: {
props: ["isSet"],
template: '<div data-testid="bird-secret-state">{{ isSet ? "set" : "unset" }}</div>',
},
}));
vi.mock("@/components/displays/superuser/configuration/ConfigurationSwitch.vue", () => ({
default: { template: "<div />" },
}));
vi.mock("@/components/global/PageTitle.vue", () => ({
default: { template: "<header />" },
}));
vi.mock("@/components/page/wrappers/RestrictedPageWrapper.vue", () => ({
default: { template: "<div><slot /></div>" },
}));
vi.mock("@/views/dashboards/superUserDashboard/configuration/ConfigurationSubPageWrapper.vue", () => ({
default: { template: '<main><slot name="title" /><slot name="content" /></main>' },
}));
vi.mock("@/components/session/token/SessionUser.vue", () => ({
SessionUser: {
canAccessSuperUser: () => true,
superUser: {
modules: {
bird: {
config: {
get_all: birdMocks.getAll,
enabled: { set: vi.fn() },
keys: {
api_key: { set: vi.fn() },
server_url: { set: vi.fn() },
workspaceId: { set: vi.fn() },
channelId: { set: vi.fn() },
participantId: { set: vi.fn() },
allowed_channel_ids_json: { set: vi.fn() },
control_plane_enabled: { set: vi.fn() },
control_plane_token: { set: vi.fn() },
webhook_signing_key: { set: vi.fn() },
webhook_public_url: { set: vi.fn() },
webhook_replay_window_seconds: { set: vi.fn() },
flow_enabled: { set: vi.fn() },
flow_shared_secret: { set: vi.fn() },
flow_policy_json: { set: vi.fn() },
operations_actions_enabled: { set: vi.fn() },
outbound_messages_enabled: { set: vi.fn() },
template_policy_json: { set: vi.fn() },
},
},
functions: {
getHealth: birdMocks.getStatus,
},
},
},
},
},
}));
import ConfigurationBird from "@/views/dashboards/superUserDashboard/configuration/ConfigurationBird.vue";
const global = {
mocks: {
$t: (key) => key,
},
};
describe("Bird configuration", () => {
beforeEach(() => {
birdMocks.getAll.mockReset();
birdMocks.getStatus.mockReset();
});
it("renders healthy read-only status and provider channel state", async () => {
birdMocks.getAll.mockResolvedValue({
data: {
data: {
enabled: { variable: "enabled", value: true },
workspaceId: { variable: "workspaceId", value: "workspace-current" },
},
},
});
birdMocks.getStatus.mockResolvedValue({
data: {
data: {
enabled: true,
configured: true,
providerReachable: true,
workspaceId: "workspace-current",
channelId: "channel-1",
check: "channels.list",
channels: [{ id: "channel-1", name: "Customer WhatsApp", platform: "whatsapp", status: "active" }],
},
},
});
const wrapper = mount(ConfigurationBird, { global });
await flushPromises();
expect(wrapper.get('[data-testid="bird-health-state"]').text()).toBe("configuration.bird.state.healthy");
expect(wrapper.text()).toContain("configuration.bird.read_only_health");
expect(wrapper.text()).toContain("channels.list");
expect(wrapper.text()).toContain("Customer WhatsApp");
expect(wrapper.text()).toContain("whatsapp");
expect(wrapper.text()).toContain("active");
});
it("uses workplaceId only as a display fallback while exposing the canonical field", async () => {
birdMocks.getAll.mockResolvedValue({
data: {
data: {
enabled: { variable: "enabled", value: false },
workplaceId: { variable: "workplaceId", value: "workspace-legacy" },
},
},
});
birdMocks.getStatus.mockResolvedValue({
data: {
data: {
enabled: false,
configured: false,
healthy: false,
},
},
});
const wrapper = mount(ConfigurationBird, { global });
await flushPromises();
expect(wrapper.get('[data-testid="bird-health-state"]').text()).toBe("configuration.bird.state.disabled");
expect(wrapper.text()).toContain("configuration.bird.workspace_id:workspace-legacy");
});
it("fails closed to an unavailable health state", async () => {
birdMocks.getAll.mockRejectedValue(new Error("Config unavailable"));
birdMocks.getStatus.mockRejectedValue(new Error("Health unavailable"));
const wrapper = mount(ConfigurationBird, { global });
await flushPromises();
expect(wrapper.get('[data-testid="bird-config-unavailable"]').text()).toBe("configuration.bird.config_unavailable");
expect(wrapper.get('[data-testid="bird-health-state"]').text()).toBe("configuration.bird.state.unavailable");
});
it("uses redacted secret metadata and never renders an accidentally returned secret value", async () => {
birdMocks.getAll.mockResolvedValue({
data: {
data: {
enabled: { variable: "enabled", value: true },
api_key: {
variable: "api_key",
value: "must-not-reach-the-dom",
isSecret: true,
isSet: true,
},
},
},
});
birdMocks.getStatus.mockResolvedValue({
data: {
data: {
enabled: true,
configured: true,
healthy: true,
channels: [],
},
},
});
const wrapper = mount(ConfigurationBird, { global });
await flushPromises();
expect(wrapper.get('[data-testid="bird-secret-state"]').text()).toBe("set");
expect(wrapper.text()).not.toContain("must-not-reach-the-dom");
});
it("redacts the legacy API key even before isSecret metadata is deployed", async () => {
birdMocks.getAll.mockResolvedValue({
data: {
data: {
enabled: { variable: "enabled", value: true },
api_key: { variable: "api_key", value: "legacy-raw-secret" },
},
},
});
birdMocks.getStatus.mockResolvedValue({
data: { data: { enabled: true, configured: true, healthy: true, channels: [] } },
});
const wrapper = mount(ConfigurationBird, { global });
await flushPromises();
expect(wrapper.get('[data-testid="bird-secret-state"]').text()).toBe("set");
expect(wrapper.text()).not.toContain("legacy-raw-secret");
});
});