feat(FN-2394): add Fusion reinstall flow for Pi extensions
- Add dashboard route and server handling to reinstall the Fusion Pi extension - Introduce a client API helper and wire a reinstall action into PiExtensionsManager - Polish action spacing and document Fusion reinstall recovery in the CLI README - Expand route, API, and component tests including reinstall refresh stability coverage - Add a changeset for @runfusion/fusion patch release
This commit is contained in:
@@ -7,6 +7,7 @@ import { PiExtensionsManager } from "../PiExtensionsManager";
|
||||
const mockFetchPiSettings = vi.fn();
|
||||
const mockUpdatePiSettings = vi.fn();
|
||||
const mockInstallPiPackage = vi.fn();
|
||||
const mockReinstallFusionPiPackage = vi.fn();
|
||||
const mockFetchPiExtensions = vi.fn();
|
||||
const mockUpdatePiExtensions = vi.fn();
|
||||
|
||||
@@ -53,6 +54,7 @@ vi.mock("../../api", () => ({
|
||||
fetchPiSettings: (...args: unknown[]) => mockFetchPiSettings(...args),
|
||||
updatePiSettings: (...args: unknown[]) => mockUpdatePiSettings(...args),
|
||||
installPiPackage: (...args: unknown[]) => mockInstallPiPackage(...args),
|
||||
reinstallFusionPiPackage: (...args: unknown[]) => mockReinstallFusionPiPackage(...args),
|
||||
fetchPiExtensions: (...args: unknown[]) => mockFetchPiExtensions(...args),
|
||||
updatePiExtensions: (...args: unknown[]) => mockUpdatePiExtensions(...args),
|
||||
}));
|
||||
@@ -91,6 +93,7 @@ describe("PiExtensionsManager", () => {
|
||||
// Default mock for fetchPiExtensions to return empty settings
|
||||
mockFetchPiExtensions.mockResolvedValue({ extensions: [], disabledIds: [], settingsPath: "" });
|
||||
mockUpdatePiExtensions.mockResolvedValue({ extensions: [], disabledIds: [], settingsPath: "" });
|
||||
mockReinstallFusionPiPackage.mockResolvedValue({ success: true, source: "npm:@runfusion/fusion" });
|
||||
});
|
||||
|
||||
describe("Rendering", () => {
|
||||
@@ -113,6 +116,15 @@ describe("PiExtensionsManager", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("renders reinstall Fusion skill action", async () => {
|
||||
mockFetchPiSettings.mockResolvedValueOnce(mockPiSettings);
|
||||
render(<PiExtensionsManager addToast={addToast} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole("button", { name: "Reinstall Fusion skill" })).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
it("renders package list with source badges", async () => {
|
||||
mockFetchPiSettings.mockResolvedValueOnce(mockPiSettings);
|
||||
render(<PiExtensionsManager addToast={addToast} />);
|
||||
@@ -268,6 +280,55 @@ describe("PiExtensionsManager", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Reinstall Fusion action", () => {
|
||||
it("calls reinstall API and refreshes settings and extensions on success", async () => {
|
||||
mockFetchPiSettings.mockResolvedValue(mockPiSettings);
|
||||
mockFetchPiExtensions.mockResolvedValue({ extensions: [], disabledIds: [], settingsPath: "" });
|
||||
mockReinstallFusionPiPackage.mockResolvedValueOnce({ success: true, source: "npm:@runfusion/fusion" });
|
||||
|
||||
render(<PiExtensionsManager addToast={addToast} projectId="proj-123" />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole("button", { name: "Reinstall Fusion skill" })).toBeTruthy();
|
||||
});
|
||||
|
||||
const settingsCallsBefore = mockFetchPiSettings.mock.calls.length;
|
||||
const extensionCallsBefore = mockFetchPiExtensions.mock.calls.length;
|
||||
|
||||
await userEvent.click(screen.getByRole("button", { name: "Reinstall Fusion skill" }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockReinstallFusionPiPackage).toHaveBeenCalledWith("proj-123");
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(mockFetchPiSettings.mock.calls.length).toBeGreaterThan(settingsCallsBefore);
|
||||
expect(mockFetchPiExtensions.mock.calls.length).toBeGreaterThan(extensionCallsBefore);
|
||||
});
|
||||
expect(addToast).toHaveBeenCalledWith("Fusion skill reinstalled successfully", "success");
|
||||
});
|
||||
|
||||
it("shows error toast and resets loading state when reinstall fails", async () => {
|
||||
mockFetchPiSettings.mockResolvedValue(mockPiSettings);
|
||||
mockReinstallFusionPiPackage.mockRejectedValueOnce(new Error("Boom"));
|
||||
|
||||
render(<PiExtensionsManager addToast={addToast} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole("button", { name: "Reinstall Fusion skill" })).toBeTruthy();
|
||||
});
|
||||
|
||||
await userEvent.click(screen.getByRole("button", { name: "Reinstall Fusion skill" }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(addToast).toHaveBeenCalledWith("Failed to reinstall Fusion skill: Boom", "error");
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole("button", { name: "Reinstall Fusion skill" })).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Remove package", () => {
|
||||
it("calls updatePiSettings with package removed from list", async () => {
|
||||
mockFetchPiSettings.mockResolvedValueOnce(mockPiSettings);
|
||||
|
||||
Reference in New Issue
Block a user