genlayer 0.12.1 → 0.12.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/.github/workflows/publish-beta.yml +2 -2
  2. package/.github/workflows/publish.yml +2 -2
  3. package/.github/workflows/validate-code.yml +1 -1
  4. package/CHANGELOG.md +6 -0
  5. package/dist/index.js +24736 -108331
  6. package/docker-compose.yml +1 -1
  7. package/esbuild.config.dev.js +18 -0
  8. package/esbuild.config.js +10 -5
  9. package/esbuild.config.prod.js +16 -0
  10. package/eslint.config.js +59 -0
  11. package/package.json +12 -9
  12. package/scripts/postinstall.js +10 -6
  13. package/src/commands/config/getSetReset.ts +25 -18
  14. package/src/commands/contracts/deploy.ts +105 -25
  15. package/src/commands/contracts/index.ts +5 -1
  16. package/src/commands/general/index.ts +10 -4
  17. package/src/commands/general/init.ts +136 -189
  18. package/src/commands/general/start.ts +76 -77
  19. package/src/commands/general/stop.ts +6 -5
  20. package/src/commands/keygen/create.ts +9 -11
  21. package/src/commands/update/index.ts +3 -8
  22. package/src/commands/update/ollama.ts +56 -56
  23. package/src/commands/validators/validators.ts +48 -55
  24. package/src/lib/actions/BaseAction.ts +75 -4
  25. package/src/lib/config/simulator.ts +1 -1
  26. package/src/lib/services/simulator.ts +3 -2
  27. package/tests/actions/create.test.ts +18 -30
  28. package/tests/actions/deploy.test.ts +200 -30
  29. package/tests/actions/getSetReset.test.ts +29 -42
  30. package/tests/actions/init.test.ts +240 -475
  31. package/tests/actions/ollama.test.ts +40 -55
  32. package/tests/actions/start.test.ts +107 -108
  33. package/tests/actions/stop.test.ts +23 -4
  34. package/tests/actions/validators.test.ts +273 -142
  35. package/tests/commands/call.test.ts +4 -1
  36. package/tests/commands/deploy.test.ts +11 -0
  37. package/tests/commands/init.test.ts +11 -12
  38. package/tests/commands/up.test.ts +31 -23
  39. package/tests/commands/update.test.ts +2 -5
  40. package/tests/libs/baseAction.test.ts +175 -0
  41. package/tests/services/simulator.test.ts +15 -0
  42. package/.eslintrc.js +0 -58
  43. package/esbuild.config.dev +0 -16
  44. package/esbuild.config.prod +0 -16
@@ -1,7 +1,6 @@
1
1
  import { describe, test, vi, beforeEach, afterEach, expect, Mock } from "vitest";
2
2
  import { OllamaAction } from "../../src/commands/update/ollama";
3
3
  import { rpcClient } from "../../src/lib/clients/jsonRpcClient";
4
-
5
4
  import Docker from "dockerode";
6
5
 
7
6
  vi.mock("dockerode");
@@ -37,6 +36,11 @@ describe("OllamaAction", () => {
37
36
  } as unknown as Docker.Container);
38
37
 
39
38
  Docker.prototype.getContainer = mockGetContainer;
39
+
40
+ vi.spyOn(ollamaAction as any, "startSpinner").mockImplementation(() => {});
41
+ vi.spyOn(ollamaAction as any, "setSpinnerText").mockImplementation(() => {});
42
+ vi.spyOn(ollamaAction as any, "succeedSpinner").mockImplementation(() => {});
43
+ vi.spyOn(ollamaAction as any, "failSpinner").mockImplementation(() => {});
40
44
  });
41
45
 
42
46
  afterEach(() => {
@@ -49,6 +53,7 @@ describe("OllamaAction", () => {
49
53
  config: { key: "value" },
50
54
  plugin_config: { pluginKey: "pluginValue" },
51
55
  };
56
+
52
57
  vi.mocked(rpcClient.request).mockResolvedValueOnce({
53
58
  result: [mockProvider],
54
59
  });
@@ -62,10 +67,9 @@ describe("OllamaAction", () => {
62
67
  }
63
68
  });
64
69
 
65
- console.log = vi.fn();
66
-
67
70
  await ollamaAction.updateModel("mocked_model");
68
71
 
72
+ expect(ollamaAction["startSpinner"]).toHaveBeenCalledWith(`Updating model "mocked_model"...`);
69
73
  expect(mockGetContainer).toHaveBeenCalledWith("ollama");
70
74
  expect(mockExec).toHaveBeenCalledWith({
71
75
  Cmd: ["ollama", "pull", "mocked_model"],
@@ -73,10 +77,8 @@ describe("OllamaAction", () => {
73
77
  AttachStderr: true,
74
78
  });
75
79
  expect(mockStart).toHaveBeenCalledWith({ Detach: false, Tty: false });
76
- expect(mockStream.on).toHaveBeenCalledWith("data", expect.any(Function));
77
- expect(mockStream.on).toHaveBeenCalledWith("end", expect.any(Function));
78
- expect(console.log).toHaveBeenCalledWith("Mocked output success");
79
- expect(console.log).toHaveBeenCalledWith('Model "mocked_model" updated successfully');
80
+ expect(ollamaAction["setSpinnerText"]).toHaveBeenCalledWith("Mocked output success");
81
+ expect(ollamaAction["succeedSpinner"]).toHaveBeenCalledWith(`Model "mocked_model" updated successfully`);
80
82
  });
81
83
 
82
84
  test("should remove the model using 'rm'", async () => {
@@ -89,10 +91,9 @@ describe("OllamaAction", () => {
89
91
  }
90
92
  });
91
93
 
92
- console.log = vi.fn();
93
-
94
94
  await ollamaAction.removeModel("mocked_model");
95
95
 
96
+ expect(ollamaAction["startSpinner"]).toHaveBeenCalledWith(`Executing 'rm' command on model "mocked_model"...`);
96
97
  expect(mockGetContainer).toHaveBeenCalledWith("ollama");
97
98
  expect(mockExec).toHaveBeenCalledWith({
98
99
  Cmd: ["ollama", "rm", "mocked_model"],
@@ -100,10 +101,8 @@ describe("OllamaAction", () => {
100
101
  AttachStderr: true,
101
102
  });
102
103
  expect(mockStart).toHaveBeenCalledWith({ Detach: false, Tty: false });
103
- expect(mockStream.on).toHaveBeenCalledWith("data", expect.any(Function));
104
- expect(mockStream.on).toHaveBeenCalledWith("end", expect.any(Function));
105
- expect(console.log).toHaveBeenCalledWith("Mocked output success");
106
- expect(console.log).toHaveBeenCalledWith('Model "mocked_model" removed successfully');
104
+ expect(ollamaAction["setSpinnerText"]).toHaveBeenCalledWith("Mocked output success");
105
+ expect(ollamaAction["succeedSpinner"]).toHaveBeenCalledWith(`Model "mocked_model" removed successfully`);
107
106
  });
108
107
 
109
108
  test("should log an error if an exception occurs during 'pull'", async () => {
@@ -112,48 +111,26 @@ describe("OllamaAction", () => {
112
111
  config: { key: "value" },
113
112
  plugin_config: { pluginKey: "pluginValue" },
114
113
  };
114
+
115
115
  vi.mocked(rpcClient.request).mockResolvedValueOnce({
116
116
  result: [mockProvider],
117
117
  });
118
118
 
119
119
  const error = new Error("Mocked error");
120
- mockGetContainer.mockReturnValueOnce(
121
- {
122
- exec: () => {
123
- throw new Error("Mocked error");
124
- }
125
- }
126
- );
127
- console.error = vi.fn();
120
+ mockExec.mockRejectedValue(error);
128
121
 
129
122
  await ollamaAction.updateModel("mocked_model");
130
123
 
131
- expect(mockGetContainer).toHaveBeenCalledWith("ollama");
132
- expect(console.error).toHaveBeenCalledWith(
133
- 'Error executing command "pull" on model "mocked_model":',
134
- error
135
- );
124
+ expect(ollamaAction["failSpinner"]).toHaveBeenCalledWith(`Error executing command "pull" on model "mocked_model"`, error);
136
125
  });
137
126
 
138
127
  test("should log an error if an exception occurs during 'rm'", async () => {
139
128
  const error = new Error("Mocked error");
140
- mockGetContainer.mockReturnValueOnce(
141
- {
142
- exec: () => {
143
- throw new Error("Mocked error");
144
- }
145
- }
146
- );
147
-
148
- console.error = vi.fn();
129
+ mockExec.mockRejectedValue(error);
149
130
 
150
131
  await ollamaAction.removeModel("mocked_model");
151
132
 
152
- expect(mockGetContainer).toHaveBeenCalledWith("ollama");
153
- expect(console.error).toHaveBeenCalledWith(
154
- 'Error executing command "rm" on model "mocked_model":',
155
- error
156
- );
133
+ expect(ollamaAction["failSpinner"]).toHaveBeenCalledWith(`Error executing command "rm" on model "mocked_model"`, error);
157
134
  });
158
135
 
159
136
  test("should throw an error if no 'ollama' provider exists during updateModel", async () => {
@@ -161,21 +138,14 @@ describe("OllamaAction", () => {
161
138
  result: [],
162
139
  });
163
140
 
164
- const modelName = "mocked_model";
141
+ await ollamaAction.updateModel("mocked_model");
165
142
 
166
- await expect(ollamaAction.updateModel(modelName)).rejects.toThrowError(
143
+ expect(ollamaAction["failSpinner"]).toHaveBeenCalledWith(
167
144
  "No existing 'ollama' provider found. Unable to add/update a model."
168
145
  );
169
-
170
- expect(rpcClient.request).toHaveBeenCalledWith({
171
- method: "sim_getProvidersAndModels",
172
- params: [],
173
- });
174
146
  });
175
147
 
176
148
  test("should reject with an error if success is not set to true", async () => {
177
- console.error = vi.fn();
178
-
179
149
  const mockProvider = {
180
150
  plugin: "ollama",
181
151
  config: { key: "value" },
@@ -195,14 +165,29 @@ describe("OllamaAction", () => {
195
165
  }
196
166
  });
197
167
 
198
- console.log = vi.fn();
199
- console.error = vi.fn();
200
-
201
168
  await ollamaAction.updateModel("mocked_model");
202
169
 
203
- expect(console.error).toHaveBeenCalledWith(
204
- 'Error executing command "pull" on model "mocked_model":', 'internal error'
170
+ expect(ollamaAction["failSpinner"]).toHaveBeenCalledWith(
171
+ `Failed to execute 'pull' on model "mocked_model".`
205
172
  );
206
173
  });
207
174
 
208
- });
175
+ test("should log an error if an exception occurs inside updateModel", async () => {
176
+ const mockError = new Error("Mocked error");
177
+
178
+ vi.mocked(rpcClient.request).mockRejectedValue(mockError);
179
+
180
+ await ollamaAction.updateModel("mocked_model");
181
+
182
+ expect(ollamaAction["failSpinner"]).toHaveBeenCalledWith(`Error updating model "mocked_model"`, mockError);
183
+ });
184
+
185
+ test("should call get config if modelName is empty", async () => {
186
+ const defaultModel = "default_model";
187
+ vi.spyOn(ollamaAction as any, "getConfig").mockReturnValue({ defaultOllamaModel: defaultModel });
188
+
189
+ await ollamaAction.updateModel("");
190
+ expect(ollamaAction.getConfig).toHaveBeenCalledTimes(1);
191
+ });
192
+
193
+ });
@@ -1,175 +1,174 @@
1
1
  import { describe, beforeEach, afterEach, test, expect, vi, Mock } from "vitest";
2
2
  import inquirer from "inquirer";
3
- import { startAction, StartActionOptions } from "../../src/commands/general/start";
4
- import { ISimulatorService } from "../../src/lib/interfaces/ISimulatorService";
3
+ import { StartAction, StartActionOptions } from "../../src/commands/general/start";
4
+ import { SimulatorService } from "../../src/lib/services/simulator";
5
5
 
6
- describe("startAction - Additional Tests", () => {
7
- let simulatorService: ISimulatorService;
8
- let logSpy: ReturnType<typeof vi.spyOn>;
9
- let errorSpy: ReturnType<typeof vi.spyOn>;
10
- let promptSpy: ReturnType<any>;
6
+ vi.mock("../../src/lib/services/simulator");
7
+ vi.mock("inquirer");
11
8
 
12
- const defaultOptions: StartActionOptions = {
13
- resetValidators: false,
14
- numValidators: 5,
15
- headless: false,
16
- resetDb: false
17
- };
9
+ describe("StartAction", () => {
10
+ let startAction: StartAction;
11
+ let mockSimulatorService: SimulatorService;
18
12
 
19
13
  beforeEach(() => {
20
- logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
21
- errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
22
- promptSpy = vi.spyOn(inquirer, "prompt");
23
-
24
- simulatorService = {
25
- updateSimulator: vi.fn().mockResolvedValue(undefined),
26
- runSimulator: vi.fn().mockResolvedValue(undefined),
27
- waitForSimulatorToBeReady: vi.fn().mockResolvedValue({ initialized: true }),
28
- deleteAllValidators: vi.fn().mockResolvedValue(undefined),
29
- createRandomValidators: vi.fn().mockResolvedValue(undefined),
30
- openFrontend: vi.fn().mockResolvedValue(undefined),
31
- setSimulatorLocation: vi.fn().mockResolvedValue(undefined),
32
- setComposeOptions: vi.fn(),
33
- checkCliVersion: vi.fn(),
34
- getAiProvidersOptions: vi.fn(() => [
35
- { name: "Provider A", value: "providerA" },
36
- { name: "Provider B", value: "providerB" },
37
- ]),
38
- getFrontendUrl: vi.fn(() => "http://localhost:8080"),
39
- cleanDatabase: vi.fn().mockResolvedValue(undefined),
40
- } as unknown as ISimulatorService;
14
+ vi.clearAllMocks();
15
+
16
+ mockSimulatorService = new SimulatorService();
17
+ startAction = new StartAction();
18
+ startAction["simulatorService"] = mockSimulatorService;
19
+
20
+ mockSimulatorService.waitForSimulatorToBeReady = vi.fn().mockResolvedValue({ initialized: true });
21
+
22
+ vi.spyOn(startAction as any, "startSpinner").mockImplementation(() => {});
23
+ vi.spyOn(startAction as any, "setSpinnerText").mockImplementation(() => {});
24
+ vi.spyOn(startAction as any, "succeedSpinner").mockImplementation(() => {});
25
+ vi.spyOn(startAction as any, "failSpinner").mockImplementation(() => {});
41
26
  });
42
27
 
43
28
  afterEach(() => {
44
29
  vi.restoreAllMocks();
45
30
  });
46
31
 
47
- test("runs successfully with default options and keeps existing validators", async () => {
48
- await startAction(defaultOptions, simulatorService);
32
+ const defaultOptions: StartActionOptions = {
33
+ resetValidators: false,
34
+ numValidators: 5,
35
+ headless: false,
36
+ resetDb: false,
37
+ };
38
+
39
+ test("should start the simulator successfully", async () => {
40
+ mockSimulatorService.checkCliVersion = vi.fn().mockResolvedValue(undefined);
41
+ mockSimulatorService.runSimulator = vi.fn().mockResolvedValue(undefined);
42
+ mockSimulatorService.getFrontendUrl = vi.fn().mockReturnValue("http://localhost:8080");
43
+
44
+ await startAction.execute(defaultOptions);
45
+
46
+ expect(startAction["startSpinner"]).toHaveBeenCalledWith("Checking CLI version...");
47
+ expect(mockSimulatorService.checkCliVersion).toHaveBeenCalled();
49
48
 
50
- expect(simulatorService.runSimulator).toHaveBeenCalled();
51
- expect(simulatorService.waitForSimulatorToBeReady).toHaveBeenCalled();
49
+ expect(startAction["setSpinnerText"]).toHaveBeenCalledWith("Starting GenLayer Localnet (keeping the existing validators)...");
50
+ expect(mockSimulatorService.runSimulator).toHaveBeenCalled();
52
51
 
53
- expect(logSpy).toHaveBeenCalledWith("Starting GenLayer simulator keeping the existing validators");
54
- expect(logSpy).toHaveBeenCalledWith("Simulator is running!");
55
- expect(logSpy).toHaveBeenCalledWith("GenLayer simulator initialized successfully! Go to http://localhost:8080 in your browser to access it.");
52
+ expect(startAction["setSpinnerText"]).toHaveBeenCalledWith("Waiting for the simulator to be ready...");
53
+ expect(mockSimulatorService.waitForSimulatorToBeReady).toHaveBeenCalled();
56
54
 
57
- expect(simulatorService.openFrontend).toHaveBeenCalled();
55
+ expect(startAction["succeedSpinner"]).toHaveBeenCalledWith("GenLayer simulator initialized successfully! Go to http://localhost:8080 in your browser to access it.");
58
56
  });
59
57
 
60
- test("runs successfully with custom options and keeps existing validators", async () => {
61
- await startAction({...defaultOptions, headless: true, resetDb: true}, simulatorService);
58
+ test("should fail when simulator fails to start", async () => {
59
+ const errorMsg = new Error("runSimulator error");
60
+ (mockSimulatorService.runSimulator as Mock).mockRejectedValueOnce(errorMsg);
61
+
62
+ await startAction.execute(defaultOptions);
63
+
64
+ expect(startAction["failSpinner"]).toHaveBeenCalledWith("Error starting the simulator", errorMsg);
65
+ });
62
66
 
63
- expect(simulatorService.runSimulator).toHaveBeenCalled();
64
- expect(simulatorService.waitForSimulatorToBeReady).toHaveBeenCalled();
67
+ test("should fail when waiting for simulator initialization times out", async () => {
68
+ (mockSimulatorService.waitForSimulatorToBeReady as Mock).mockResolvedValue({ initialized: false, errorCode: "TIMEOUT" });
65
69
 
66
- expect(logSpy).toHaveBeenCalledWith("Starting GenLayer simulator keeping the existing validators");
70
+ await startAction.execute(defaultOptions);
67
71
 
68
- expect(logSpy).toHaveBeenCalledWith("Simulator is running!");
69
- expect(logSpy).toHaveBeenCalledWith("GenLayer simulator initialized successfully! ");
72
+ expect(startAction["failSpinner"]).toHaveBeenCalledWith("The simulator is taking too long to initialize. Please try again later.");
70
73
  });
71
74
 
75
+ test("should reset the database if resetDb is true", async () => {
76
+ const options: StartActionOptions = { ...defaultOptions, resetDb: true };
72
77
 
73
- test("logs error and stops if runSimulator fails", async () => {
74
- const errorMsg = new Error("runSimulator error");
75
- (simulatorService.runSimulator as Mock).mockRejectedValueOnce(errorMsg);
78
+ mockSimulatorService.cleanDatabase = vi.fn().mockResolvedValue(undefined);
76
79
 
77
- await startAction(defaultOptions, simulatorService);
80
+ await startAction.execute(options);
78
81
 
79
- expect(errorSpy).toHaveBeenCalledWith(errorMsg);
80
- expect(simulatorService.waitForSimulatorToBeReady).not.toHaveBeenCalled();
82
+ expect(startAction["setSpinnerText"]).toHaveBeenCalledWith("Resetting database...");
83
+ expect(mockSimulatorService.cleanDatabase).toHaveBeenCalled();
81
84
  });
82
85
 
83
- test("handles resetfValidators correctly by deleting and creating new validators", async () => {
84
- promptSpy.mockResolvedValueOnce({ selectedLlmProviders: ["providerA"] });
85
- const optionsWithReset: StartActionOptions = { ...defaultOptions, resetValidators: true };
86
+ test("should initialize validators when resetValidators is true", async () => {
87
+ const options: StartActionOptions = { ...defaultOptions, resetValidators: true };
88
+
89
+ mockSimulatorService.deleteAllValidators = vi.fn().mockResolvedValue(undefined);
90
+ mockSimulatorService.createRandomValidators = vi.fn().mockResolvedValue(undefined);
91
+ mockSimulatorService.getAiProvidersOptions = vi.fn().mockReturnValue(["Provider1", "Provider2"]);
86
92
 
87
- await startAction(optionsWithReset, simulatorService);
93
+ vi.mocked(inquirer.prompt).mockResolvedValue({ selectedLlmProviders: ["Provider1"] });
88
94
 
89
- expect(simulatorService.deleteAllValidators).toHaveBeenCalled();
90
- expect(simulatorService.createRandomValidators).toHaveBeenCalledWith(5, ["providerA"]);
91
- expect(logSpy).toHaveBeenCalledWith("New random validators successfully created...");
95
+ await startAction.execute(options);
96
+
97
+ expect(startAction["setSpinnerText"]).toHaveBeenCalledWith("Initializing validators...");
98
+ expect(mockSimulatorService.deleteAllValidators).toHaveBeenCalled();
99
+ expect(mockSimulatorService.createRandomValidators).toHaveBeenCalledWith(5, ["Provider1"]);
92
100
  });
93
101
 
94
- test("logs error if deleteAllValidators fails when resetValidators is true", async () => {
95
- const errorMsg = new Error("deleteAllValidators error");
96
- (simulatorService.deleteAllValidators as Mock).mockRejectedValueOnce(errorMsg);
97
- const optionsWithReset: StartActionOptions = { ...defaultOptions, resetValidators: true };
102
+ test("should fail when initializing validators fails", async () => {
103
+ const options: StartActionOptions = { ...defaultOptions, resetValidators: true };
104
+
105
+ mockSimulatorService.deleteAllValidators = vi.fn().mockRejectedValue(new Error("Failed to delete validators"));
98
106
 
99
- await startAction(optionsWithReset, simulatorService);
107
+ await startAction.execute(options);
100
108
 
101
- expect(errorSpy).toHaveBeenCalledWith("Unable to initialize the validators.");
102
- expect(errorSpy).toHaveBeenCalledWith(errorMsg);
103
- expect(simulatorService.createRandomValidators).not.toHaveBeenCalled();
109
+ expect(startAction["failSpinner"]).toHaveBeenCalledWith("Unable to initialize the validators", expect.any(Error));
104
110
  });
105
111
 
106
- test("prompts for LLM providers and validates at least one option is selected", async () => {
107
- const aiProviders = simulatorService.getAiProvidersOptions(false);
108
- expect(aiProviders).toEqual([
109
- { name: "Provider A", value: "providerA" },
110
- { name: "Provider B", value: "providerB" },
111
- ]);
112
+ test("should open frontend when not in headless mode", async () => {
113
+ mockSimulatorService.checkCliVersion = vi.fn().mockResolvedValue(undefined);
114
+ mockSimulatorService.runSimulator = vi.fn().mockResolvedValue(undefined);
115
+ mockSimulatorService.getFrontendUrl = vi.fn().mockReturnValue("http://localhost:8080");
116
+ mockSimulatorService.openFrontend = vi.fn().mockResolvedValue(undefined);
112
117
 
113
- promptSpy.mockImplementation(async (questions: any) => {
114
- const validateFunction = questions[0].validate;
118
+ await startAction.execute(defaultOptions);
115
119
 
116
- expect(validateFunction([])).toBe("You must choose at least one option.");
117
- expect(validateFunction(["providerA"])).toBe(true);
120
+ expect(startAction["startSpinner"]).toHaveBeenCalledWith("Opening frontend...");
121
+ expect(mockSimulatorService.openFrontend).toHaveBeenCalled();
122
+ expect(startAction["succeedSpinner"]).toHaveBeenCalledWith("Frontend opened successfully");
123
+ });
118
124
 
119
- return { selectedLlmProviders: ["providerA"] };
120
- });
125
+ test("should handle errors when opening frontend", async () => {
126
+ const errorMsg = new Error("Failed to open frontend");
127
+ (mockSimulatorService.openFrontend as Mock).mockRejectedValueOnce(errorMsg);
121
128
 
122
- const optionsWithReset: StartActionOptions = { ...defaultOptions, resetValidators: true };
123
- await startAction(optionsWithReset, simulatorService);
129
+ await startAction.execute(defaultOptions);
124
130
 
125
- expect(promptSpy).toHaveBeenCalled();
126
- expect(simulatorService.createRandomValidators).toHaveBeenCalledWith(5, ["providerA"]);
131
+ expect(startAction["failSpinner"]).toHaveBeenCalledWith("Error opening the frontend", errorMsg);
127
132
  });
128
133
 
129
- test("logs specific message if waitForSimulatorToBeReady returns TIMEOUT errorCode", async () => {
130
- (simulatorService.waitForSimulatorToBeReady as Mock).mockResolvedValue({
134
+ test("should log specific message if waitForSimulatorToBeReady returns TIMEOUT errorCode", async () => {
135
+ (mockSimulatorService.waitForSimulatorToBeReady as Mock).mockResolvedValue({
131
136
  initialized: false,
132
137
  errorCode: "TIMEOUT",
133
138
  errorMessage: "Initialization timed out",
134
139
  });
135
140
 
136
- await startAction(defaultOptions, simulatorService);
141
+ await startAction.execute(defaultOptions);
137
142
 
138
- expect(errorSpy).toHaveBeenCalledWith(
139
- "The simulator is taking too long to initialize. Please try again after the simulator is ready."
140
- );
143
+ expect(startAction["failSpinner"]).toHaveBeenCalledWith("The simulator is taking too long to initialize. Please try again later.");
141
144
  });
142
145
 
143
- test("logs error message if simulator fails to initialize with ERROR code", async () => {
144
- (simulatorService.waitForSimulatorToBeReady as Mock).mockResolvedValue({
146
+ test("should log error message if simulator fails to initialize with ERROR code", async () => {
147
+ (mockSimulatorService.waitForSimulatorToBeReady as Mock).mockResolvedValue({
145
148
  initialized: false,
146
149
  errorCode: "ERROR",
147
150
  errorMessage: "Initialization failed",
148
151
  });
149
152
 
150
- await startAction(defaultOptions, simulatorService);
153
+ await startAction.execute(defaultOptions);
151
154
 
152
- expect(logSpy).toHaveBeenCalledWith("Initialization failed");
153
- expect(errorSpy).toHaveBeenCalledWith("Unable to initialize the GenLayer simulator. Please try again.");
155
+ expect(startAction["failSpinner"]).toHaveBeenCalledWith("Unable to initialize the GenLayer simulator.", "Initialization failed");
154
156
  });
155
157
 
156
158
  test("catches and logs error if waitForSimulatorToBeReady throws an exception", async () => {
157
159
  const errorMsg = new Error("Unexpected initialization error");
158
- (simulatorService.waitForSimulatorToBeReady as Mock).mockRejectedValueOnce(errorMsg);
160
+ (mockSimulatorService.waitForSimulatorToBeReady as Mock).mockRejectedValueOnce(errorMsg);
159
161
 
160
- await startAction(defaultOptions, simulatorService);
162
+ await startAction.execute(defaultOptions);
161
163
 
162
- expect(errorSpy).toHaveBeenCalledWith(errorMsg);
164
+ expect(startAction["failSpinner"]).toHaveBeenCalledWith("Error waiting for the simulator to be ready", errorMsg);
163
165
  });
164
166
 
165
- test("catches and logs error if openFrontend throws an exception", async () => {
166
- const errorMsg = new Error("Failed to open frontend");
167
- (simulatorService.openFrontend as Mock).mockImplementationOnce(() => {
168
- throw errorMsg;
169
- });
167
+ test("should not append frontend URL when in headless mode", async () => {
168
+ await startAction.execute({ ...defaultOptions, headless: true });
170
169
 
171
- await startAction(defaultOptions, simulatorService);
172
-
173
- expect(errorSpy).toHaveBeenCalledWith(errorMsg);
170
+ expect(startAction["succeedSpinner"]).toHaveBeenCalledWith(
171
+ "GenLayer simulator initialized successfully! "
172
+ );
174
173
  });
175
174
  });
@@ -2,6 +2,8 @@ import { describe, test, vi, beforeEach, afterEach, expect } from "vitest";
2
2
  import { StopAction } from "../../src/commands/general/stop";
3
3
  import { SimulatorService } from "../../src/lib/services/simulator";
4
4
  import { ISimulatorService } from "../../src/lib/interfaces/ISimulatorService";
5
+ import chalk from "chalk";
6
+
5
7
  import inquirer from "inquirer";
6
8
 
7
9
  vi.mock("../../src/lib/services/simulator");
@@ -22,6 +24,10 @@ describe("StopAction", () => {
22
24
 
23
25
  stopAction = new StopAction();
24
26
  (stopAction as any).simulatorService = mockSimulatorService;
27
+
28
+ vi.spyOn(stopAction as any, "startSpinner").mockImplementation(() => {});
29
+ vi.spyOn(stopAction as any, "succeedSpinner").mockImplementation(() => {});
30
+ vi.spyOn(stopAction as any, "failSpinner").mockImplementation(() => {});
25
31
  });
26
32
 
27
33
  afterEach(() => {
@@ -37,22 +43,35 @@ describe("StopAction", () => {
37
43
  {
38
44
  type: "confirm",
39
45
  name: "confirmAction",
40
- message: "Are you sure you want to stop all running GenLayer containers? This will halt all active processes.",
46
+ message: chalk.yellow("Are you sure you want to stop all running GenLayer containers? This will halt all active processes."),
41
47
  default: true,
42
48
  },
43
49
  ]);
44
50
  expect(mockSimulatorService.stopDockerContainers).toHaveBeenCalled();
51
+ expect(stopAction["succeedSpinner"]).toHaveBeenCalledWith(
52
+ "All running GenLayer containers have been successfully stopped."
53
+ );
45
54
  });
46
55
 
47
56
  test("should abort if user cancels", async () => {
48
57
  vi.mocked(inquirer.prompt).mockResolvedValue({ confirmAction: false });
49
58
 
50
- console.log = vi.fn();
51
-
52
59
  await stopAction.stop();
53
60
 
54
61
  expect(inquirer.prompt).toHaveBeenCalled();
55
- expect(console.log).toHaveBeenCalledWith("Operation aborted!");
56
62
  expect(mockSimulatorService.stopDockerContainers).not.toHaveBeenCalled();
57
63
  });
64
+
65
+ test("should handle errors and call failSpinner", async () => {
66
+ vi.mocked(inquirer.prompt).mockResolvedValue({ confirmAction: true });
67
+ const error = new Error("Test Error");
68
+ mockSimulatorService.stopDockerContainers = vi.fn().mockRejectedValue(error);
69
+
70
+ await stopAction.stop();
71
+
72
+ expect(stopAction["failSpinner"]).toHaveBeenCalledWith(
73
+ "An error occurred while stopping the containers.",
74
+ error
75
+ );
76
+ });
58
77
  });