Skip to content

Commit 64396d0

Browse files
authored
Merge pull request #757 from iotaledger/feat/cli-testing
new testing framework for wasp-cli
2 parents bb6452c + 35be9a0 commit 64396d0

File tree

10 files changed

+2370
-0
lines changed

10 files changed

+2370
-0
lines changed

go.work.sum

Lines changed: 257 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
package test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func TestRootCommand(t *testing.T) {
10+
h := NewTestHarness(t)
11+
h.SetupTestConfig()
12+
defer h.CleanupTestConfig()
13+
14+
t.Run("help command", func(t *testing.T) {
15+
output := h.MustRunCommand("--help")
16+
h.AssertOutputContains(output, "wasp-cli")
17+
h.AssertOutputContains(output, "Usage:")
18+
})
19+
20+
t.Run("version command", func(t *testing.T) {
21+
output := h.MustRunCommand("--version")
22+
// Should contain version information
23+
require.NotEmpty(t, output)
24+
})
25+
}
26+
27+
func TestWalletCommands(t *testing.T) {
28+
h := NewTestHarness(t)
29+
h.SetupTestConfig()
30+
defer h.CleanupTestConfig()
31+
32+
t.Run("wallet help", func(t *testing.T) {
33+
output := h.MustRunCommand("wallet", "--help")
34+
h.AssertOutputContains(output, "wallet")
35+
h.AssertOutputContains(output, "address")
36+
h.AssertOutputContains(output, "balance")
37+
})
38+
39+
t.Run("wallet address without setup", func(t *testing.T) {
40+
// The CLI can derive a default address; expect success and output
41+
_ = h.MustRunCommand("wallet", "address")
42+
// Some environments may not print address to captured stdout, just ensure it succeeds
43+
})
44+
}
45+
46+
func TestChainCommands(t *testing.T) {
47+
h := NewTestHarness(t)
48+
h.SetupTestConfig()
49+
defer h.CleanupTestConfig()
50+
51+
t.Run("chain help", func(t *testing.T) {
52+
output := h.MustRunCommand("chain", "--help")
53+
h.AssertOutputContains(output, "chain")
54+
h.AssertOutputContains(output, "deploy")
55+
h.AssertOutputContains(output, "info")
56+
})
57+
58+
t.Run("chain info without chain", func(t *testing.T) {
59+
// This should fail because no chain is configured
60+
_, err := h.RunCommandExpectError("chain", "info")
61+
require.Error(t, err)
62+
})
63+
64+
t.Run("chain deploy missing required flags", func(t *testing.T) {
65+
// Deploy command requires --chain flag
66+
_, err := h.RunCommandExpectError("chain", "deploy")
67+
require.Error(t, err)
68+
})
69+
70+
t.Run("chain deploy with chain flag but no setup", func(t *testing.T) {
71+
// This should fail because dependencies aren't set up
72+
_, err := h.RunCommandExpectError("chain", "deploy", "--chain=test-chain")
73+
require.Error(t, err)
74+
})
75+
}
76+
77+
func TestAuthCommands(t *testing.T) {
78+
h := NewTestHarness(t)
79+
h.SetupTestConfig()
80+
defer h.CleanupTestConfig()
81+
82+
t.Run("auth help", func(t *testing.T) {
83+
output := h.MustRunCommand("auth", "--help")
84+
h.AssertOutputContains(output, "auth")
85+
h.AssertOutputContains(output, "login")
86+
})
87+
88+
t.Run("auth info without login", func(t *testing.T) {
89+
_, err := h.RunCommand("auth", "info")
90+
require.Error(t, err)
91+
// Should complain about missing wasp node configuration
92+
require.Contains(t, err.Error(), "no wasp node configured")
93+
})
94+
}
95+
96+
func TestCodecCommands(t *testing.T) {
97+
h := NewTestHarness(t)
98+
h.SetupTestConfig()
99+
defer h.CleanupTestConfig()
100+
101+
t.Run("codec help", func(t *testing.T) {
102+
output := h.MustRunCommand("codec", "--help")
103+
h.AssertOutputContains(output, "codec")
104+
h.AssertOutputContains(output, "encode")
105+
h.AssertOutputContains(output, "decode")
106+
})
107+
108+
t.Run("codec encode shows help when missing subcommand", func(t *testing.T) {
109+
output := h.MustRunCommand("codec", "encode")
110+
h.AssertOutputContains(output, "Usage:")
111+
})
112+
}
113+
114+
func TestPeeringCommands(t *testing.T) {
115+
h := NewTestHarness(t)
116+
h.SetupTestConfig()
117+
defer h.CleanupTestConfig()
118+
119+
t.Run("peering help", func(t *testing.T) {
120+
output := h.MustRunCommand("peering", "--help")
121+
h.AssertOutputContains(output, "peering")
122+
h.AssertOutputContains(output, "info")
123+
h.AssertOutputContains(output, "list-trusted")
124+
})
125+
126+
t.Run("peering info without node", func(t *testing.T) {
127+
// Should fail because no node is configured
128+
_, err := h.RunCommandExpectError("peering", "info")
129+
require.Error(t, err)
130+
})
131+
}
132+
133+
func TestInvalidCommands(t *testing.T) {
134+
h := NewTestHarness(t)
135+
h.SetupTestConfig()
136+
defer h.CleanupTestConfig()
137+
138+
t.Run("invalid command", func(t *testing.T) {
139+
_, err := h.RunCommandExpectError("invalid-command")
140+
require.Error(t, err)
141+
})
142+
143+
t.Run("invalid subcommand", func(t *testing.T) {
144+
_, err := h.RunCommandExpectError("wallet", "invalid-subcommand")
145+
require.Error(t, err)
146+
})
147+
}
148+
149+
func TestOutputFormats(t *testing.T) {
150+
h := NewTestHarness(t)
151+
h.SetupTestConfig()
152+
defer h.CleanupTestConfig()
153+
154+
t.Run("help output format", func(t *testing.T) {
155+
output := h.MustRunCommand("--help")
156+
lines := h.GetOutputLines(output)
157+
158+
// Should have multiple lines
159+
require.Greater(t, len(lines), 5)
160+
161+
// Should contain usage information
162+
found := false
163+
for _, line := range lines {
164+
if contains(line, "Usage:") {
165+
found = true
166+
break
167+
}
168+
}
169+
require.True(t, found, "Should contain Usage information")
170+
})
171+
}
172+
173+
// Helper function to check if a string contains a substring (case-insensitive)
174+
func contains(s, substr string) bool {
175+
return len(s) >= len(substr) &&
176+
(s == substr ||
177+
len(s) > len(substr) &&
178+
(s[:len(substr)] == substr ||
179+
s[len(s)-len(substr):] == substr ||
180+
containsSubstring(s, substr)))
181+
}
182+
183+
func containsSubstring(s, substr string) bool {
184+
for i := 0; i <= len(s)-len(substr); i++ {
185+
if s[i:i+len(substr)] == substr {
186+
return true
187+
}
188+
}
189+
return false
190+
}
191+
192+
// TestMockFunctionality tests that our mocks work correctly
193+
func TestMockFunctionality(t *testing.T) {
194+
t.Run("MockL1Client", func(t *testing.T) {
195+
mock := NewMockL1Client()
196+
197+
// Test default values
198+
require.Equal(t, uint64(1000000), mock.Balance)
199+
require.False(t, mock.GetBalanceCalled)
200+
201+
// Test setting values
202+
mock.SetBalance(500000)
203+
require.Equal(t, uint64(500000), mock.Balance)
204+
205+
// Test reset
206+
mock.GetBalanceCalled = true
207+
mock.Reset()
208+
require.False(t, mock.GetBalanceCalled)
209+
})
210+
211+
t.Run("MockWallet", func(t *testing.T) {
212+
mock := NewMockWallet()
213+
214+
// Test address
215+
addr := mock.Address()
216+
require.NotNil(t, addr)
217+
require.True(t, mock.AddressCalled)
218+
219+
// Test reset
220+
mock.Reset()
221+
require.False(t, mock.AddressCalled)
222+
})
223+
224+
t.Run("MockChainService", func(t *testing.T) {
225+
mock := NewMockChainService()
226+
227+
// Test default values
228+
require.Empty(t, mock.ChainInfo)
229+
require.False(t, mock.GetChainInfoCalled)
230+
231+
// Test setting values
232+
info := map[string]interface{}{"test": "value"}
233+
mock.SetChainInfo(info)
234+
require.Equal(t, info, mock.ChainInfo)
235+
236+
// Test reset
237+
mock.GetChainInfoCalled = true
238+
mock.Reset()
239+
require.False(t, mock.GetChainInfoCalled)
240+
require.Empty(t, mock.ChainInfo)
241+
})
242+
}
243+
244+
func TestTestFixtures(t *testing.T) {
245+
fixtures := NewTestFixtures()
246+
247+
// Test that fixtures are properly initialized
248+
require.NotNil(t, fixtures.TestAddress1)
249+
require.NotNil(t, fixtures.TestAddress2)
250+
require.NotEqual(t, fixtures.TestAddress1, fixtures.TestAddress2)
251+
252+
require.NotEqual(t, fixtures.TestChainID1, fixtures.TestChainID2)
253+
254+
// Test wallet creation
255+
wallet := fixtures.GetTestWallet()
256+
require.NotNil(t, wallet)
257+
require.NotNil(t, wallet.Address())
258+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
// TestSimpleExample demonstrates the basic testing approach
10+
func TestSimpleExample(t *testing.T) {
11+
h := NewTestHarness(t)
12+
h.SetupTestConfig()
13+
defer h.CleanupTestConfig()
14+
15+
// Test that we can create a harness and run basic commands
16+
t.Run("basic help command", func(t *testing.T) {
17+
output := h.MustRunCommand("--help")
18+
require.NotEmpty(t, output)
19+
require.Contains(t, output, "wasp-cli")
20+
})
21+
}
22+
23+
// TestMockBasics demonstrates mock functionality
24+
func TestMockBasics(t *testing.T) {
25+
// Test L1Client mock
26+
l1Mock := NewMockL1Client()
27+
require.Equal(t, uint64(1000000), l1Mock.Balance)
28+
29+
l1Mock.SetBalance(500000)
30+
require.Equal(t, uint64(500000), l1Mock.Balance)
31+
32+
// Test Wallet mock
33+
walletMock := NewMockWallet()
34+
addr := walletMock.Address()
35+
require.NotNil(t, addr)
36+
require.True(t, walletMock.AddressCalled)
37+
38+
// Test Chain Service mock
39+
chainMock := NewMockChainService()
40+
require.Empty(t, chainMock.ChainInfo)
41+
42+
info := map[string]interface{}{"test": "value"}
43+
chainMock.SetChainInfo(info)
44+
require.Equal(t, info, chainMock.ChainInfo)
45+
}
46+
47+
// TestFixturesBasics demonstrates test fixtures
48+
func TestFixturesBasics(t *testing.T) {
49+
fixtures := NewTestFixtures()
50+
51+
require.NotNil(t, fixtures.TestAddress1)
52+
require.NotNil(t, fixtures.TestAddress2)
53+
require.NotEqual(t, fixtures.TestAddress1, fixtures.TestAddress2)
54+
55+
wallet := fixtures.GetTestWallet()
56+
require.NotNil(t, wallet)
57+
}

0 commit comments

Comments
 (0)