logos-storage-installer/src/ui/mainMenu.test.js

244 lines
7.0 KiB
JavaScript
Raw Normal View History

2025-03-07 13:14:32 +01:00
import { describe, beforeEach, it, expect, vi } from "vitest";
2025-04-02 10:53:19 +02:00
import { MainMenu } from "./mainMenu.js";
import { mockUiService, mockCodexApp } from "../__mocks__/service.mocks.js";
2025-04-01 14:09:20 +02:00
import { mockInstallMenu, mockConfigMenu } from "../__mocks__/ui.mocks.js";
2025-04-15 14:01:44 +02:00
import {
mockInstaller,
mockProcessControl,
} from "../__mocks__/handler.mocks.js";
2025-04-01 14:09:20 +02:00
import { mockMenuLoop } from "../__mocks__/utils.mocks.js";
2025-03-07 13:14:32 +01:00
describe("mainmenu", () => {
let mainmenu;
2025-03-31 15:02:37 +02:00
2025-03-07 13:14:32 +01:00
beforeEach(() => {
vi.resetAllMocks();
2025-04-01 14:33:44 +02:00
mainmenu = new MainMenu(
mockUiService,
mockMenuLoop,
mockInstallMenu,
mockConfigMenu,
2025-04-15 14:01:44 +02:00
mockInstaller,
mockProcessControl,
mockCodexApp,
2025-04-01 14:33:44 +02:00
);
2025-04-01 14:09:20 +02:00
});
2025-03-07 13:14:32 +01:00
2025-04-15 14:01:44 +02:00
describe("constructor", () => {
it("initializes the menu loop with the promptMainMenu function", () => {
expect(mockMenuLoop.initialize).toHaveBeenCalledWith(
mainmenu.promptMainMenu,
);
});
2025-03-07 13:14:32 +01:00
});
2025-04-15 14:01:44 +02:00
describe("show", () => {
it("shows the logo", async () => {
await mainmenu.show();
expect(mockUiService.showLogo).toHaveBeenCalled();
});
it("starts the menu loop", async () => {
await mainmenu.show();
expect(mockMenuLoop.showLoop).toHaveBeenCalled();
});
});
describe("promptMainMenu", () => {
beforeEach(() => {
mainmenu.showRunningMenu = vi.fn();
mainmenu.showNotRunningMenu = vi.fn();
mainmenu.showNotInstalledMenu = vi.fn();
});
it("shows running menu when number of codex processes is greater than zero", async () => {
mockProcessControl.getNumberOfCodexProcesses.mockResolvedValue(1);
2025-03-07 13:14:32 +01:00
2025-04-15 14:01:44 +02:00
await mainmenu.promptMainMenu();
expect(mainmenu.showRunningMenu).toHaveBeenCalled();
expect(mainmenu.showNotRunningMenu).not.toHaveBeenCalled();
expect(mainmenu.showNotInstalledMenu).not.toHaveBeenCalled();
});
it("shows not running menu when number of codex processes is zero and codex is installed", async () => {
mockProcessControl.getNumberOfCodexProcesses.mockResolvedValue(0);
mockInstaller.isCodexInstalled.mockResolvedValue(true);
await mainmenu.promptMainMenu();
expect(mainmenu.showRunningMenu).not.toHaveBeenCalled();
expect(mainmenu.showNotRunningMenu).toHaveBeenCalled();
expect(mainmenu.showNotInstalledMenu).not.toHaveBeenCalled();
});
it("shows not installed menu when number of codex processes is zero and codex is not installed", async () => {
mockProcessControl.getNumberOfCodexProcesses.mockResolvedValue(0);
mockInstaller.isCodexInstalled.mockResolvedValue(false);
await mainmenu.promptMainMenu();
expect(mainmenu.showRunningMenu).not.toHaveBeenCalled();
expect(mainmenu.showNotRunningMenu).not.toHaveBeenCalled();
expect(mainmenu.showNotInstalledMenu).toHaveBeenCalled();
});
2025-04-01 14:09:20 +02:00
});
2025-04-15 14:01:44 +02:00
describe("showNotInstalledMenu", () => {
it("shows a menu with options to install Codex or exit", async () => {
await mainmenu.showNotInstalledMenu();
2025-04-01 14:09:20 +02:00
2025-04-15 14:01:44 +02:00
expect(mockUiService.askMultipleChoice).toHaveBeenCalledWith(
"Codex is not installed",
[
{ label: "Install Codex", action: mockInstallMenu.show },
{ label: "Exit", action: mockMenuLoop.stopLoop },
],
);
});
2025-04-01 14:09:20 +02:00
});
2025-04-15 14:01:44 +02:00
describe("showRunningMenu", () => {
it("shows a menu with options to stop Codex, open Codex app, or exit", async () => {
await mainmenu.showRunningMenu();
2025-04-01 14:09:20 +02:00
2025-04-15 14:01:44 +02:00
expect(mockUiService.askMultipleChoice).toHaveBeenCalledWith(
"Codex is running",
[
{ label: "Open Codex app", action: mockCodexApp.openCodexApp },
{ label: "Stop Codex", action: mainmenu.stopCodex },
{ label: "Exit (Codex keeps running)", action: mockMenuLoop.stopLoop },
2025-04-15 14:01:44 +02:00
],
);
});
2025-04-01 14:09:20 +02:00
});
2025-03-07 13:14:32 +01:00
2025-04-15 14:01:44 +02:00
describe("showNotRunningMenu", () => {
it("shows a menu with options to start Codex, configure, uninstall, or exit", async () => {
await mainmenu.showNotRunningMenu();
expect(mockUiService.askMultipleChoice).toHaveBeenCalledWith(
2025-04-16 09:42:11 +02:00
"Codex is installed but not running",
2025-04-15 14:01:44 +02:00
[
{
label: "Start Codex",
action: mainmenu.startCodex,
2025-04-15 14:01:44 +02:00
},
{ label: "Edit Codex config", action: mockConfigMenu.show },
{ label: "Uninstall Codex", action: mockInstallMenu.show },
{ label: "Exit", action: mockMenuLoop.stopLoop },
],
);
});
2025-03-07 13:14:32 +01:00
});
describe("process control", () => {
const mockSpinner = {
isMock: "yes",
};
beforeEach(() => {
mockUiService.createAndStartSpinner.mockReturnValue(mockSpinner);
});
describe("startCodex", () => {
it("starts codex", async () => {
await mainmenu.startCodex();
expect(mockProcessControl.startCodexProcess).toHaveBeenCalled();
});
it("shows error message when process control throws", async () => {
mockProcessControl.startCodexProcess.mockRejectedValueOnce(
new Error("A!"),
);
await mainmenu.startCodex();
expect(mockUiService.showErrorMessage).toHaveBeenCalledWith(
'Failed to start Codex. "Error: A!"',
);
});
it("starts spinner", async () => {
await mainmenu.startCodex();
expect(mockUiService.createAndStartSpinner).toHaveBeenCalledWith(
"Starting...",
);
});
it("stops spinner on success", async () => {
await mainmenu.startCodex();
expect(mockUiService.stopSpinnerSuccess).toHaveBeenCalledWith(
mockSpinner,
);
});
it("stops spinner on failure", async () => {
mockProcessControl.startCodexProcess.mockRejectedValueOnce(
new Error("A!"),
);
await mainmenu.startCodex();
expect(mockUiService.stopSpinnerError).toHaveBeenCalledWith(
mockSpinner,
);
});
});
describe("stopCodex", () => {
it("stops codex", async () => {
await mainmenu.stopCodex();
expect(mockProcessControl.stopCodexProcess).toHaveBeenCalled();
});
it("shows error message when process control throws", async () => {
mockProcessControl.stopCodexProcess.mockRejectedValueOnce(
new Error("A!"),
);
await mainmenu.stopCodex();
expect(mockUiService.showErrorMessage).toHaveBeenCalledWith(
'Failed to stop Codex. "Error: A!"',
);
});
it("starts spinner", async () => {
await mainmenu.stopCodex();
expect(mockUiService.createAndStartSpinner).toHaveBeenCalledWith(
"Stopping...",
);
});
it("stops spinner on success", async () => {
await mainmenu.stopCodex();
expect(mockUiService.stopSpinnerSuccess).toHaveBeenCalledWith(
mockSpinner,
);
});
it("stops spinner on failure", async () => {
mockProcessControl.stopCodexProcess.mockRejectedValueOnce(
new Error("A!"),
);
await mainmenu.stopCodex();
expect(mockUiService.stopSpinnerError).toHaveBeenCalledWith(
mockSpinner,
);
});
});
});
2025-03-07 13:14:32 +01:00
});