d7620d912d
Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
133 lines
4.3 KiB
TypeScript
133 lines
4.3 KiB
TypeScript
import { cleanup, render, screen, waitFor } from "@testing-library/react";
|
|
import { TooltipProvider } from "@kandev/ui/tooltip";
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
import type { RuntimeFlagState } from "@/lib/types/runtime-flags";
|
|
import { renderSettingsRoute } from "./settings-routes";
|
|
|
|
// Route-level coverage. The component-level suite in
|
|
// components/settings/system/feature-toggles-settings.test.tsx cannot catch a
|
|
// route that supplies the wrong prop, which is exactly how the restart action
|
|
// was lost in #1389.
|
|
const mocks = vi.hoisted(() => ({
|
|
fetchRestartCapability: vi.fn(),
|
|
fetchRuntimeFlags: vi.fn(),
|
|
updateRuntimeFlag: vi.fn(),
|
|
fetchSystemInfo: vi.fn(),
|
|
requestRestart: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("@/lib/api/domains/system-api", () => ({
|
|
fetchRestartCapability: mocks.fetchRestartCapability,
|
|
fetchSystemInfo: mocks.fetchSystemInfo,
|
|
requestRestart: mocks.requestRestart,
|
|
}));
|
|
|
|
vi.mock("@/lib/api/domains/runtime-flags-api", () => ({
|
|
fetchRuntimeFlags: mocks.fetchRuntimeFlags,
|
|
updateRuntimeFlag: mocks.updateRuntimeFlag,
|
|
}));
|
|
|
|
vi.mock("@/components/toast-provider", () => ({
|
|
useToast: () => ({ toast: vi.fn() }),
|
|
}));
|
|
|
|
vi.mock("@/components/settings/settings-save-provider", () => ({
|
|
useSettingsSaveContributor: () => {},
|
|
}));
|
|
|
|
const PENDING_RESTART_FLAG: RuntimeFlagState = {
|
|
key: "features.office",
|
|
kind: "feature",
|
|
label: "Office mode",
|
|
description: "Enables autonomous agent office workflows and related settings.",
|
|
stability: "experimental",
|
|
risk_level: "medium",
|
|
risk_description: "Office mode is still evolving.",
|
|
effective_value: false,
|
|
default_value: false,
|
|
override_value: true,
|
|
source: "override",
|
|
env_var: "KANDEV_FEATURES_OFFICE",
|
|
env_locked: false,
|
|
restart_required: true,
|
|
requires_restart_to_apply: true,
|
|
mutable: true,
|
|
};
|
|
|
|
function renderFeatureTogglesRoute() {
|
|
return render(
|
|
<TooltipProvider>{renderSettingsRoute("/settings/system/feature-toggles")}</TooltipProvider>,
|
|
);
|
|
}
|
|
|
|
beforeEach(() => {
|
|
mocks.fetchRestartCapability.mockReset();
|
|
mocks.fetchRuntimeFlags.mockReset();
|
|
mocks.fetchRuntimeFlags.mockResolvedValue({ flags: [PENDING_RESTART_FLAG] });
|
|
});
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe("feature toggles route restart capability", () => {
|
|
it("offers the in-app restart action when the running backend supports restart", async () => {
|
|
mocks.fetchRestartCapability.mockResolvedValue({
|
|
supported: true,
|
|
mode: "supervisor",
|
|
adapter: "supervisor",
|
|
});
|
|
|
|
renderFeatureTogglesRoute();
|
|
|
|
expect(await screen.findByRole("button", { name: "Restart" })).not.toBeNull();
|
|
expect(screen.queryByText(/terminal or service manager/)).toBeNull();
|
|
});
|
|
|
|
it("falls back to manual guidance when the running backend cannot restart", async () => {
|
|
mocks.fetchRestartCapability.mockResolvedValue({
|
|
supported: false,
|
|
mode: "manual",
|
|
reason: "Automatic restart is not available for this launch mode.",
|
|
});
|
|
|
|
renderFeatureTogglesRoute();
|
|
|
|
expect(await screen.findByText(/terminal or service manager/)).not.toBeNull();
|
|
expect(screen.queryByRole("button", { name: "Restart" })).toBeNull();
|
|
});
|
|
|
|
it("fails closed to manual guidance when the capability request rejects", async () => {
|
|
mocks.fetchRestartCapability.mockRejectedValue(new Error("network down"));
|
|
|
|
renderFeatureTogglesRoute();
|
|
|
|
expect(await screen.findByText(/terminal or service manager/)).not.toBeNull();
|
|
expect(screen.queryByRole("button", { name: "Restart" })).toBeNull();
|
|
});
|
|
|
|
it("renders the toggle cards without waiting for the capability request", async () => {
|
|
let resolveCapability: (value: unknown) => void = () => {};
|
|
mocks.fetchRestartCapability.mockReturnValue(
|
|
new Promise((resolve) => {
|
|
resolveCapability = resolve;
|
|
}),
|
|
);
|
|
|
|
renderFeatureTogglesRoute();
|
|
|
|
// Cards are reachable while the capability request is still in flight.
|
|
expect(await screen.findByText("Office mode")).not.toBeNull();
|
|
expect(screen.queryByText(/terminal or service manager/)).toBeNull();
|
|
expect(screen.queryByRole("button", { name: "Restart" })).toBeNull();
|
|
|
|
resolveCapability({ supported: true, mode: "supervisor" });
|
|
|
|
await waitFor(() => {
|
|
expect(screen.queryByRole("button", { name: "Restart" })).not.toBeNull();
|
|
});
|
|
});
|
|
});
|