genlayer 0.18.0 → 0.18.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.
- package/CHANGELOG.md +9 -0
- package/dist/index.js +25711 -12445
- package/package.json +2 -2
- package/src/commands/contracts/call.ts +7 -49
- package/src/commands/contracts/deploy.ts +17 -13
- package/src/commands/contracts/index.ts +36 -11
- package/src/commands/contracts/write.ts +49 -0
- package/src/commands/general/init.ts +15 -20
- package/src/commands/general/start.ts +14 -10
- package/src/commands/keygen/create.ts +2 -2
- package/src/commands/network/index.ts +14 -0
- package/src/commands/network/setNetwork.ts +60 -0
- package/src/index.ts +9 -7
- package/src/lib/actions/BaseAction.ts +20 -18
- package/tests/actions/call.test.ts +22 -86
- package/tests/actions/create.test.ts +8 -8
- package/tests/actions/deploy.test.ts +72 -60
- package/tests/actions/init.test.ts +173 -102
- package/tests/actions/setNetwork.test.ts +199 -0
- package/tests/actions/start.test.ts +48 -24
- package/tests/actions/write.test.ts +102 -0
- package/tests/commands/network.test.ts +60 -0
- package/tests/commands/write.test.ts +76 -0
- package/tests/index.test.ts +5 -2
- package/tests/libs/baseAction.test.ts +37 -26
- package/tests/services/simulator.test.ts +98 -102
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {describe, beforeEach, afterEach, test, expect, vi, Mock} from "vitest";
|
|
2
2
|
import inquirer from "inquirer";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import {StartAction, StartActionOptions} from "../../src/commands/general/start";
|
|
4
|
+
import {SimulatorService} from "../../src/lib/services/simulator";
|
|
5
5
|
|
|
6
6
|
vi.mock("../../src/lib/services/simulator");
|
|
7
7
|
vi.mock("inquirer");
|
|
@@ -18,7 +18,7 @@ describe("StartAction", () => {
|
|
|
18
18
|
startAction = new StartAction();
|
|
19
19
|
startAction["simulatorService"] = mockSimulatorService;
|
|
20
20
|
|
|
21
|
-
mockSimulatorService.waitForSimulatorToBeReady = vi.fn().mockResolvedValue({
|
|
21
|
+
mockSimulatorService.waitForSimulatorToBeReady = vi.fn().mockResolvedValue({initialized: true});
|
|
22
22
|
mockSimulatorService.stopDockerContainers = vi.fn().mockResolvedValue(undefined);
|
|
23
23
|
mockSimulatorService.getAiProvidersOptions = vi.fn().mockResolvedValue(undefined);
|
|
24
24
|
|
|
@@ -43,9 +43,9 @@ describe("StartAction", () => {
|
|
|
43
43
|
|
|
44
44
|
test("should check if localnet is running and proceed without confirmation when not running", async () => {
|
|
45
45
|
mockSimulatorService.isLocalnetRunning = vi.fn().mockResolvedValue(false);
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
await startAction.execute(defaultOptions);
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
expect(mockSimulatorService.isLocalnetRunning).toHaveBeenCalled();
|
|
50
50
|
expect(mockConfirmPrompt).not.toHaveBeenCalled();
|
|
51
51
|
expect(mockSimulatorService.runSimulator).toHaveBeenCalled();
|
|
@@ -53,11 +53,13 @@ describe("StartAction", () => {
|
|
|
53
53
|
|
|
54
54
|
test("should prompt for confirmation when localnet is already running", async () => {
|
|
55
55
|
mockSimulatorService.isLocalnetRunning = vi.fn().mockResolvedValue(true);
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
await startAction.execute(defaultOptions);
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
expect(mockSimulatorService.isLocalnetRunning).toHaveBeenCalled();
|
|
60
|
-
expect(mockConfirmPrompt).toHaveBeenCalledWith(
|
|
60
|
+
expect(mockConfirmPrompt).toHaveBeenCalledWith(
|
|
61
|
+
"GenLayer Localnet is already running. Do you want to proceed?",
|
|
62
|
+
);
|
|
61
63
|
expect(mockSimulatorService.runSimulator).toHaveBeenCalled();
|
|
62
64
|
});
|
|
63
65
|
|
|
@@ -71,13 +73,17 @@ describe("StartAction", () => {
|
|
|
71
73
|
expect(startAction["startSpinner"]).toHaveBeenCalledWith("Checking CLI version...");
|
|
72
74
|
expect(mockSimulatorService.checkCliVersion).toHaveBeenCalled();
|
|
73
75
|
|
|
74
|
-
expect(startAction["setSpinnerText"]).toHaveBeenCalledWith(
|
|
76
|
+
expect(startAction["setSpinnerText"]).toHaveBeenCalledWith(
|
|
77
|
+
"Starting GenLayer Localnet (keeping the existing validators)...",
|
|
78
|
+
);
|
|
75
79
|
expect(mockSimulatorService.runSimulator).toHaveBeenCalled();
|
|
76
80
|
|
|
77
81
|
expect(startAction["setSpinnerText"]).toHaveBeenCalledWith("Waiting for the simulator to be ready...");
|
|
78
82
|
expect(mockSimulatorService.waitForSimulatorToBeReady).toHaveBeenCalled();
|
|
79
83
|
|
|
80
|
-
expect(startAction["succeedSpinner"]).toHaveBeenCalledWith(
|
|
84
|
+
expect(startAction["succeedSpinner"]).toHaveBeenCalledWith(
|
|
85
|
+
"GenLayer simulator initialized successfully! Go to http://localhost:8080 in your browser to access it.",
|
|
86
|
+
);
|
|
81
87
|
});
|
|
82
88
|
|
|
83
89
|
test("should fail when simulator fails to start", async () => {
|
|
@@ -90,15 +96,20 @@ describe("StartAction", () => {
|
|
|
90
96
|
});
|
|
91
97
|
|
|
92
98
|
test("should fail when waiting for simulator initialization times out", async () => {
|
|
93
|
-
(mockSimulatorService.waitForSimulatorToBeReady as Mock).mockResolvedValue({
|
|
99
|
+
(mockSimulatorService.waitForSimulatorToBeReady as Mock).mockResolvedValue({
|
|
100
|
+
initialized: false,
|
|
101
|
+
errorCode: "TIMEOUT",
|
|
102
|
+
});
|
|
94
103
|
|
|
95
104
|
await startAction.execute(defaultOptions);
|
|
96
105
|
|
|
97
|
-
expect(startAction["failSpinner"]).toHaveBeenCalledWith(
|
|
106
|
+
expect(startAction["failSpinner"]).toHaveBeenCalledWith(
|
|
107
|
+
"The simulator is taking too long to initialize. Please try again later.",
|
|
108
|
+
);
|
|
98
109
|
});
|
|
99
110
|
|
|
100
111
|
test("should reset the database if resetDb is true", async () => {
|
|
101
|
-
const options: StartActionOptions = {
|
|
112
|
+
const options: StartActionOptions = {...defaultOptions, resetDb: true};
|
|
102
113
|
|
|
103
114
|
mockSimulatorService.cleanDatabase = vi.fn().mockResolvedValue(undefined);
|
|
104
115
|
|
|
@@ -109,13 +120,13 @@ describe("StartAction", () => {
|
|
|
109
120
|
});
|
|
110
121
|
|
|
111
122
|
test("should initialize validators when resetValidators is true", async () => {
|
|
112
|
-
const options: StartActionOptions = {
|
|
123
|
+
const options: StartActionOptions = {...defaultOptions, resetValidators: true};
|
|
113
124
|
|
|
114
125
|
mockSimulatorService.deleteAllValidators = vi.fn().mockResolvedValue(undefined);
|
|
115
126
|
mockSimulatorService.createRandomValidators = vi.fn().mockResolvedValue(undefined);
|
|
116
127
|
mockSimulatorService.getAiProvidersOptions = vi.fn().mockReturnValue(["Provider1", "Provider2"]);
|
|
117
128
|
|
|
118
|
-
vi.mocked(inquirer.prompt).mockResolvedValue({
|
|
129
|
+
vi.mocked(inquirer.prompt).mockResolvedValue({selectedLlmProviders: ["Provider1"]});
|
|
119
130
|
|
|
120
131
|
await startAction.execute(options);
|
|
121
132
|
|
|
@@ -125,13 +136,18 @@ describe("StartAction", () => {
|
|
|
125
136
|
});
|
|
126
137
|
|
|
127
138
|
test("should fail when initializing validators fails", async () => {
|
|
128
|
-
const options: StartActionOptions = {
|
|
139
|
+
const options: StartActionOptions = {...defaultOptions, resetValidators: true};
|
|
129
140
|
|
|
130
|
-
mockSimulatorService.deleteAllValidators = vi
|
|
141
|
+
mockSimulatorService.deleteAllValidators = vi
|
|
142
|
+
.fn()
|
|
143
|
+
.mockRejectedValue(new Error("Failed to delete validators"));
|
|
131
144
|
|
|
132
145
|
await startAction.execute(options);
|
|
133
146
|
|
|
134
|
-
expect(startAction["failSpinner"]).toHaveBeenCalledWith(
|
|
147
|
+
expect(startAction["failSpinner"]).toHaveBeenCalledWith(
|
|
148
|
+
"Unable to initialize the validators",
|
|
149
|
+
expect.any(Error),
|
|
150
|
+
);
|
|
135
151
|
});
|
|
136
152
|
|
|
137
153
|
test("should open frontend when not in headless mode", async () => {
|
|
@@ -165,7 +181,9 @@ describe("StartAction", () => {
|
|
|
165
181
|
|
|
166
182
|
await startAction.execute(defaultOptions);
|
|
167
183
|
|
|
168
|
-
expect(startAction["failSpinner"]).toHaveBeenCalledWith(
|
|
184
|
+
expect(startAction["failSpinner"]).toHaveBeenCalledWith(
|
|
185
|
+
"The simulator is taking too long to initialize. Please try again later.",
|
|
186
|
+
);
|
|
169
187
|
});
|
|
170
188
|
|
|
171
189
|
test("should log error message if simulator fails to initialize with ERROR code", async () => {
|
|
@@ -177,7 +195,10 @@ describe("StartAction", () => {
|
|
|
177
195
|
|
|
178
196
|
await startAction.execute(defaultOptions);
|
|
179
197
|
|
|
180
|
-
expect(startAction["failSpinner"]).toHaveBeenCalledWith(
|
|
198
|
+
expect(startAction["failSpinner"]).toHaveBeenCalledWith(
|
|
199
|
+
"Unable to initialize the GenLayer simulator.",
|
|
200
|
+
"Initialization failed",
|
|
201
|
+
);
|
|
181
202
|
});
|
|
182
203
|
|
|
183
204
|
test("catches and logs error if waitForSimulatorToBeReady throws an exception", async () => {
|
|
@@ -186,14 +207,17 @@ describe("StartAction", () => {
|
|
|
186
207
|
|
|
187
208
|
await startAction.execute(defaultOptions);
|
|
188
209
|
|
|
189
|
-
expect(startAction["failSpinner"]).toHaveBeenCalledWith(
|
|
210
|
+
expect(startAction["failSpinner"]).toHaveBeenCalledWith(
|
|
211
|
+
"Error waiting for the simulator to be ready",
|
|
212
|
+
errorMsg,
|
|
213
|
+
);
|
|
190
214
|
});
|
|
191
215
|
|
|
192
216
|
test("should not append frontend URL when in headless mode", async () => {
|
|
193
|
-
await startAction.execute({
|
|
217
|
+
await startAction.execute({...defaultOptions, headless: true});
|
|
194
218
|
|
|
195
219
|
expect(startAction["succeedSpinner"]).toHaveBeenCalledWith(
|
|
196
|
-
"GenLayer simulator initialized successfully! "
|
|
220
|
+
"GenLayer simulator initialized successfully! ",
|
|
197
221
|
);
|
|
198
222
|
});
|
|
199
223
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {describe, test, vi, beforeEach, afterEach, expect} from "vitest";
|
|
2
|
+
import {createClient, createAccount} from "genlayer-js";
|
|
3
|
+
import {WriteAction} from "../../src/commands/contracts/write";
|
|
4
|
+
|
|
5
|
+
vi.mock("genlayer-js");
|
|
6
|
+
|
|
7
|
+
describe("WriteAction", () => {
|
|
8
|
+
let writeAction: WriteAction;
|
|
9
|
+
const mockClient = {
|
|
10
|
+
writeContract: vi.fn(),
|
|
11
|
+
waitForTransactionReceipt: vi.fn(),
|
|
12
|
+
initializeConsensusSmartContract: vi.fn(),
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const mockPrivateKey = "mocked_private_key";
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
vi.clearAllMocks();
|
|
19
|
+
vi.mocked(createClient).mockReturnValue(mockClient as any);
|
|
20
|
+
vi.mocked(createAccount).mockReturnValue({privateKey: mockPrivateKey} as any);
|
|
21
|
+
writeAction = new WriteAction();
|
|
22
|
+
vi.spyOn(writeAction as any, "getPrivateKey").mockResolvedValue(mockPrivateKey);
|
|
23
|
+
|
|
24
|
+
vi.spyOn(writeAction as any, "startSpinner").mockImplementation(() => {});
|
|
25
|
+
vi.spyOn(writeAction as any, "succeedSpinner").mockImplementation(() => {});
|
|
26
|
+
vi.spyOn(writeAction as any, "failSpinner").mockImplementation(() => {});
|
|
27
|
+
vi.spyOn(writeAction as any, "log").mockImplementation(() => {});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
vi.restoreAllMocks();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("calls writeContract successfully", async () => {
|
|
35
|
+
const options = {args: [42, "Update"]};
|
|
36
|
+
const mockHash = "0xMockedTransactionHash";
|
|
37
|
+
const mockReceipt = {status: "success"};
|
|
38
|
+
|
|
39
|
+
vi.mocked(mockClient.writeContract).mockResolvedValue(mockHash);
|
|
40
|
+
vi.mocked(mockClient.waitForTransactionReceipt).mockResolvedValue(mockReceipt);
|
|
41
|
+
|
|
42
|
+
await writeAction.write({
|
|
43
|
+
contractAddress: "0xMockedContract",
|
|
44
|
+
method: "updateData",
|
|
45
|
+
...options,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
expect(mockClient.writeContract).toHaveBeenCalledWith({
|
|
49
|
+
address: "0xMockedContract",
|
|
50
|
+
functionName: "updateData",
|
|
51
|
+
args: [42, "Update"],
|
|
52
|
+
value: 0n,
|
|
53
|
+
});
|
|
54
|
+
expect(writeAction["log"]).toHaveBeenCalledWith("Write Transaction Hash:", mockHash);
|
|
55
|
+
expect(writeAction["succeedSpinner"]).toHaveBeenCalledWith(
|
|
56
|
+
"Write operation successfully executed",
|
|
57
|
+
mockReceipt,
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("handles writeContract errors", async () => {
|
|
62
|
+
vi.mocked(mockClient.writeContract).mockRejectedValue(new Error("Mocked write error"));
|
|
63
|
+
|
|
64
|
+
await writeAction.write({contractAddress: "0xMockedContract", method: "updateData", args: [1]});
|
|
65
|
+
|
|
66
|
+
expect(writeAction["failSpinner"]).toHaveBeenCalledWith(
|
|
67
|
+
"Error during write operation",
|
|
68
|
+
expect.any(Error),
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("uses custom RPC URL for write operations", async () => {
|
|
73
|
+
const options = {args: [42, "Update"], rpc: "https://custom-rpc-url.com"};
|
|
74
|
+
const mockHash = "0xMockedTransactionHash";
|
|
75
|
+
const mockReceipt = {status: "success"};
|
|
76
|
+
|
|
77
|
+
vi.mocked(mockClient.writeContract).mockResolvedValue(mockHash);
|
|
78
|
+
vi.mocked(mockClient.waitForTransactionReceipt).mockResolvedValue(mockReceipt);
|
|
79
|
+
|
|
80
|
+
await writeAction.write({
|
|
81
|
+
contractAddress: "0xMockedContract",
|
|
82
|
+
method: "updateData",
|
|
83
|
+
...options,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
expect(createClient).toHaveBeenCalledWith(
|
|
87
|
+
expect.objectContaining({
|
|
88
|
+
endpoint: "https://custom-rpc-url.com",
|
|
89
|
+
}),
|
|
90
|
+
);
|
|
91
|
+
expect(mockClient.writeContract).toHaveBeenCalledWith({
|
|
92
|
+
address: "0xMockedContract",
|
|
93
|
+
functionName: "updateData",
|
|
94
|
+
args: [42, "Update"],
|
|
95
|
+
value: 0n,
|
|
96
|
+
});
|
|
97
|
+
expect(writeAction["succeedSpinner"]).toHaveBeenCalledWith(
|
|
98
|
+
"Write operation successfully executed",
|
|
99
|
+
mockReceipt,
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {Command} from "commander";
|
|
2
|
+
import {vi, describe, beforeEach, afterEach, test, expect} from "vitest";
|
|
3
|
+
import {initializeNetworkCommands} from "../../src/commands/network";
|
|
4
|
+
import {NetworkActions} from "../../src/commands/network/setNetwork";
|
|
5
|
+
|
|
6
|
+
vi.mock("../../src/commands/network/setNetwork");
|
|
7
|
+
|
|
8
|
+
describe("network commands", () => {
|
|
9
|
+
let program: Command;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
program = new Command();
|
|
13
|
+
initializeNetworkCommands(program);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
vi.restoreAllMocks();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("NetworkActions.setNetwork is called with the correct network name", async () => {
|
|
21
|
+
program.parse(["node", "test", "network", "localnet"]);
|
|
22
|
+
expect(NetworkActions).toHaveBeenCalledTimes(1);
|
|
23
|
+
expect(NetworkActions.prototype.setNetwork).toHaveBeenCalledWith("localnet");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("NetworkActions.setNetwork is called with testnet-asimov", async () => {
|
|
27
|
+
program.parse(["node", "test", "network", "testnet-asimov"]);
|
|
28
|
+
expect(NetworkActions).toHaveBeenCalledTimes(1);
|
|
29
|
+
expect(NetworkActions.prototype.setNetwork).toHaveBeenCalledWith("testnet-asimov");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("NetworkActions.setNetwork is called with studionet", async () => {
|
|
33
|
+
program.parse(["node", "test", "network", "studionet"]);
|
|
34
|
+
expect(NetworkActions).toHaveBeenCalledTimes(1);
|
|
35
|
+
expect(NetworkActions.prototype.setNetwork).toHaveBeenCalledWith("studionet");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("NetworkActions.setNetwork is called without a network name", async () => {
|
|
39
|
+
program.parse(["node", "test", "network"]);
|
|
40
|
+
expect(NetworkActions).toHaveBeenCalledTimes(1);
|
|
41
|
+
expect(NetworkActions.prototype.setNetwork).toHaveBeenCalledWith(undefined);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("NetworkActions is instantiated when the command is executed", async () => {
|
|
45
|
+
program.parse(["node", "test", "network", "localnet"]);
|
|
46
|
+
expect(NetworkActions).toHaveBeenCalledTimes(1);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("NetworkActions.setNetwork is called without throwing errors for valid network", async () => {
|
|
50
|
+
program.parse(["node", "test", "network", "localnet"]);
|
|
51
|
+
vi.mocked(NetworkActions.prototype.setNetwork).mockResolvedValue();
|
|
52
|
+
expect(() => program.parse(["node", "test", "network", "localnet"])).not.toThrow();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("NetworkActions.setNetwork is called with empty string", async () => {
|
|
56
|
+
program.parse(["node", "test", "network", ""]);
|
|
57
|
+
expect(NetworkActions).toHaveBeenCalledTimes(1);
|
|
58
|
+
expect(NetworkActions.prototype.setNetwork).toHaveBeenCalledWith("");
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {Command} from "commander";
|
|
2
|
+
import {WriteAction} from "../../src/commands/contracts/write";
|
|
3
|
+
import {vi, describe, beforeEach, afterEach, test, expect} from "vitest";
|
|
4
|
+
import {initializeContractsCommands} from "../../src/commands/contracts";
|
|
5
|
+
|
|
6
|
+
vi.mock("../../src/commands/contracts/write");
|
|
7
|
+
vi.mock("esbuild", () => ({
|
|
8
|
+
buildSync: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
describe("write command", () => {
|
|
12
|
+
let program: Command;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
program = new Command();
|
|
16
|
+
initializeContractsCommands(program);
|
|
17
|
+
vi.clearAllMocks();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
vi.restoreAllMocks();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("WriteAction.write is called with default options", async () => {
|
|
25
|
+
program.parse(["node", "test", "write", "0xMockedContract", "setData"]);
|
|
26
|
+
expect(WriteAction).toHaveBeenCalledTimes(1);
|
|
27
|
+
expect(WriteAction.prototype.write).toHaveBeenCalledWith({
|
|
28
|
+
contractAddress: "0xMockedContract",
|
|
29
|
+
method: "setData",
|
|
30
|
+
args: [],
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("WriteAction.write is called with positional arguments and options", async () => {
|
|
35
|
+
program.parse([
|
|
36
|
+
"node",
|
|
37
|
+
"test",
|
|
38
|
+
"write",
|
|
39
|
+
"0xMockedContract",
|
|
40
|
+
"updateCounter",
|
|
41
|
+
"--args",
|
|
42
|
+
"100",
|
|
43
|
+
"someString",
|
|
44
|
+
"true",
|
|
45
|
+
"--rpc",
|
|
46
|
+
"https://custom-rpc-url-for-write.com",
|
|
47
|
+
]);
|
|
48
|
+
expect(WriteAction).toHaveBeenCalledTimes(1);
|
|
49
|
+
expect(WriteAction.prototype.write).toHaveBeenCalledWith({
|
|
50
|
+
contractAddress: "0xMockedContract",
|
|
51
|
+
method: "updateCounter",
|
|
52
|
+
args: [100, "someString", true],
|
|
53
|
+
rpc: "https://custom-rpc-url-for-write.com",
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("WriteAction is instantiated when the write command is executed", async () => {
|
|
58
|
+
program.parse(["node", "test", "write", "0xMockedContract", "anotherMethod"]);
|
|
59
|
+
expect(WriteAction).toHaveBeenCalledTimes(1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("throws error for unrecognized options", async () => {
|
|
63
|
+
const writeCommand = program.commands.find(cmd => cmd.name() === "write");
|
|
64
|
+
writeCommand?.exitOverride();
|
|
65
|
+
expect(() =>
|
|
66
|
+
program.parse(["node", "test", "write", "0xMockedContract", "someMethod", "--invalid-option"]),
|
|
67
|
+
).toThrowError("error: unknown option '--invalid-option'");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("WriteAction.write is called without throwing errors for valid options", async () => {
|
|
71
|
+
program.parse(["node", "test", "write", "0xMockedContract", "validMethod"]);
|
|
72
|
+
vi.mocked(WriteAction.prototype.write).mockResolvedValueOnce(undefined);
|
|
73
|
+
// Need to parse again inside expect to ensure the mockResolvedValueOnce is used for the assertion context
|
|
74
|
+
expect(() => program.parse(["node", "test", "write", "0xMockedContract", "validMethod"])).not.toThrow();
|
|
75
|
+
});
|
|
76
|
+
});
|
package/tests/index.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import {describe, it, vi, expect} from "vitest";
|
|
2
|
+
import {initializeCLI} from "../src/index";
|
|
3
3
|
|
|
4
4
|
vi.mock("commander", () => ({
|
|
5
5
|
program: {
|
|
@@ -37,6 +37,9 @@ vi.mock("../src/commands/scaffold", () => ({
|
|
|
37
37
|
initializeScaffoldCommands: vi.fn(),
|
|
38
38
|
}));
|
|
39
39
|
|
|
40
|
+
vi.mock("../src/commands/network", () => ({
|
|
41
|
+
initializeNetworkCommands: vi.fn(),
|
|
42
|
+
}));
|
|
40
43
|
|
|
41
44
|
describe("CLI", () => {
|
|
42
45
|
it("should initialize CLI", () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {describe, test, vi, beforeEach, afterEach, expect, Mock} from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import {BaseAction} from "../../src/lib/actions/BaseAction";
|
|
3
3
|
import inquirer from "inquirer";
|
|
4
|
-
import ora, {
|
|
4
|
+
import ora, {Ora} from "ora";
|
|
5
5
|
import chalk from "chalk";
|
|
6
6
|
|
|
7
7
|
vi.mock("inquirer");
|
|
@@ -61,14 +61,14 @@ describe("BaseAction", () => {
|
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
test("should confirm prompt and proceed when confirmed", async () => {
|
|
64
|
-
vi.mocked(inquirer.prompt).mockResolvedValue({
|
|
64
|
+
vi.mocked(inquirer.prompt).mockResolvedValue({confirmAction: true});
|
|
65
65
|
|
|
66
66
|
await expect(baseAction["confirmPrompt"]("Are you sure?")).resolves.not.toThrow();
|
|
67
67
|
expect(inquirer.prompt).toHaveBeenCalled();
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
test("should confirm prompt and exit when declined", async () => {
|
|
71
|
-
vi.mocked(inquirer.prompt).mockResolvedValue({
|
|
71
|
+
vi.mocked(inquirer.prompt).mockResolvedValue({confirmAction: false});
|
|
72
72
|
const processExitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
73
73
|
throw new Error("process exited");
|
|
74
74
|
});
|
|
@@ -103,7 +103,7 @@ describe("BaseAction", () => {
|
|
|
103
103
|
});
|
|
104
104
|
|
|
105
105
|
test("should log a success message with data", () => {
|
|
106
|
-
const data = {
|
|
106
|
+
const data = {key: "value"};
|
|
107
107
|
|
|
108
108
|
baseAction["logSuccess"]("Success message", data);
|
|
109
109
|
|
|
@@ -117,14 +117,22 @@ describe("BaseAction", () => {
|
|
|
117
117
|
baseAction["logError"]("Error message", error);
|
|
118
118
|
|
|
119
119
|
expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining("✖ Error message"));
|
|
120
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
121
|
+
chalk.red(
|
|
122
|
+
JSON.stringify(
|
|
123
|
+
{
|
|
124
|
+
name: error.name,
|
|
125
|
+
message: error.message,
|
|
126
|
+
},
|
|
127
|
+
null,
|
|
128
|
+
2,
|
|
129
|
+
),
|
|
130
|
+
),
|
|
131
|
+
);
|
|
124
132
|
});
|
|
125
133
|
|
|
126
134
|
test("should log an info message with data", () => {
|
|
127
|
-
const data = {
|
|
135
|
+
const data = {info: "This is some info"};
|
|
128
136
|
|
|
129
137
|
baseAction["logInfo"]("Info message", data);
|
|
130
138
|
|
|
@@ -133,7 +141,7 @@ describe("BaseAction", () => {
|
|
|
133
141
|
});
|
|
134
142
|
|
|
135
143
|
test("should log a warning message with data", () => {
|
|
136
|
-
const data = {
|
|
144
|
+
const data = {warning: "This is a warning"};
|
|
137
145
|
|
|
138
146
|
baseAction["logWarning"]("Warning message", data);
|
|
139
147
|
|
|
@@ -142,7 +150,7 @@ describe("BaseAction", () => {
|
|
|
142
150
|
});
|
|
143
151
|
|
|
144
152
|
test("should succeed the spinner with a message and log result if data is provided", () => {
|
|
145
|
-
const mockData = {
|
|
153
|
+
const mockData = {key: "value"};
|
|
146
154
|
|
|
147
155
|
baseAction["succeedSpinner"]("Success", mockData);
|
|
148
156
|
|
|
@@ -156,11 +164,11 @@ describe("BaseAction", () => {
|
|
|
156
164
|
(error as any).code = 500;
|
|
157
165
|
|
|
158
166
|
const result = (baseAction as any).formatOutput(error);
|
|
159
|
-
expect(result).toBe(JSON.stringify({
|
|
167
|
+
expect(result).toBe(JSON.stringify({name: "Error", message: "Something went wrong", code: 500}, null, 2));
|
|
160
168
|
});
|
|
161
169
|
|
|
162
170
|
test("should format an object as JSON string", () => {
|
|
163
|
-
const data = {
|
|
171
|
+
const data = {key: "value", num: 42};
|
|
164
172
|
const result = (baseAction as any).formatOutput(data);
|
|
165
173
|
|
|
166
174
|
expect(result).toBe(JSON.stringify(data, null, 2));
|
|
@@ -176,16 +184,20 @@ describe("BaseAction", () => {
|
|
|
176
184
|
const testMap = new Map<string, any>([
|
|
177
185
|
["key1", "value1"],
|
|
178
186
|
["key2", 42],
|
|
179
|
-
["key3", {
|
|
187
|
+
["key3", {nested: "object"}],
|
|
180
188
|
]);
|
|
181
|
-
|
|
189
|
+
|
|
182
190
|
const result = (baseAction as any).formatOutput(testMap);
|
|
183
|
-
const expected = JSON.stringify(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
191
|
+
const expected = JSON.stringify(
|
|
192
|
+
{
|
|
193
|
+
key1: "value1",
|
|
194
|
+
key2: 42,
|
|
195
|
+
key3: {nested: "object"},
|
|
196
|
+
},
|
|
197
|
+
null,
|
|
198
|
+
2,
|
|
199
|
+
);
|
|
200
|
+
|
|
189
201
|
expect(result).toBe(expected);
|
|
190
202
|
});
|
|
191
203
|
|
|
@@ -198,7 +210,6 @@ describe("BaseAction", () => {
|
|
|
198
210
|
getKeypairPath: vi.fn(),
|
|
199
211
|
setKeypairPath: vi.fn(),
|
|
200
212
|
} as any;
|
|
201
|
-
|
|
202
213
|
});
|
|
203
214
|
|
|
204
215
|
test("should return private key when it exists", async () => {
|
|
@@ -214,15 +225,15 @@ describe("BaseAction", () => {
|
|
|
214
225
|
vi.mocked(baseAction["keypairManager"].getPrivateKey)
|
|
215
226
|
.mockReturnValueOnce(undefined)
|
|
216
227
|
.mockReturnValueOnce(mockPrivateKey);
|
|
217
|
-
|
|
218
|
-
|
|
228
|
+
vi.mocked(inquirer.prompt).mockResolvedValue({confirmAction: true});
|
|
229
|
+
await baseAction["getPrivateKey"]();
|
|
219
230
|
|
|
220
231
|
expect(baseAction["keypairManager"].createKeypair).toHaveBeenCalled();
|
|
221
232
|
});
|
|
222
233
|
|
|
223
234
|
test("should exit when private key doesn't exist and user declines", async () => {
|
|
224
235
|
vi.mocked(baseAction["keypairManager"].getPrivateKey).mockReturnValueOnce(undefined);
|
|
225
|
-
vi.mocked(inquirer.prompt).mockResolvedValue({
|
|
236
|
+
vi.mocked(inquirer.prompt).mockResolvedValue({confirmAction: false});
|
|
226
237
|
vi.spyOn(process, "exit").mockImplementation(() => {
|
|
227
238
|
throw new Error("process exited");
|
|
228
239
|
});
|