genlayer 0.5.0 → 0.5.1-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.
@@ -5,6 +5,13 @@ import { initAction } from "../../src/commands/general/init";
5
5
  import { tmpdir } from "os";
6
6
  import {mkdtempSync} from "fs";
7
7
  import {join} from "path";
8
+ import fs from "fs";
9
+ import * as dotenv from "dotenv";
10
+
11
+
12
+ vi.mock("fs");
13
+ vi.mock("dotenv");
14
+
8
15
 
9
16
  const tempDir = mkdtempSync(join(tmpdir(), "test-initAction-"));
10
17
  const defaultActionOptions = { numValidators: 5, branch: "main", location: tempDir, headless: false, resetDb: false };
@@ -18,9 +25,7 @@ describe("init action", () => {
18
25
  let simServCheckVersionRequirements: ReturnType<any>;
19
26
  let simServResetDockerContainers: ReturnType<any>;
20
27
  let simServResetDockerImages: ReturnType<any>;
21
- let simServDownloadSimulator: ReturnType<any>;
22
28
  let simServgetAiProvidersOptions: ReturnType<any>;
23
- let simServConfigSimulator: ReturnType<any>;
24
29
  let simServRunSimulator: ReturnType<any>;
25
30
  let simServWaitForSimulator: ReturnType<any>;
26
31
  let simServPullOllamaModel: ReturnType<any>;
@@ -28,6 +33,7 @@ describe("init action", () => {
28
33
  let simServCreateRandomValidators: ReturnType<any>;
29
34
  let simServOpenFrontend: ReturnType<any>;
30
35
  let simGetSimulatorUrl: ReturnType<any>;
36
+ let simAddConfigToEnvFile: ReturnType<any>;
31
37
 
32
38
  beforeEach(() => {
33
39
  vi.clearAllMocks();
@@ -40,8 +46,6 @@ describe("init action", () => {
40
46
  simServCheckVersionRequirements = vi.spyOn(simulatorService, "checkVersionRequirements");
41
47
  simServResetDockerContainers = vi.spyOn(simulatorService, "resetDockerContainers");
42
48
  simServResetDockerImages = vi.spyOn(simulatorService, "resetDockerImages");
43
- simServDownloadSimulator = vi.spyOn(simulatorService, "downloadSimulator");
44
- simServConfigSimulator = vi.spyOn(simulatorService, "configSimulator");
45
49
  simServgetAiProvidersOptions = vi.spyOn(simulatorService, "getAiProvidersOptions");
46
50
  simServRunSimulator = vi.spyOn(simulatorService, "runSimulator");
47
51
  simServWaitForSimulator = vi.spyOn(simulatorService, "waitForSimulatorToBeReady");
@@ -50,6 +54,7 @@ describe("init action", () => {
50
54
  simServCreateRandomValidators = vi.spyOn(simulatorService, "createRandomValidators");
51
55
  simServOpenFrontend = vi.spyOn(simulatorService, "openFrontend");
52
56
  simGetSimulatorUrl = vi.spyOn(simulatorService, "getFrontendUrl")
57
+ simAddConfigToEnvFile = vi.spyOn(simulatorService, "addConfigToEnvFile")
53
58
 
54
59
  simServCheckVersionRequirements.mockResolvedValue({
55
60
  node: '',
@@ -59,22 +64,17 @@ describe("init action", () => {
59
64
  git: true,
60
65
  docker: true,
61
66
  })
67
+ simAddConfigToEnvFile.mockResolvedValue(true);
68
+ const mockEnvContent = "FRONTEND_PORT=8080";
69
+ const mockEnvConfig = { FRONTEND_PORT: "8080" };
70
+ vi.mocked(fs.readFileSync).mockReturnValue(mockEnvContent);
71
+ vi.mocked(dotenv.parse).mockReturnValue(mockEnvConfig);
62
72
  });
63
73
 
64
74
  afterEach(() => {
65
75
  vi.restoreAllMocks();
66
76
  });
67
77
 
68
- test("if both requirements are missing, then the execution fails", async () => {
69
- simServCheckInstallRequirements.mockResolvedValue({ git: false, docker: false });
70
-
71
- await initAction(defaultActionOptions, simulatorService);
72
-
73
- expect(error).toHaveBeenCalledWith(
74
- "Git and Docker are not installed. Please install them and try again.\n"
75
- );
76
- });
77
-
78
78
  test("if only docker is missing, then the execution fails", async () => {
79
79
  simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: false });
80
80
 
@@ -83,14 +83,6 @@ describe("init action", () => {
83
83
  expect(error).toHaveBeenCalledWith("Docker is not installed. Please install Docker and try again.\n");
84
84
  });
85
85
 
86
- test("if only git is missing, then the execution fails", async () => {
87
- simServCheckInstallRequirements.mockResolvedValue({ git: false, docker: true });
88
-
89
- await initAction(defaultActionOptions, simulatorService);
90
-
91
- expect(error).toHaveBeenCalledWith("Git is not installed. Please install Git and try again.\n");
92
- });
93
-
94
86
  test("if check install requirements fail, then the execution aborts", async () => {
95
87
  simServCheckInstallRequirements.mockRejectedValue(new Error("Error"));
96
88
 
@@ -169,7 +161,6 @@ describe("init action", () => {
169
161
  { name: "OpenAI", value: "openai" },
170
162
  { name: "Heurist", value: "heuristai" },
171
163
  ]);
172
- simServConfigSimulator.mockResolvedValue(true);
173
164
  simServRunSimulator.mockResolvedValue(true);
174
165
  simServWaitForSimulator.mockResolvedValue({ initialized: true });
175
166
  simServPullOllamaModel.mockResolvedValue(true);
@@ -200,7 +191,6 @@ describe("init action", () => {
200
191
  { name: "OpenAI", value: "openai" },
201
192
  { name: "Heurist", value: "heuristai" },
202
193
  ]);
203
- simServConfigSimulator.mockResolvedValue(true);
204
194
  simServRunSimulator.mockResolvedValue(true);
205
195
  simServWaitForSimulator.mockResolvedValue({ initialized: true });
206
196
  simServPullOllamaModel.mockResolvedValue(true);
@@ -230,7 +220,6 @@ describe("init action", () => {
230
220
  { name: "OpenAI", value: "openai" },
231
221
  { name: "Heurist", value: "heuristai" },
232
222
  ]);
233
- simServConfigSimulator.mockResolvedValue(true);
234
223
  simServRunSimulator.mockResolvedValue(true);
235
224
  simServWaitForSimulator.mockResolvedValue({ initialized: true });
236
225
  simServPullOllamaModel.mockResolvedValue(true);
@@ -248,18 +237,6 @@ describe("init action", () => {
248
237
  expect(error).toHaveBeenCalledWith('Unable to initialize the validators.');
249
238
  });
250
239
 
251
-
252
- test("if configSimulator fails, then the execution aborts", async () => {
253
- inquirerPrompt.mockResolvedValue({ confirmReset: true, confirmDownload: true, selectedLlmProviders: [] });
254
- simServConfigSimulator.mockRejectedValue(new Error("Error"));
255
- simServResetDockerContainers.mockResolvedValue(true);
256
- simServResetDockerImages.mockResolvedValue(true);
257
-
258
- await initAction(defaultActionOptions, simulatorService);
259
-
260
- expect(error).toHaveBeenCalledWith(new Error("Error"));
261
- });
262
-
263
240
  test("if runSimulator fails, then the execution aborts", async () => {
264
241
  inquirerPrompt.mockResolvedValue({ confirmReset: true, confirmDownload: true, selectedLlmProviders: [] });
265
242
  simServRunSimulator.mockRejectedValue(new Error("Error"));
@@ -285,7 +262,7 @@ describe("init action", () => {
285
262
  { name: "Heurist", value: "heuristai" },
286
263
  { name: "Ollama", value: "ollama" },
287
264
  ]);
288
- simServConfigSimulator.mockResolvedValue(true);
265
+
289
266
  simServRunSimulator.mockResolvedValue(true);
290
267
  simServWaitForSimulator.mockResolvedValue({ initialized: true });
291
268
  simServPullOllamaModel.mockResolvedValue(true);
@@ -308,20 +285,6 @@ describe("init action", () => {
308
285
  expect(error).toHaveBeenCalledWith(errorMsg);
309
286
  });
310
287
 
311
- test("logs 'Aborted!' if confirmDownload is false", async () => {
312
- inquirerPrompt
313
- .mockResolvedValueOnce({ confirmReset: true })
314
- .mockResolvedValueOnce({ confirmDownload: false });
315
-
316
- simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
317
- simServResetDockerContainers.mockResolvedValue(true);
318
- simServResetDockerImages.mockResolvedValue(true);
319
-
320
- await initAction(defaultActionOptions, simulatorService);
321
-
322
- expect(log).toHaveBeenCalledWith("Aborted!");
323
- });
324
-
325
288
  test("logs error if resetDockerContainers throws", async () => {
326
289
  inquirerPrompt.mockResolvedValue({ confirmReset: true });
327
290
  simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
@@ -334,9 +297,11 @@ describe("init action", () => {
334
297
  });
335
298
 
336
299
  test("prompts for LLM providers and validates that at least one is selected", async () => {
300
+ const mockEnvContent = "FRONTEND_PORT=8080";
301
+ vi.mocked(fs.readFileSync).mockReturnValue(mockEnvContent);
302
+
337
303
  inquirerPrompt
338
304
  .mockResolvedValueOnce({ confirmReset: true })
339
- .mockResolvedValueOnce({ confirmDownload: true })
340
305
  .mockImplementation((questions: any) => {
341
306
  if (questions[0].type === "checkbox") {
342
307
  const validateFunction = questions[0].validate;
@@ -353,11 +318,9 @@ describe("init action", () => {
353
318
  }
354
319
  });
355
320
 
356
- simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
321
+ simServCheckInstallRequirements.mockResolvedValue({ docker: true });
357
322
  simServResetDockerContainers.mockResolvedValue(true);
358
323
  simServResetDockerImages.mockResolvedValue(true);
359
- simServDownloadSimulator.mockResolvedValue({ wasInstalled: false });
360
- simServConfigSimulator.mockResolvedValue(true);
361
324
  simServRunSimulator.mockResolvedValue(true);
362
325
  simServWaitForSimulator.mockResolvedValue({ initialized: true });
363
326
  simServDeleteAllValidators.mockResolvedValue(true);
@@ -367,31 +330,16 @@ describe("init action", () => {
367
330
  await initAction(defaultActionOptions, simulatorService);
368
331
  });
369
332
 
370
- test("logs error if downloadSimulator throws", async () => {
371
- inquirerPrompt.mockResolvedValue({ confirmReset: true, confirmDownload: true });
372
- simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
373
- simServResetDockerContainers.mockResolvedValue(true);
374
- simServResetDockerImages.mockResolvedValue(true);
375
- const errorMsg = new Error("downloadSimulator error");
376
- simServDownloadSimulator.mockRejectedValueOnce(errorMsg);
377
-
378
- await initAction(defaultActionOptions, simulatorService);
379
-
380
- expect(error).toHaveBeenCalledWith(errorMsg);
381
- });
382
333
 
383
334
  test("logs error message if simulator fails to initialize with ERROR code", async () => {
384
335
  inquirerPrompt
385
336
  .mockResolvedValueOnce({ confirmReset: true })
386
- .mockResolvedValueOnce({ confirmDownload: true })
387
337
  .mockResolvedValueOnce({ selectedLlmProviders: ["openai"] })
388
338
  .mockResolvedValueOnce({ openai: "API_KEY1" });
389
339
 
390
- simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
340
+ simServCheckInstallRequirements.mockResolvedValue({ docker: true });
391
341
  simServResetDockerContainers.mockResolvedValue(true);
392
342
  simServResetDockerImages.mockResolvedValue(true);
393
- simServDownloadSimulator.mockResolvedValue({ wasInstalled: false });
394
- simServConfigSimulator.mockResolvedValue(true);
395
343
  simServRunSimulator.mockResolvedValue(true);
396
344
 
397
345
  simServWaitForSimulator.mockResolvedValue({
@@ -416,8 +364,6 @@ describe("init action", () => {
416
364
  simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
417
365
  simServResetDockerContainers.mockResolvedValue(true);
418
366
  simServResetDockerImages.mockResolvedValue(true);
419
- simServDownloadSimulator.mockResolvedValue({ wasInstalled: false });
420
- simServConfigSimulator.mockResolvedValue(true);
421
367
  const errorMsg = new Error("runSimulator error");
422
368
  simServRunSimulator.mockRejectedValueOnce(errorMsg);
423
369
 
@@ -436,8 +382,6 @@ describe("init action", () => {
436
382
  simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
437
383
  simServResetDockerContainers.mockResolvedValue(true);
438
384
  simServResetDockerImages.mockResolvedValue(true);
439
- simServDownloadSimulator.mockResolvedValue({ wasInstalled: false });
440
- simServConfigSimulator.mockResolvedValue(true);
441
385
  simServRunSimulator.mockResolvedValue(true);
442
386
  simServWaitForSimulator.mockResolvedValue({
443
387
  initialized: false,
@@ -455,15 +399,12 @@ describe("init action", () => {
455
399
  test("catches and logs error if waitForSimulatorToBeReady throws an exception", async () => {
456
400
  inquirerPrompt
457
401
  .mockResolvedValueOnce({ confirmReset: true })
458
- .mockResolvedValueOnce({ confirmDownload: true })
459
402
  .mockResolvedValueOnce({ selectedLlmProviders: ["openai"] })
460
403
  .mockResolvedValueOnce({ openai: "API_KEY1" });
461
404
 
462
- simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
405
+ simServCheckInstallRequirements.mockResolvedValue({ docker: true });
463
406
  simServResetDockerContainers.mockResolvedValue(true);
464
407
  simServResetDockerImages.mockResolvedValue(true);
465
- simServDownloadSimulator.mockResolvedValue({ wasInstalled: false });
466
- simServConfigSimulator.mockResolvedValue(true);
467
408
  simServRunSimulator.mockResolvedValue(true);
468
409
 
469
410
  const errorMsg = new Error("Unexpected simulator error");
@@ -475,17 +416,17 @@ describe("init action", () => {
475
416
  });
476
417
 
477
418
  test("catches and logs error if openFrontend throws an exception", async () => {
419
+ const mockEnvContent = "FRONTEND_PORT=8080";
420
+ vi.mocked(fs.readFileSync).mockReturnValue(mockEnvContent);
421
+
478
422
  inquirerPrompt
479
423
  .mockResolvedValueOnce({ confirmReset: true })
480
- .mockResolvedValueOnce({ confirmDownload: true })
481
424
  .mockResolvedValueOnce({ selectedLlmProviders: ["openai"] })
482
425
  .mockResolvedValueOnce({ openai: "API_KEY1" });
483
426
 
484
- simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
427
+ simServCheckInstallRequirements.mockResolvedValue({ docker: true });
485
428
  simServResetDockerContainers.mockResolvedValue(true);
486
429
  simServResetDockerImages.mockResolvedValue(true);
487
- simServDownloadSimulator.mockResolvedValue({ wasInstalled: false });
488
- simServConfigSimulator.mockResolvedValue(true);
489
430
  simServRunSimulator.mockResolvedValue(true);
490
431
  simServWaitForSimulator.mockResolvedValue({ initialized: true });
491
432
  simServDeleteAllValidators.mockResolvedValue(true);
@@ -12,8 +12,6 @@ describe("startAction - Additional Tests", () => {
12
12
  const defaultOptions: StartActionOptions = {
13
13
  resetValidators: false,
14
14
  numValidators: 5,
15
- branch: "main",
16
- location: '',
17
15
  headless: false,
18
16
  resetDb: false
19
17
  };
@@ -49,13 +47,10 @@ describe("startAction - Additional Tests", () => {
49
47
  test("runs successfully with default options and keeps existing validators", async () => {
50
48
  await startAction(defaultOptions, simulatorService);
51
49
 
52
- expect(simulatorService.updateSimulator).toHaveBeenCalledWith("main");
53
50
  expect(simulatorService.runSimulator).toHaveBeenCalled();
54
51
  expect(simulatorService.waitForSimulatorToBeReady).toHaveBeenCalled();
55
52
 
56
53
  expect(logSpy).toHaveBeenCalledWith("Starting GenLayer simulator keeping the existing validators");
57
- expect(logSpy).toHaveBeenCalledWith("Updating GenLayer Simulator...");
58
- expect(logSpy).toHaveBeenCalledWith("Running the GenLayer Simulator...");
59
54
  expect(logSpy).toHaveBeenCalledWith("Simulator is running!");
60
55
  expect(logSpy).toHaveBeenCalledWith("GenLayer simulator initialized successfully! Go to http://localhost:8080 in your browser to access it.");
61
56
 
@@ -65,26 +60,15 @@ describe("startAction - Additional Tests", () => {
65
60
  test("runs successfully with custom options and keeps existing validators", async () => {
66
61
  await startAction({...defaultOptions, headless: true, resetDb: true}, simulatorService);
67
62
 
68
- expect(simulatorService.updateSimulator).toHaveBeenCalledWith("main");
69
63
  expect(simulatorService.runSimulator).toHaveBeenCalled();
70
64
  expect(simulatorService.waitForSimulatorToBeReady).toHaveBeenCalled();
71
65
 
72
66
  expect(logSpy).toHaveBeenCalledWith("Starting GenLayer simulator keeping the existing validators");
73
- expect(logSpy).toHaveBeenCalledWith("Updating GenLayer Simulator...");
74
- expect(logSpy).toHaveBeenCalledWith("Running the GenLayer Simulator...");
67
+
75
68
  expect(logSpy).toHaveBeenCalledWith("Simulator is running!");
76
69
  expect(logSpy).toHaveBeenCalledWith("GenLayer simulator initialized successfully! ");
77
70
  });
78
71
 
79
- test("logs error and stops if updateSimulator fails", async () => {
80
- const errorMsg = new Error("updateSimulator error");
81
- (simulatorService.updateSimulator as Mock).mockRejectedValueOnce(errorMsg);
82
-
83
- await startAction(defaultOptions, simulatorService);
84
-
85
- expect(errorSpy).toHaveBeenCalledWith(errorMsg);
86
- expect(simulatorService.runSimulator).not.toHaveBeenCalled();
87
- });
88
72
 
89
73
  test("logs error and stops if runSimulator fails", async () => {
90
74
  const errorMsg = new Error("runSimulator error");
@@ -7,8 +7,6 @@ import simulatorService from '../../src/lib/services/simulator'
7
7
  const openFrontendSpy = vi.spyOn(simulatorService, "openFrontend");
8
8
  const defaultOptions = {
9
9
  numValidators: "5",
10
- branch: "main",
11
- location: process.cwd(),
12
10
  headless: false,
13
11
  resetDb: false
14
12
  }
@@ -52,21 +50,6 @@ describe("init command", () => {
52
50
  expect(numValidatorsOption?.defaultValue).toBe("5");
53
51
  });
54
52
 
55
- test("option --branch is accepted", async () => {
56
- expect(() => program.parse(["node", "test", "init", "--branch", "example"])).not.toThrow();
57
- });
58
-
59
- test("option --branch default value is main", async () => {
60
- const branchOption = getCommandOption(initCommand, "--branch");
61
- expect(branchOption?.defaultValue).toBe("main");
62
- });
63
-
64
- test("option --location default value is user's current directory", async () => {
65
- // Given // When
66
- const locationOption = getCommandOption(initCommand, "--location");
67
- expect(locationOption?.defaultValue).toBe(process.cwd());
68
- });
69
-
70
53
 
71
54
  test("random option is not accepted", async () => {
72
55
  initCommand?.exitOverride();
@@ -10,8 +10,6 @@ const action = vi.fn();
10
10
  const defaultOptions = {
11
11
  resetValidators: false,
12
12
  numValidators: "5",
13
- branch: "main",
14
- location: process.cwd(),
15
13
  headless: false ,
16
14
  resetDb: false
17
15
  }
@@ -58,14 +56,6 @@ describe("up command", () => {
58
56
  expect(numValidatorsOption?.defaultValue).toBe("5");
59
57
  });
60
58
 
61
- test("option --branch is accepted", async () => {
62
- expect(() => program.parse(["node", "test", "up", "--branch", "development"])).not.toThrow();
63
- });
64
-
65
- test("option --branch default value is main", async () => {
66
- const branchOption = getCommandOption(upCommand, "--branch");
67
- expect(branchOption?.defaultValue).toBe("main");
68
- });
69
59
 
70
60
  test("unrecognized option is not accepted", async () => {
71
61
  upCommand?.exitOverride();
@@ -91,15 +81,13 @@ describe("up command", () => {
91
81
  "--reset-validators",
92
82
  "--numValidators",
93
83
  "10",
94
- "--branch",
95
- "development",
96
84
  "--headless",
97
85
  "true",
98
86
  "--reset-db",
99
87
  "true"
100
88
  ]);
101
89
  expect(action).toHaveBeenCalledTimes(1);
102
- expect(action).toHaveBeenCalledWith({...defaultOptions, headless: true, branch: 'development', numValidators: '10', resetValidators: true, resetDb: true});
90
+ expect(action).toHaveBeenCalledWith({...defaultOptions, headless: true, numValidators: '10', resetValidators: true, resetDb: true});
103
91
  expect(openFrontendSpy).not.toHaveBeenCalled();
104
92
  });
105
93
  });
@@ -12,8 +12,6 @@ import {
12
12
  import {
13
13
  DOCKER_IMAGES_AND_CONTAINERS_NAME_PREFIX,
14
14
  VERSION_REQUIREMENTS,
15
- } from "../../src/lib/config/simulator";
16
- import {
17
15
  STARTING_TIMEOUT_ATTEMPTS,
18
16
  DEFAULT_RUN_SIMULATOR_COMMAND,
19
17
  } from "../../src/lib/config/simulator";
@@ -59,23 +57,14 @@ describe("SimulatorService - Basic Tests", () => {
59
57
  vi.mocked(path.join).mockImplementation((...args) => args.join("/"));
60
58
  });
61
59
 
62
- test("should return the correct simulator location path", () => {
63
- const expectedPath = "/mock/home/genlayer-simulator";
64
- simulatorService.setSimulatorLocation("/mock/home/genlayer-simulator");
65
- const simulatorLocation = simulatorService.getSimulatorLocation();
66
- expect(simulatorLocation).toBe(expectedPath);
67
- });
68
60
 
69
61
  test("should read the correct frontend URL from .env config", () => {
70
- const mockEnvFilePath = "/mock/home/genlayer-simulator/.env";
71
62
  const mockEnvContent = "FRONTEND_PORT=8080";
72
63
  const mockEnvConfig = { FRONTEND_PORT: "8080" };
73
64
  vi.mocked(fs.readFileSync).mockReturnValue(mockEnvContent);
74
65
  vi.mocked(dotenv.parse).mockReturnValue(mockEnvConfig);
75
- simulatorService.setSimulatorLocation("/mock/home/genlayer-simulator");
76
66
  const frontendUrl = simulatorService.getFrontendUrl();
77
67
  expect(frontendUrl).toBe("http://localhost:8080");
78
- expect(fs.readFileSync).toHaveBeenCalledWith(mockEnvFilePath, "utf8");
79
68
  });
80
69
 
81
70
  test("should check version requirements and return missing versions", async () => {
@@ -95,20 +84,6 @@ describe("SimulatorService - Basic Tests", () => {
95
84
  await expect(simulatorService.checkVersion("14.0.0", "node")).rejects.toThrow();
96
85
  });
97
86
 
98
- test("should download simulator if not already installed", async () => {
99
- const result = await simulatorService.downloadSimulator();
100
- expect(result.wasInstalled).toBe(false);
101
- expect(executeCommand).toHaveBeenCalled();
102
- });
103
-
104
- test("should skip download if simulator is already installed", async () => {
105
- vi.mocked(executeCommand).mockRejectedValueOnce(new Error("Mocked command error"));
106
- vi.spyOn(fs, "existsSync").mockReturnValue(true);
107
- const result = await simulatorService.downloadSimulator();
108
- expect(result.wasInstalled).toBe(true);
109
- expect(executeCommand).toHaveBeenCalled();
110
- expect(fs.existsSync).toHaveBeenCalled();
111
- });
112
87
 
113
88
  test("should return initialized true when simulator responds with OK (result.status = OK)", async () => {
114
89
  vi.mocked(rpcClient.request).mockResolvedValueOnce({ result: {status: 'OK'} });
@@ -150,7 +125,7 @@ describe("SimulatorService - Basic Tests", () => {
150
125
  stderr: "",
151
126
  });
152
127
  const result = await simulatorService.runSimulator();
153
- const expectedCommand = DEFAULT_RUN_SIMULATOR_COMMAND("/mock/home/genlayer-simulator", '');
128
+ const expectedCommand = DEFAULT_RUN_SIMULATOR_COMMAND(simulatorService.location, '');
154
129
  expect(executeCommand).toHaveBeenCalledWith(expectedCommand);
155
130
  expect(result).toEqual({ stdout: "Simulator started", stderr: "" });
156
131
  });
@@ -163,11 +138,57 @@ describe("SimulatorService - Basic Tests", () => {
163
138
  simulatorService.setComposeOptions(true)
164
139
  const commandOption = simulatorService.getComposeOptions();
165
140
  const result = await simulatorService.runSimulator();
166
- const expectedCommand = DEFAULT_RUN_SIMULATOR_COMMAND("/mock/home/genlayer-simulator", commandOption);
141
+ const expectedCommand = DEFAULT_RUN_SIMULATOR_COMMAND(simulatorService.location, commandOption);
167
142
  expect(executeCommand).toHaveBeenCalledWith(expectedCommand);
168
143
  expect(result).toEqual({ stdout: "Simulator started", stderr: "" });
169
144
  });
170
145
 
146
+ test("should create a backup of the .env file and add new config", () => {
147
+ const envFilePath = `/.env`;
148
+ const originalEnvContent = "KEY1=value1\nKEY2=value2";
149
+ const parsedEnvConfig = { KEY1: "value1", KEY2: "value2" };
150
+ const newConfig = { KEY3: "value3", KEY2: "newValue2" };
151
+
152
+ vi.mocked(fs.readFileSync).mockImplementation((filePath: any) => {
153
+ if (filePath === envFilePath) return originalEnvContent;
154
+ return "";
155
+ });
156
+
157
+ vi.mocked(dotenv.parse).mockReturnValue(parsedEnvConfig);
158
+ const writeFileSyncMock = vi.mocked(fs.writeFileSync);
159
+
160
+ simulatorService.addConfigToEnvFile(newConfig);
161
+
162
+ const expectedUpdatedContent = `KEY1=value1\nKEY2=newValue2\nKEY3=value3`;
163
+ expect(writeFileSyncMock).toHaveBeenCalledWith(envFilePath, expectedUpdatedContent);
164
+ });
165
+
166
+ test("should handle empty .env file and add new config", () => {
167
+ const envFilePath = `/.env`;
168
+ const newConfig = { NEW_KEY: "newValue" };
169
+
170
+ vi.mocked(fs.readFileSync).mockReturnValue("");
171
+ vi.mocked(dotenv.parse).mockReturnValue({});
172
+ const writeFileSyncMock = vi.mocked(fs.writeFileSync);
173
+
174
+ simulatorService.addConfigToEnvFile(newConfig);
175
+
176
+ expect(writeFileSyncMock).toHaveBeenCalledWith(`${envFilePath}.bak`, "");
177
+ const expectedUpdatedContent = `NEW_KEY=newValue`;
178
+ expect(writeFileSyncMock).toHaveBeenCalledWith(envFilePath, expectedUpdatedContent);
179
+ });
180
+
181
+ test("should throw error when .env file does not exist", () => {
182
+ vi.mocked(fs.readFileSync).mockImplementation(() => {
183
+ throw new Error("File not found");
184
+ });
185
+
186
+ expect(() => simulatorService.addConfigToEnvFile({ KEY: "value" })).toThrow(
187
+ "File not found"
188
+ );
189
+ });
190
+
191
+
171
192
  test("should open the frontend URL and return true", async () => {
172
193
  vi.spyOn(simulatorService, "getFrontendUrl").mockReturnValue("http://localhost:8080");
173
194
  const result = await simulatorService.openFrontend();
@@ -242,47 +263,14 @@ describe("SimulatorService - Basic Tests", () => {
242
263
  expect(result).toEqual({ initialized: false, errorCode: "ERROR", errorMessage: fetchError.message });
243
264
  });
244
265
 
245
- test("should throw an error if executeCommand fails and simulator location does not exist", async () => {
246
- const mockError = new Error("git clone failed");
247
- vi.mocked(executeCommand).mockRejectedValueOnce(mockError);
248
- vi.mocked(fs.existsSync).mockReturnValue(false);
249
- await expect(simulatorService.downloadSimulator()).rejects.toThrow("git clone failed");
250
- expect(executeCommand).toHaveBeenCalled();
251
- expect(fs.existsSync).toHaveBeenCalledWith("/mock/home/genlayer-simulator");
252
- });
253
-
254
266
  test("should call executeCommand if docker ps command fails", async () => {
255
267
  vi.mocked(checkCommand)
256
268
  .mockResolvedValueOnce(undefined)
257
269
 
258
-
259
270
  const result = await simulatorService.checkInstallRequirements();
260
271
  expect(result.docker).toBe(true);
261
- expect(result.git).toBe(true);
262
272
  });
263
273
 
264
- test("should update envConfig with newConfig values", () => {
265
- const envFilePath = path.join("/mock/home/genlayer-simulator", ".env");
266
- const originalEnvContent = "KEY1=value1\nKEY2=value2";
267
- const envConfig = { KEY1: "value1", KEY2: "value2" };
268
- const newConfig = { KEY2: "new_value2", KEY3: "value3" };
269
- vi.mocked(fs.readFileSync)
270
- .mockReturnValueOnce(originalEnvContent)
271
- .mockReturnValueOnce(originalEnvContent);
272
- vi.mocked(dotenv.parse).mockReturnValue(envConfig);
273
- const writeFileSyncSpy = vi.spyOn(fs, "writeFileSync");
274
- simulatorService["addConfigToEnvFile"](newConfig);
275
- expect(envConfig).toEqual({
276
- KEY1: "value1",
277
- KEY2: "new_value2",
278
- KEY3: "value3",
279
- });
280
- expect(writeFileSyncSpy).toHaveBeenCalledWith(`${envFilePath}.bak`, originalEnvContent);
281
- expect(writeFileSyncSpy).toHaveBeenCalledWith(
282
- envFilePath,
283
- "KEY1=value1\nKEY2=new_value2\nKEY3=value3"
284
- );
285
- });
286
274
 
287
275
  test("should return providers without errors", () => {
288
276
  expect(simulatorService.getAiProvidersOptions(true)).toEqual(expect.any(Array));
@@ -314,8 +302,60 @@ describe("SimulatorService - Docker Tests", () => {
314
302
  mockPing = vi.mocked(Docker.prototype.ping);
315
303
  });
316
304
 
317
- test("should pull the Ollama model", async () => {
318
- mockGetContainer.mockReturnValueOnce({exec: mockExec} as unknown as Docker.Container);
305
+ test("should handle errors during the execution of pullOllamaModel gracefully", async () => {
306
+ const mockExec = vi.fn();
307
+ const mockStart = vi.fn();
308
+
309
+ mockExec.mockResolvedValue({
310
+ start: mockStart,
311
+ });
312
+
313
+ const mockStream = {
314
+ on: vi.fn((event, callback) => {
315
+ if (event === "data") callback("Mock data chunk");
316
+ if (event === "error") callback(new Error("Mock error during stream"));
317
+ }),
318
+ };
319
+
320
+ mockStart.mockResolvedValue(mockStream);
321
+
322
+ mockGetContainer.mockReturnValueOnce({
323
+ exec: mockExec,
324
+ } as unknown as Docker.Container);
325
+
326
+ const result = await simulatorService.pullOllamaModel();
327
+
328
+ expect(result).toBe(false);
329
+ expect(mockGetContainer).toHaveBeenCalledWith("ollama");
330
+ expect(mockExec).toHaveBeenCalledWith({
331
+ Cmd: ["ollama", "pull", "llama3"],
332
+ AttachStdout: true,
333
+ AttachStderr: true,
334
+ });
335
+ expect(mockStart).toHaveBeenCalledWith({ Detach: false, Tty: false });
336
+ expect(mockStream.on).toHaveBeenCalledWith("error", expect.any(Function));
337
+ });
338
+
339
+ test("should successfully execute pullOllamaModel and return true", async () => {
340
+ const mockExec = vi.fn();
341
+ const mockStart = vi.fn();
342
+
343
+ mockExec.mockResolvedValue({
344
+ start: mockStart,
345
+ });
346
+
347
+ const mockStream = {
348
+ on: vi.fn((event, callback) => {
349
+ if (event === "data") callback("Mock data chunk");
350
+ if (event === "end") callback();
351
+ }),
352
+ };
353
+
354
+ mockStart.mockResolvedValue(mockStream);
355
+
356
+ mockGetContainer.mockReturnValueOnce({
357
+ exec: mockExec,
358
+ } as unknown as Docker.Container);
319
359
 
320
360
  const result = await simulatorService.pullOllamaModel();
321
361
 
@@ -323,9 +363,15 @@ describe("SimulatorService - Docker Tests", () => {
323
363
  expect(mockGetContainer).toHaveBeenCalledWith("ollama");
324
364
  expect(mockExec).toHaveBeenCalledWith({
325
365
  Cmd: ["ollama", "pull", "llama3"],
366
+ AttachStdout: true,
367
+ AttachStderr: true,
326
368
  });
369
+ expect(mockStart).toHaveBeenCalledWith({ Detach: false, Tty: false });
370
+ expect(mockStream.on).toHaveBeenCalledWith("data", expect.any(Function));
371
+ expect(mockStream.on).toHaveBeenCalledWith("end", expect.any(Function));
327
372
  });
328
373
 
374
+
329
375
  test("should stop and remove Docker containers with the specified prefix", async () => {
330
376
  const mockContainers = [
331
377
  {
@@ -411,12 +457,12 @@ describe("SimulatorService - Docker Tests", () => {
411
457
  expect(executeCommand).toHaveBeenCalledTimes(1);
412
458
  });
413
459
 
414
- test("should throw an unexpected error when checking docker installation requirement", async () => {
460
+ test("should call execute command again to start docker service", async () => {
415
461
  vi.mocked(checkCommand)
416
462
  .mockResolvedValueOnce(undefined)
417
463
  .mockRejectedValue(undefined);
418
- mockPing.mockRejectedValueOnce("Unexpected docker error");
419
- await expect(simulatorService.checkInstallRequirements()).rejects.toThrow("Unexpected docker error");
464
+ mockPing.mockRejectedValueOnce("");
465
+ await expect(simulatorService.checkInstallRequirements()).resolves.toStrictEqual({ docker: true });
420
466
  });
421
467
 
422
468
  test("should warn the user when an update is available", async () => {
package/vitest.config.ts CHANGED
@@ -5,7 +5,7 @@ export default defineConfig({
5
5
  globals: true,
6
6
  environment: 'jsdom',
7
7
  coverage: {
8
- exclude: [...configDefaults.exclude, '*.js', 'tests/**/*.ts', 'src/types'],
8
+ exclude: [...configDefaults.exclude, '*.js', 'tests/**/*.ts', 'src/types', 'scripts'],
9
9
  }
10
10
  }
11
11
  });