mirror of
https://github.com/logos-storage/logos-storage-installer.git
synced 2026-01-05 15:03:06 +00:00
covers configmenu with tests
This commit is contained in:
parent
1f694f7534
commit
36395b62ec
@ -5,7 +5,7 @@ export const mockUiService = {
|
||||
showInfoMessage: vi.fn(),
|
||||
showErrorMessage: vi.fn(),
|
||||
askMultipleChoice: vi.fn(),
|
||||
askPrompt: vi.fn()
|
||||
askPrompt: vi.fn(),
|
||||
};
|
||||
|
||||
export const mockConfigService = {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { vi } from "vitest";
|
||||
|
||||
export const mockInstallMenu = {
|
||||
show: vi.fn()
|
||||
show: vi.fn(),
|
||||
};
|
||||
|
||||
export const mockConfigMenu = {
|
||||
show: vi.fn()
|
||||
show: vi.fn(),
|
||||
};
|
||||
|
||||
@ -99,7 +99,12 @@ export async function main() {
|
||||
const pathSelector = new PathSelector(uiService, fsService);
|
||||
const numberSelector = new NumberSelector(uiService);
|
||||
const installMenu = new InstallMenu(uiService, configService);
|
||||
const configMenu = new ConfigMenu(uiService, configService, pathSelector, numberSelector)
|
||||
const configMenu = new ConfigMenu(
|
||||
uiService,
|
||||
configService,
|
||||
pathSelector,
|
||||
numberSelector,
|
||||
);
|
||||
const mainMenu = new MainMenu(uiService, installMenu, configMenu);
|
||||
|
||||
await mainMenu.show();
|
||||
|
||||
@ -28,7 +28,7 @@ export class ConfigService {
|
||||
|
||||
get = () => {
|
||||
return this.config;
|
||||
}
|
||||
};
|
||||
|
||||
loadConfig = () => {
|
||||
const filePath = this.getConfigFilename();
|
||||
@ -44,7 +44,7 @@ export class ConfigService {
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
saveConfig = () => {
|
||||
const filePath = this.getConfigFilename();
|
||||
@ -56,9 +56,9 @@ export class ConfigService {
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
getConfigFilename = () => {
|
||||
return path.join(getAppDataDir(), "config.json");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,54 +1,66 @@
|
||||
export class ConfigMenu {
|
||||
constructor(uiService, configService, pathSelector, numberSelector) {
|
||||
constructor(
|
||||
uiService,
|
||||
menuLoop,
|
||||
configService,
|
||||
pathSelector,
|
||||
numberSelector,
|
||||
) {
|
||||
this.ui = uiService;
|
||||
this.loop = menuLoop;
|
||||
this.configService = configService;
|
||||
this.pathSelector = pathSelector;
|
||||
this.numberSelector = numberSelector;
|
||||
|
||||
this.loop.initialize(this.showConfigMenu);
|
||||
}
|
||||
|
||||
show = async() => {
|
||||
this.running = true;
|
||||
show = async () => {
|
||||
this.config = this.configService.get();
|
||||
while (this.running) {
|
||||
this.ui.showInfoMessage("Codex Configuration");
|
||||
await this.ui.askMultipleChoice("Select to edit:",[
|
||||
{
|
||||
label: `Data path = "${this.config.dataDir}"`,
|
||||
action: this.editDataDir,
|
||||
},
|
||||
{
|
||||
label: `Logs path = "${this.config.logsDir}"`,
|
||||
action: this.editLogsDir,
|
||||
},
|
||||
{
|
||||
label: `Storage quota = ${this.bytesAmountToString(this.config.storageQuota)}`,
|
||||
action: this.editStorageQuota,
|
||||
},
|
||||
{
|
||||
label: `Discovery port = ${this.config.ports.discPort}`,
|
||||
action: this.editDiscPort,
|
||||
},
|
||||
{
|
||||
label: `P2P listen port = ${this.config.ports.listenPort}`,
|
||||
action: this.editListenPort,
|
||||
},
|
||||
{
|
||||
label: `API port = ${this.config.ports.apiPort}`,
|
||||
action: this.editApiPort,
|
||||
},
|
||||
{
|
||||
label: "Save changes and exit",
|
||||
action: this.saveChangesAndExit,
|
||||
},
|
||||
{
|
||||
label: "Discard changes and exit",
|
||||
action: this.discardChangesAndExit,
|
||||
}
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
this.ui.showInfoMessage("Codex Configuration");
|
||||
await this.loop.showLoop();
|
||||
};
|
||||
|
||||
showConfigMenu = async () => {
|
||||
await this.ui.askMultipleChoice("Select to edit:", [
|
||||
{
|
||||
label: `Data path = "${this.config.dataDir}"`,
|
||||
action: this.editDataDir,
|
||||
},
|
||||
{
|
||||
label: `Logs path = "${this.config.logsDir}"`,
|
||||
action: this.editLogsDir,
|
||||
},
|
||||
{
|
||||
label: `Storage quota = ${this.bytesAmountToString(this.config.storageQuota)}`,
|
||||
action: this.editStorageQuota,
|
||||
},
|
||||
{
|
||||
label: `Discovery port = ${this.config.ports.discPort}`,
|
||||
action: this.editDiscPort,
|
||||
},
|
||||
{
|
||||
label: `P2P listen port = ${this.config.ports.listenPort}`,
|
||||
action: this.editListenPort,
|
||||
},
|
||||
{
|
||||
label: `API port = ${this.config.ports.apiPort}`,
|
||||
action: this.editApiPort,
|
||||
},
|
||||
{
|
||||
label: "Save changes and exit",
|
||||
action: this.saveChangesAndExit,
|
||||
},
|
||||
{
|
||||
label: "Discard changes and exit",
|
||||
action: this.discardChangesAndExit,
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
// this and the byte-format handling in
|
||||
// numberSelector should be extracted to
|
||||
// their own util.
|
||||
bytesAmountToString = (numBytes) => {
|
||||
const units = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
|
||||
@ -61,18 +73,16 @@ export class ConfigMenu {
|
||||
|
||||
if (index == 0) return `${numBytes} Bytes`;
|
||||
return `${numBytes} Bytes (${value} ${units[index]})`;
|
||||
}
|
||||
};
|
||||
|
||||
editDataDir = async () => {
|
||||
// todo
|
||||
// function updateDataDir(config, newDataDir) {
|
||||
// if (config.dataDir == newDataDir) return config;
|
||||
|
||||
// // The Codex dataDir is a little strange:
|
||||
// // If the old one is empty: The new one should not exist, so that codex creates it
|
||||
// // with the correct security permissions.
|
||||
// // If the old one does exist: We move it.
|
||||
|
||||
// if (isDir(config.dataDir)) {
|
||||
// console.log(
|
||||
// showInfoMessage(
|
||||
@ -81,7 +91,6 @@ export class ConfigMenu {
|
||||
// `To: "${newDataDir}"`,
|
||||
// ),
|
||||
// );
|
||||
|
||||
// try {
|
||||
// fs.moveSync(config.dataDir, newDataDir);
|
||||
// } catch (error) {
|
||||
@ -104,64 +113,82 @@ export class ConfigMenu {
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
// config.dataDir = newDataDir;
|
||||
// return config;
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
||||
editLogsDir = async () => {
|
||||
this.config.logsDir = await this.pathSelector.show(this.config.logsDir, true);
|
||||
}
|
||||
this.config.logsDir = await this.pathSelector.show(
|
||||
this.config.logsDir,
|
||||
true,
|
||||
);
|
||||
};
|
||||
|
||||
editStorageQuota = async () => {
|
||||
this.ui.showInfoMessage("You can use: 'GB' or 'gb', etc.");
|
||||
const newQuota = await this.numberSelector.show(this.config.storageQuota, "Storage quota", true);
|
||||
const newQuota = await this.numberSelector.show(
|
||||
this.config.storageQuota,
|
||||
"Storage quota",
|
||||
true,
|
||||
);
|
||||
if (newQuota < 100 * 1024 * 1024) {
|
||||
this.ui.showErrorMessage("Storage quote should be >= 100mb.");
|
||||
} else {
|
||||
this.config.storageQuota = newQuota;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
editDiscPort = async () => {
|
||||
const newPort = await this.numberSelector.show(this.config.ports.discPort, "Discovery port", false);
|
||||
const newPort = await this.numberSelector.show(
|
||||
this.config.ports.discPort,
|
||||
"Discovery port",
|
||||
false,
|
||||
);
|
||||
if (this.isInPortRange(newPort)) {
|
||||
this.config.ports.discPort = newPort;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
editListenPort = async () => {
|
||||
const newPort = await this.numberSelector.show(this.config.ports.listenPort, "P2P listen port", false);
|
||||
const newPort = await this.numberSelector.show(
|
||||
this.config.ports.listenPort,
|
||||
"P2P listen port",
|
||||
false,
|
||||
);
|
||||
if (this.isInPortRange(newPort)) {
|
||||
this.config.ports.listenPort = newPort;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
editApiPort = async () => {
|
||||
const newPort = await this.numberSelector.show(this.config.ports.apiPort, "API port", false);
|
||||
const newPort = await this.numberSelector.show(
|
||||
this.config.ports.apiPort,
|
||||
"API port",
|
||||
false,
|
||||
);
|
||||
if (this.isInPortRange(newPort)) {
|
||||
this.config.ports.apiPort = newPort;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
isInPortRange = (number) => {
|
||||
if (number < 1024 || number > 65535) {
|
||||
this.ui.showErrorMessage("Port should be between 1024 and 65535.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
saveChangesAndExit = async () => {
|
||||
this.configService.saveConfig();
|
||||
this.ui.showInfoMessage("Configuration changes saved.");
|
||||
this.running = false;
|
||||
}
|
||||
this.loop.stopLoop();
|
||||
};
|
||||
|
||||
discardChangesAndExit = async () => {
|
||||
this.configService.loadConfig();
|
||||
this.ui.showInfoMessage("Changes discarded.");
|
||||
this.running = false;
|
||||
}
|
||||
this.loop.stopLoop();
|
||||
};
|
||||
}
|
||||
|
||||
@ -2,143 +2,242 @@ import { describe, beforeEach, it, expect, vi } from "vitest";
|
||||
import { ConfigMenu } from "./configmenu.js";
|
||||
import { mockUiService } from "../__mocks__/service.mocks.js";
|
||||
import { mockConfigService } from "../__mocks__/service.mocks.js";
|
||||
import { mockPathSelector, mockNumberSelector } from "../__mocks__/ui.mocks.js";
|
||||
import {
|
||||
mockPathSelector,
|
||||
mockNumberSelector,
|
||||
mockMenuLoop,
|
||||
} from "../__mocks__/utils.mocks.js";
|
||||
|
||||
describe("ConfigMenu", () => {
|
||||
const config = {
|
||||
dataDir: "/data",
|
||||
logsDir: "/logs",
|
||||
storageQuota: 1024 * 1024 * 1024,
|
||||
ports: {
|
||||
discPort: 8090,
|
||||
listenPort: 8070,
|
||||
apiPort: 8080,
|
||||
},
|
||||
};
|
||||
let configMenu;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
mockConfigService.get.mockReturnValue({
|
||||
dataDir: "/data",
|
||||
logsDir: "/logs",
|
||||
storageQuota: 1024 * 1024 * 1024,
|
||||
ports: {
|
||||
discPort: 8090,
|
||||
listenPort: 8070,
|
||||
apiPort: 8080,
|
||||
}
|
||||
});
|
||||
mockConfigService.get.mockReturnValue(config);
|
||||
|
||||
configMenu = new ConfigMenu(
|
||||
mockUiService,
|
||||
mockMenuLoop,
|
||||
mockConfigService,
|
||||
mockPathSelector,
|
||||
mockNumberSelector
|
||||
mockNumberSelector,
|
||||
);
|
||||
});
|
||||
|
||||
// it("displays the configuration menu", async () => {
|
||||
// configMenu.running = false; // Prevent infinite loop
|
||||
// await configMenu.show();
|
||||
it("initializes the loop with the config menu", () => {
|
||||
expect(mockMenuLoop.initialize).toHaveBeenCalledWith(
|
||||
configMenu.showConfigMenu,
|
||||
);
|
||||
});
|
||||
|
||||
// expect(mockUiService.showInfoMessage).toHaveBeenCalledWith(
|
||||
// "Codex Configuration",
|
||||
// );
|
||||
// expect(mockUiService.askMultipleChoice).toHaveBeenCalledWith([
|
||||
// {
|
||||
// label: `Data path = "${mockConfigService.get().dataDir}"`,
|
||||
// action: configMenu.editDataDir,
|
||||
// },
|
||||
// {
|
||||
// label: `Logs path = "${mockConfigService.get().logsDir}"`,
|
||||
// action: configMenu.editLogsDir,
|
||||
// },
|
||||
// {
|
||||
// label: `Storage quota = 1Gb`,
|
||||
// action: configMenu.editStorageQuota,
|
||||
// },
|
||||
// {
|
||||
// label: `Discovery port = ${mockConfigService.get().ports.discPort}`,
|
||||
// action: configMenu.editDiscPort,
|
||||
// },
|
||||
// {
|
||||
// label: `P2P listen port = ${mockConfigService.get().ports.listenPort}`,
|
||||
// action: configMenu.editListenPort,
|
||||
// },
|
||||
// {
|
||||
// label: `API port = ${mockConfigService.get().ports.apiPort}`,
|
||||
// action: configMenu.editApiPort,
|
||||
// },
|
||||
// {
|
||||
// label: "Save changes and exit",
|
||||
// action: configMenu.saveChangesAndExit,
|
||||
// },
|
||||
// {
|
||||
// label: "Discard changes and exit",
|
||||
// action: configMenu.discardChangesAndExit,
|
||||
// }
|
||||
// ]);
|
||||
// });
|
||||
it("shows the config menu header", async () => {
|
||||
await configMenu.show();
|
||||
expect(mockUiService.showInfoMessage).toHaveBeenCalledWith(
|
||||
"Codex Configuration",
|
||||
);
|
||||
});
|
||||
|
||||
// it("edits the logs directory", async () => {
|
||||
// mockPathSelector.show.mockResolvedValue("/new-logs");
|
||||
// await configMenu.editLogsDir();
|
||||
it("starts the menu loop", async () => {
|
||||
await configMenu.show();
|
||||
expect(mockMenuLoop.showLoop).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// expect(mockPathSelector.show).toHaveBeenCalledWith("/logs", true);
|
||||
// expect(configMenu.config.logsDir).toEqual("/new-logs");
|
||||
// });
|
||||
it("sets the config field", async () => {
|
||||
await configMenu.show();
|
||||
expect(configMenu.config).toEqual(config);
|
||||
});
|
||||
|
||||
// it("edits the storage quota", async () => {
|
||||
// mockNumberSelector.show.mockResolvedValue(200 * 1024 * 1024);
|
||||
// await configMenu.editStorageQuota();
|
||||
describe("config menu options", () => {
|
||||
beforeEach(() => {
|
||||
configMenu.config = config;
|
||||
});
|
||||
|
||||
// expect(mockUiService.showInfoMessage).toHaveBeenCalledWith(
|
||||
// "You can use: 'GB' or 'gb', etc.",
|
||||
// );
|
||||
// expect(mockNumberSelector.show).toHaveBeenCalledWith(
|
||||
// 1024 * 1024 * 1024,
|
||||
// "Storage quota",
|
||||
// true,
|
||||
// );
|
||||
// expect(configMenu.config.storageQuota).toEqual(200 * 1024 * 1024);
|
||||
// });
|
||||
it("displays the configuration menu", async () => {
|
||||
await configMenu.showConfigMenu();
|
||||
expect(mockUiService.askMultipleChoice).toHaveBeenCalledWith(
|
||||
"Select to edit:",
|
||||
[
|
||||
{
|
||||
label: `Data path = "${mockConfigService.get().dataDir}"`,
|
||||
action: configMenu.editDataDir,
|
||||
},
|
||||
{
|
||||
label: `Logs path = "${mockConfigService.get().logsDir}"`,
|
||||
action: configMenu.editLogsDir,
|
||||
},
|
||||
{
|
||||
label: `Storage quota = 1073741824 Bytes (1024 MB)`,
|
||||
action: configMenu.editStorageQuota,
|
||||
},
|
||||
{
|
||||
label: `Discovery port = ${mockConfigService.get().ports.discPort}`,
|
||||
action: configMenu.editDiscPort,
|
||||
},
|
||||
{
|
||||
label: `P2P listen port = ${mockConfigService.get().ports.listenPort}`,
|
||||
action: configMenu.editListenPort,
|
||||
},
|
||||
{
|
||||
label: `API port = ${mockConfigService.get().ports.apiPort}`,
|
||||
action: configMenu.editApiPort,
|
||||
},
|
||||
{
|
||||
label: "Save changes and exit",
|
||||
action: configMenu.saveChangesAndExit,
|
||||
},
|
||||
{
|
||||
label: "Discard changes and exit",
|
||||
action: configMenu.discardChangesAndExit,
|
||||
},
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
// it("shows an error if storage quota is too small", async () => {
|
||||
// mockNumberSelector.show.mockResolvedValue(50 * 1024 * 1024);
|
||||
// await configMenu.editStorageQuota();
|
||||
it("edits the logs directory", async () => {
|
||||
const originalPath = config.logsDir;
|
||||
mockPathSelector.show.mockResolvedValue("/new-logs");
|
||||
await configMenu.editLogsDir();
|
||||
|
||||
// expect(mockUiService.showErrorMessage).toHaveBeenCalledWith(
|
||||
// "Storage quote should be >= 100mb.",
|
||||
// );
|
||||
// expect(configMenu.config.storageQuota).toEqual(1024 * 1024 * 1024); // Unchanged
|
||||
// });
|
||||
expect(mockPathSelector.show).toHaveBeenCalledWith(originalPath, true);
|
||||
expect(configMenu.config.logsDir).toEqual("/new-logs");
|
||||
});
|
||||
|
||||
// it("edits the discovery port", async () => {
|
||||
// mockNumberSelector.show.mockResolvedValue(9000);
|
||||
// await configMenu.editDiscPort();
|
||||
it("edits the storage quota", async () => {
|
||||
const originalQuota = config.storageQuota;
|
||||
const newQuota = 200 * 1024 * 1024;
|
||||
mockNumberSelector.show.mockResolvedValue(newQuota);
|
||||
|
||||
// expect(mockNumberSelector.show).toHaveBeenCalledWith(8090, "Discovery port", false);
|
||||
// expect(configMenu.config.ports.discPort).toEqual(9000);
|
||||
// });
|
||||
await configMenu.editStorageQuota();
|
||||
|
||||
// it("shows an error if port is out of range", async () => {
|
||||
// mockNumberSelector.show.mockResolvedValue(1000);
|
||||
// await configMenu.editDiscPort();
|
||||
expect(mockUiService.showInfoMessage).toHaveBeenCalledWith(
|
||||
"You can use: 'GB' or 'gb', etc.",
|
||||
);
|
||||
expect(mockNumberSelector.show).toHaveBeenCalledWith(
|
||||
originalQuota,
|
||||
"Storage quota",
|
||||
true,
|
||||
);
|
||||
expect(configMenu.config.storageQuota).toEqual(newQuota);
|
||||
});
|
||||
|
||||
// expect(mockUiService.showErrorMessage).toHaveBeenCalledWith(
|
||||
// "Port should be between 1024 and 65535.",
|
||||
// );
|
||||
// expect(configMenu.config.ports.discPort).toEqual(8090); // Unchanged
|
||||
// });
|
||||
it("shows an error if storage quota is too small", async () => {
|
||||
const originalQuota = config.storageQuota;
|
||||
mockNumberSelector.show.mockResolvedValue(50 * 1024 * 1024);
|
||||
|
||||
// it("saves changes and exits", async () => {
|
||||
// await configMenu.saveChangesAndExit();
|
||||
await configMenu.editStorageQuota();
|
||||
|
||||
// expect(mockConfigService.saveConfig).toHaveBeenCalled();
|
||||
// expect(mockUiService.showInfoMessage).toHaveBeenCalledWith(
|
||||
// "Configuration changes saved.",
|
||||
// );
|
||||
// expect(configMenu.running).toEqual(false);
|
||||
// });
|
||||
expect(mockUiService.showErrorMessage).toHaveBeenCalledWith(
|
||||
"Storage quote should be >= 100mb.",
|
||||
);
|
||||
expect(configMenu.config.storageQuota).toEqual(originalQuota);
|
||||
});
|
||||
|
||||
// it("discards changes and exits", async () => {
|
||||
// await configMenu.discardChangesAndExit();
|
||||
it("edits the discovery port", async () => {
|
||||
const originalPort = config.ports.discPort;
|
||||
const newPort = 9000;
|
||||
mockNumberSelector.show.mockResolvedValue(newPort);
|
||||
|
||||
// expect(mockConfigService.loadConfig).toHaveBeenCalled();
|
||||
// expect(mockUiService.showInfoMessage).toHaveBeenCalledWith(
|
||||
// "Changes discarded.",
|
||||
// );
|
||||
// expect(configMenu.running).toEqual(false);
|
||||
// });
|
||||
await configMenu.editDiscPort();
|
||||
|
||||
expect(mockNumberSelector.show).toHaveBeenCalledWith(
|
||||
originalPort,
|
||||
"Discovery port",
|
||||
false,
|
||||
);
|
||||
expect(configMenu.config.ports.discPort).toEqual(newPort);
|
||||
});
|
||||
|
||||
it("shows an error if discovery port is out of range", async () => {
|
||||
const originalPort = config.ports.discPort;
|
||||
mockNumberSelector.show.mockResolvedValue(1000);
|
||||
await configMenu.editDiscPort();
|
||||
|
||||
expect(mockUiService.showErrorMessage).toHaveBeenCalledWith(
|
||||
"Port should be between 1024 and 65535.",
|
||||
);
|
||||
expect(configMenu.config.ports.discPort).toEqual(originalPort);
|
||||
});
|
||||
|
||||
it("edits the listen port", async () => {
|
||||
const originalPort = config.ports.listenPort;
|
||||
const newPort = 9000;
|
||||
mockNumberSelector.show.mockResolvedValue(newPort);
|
||||
|
||||
await configMenu.editListenPort();
|
||||
|
||||
expect(mockNumberSelector.show).toHaveBeenCalledWith(
|
||||
originalPort,
|
||||
"P2P listen port",
|
||||
false,
|
||||
);
|
||||
expect(configMenu.config.ports.listenPort).toEqual(newPort);
|
||||
});
|
||||
|
||||
it("shows an error if listen port is out of range", async () => {
|
||||
const originalPort = config.ports.listenPort;
|
||||
mockNumberSelector.show.mockResolvedValue(1000);
|
||||
await configMenu.editListenPort();
|
||||
|
||||
expect(mockUiService.showErrorMessage).toHaveBeenCalledWith(
|
||||
"Port should be between 1024 and 65535.",
|
||||
);
|
||||
expect(configMenu.config.ports.listenPort).toEqual(originalPort);
|
||||
});
|
||||
|
||||
it("edits the API port", async () => {
|
||||
const originalPort = config.ports.apiPort;
|
||||
const newPort = 9000;
|
||||
mockNumberSelector.show.mockResolvedValue(newPort);
|
||||
|
||||
await configMenu.editApiPort();
|
||||
|
||||
expect(mockNumberSelector.show).toHaveBeenCalledWith(
|
||||
originalPort,
|
||||
"API port",
|
||||
false,
|
||||
);
|
||||
expect(configMenu.config.ports.apiPort).toEqual(newPort);
|
||||
});
|
||||
|
||||
it("shows an error if API port is out of range", async () => {
|
||||
const originalPort = config.ports.apiPort;
|
||||
mockNumberSelector.show.mockResolvedValue(1000);
|
||||
await configMenu.editApiPort();
|
||||
|
||||
expect(mockUiService.showErrorMessage).toHaveBeenCalledWith(
|
||||
"Port should be between 1024 and 65535.",
|
||||
);
|
||||
expect(configMenu.config.ports.apiPort).toEqual(originalPort);
|
||||
});
|
||||
|
||||
it("saves changes and exits", async () => {
|
||||
await configMenu.saveChangesAndExit();
|
||||
|
||||
expect(mockConfigService.saveConfig).toHaveBeenCalled();
|
||||
expect(mockUiService.showInfoMessage).toHaveBeenCalledWith(
|
||||
"Configuration changes saved.",
|
||||
);
|
||||
expect(mockMenuLoop.stopLoop).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("discards changes and exits", async () => {
|
||||
await configMenu.discardChangesAndExit();
|
||||
|
||||
expect(mockConfigService.loadConfig).toHaveBeenCalled();
|
||||
expect(mockUiService.showInfoMessage).toHaveBeenCalledWith(
|
||||
"Changes discarded.",
|
||||
);
|
||||
expect(mockMenuLoop.stopLoop).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -10,11 +10,18 @@ describe("mainmenu", () => {
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
|
||||
mainmenu = new MainMenu(mockUiService, mockMenuLoop, mockInstallMenu, mockConfigMenu);
|
||||
mainmenu = new MainMenu(
|
||||
mockUiService,
|
||||
mockMenuLoop,
|
||||
mockInstallMenu,
|
||||
mockConfigMenu,
|
||||
);
|
||||
});
|
||||
|
||||
it("initializes the menu loop with the promptMainMenu function", () => {
|
||||
expect(mockMenuLoop.initialize).toHaveBeenCalledWith(mainmenu.promptMainMenu);
|
||||
expect(mockMenuLoop.initialize).toHaveBeenCalledWith(
|
||||
mainmenu.promptMainMenu,
|
||||
);
|
||||
});
|
||||
|
||||
it("shows the logo", async () => {
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
export class MenuLoop {
|
||||
initialize = (menuPrompt) => {
|
||||
this.menuPrompt = menuPrompt;
|
||||
}
|
||||
initialize = (menuPrompt) => {
|
||||
this.menuPrompt = menuPrompt;
|
||||
};
|
||||
|
||||
showOnce = async () => {
|
||||
await this.menuPrompt();
|
||||
}
|
||||
showOnce = async () => {
|
||||
await this.menuPrompt();
|
||||
};
|
||||
|
||||
showLoop = async () => {
|
||||
this.running = true;
|
||||
while (this.running) {
|
||||
await this.menuPrompt();
|
||||
}
|
||||
showLoop = async () => {
|
||||
this.running = true;
|
||||
while (this.running) {
|
||||
await this.menuPrompt();
|
||||
}
|
||||
};
|
||||
|
||||
stopLoop = () => {
|
||||
this.running = false;
|
||||
}
|
||||
stopLoop = () => {
|
||||
this.running = false;
|
||||
};
|
||||
}
|
||||
|
||||
@ -2,41 +2,41 @@ import { describe, beforeEach, it, expect, vi } from "vitest";
|
||||
import { MenuLoop } from "./menuLoop.js";
|
||||
|
||||
describe("MenuLoop", () => {
|
||||
let menuLoop;
|
||||
const mockPrompt = vi.fn();
|
||||
let menuLoop;
|
||||
const mockPrompt = vi.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
menuLoop = new MenuLoop();
|
||||
menuLoop.initialize(mockPrompt);
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
menuLoop = new MenuLoop();
|
||||
menuLoop.initialize(mockPrompt);
|
||||
});
|
||||
|
||||
it("can show menu once", async () => {
|
||||
await menuLoop.showOnce();
|
||||
expect(mockPrompt).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("can stop the menu loop", async () => {
|
||||
mockPrompt.mockImplementation(() => {
|
||||
menuLoop.stopLoop();
|
||||
});
|
||||
await menuLoop.showLoop();
|
||||
|
||||
expect(mockPrompt).toHaveBeenCalledTimes(1);
|
||||
expect(menuLoop.running).toBe(false);
|
||||
});
|
||||
|
||||
it("can run menu in a loop", async () => {
|
||||
let calls = 0;
|
||||
mockPrompt.mockImplementation(() => {
|
||||
calls++;
|
||||
if (calls >= 3) {
|
||||
menuLoop.stopLoop();
|
||||
}
|
||||
});
|
||||
|
||||
it("can show menu once", async () => {
|
||||
await menuLoop.showOnce();
|
||||
expect(mockPrompt).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
await menuLoop.showLoop();
|
||||
|
||||
it("can stop the menu loop", async () => {
|
||||
mockPrompt.mockImplementation(() => {
|
||||
menuLoop.stopLoop();
|
||||
});
|
||||
await menuLoop.showLoop();
|
||||
|
||||
expect(mockPrompt).toHaveBeenCalledTimes(1);
|
||||
expect(menuLoop.running).toBe(false);
|
||||
});
|
||||
|
||||
it("can run menu in a loop", async () => {
|
||||
let calls = 0;
|
||||
mockPrompt.mockImplementation(() => {
|
||||
calls++;
|
||||
if (calls >= 3) {
|
||||
menuLoop.stopLoop();
|
||||
}
|
||||
});
|
||||
|
||||
await menuLoop.showLoop();
|
||||
|
||||
expect(mockPrompt).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
expect(mockPrompt).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
});
|
||||
|
||||
@ -3,11 +3,7 @@ export class NumberSelector {
|
||||
this.uiService = uiService;
|
||||
}
|
||||
|
||||
show = async (
|
||||
currentValue,
|
||||
promptMessage,
|
||||
allowMetricPostfixes,
|
||||
) => {
|
||||
show = async (currentValue, promptMessage, allowMetricPostfixes) => {
|
||||
try {
|
||||
var valueStr = await this.promptForValueStr(promptMessage);
|
||||
valueStr = valueStr.replaceAll(" ", "");
|
||||
|
||||
@ -34,11 +34,7 @@ describe("number selector", () => {
|
||||
|
||||
mockUiService.askPrompt.mockResolvedValue("what?!");
|
||||
|
||||
const number = await numberSelector.show(
|
||||
currentValue,
|
||||
prompt,
|
||||
false,
|
||||
);
|
||||
const number = await numberSelector.show(currentValue, prompt, false);
|
||||
|
||||
expect(number).toEqual(currentValue);
|
||||
});
|
||||
|
||||
@ -106,14 +106,14 @@ export class PathSelector {
|
||||
console.log("The path does not exist.");
|
||||
}
|
||||
this.updateCurrentIfValidParts(this.splitPath(newFullPath));
|
||||
}
|
||||
};
|
||||
|
||||
updateCurrentIfValidParts = (newParts) => {
|
||||
if (!this.hasValidRoot(newParts)) {
|
||||
console.log("The path has no valid root.");
|
||||
}
|
||||
this.currentPath = newParts;
|
||||
}
|
||||
};
|
||||
|
||||
enterPath = async () => {
|
||||
const newPath = await this.ui.askPrompt("Enter Path:");
|
||||
@ -156,8 +156,8 @@ export class PathSelector {
|
||||
action: () => {
|
||||
selected = option;
|
||||
},
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
await this.ui.askMultipleChoice("Select an subdir", uiOptions);
|
||||
|
||||
@ -174,7 +174,7 @@ export class PathSelector {
|
||||
selectThisPath = async () => {
|
||||
this.resultingPath = this.combine(this.currentPath);
|
||||
this.running = false;
|
||||
}
|
||||
};
|
||||
|
||||
cancel = async () => {
|
||||
this.resultingPath = this.startingPath;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user