Skip to content

Commit a9e5eb6

Browse files
sirtimidclaude
andcommitted
fix(evm-wallet-experiment): update openclaw plugin tests for decoded CLI output
The new `daemon queueMessage` CLI auto-decodes CapData, so test mocks must return plain JSON instead of CapData-wrapped responses. Also updates spawn argument assertions to match the new CLI arg structure (daemon queueMessage kref method argsJson) and the error test to use prettified error strings ("[Error: msg]") instead of CapData #error objects. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent b98307b commit a9e5eb6

1 file changed

Lines changed: 77 additions & 77 deletions

File tree

packages/evm-wallet-experiment/test/openclaw-plugin.test.ts

Lines changed: 77 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@ type MockReadable = EventEmitter & {
2828
};
2929

3030
/**
31-
* Encode a value as Endo CapData JSON.
31+
* Encode a value as the JSON output of `ocap daemon queueMessage`.
3232
*
33-
* @param value - The value to encode.
34-
* @returns JSON string with `body` and `slots`.
33+
* The CLI auto-decodes CapData via prettifySmallcaps, so the output
34+
* is plain JSON (not CapData-wrapped).
35+
*
36+
* @param value - The decoded value the CLI would output.
37+
* @returns JSON string.
3538
*/
36-
function makeCapData(value: unknown): string {
37-
return JSON.stringify({
38-
body: `#${JSON.stringify(value)}`,
39-
slots: [],
40-
});
39+
function makeCliOutput(value: unknown): string {
40+
return JSON.stringify(value);
4141
}
4242

4343
/**
@@ -126,9 +126,9 @@ describe('openclaw wallet plugin', () => {
126126
expect(tools.has('wallet_token_resolve')).toBe(true);
127127
});
128128

129-
it('decodes CapData string response for wallet_balance', async () => {
129+
it('decodes CLI JSON response for wallet_balance', async () => {
130130
mockSpawn.mockImplementationOnce(() =>
131-
makeSpawnResult({ stdout: makeCapData('0xde0b6b3a7640000') }),
131+
makeSpawnResult({ stdout: makeCliOutput('0xde0b6b3a7640000') }),
132132
);
133133
const tools = setupPlugin();
134134
const tool = tools.get('wallet_balance');
@@ -152,7 +152,7 @@ describe('openclaw wallet plugin', () => {
152152
smartAccountAddress: account,
153153
};
154154
mockSpawn.mockImplementationOnce(() =>
155-
makeSpawnResult({ stdout: makeCapData(rawCapabilities) }),
155+
makeSpawnResult({ stdout: makeCliOutput(rawCapabilities) }),
156156
);
157157

158158
const tools = setupPlugin();
@@ -177,22 +177,22 @@ describe('openclaw wallet plugin', () => {
177177
mockSpawn
178178
// 1. getAccounts
179179
.mockImplementationOnce(() =>
180-
makeSpawnResult({ stdout: makeCapData([account]) }),
180+
makeSpawnResult({ stdout: makeCliOutput([account]) }),
181181
)
182182
// 2. sendTransaction
183183
.mockImplementationOnce(() =>
184-
makeSpawnResult({ stdout: makeCapData('0xtxhash') }),
184+
makeSpawnResult({ stdout: makeCliOutput('0xtxhash') }),
185185
)
186186
// 3. getCapabilities (best-effort, for chain ID)
187187
.mockImplementationOnce(() =>
188188
makeSpawnResult({
189-
stdout: makeCapData({ chainId: 11155111 }),
189+
stdout: makeCliOutput({ chainId: 11155111 }),
190190
}),
191191
)
192192
// 4. getTransactionReceipt (best-effort, resolve UserOp hash)
193193
.mockImplementationOnce(() =>
194194
makeSpawnResult({
195-
stdout: makeCapData({
195+
stdout: makeCliOutput({
196196
txHash: '0xrealtxhash',
197197
userOpHash: '0xtxhash',
198198
success: true,
@@ -216,26 +216,22 @@ describe('openclaw wallet plugin', () => {
216216
);
217217
expect(result.content[0]?.text).toContain('UserOp hash: 0xtxhash');
218218

219-
const sendCallArgs = mockSpawn.mock.calls[1]?.[1];
220-
expect(Array.isArray(sendCallArgs)).toBe(true);
221-
const daemonArgs = sendCallArgs as string[];
222-
const payload = JSON.parse(daemonArgs[3] ?? 'null') as [
223-
string,
224-
string,
225-
unknown[],
226-
];
219+
// New CLI format: ['daemon', 'queueMessage', kref, method, argsJson]
220+
const sendCallArgs = mockSpawn.mock.calls[1]?.[1] as string[];
221+
expect(sendCallArgs[1]).toBe('queueMessage');
222+
expect(sendCallArgs[2]).toBe('ko4');
223+
expect(sendCallArgs[3]).toBe('sendTransaction');
224+
const sendArgs = JSON.parse(sendCallArgs[4] ?? 'null') as unknown[];
227225

228226
// 0.08 ETH = 80000000000000000 wei = 0x11c37937e080000
229-
expect(payload).toStrictEqual([
230-
'ko4',
231-
'sendTransaction',
232-
[{ from: account, to: recipient, value: '0x11c37937e080000' }],
227+
expect(sendArgs).toStrictEqual([
228+
{ from: account, to: recipient, value: '0x11c37937e080000' },
233229
]);
234230
});
235231

236232
it('returns error when wallet_send cannot infer a sender', async () => {
237233
mockSpawn.mockImplementationOnce(() =>
238-
makeSpawnResult({ stdout: makeCapData([]) }),
234+
makeSpawnResult({ stdout: makeCliOutput([]) }),
239235
);
240236

241237
const tools = setupPlugin();
@@ -270,23 +266,18 @@ describe('openclaw wallet plugin', () => {
270266
expect(mockSpawn).not.toHaveBeenCalled();
271267
});
272268

273-
it('surfaces CapData error from vat exception', async () => {
274-
// Simulate: getAccounts succeeds, sendTransaction returns a CapData error
269+
it('surfaces prettified error from vat exception', async () => {
270+
// Simulate: getAccounts succeeds, sendTransaction returns a prettified error.
271+
// prettifySmallcaps converts #error CapData to strings like "[ErrorName: msg]".
275272
mockSpawn
276273
.mockImplementationOnce(() =>
277-
makeSpawnResult({ stdout: makeCapData([account]) }),
274+
makeSpawnResult({ stdout: makeCliOutput([account]) }),
278275
)
279276
.mockImplementationOnce(() =>
280277
makeSpawnResult({
281-
stdout: JSON.stringify({
282-
body: `#${JSON.stringify({
283-
'#error':
284-
'Bundler RPC error -32521: UserOperation reverted during simulation',
285-
errorId: 'error:liveSlots:v1#70003',
286-
name: 'Error',
287-
})}`,
288-
slots: [],
289-
}),
278+
stdout: makeCliOutput(
279+
'[Error: Bundler RPC error -32521: UserOperation reverted during simulation]',
280+
),
290281
}),
291282
);
292283

@@ -313,16 +304,16 @@ describe('openclaw wallet plugin', () => {
313304
mockSpawn
314305
// 1. getAccounts (to resolve owner)
315306
.mockImplementationOnce(() =>
316-
makeSpawnResult({ stdout: makeCapData([account]) }),
307+
makeSpawnResult({ stdout: makeCliOutput([account]) }),
317308
)
318309
// 2. getTokenBalance
319310
.mockImplementationOnce(() =>
320-
makeSpawnResult({ stdout: makeCapData('1000000') }),
311+
makeSpawnResult({ stdout: makeCliOutput('1000000') }),
321312
)
322313
// 3. getTokenMetadata
323314
.mockImplementationOnce(() =>
324315
makeSpawnResult({
325-
stdout: makeCapData({
316+
stdout: makeCliOutput({
326317
name: 'USD Coin',
327318
symbol: 'USDC',
328319
decimals: 6,
@@ -345,7 +336,7 @@ describe('openclaw wallet plugin', () => {
345336
// 1. getTokenMetadata (for decimals)
346337
.mockImplementationOnce(() =>
347338
makeSpawnResult({
348-
stdout: makeCapData({
339+
stdout: makeCliOutput({
349340
name: 'USD Coin',
350341
symbol: 'USDC',
351342
decimals: 6,
@@ -354,18 +345,18 @@ describe('openclaw wallet plugin', () => {
354345
)
355346
// 2. sendErc20Transfer
356347
.mockImplementationOnce(() =>
357-
makeSpawnResult({ stdout: makeCapData('0xtokentxhash') }),
348+
makeSpawnResult({ stdout: makeCliOutput('0xtokentxhash') }),
358349
)
359350
// 3. getCapabilities (best-effort)
360351
.mockImplementationOnce(() =>
361352
makeSpawnResult({
362-
stdout: makeCapData({ chainId: 11155111 }),
353+
stdout: makeCliOutput({ chainId: 11155111 }),
363354
}),
364355
)
365356
// 4. getTransactionReceipt (best-effort)
366357
.mockImplementationOnce(() =>
367358
makeSpawnResult({
368-
stdout: makeCapData({ txHash: '0xrealtokentx', success: true }),
359+
stdout: makeCliOutput({ txHash: '0xrealtokentx', success: true }),
369360
}),
370361
);
371362

@@ -388,30 +379,30 @@ describe('openclaw wallet plugin', () => {
388379
);
389380

390381
// Verify the sendErc20Transfer daemon call
382+
// New CLI format: ['daemon', 'queueMessage', kref, method, argsJson]
391383
const sendCallArgs = mockSpawn.mock.calls[1]?.[1] as string[];
392-
const payload = JSON.parse(sendCallArgs[3] ?? 'null');
393-
expect(payload[1]).toBe('sendErc20Transfer');
384+
expect(sendCallArgs[3]).toBe('sendErc20Transfer');
394385
});
395386

396387
it('waits for a delayed UserOp receipt before showing tx hash', async () => {
397388
mockSpawn
398389
.mockImplementationOnce(() =>
399-
makeSpawnResult({ stdout: makeCapData([account]) }),
390+
makeSpawnResult({ stdout: makeCliOutput([account]) }),
400391
)
401392
.mockImplementationOnce(() =>
402-
makeSpawnResult({ stdout: makeCapData('0xuserophash') }),
393+
makeSpawnResult({ stdout: makeCliOutput('0xuserophash') }),
403394
)
404395
.mockImplementationOnce(() =>
405396
makeSpawnResult({
406-
stdout: makeCapData({ chainId: 11155111 }),
397+
stdout: makeCliOutput({ chainId: 11155111 }),
407398
}),
408399
)
409400
.mockImplementationOnce(() =>
410-
makeSpawnResult({ stdout: makeCapData(null) }),
401+
makeSpawnResult({ stdout: makeCliOutput(null) }),
411402
)
412403
.mockImplementationOnce(() =>
413404
makeSpawnResult({
414-
stdout: makeCapData({
405+
stdout: makeCliOutput({
415406
success: true,
416407
receipt: { transactionHash: '0xresolvedtx' },
417408
}),
@@ -437,18 +428,18 @@ describe('openclaw wallet plugin', () => {
437428
it('reports pending UserOp without tx explorer URL', async () => {
438429
mockSpawn
439430
.mockImplementationOnce(() =>
440-
makeSpawnResult({ stdout: makeCapData([account]) }),
431+
makeSpawnResult({ stdout: makeCliOutput([account]) }),
441432
)
442433
.mockImplementationOnce(() =>
443-
makeSpawnResult({ stdout: makeCapData('0xpendinguserop') }),
434+
makeSpawnResult({ stdout: makeCliOutput('0xpendinguserop') }),
444435
)
445436
.mockImplementationOnce(() =>
446437
makeSpawnResult({
447-
stdout: makeCapData({ chainId: 11155111 }),
438+
stdout: makeCliOutput({ chainId: 11155111 }),
448439
}),
449440
)
450441
.mockImplementationOnce(() =>
451-
makeSpawnResult({ stdout: makeCapData(null) }),
442+
makeSpawnResult({ stdout: makeCliOutput(null) }),
452443
)
453444
.mockImplementationOnce(() =>
454445
makeSpawnResult({ stderr: 'timed out', code: 1 }),
@@ -476,7 +467,7 @@ describe('openclaw wallet plugin', () => {
476467

477468
mockSpawn.mockImplementationOnce(() =>
478469
makeSpawnResult({
479-
stdout: makeCapData({
470+
stdout: makeCliOutput({
480471
name: 'USD Coin',
481472
symbol: 'USDC',
482473
decimals: 6,
@@ -506,7 +497,11 @@ describe('openclaw wallet plugin', () => {
506497

507498
mockSpawn.mockImplementationOnce(() =>
508499
makeSpawnResult({
509-
stdout: makeCapData({ name: 'USD Coin', symbol: 'USDC', decimals: 6 }),
500+
stdout: makeCliOutput({
501+
name: 'USD Coin',
502+
symbol: 'USDC',
503+
decimals: 6,
504+
}),
510505
}),
511506
);
512507

@@ -531,21 +526,21 @@ describe('openclaw wallet plugin', () => {
531526
// 1. getCapabilities (for chain ID during token resolution)
532527
.mockImplementationOnce(() =>
533528
makeSpawnResult({
534-
stdout: makeCapData({ chainId: 1 }),
529+
stdout: makeCliOutput({ chainId: 1 }),
535530
}),
536531
)
537532
// 2. getAccounts (to resolve owner)
538533
.mockImplementationOnce(() =>
539-
makeSpawnResult({ stdout: makeCapData([account]) }),
534+
makeSpawnResult({ stdout: makeCliOutput([account]) }),
540535
)
541536
// 3. getTokenBalance
542537
.mockImplementationOnce(() =>
543-
makeSpawnResult({ stdout: makeCapData('1000000') }),
538+
makeSpawnResult({ stdout: makeCliOutput('1000000') }),
544539
)
545540
// 4. getTokenMetadata
546541
.mockImplementationOnce(() =>
547542
makeSpawnResult({
548-
stdout: makeCapData({
543+
stdout: makeCliOutput({
549544
name: 'USD Coin',
550545
symbol: 'USDC',
551546
decimals: 6,
@@ -578,9 +573,10 @@ describe('openclaw wallet plugin', () => {
578573
expect(result.content[0]?.text).toContain('USDC');
579574
expect(result.content[0]?.text).toContain('raw: 1000000');
580575
// Verify the resolved address was used for daemon calls
576+
// New CLI format: ['daemon', 'queueMessage', kref, method, argsJson]
581577
const balanceCallArgs = mockSpawn.mock.calls[2]?.[1] as string[];
582-
const balancePayload = JSON.parse(balanceCallArgs[3] ?? 'null');
583-
expect(balancePayload[2][0].token).toBe(
578+
const balanceArgs = JSON.parse(balanceCallArgs[4] ?? 'null') as unknown[];
579+
expect((balanceArgs[0] as Record<string, unknown>).token).toBe(
584580
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
585581
);
586582
// Single fetch call (MetaMask API returns everything in one request)
@@ -594,7 +590,7 @@ describe('openclaw wallet plugin', () => {
594590
// getCapabilities for chain ID
595591
mockSpawn.mockImplementationOnce(() =>
596592
makeSpawnResult({
597-
stdout: makeCapData({ chainId: 11155111 }),
593+
stdout: makeCliOutput({ chainId: 11155111 }),
598594
}),
599595
);
600596

@@ -621,7 +617,7 @@ describe('openclaw wallet plugin', () => {
621617

622618
mockSpawn.mockImplementationOnce(() =>
623619
makeSpawnResult({
624-
stdout: makeCapData({ chainId: 1 }),
620+
stdout: makeCliOutput({ chainId: 1 }),
625621
}),
626622
);
627623

@@ -666,7 +662,7 @@ describe('openclaw wallet plugin', () => {
666662

667663
mockSpawn.mockImplementationOnce(() =>
668664
makeSpawnResult({
669-
stdout: makeCapData({ chainId: 1 }),
665+
stdout: makeCliOutput({ chainId: 1 }),
670666
}),
671667
);
672668

@@ -767,16 +763,20 @@ describe('openclaw wallet plugin', () => {
767763
mockSpawn
768764
.mockImplementationOnce(() =>
769765
makeSpawnResult({
770-
stdout: makeCapData({ chainId: 1 }),
766+
stdout: makeCliOutput({ chainId: 1 }),
771767
}),
772768
)
773769
.mockImplementationOnce(() =>
774770
makeSpawnResult({
775-
stdout: makeCapData({ name: 'Tether', symbol: 'USDT', decimals: 6 }),
771+
stdout: makeCliOutput({
772+
name: 'Tether',
773+
symbol: 'USDT',
774+
decimals: 6,
775+
}),
776776
}),
777777
)
778778
.mockImplementationOnce(() =>
779-
makeSpawnResult({ stdout: makeCapData(quote) }),
779+
makeSpawnResult({ stdout: makeCliOutput(quote) }),
780780
);
781781

782782
const tools = setupPlugin();
@@ -812,25 +812,25 @@ describe('openclaw wallet plugin', () => {
812812
mockSpawn
813813
.mockImplementationOnce(() =>
814814
makeSpawnResult({
815-
stdout: makeCapData({ chainId: 1 }),
815+
stdout: makeCliOutput({ chainId: 1 }),
816816
}),
817817
)
818818
.mockImplementationOnce(() =>
819819
makeSpawnResult({
820-
stdout: makeCapData({ decimals: 6, symbol: 'USDT' }),
820+
stdout: makeCliOutput({ decimals: 6, symbol: 'USDT' }),
821821
}),
822822
)
823823
.mockImplementationOnce(() =>
824-
makeSpawnResult({ stdout: makeCapData(swapResult) }),
824+
makeSpawnResult({ stdout: makeCliOutput(swapResult) }),
825825
)
826826
.mockImplementationOnce(() =>
827827
makeSpawnResult({
828-
stdout: makeCapData({ chainId: 1 }),
828+
stdout: makeCliOutput({ chainId: 1 }),
829829
}),
830830
)
831831
.mockImplementationOnce(() =>
832832
makeSpawnResult({
833-
stdout: makeCapData({
833+
stdout: makeCliOutput({
834834
txHash:
835835
'0xabc123def456abc123def456abc123def456abc123def456abc123def456abc1',
836836
}),

0 commit comments

Comments
 (0)