From f51489f41e917559e97c3d738cee3307a7946be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gergely=20B=C3=A9k=C3=A9si?= Date: Fri, 24 Apr 2026 09:56:47 +0200 Subject: [PATCH 01/21] feat: add unit flag for cheque deposit and withraw --- src/command/cheque/cheque-command.ts | 2 ++ src/command/cheque/deposit.ts | 32 +++++++++++++++++++++++----- src/command/cheque/withdraw.ts | 30 ++++++++++++++++++++++---- src/utils/text.ts | 4 ++++ 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/command/cheque/cheque-command.ts b/src/command/cheque/cheque-command.ts index 33856028..7f2abab3 100644 --- a/src/command/cheque/cheque-command.ts +++ b/src/command/cheque/cheque-command.ts @@ -8,6 +8,8 @@ interface Cashable { amount: BZZ } +export const VALID_UNITS = ['bzz', 'plur'] + export class ChequeCommand extends RootCommand { protected async getFilteredCheques(minimum: bigint): Promise { const cheques = await this.getCashableCheques() diff --git a/src/command/cheque/deposit.ts b/src/command/cheque/deposit.ts index 39aef38d..f08093a6 100644 --- a/src/command/cheque/deposit.ts +++ b/src/command/cheque/deposit.ts @@ -1,6 +1,8 @@ -import { Argument, LeafCommand } from 'furious-commander' -import { createKeyValue } from '../../utils/text' -import { ChequeCommand } from './cheque-command' +import { Argument, LeafCommand, Option } from 'furious-commander' +import { createKeyValue, errorText } from '../../utils/text' +import { ChequeCommand, VALID_UNITS } from './cheque-command' +import { BZZ } from '@ethersphere/bee-js' +import { exit } from 'process' export class Deposit extends ChequeCommand implements LeafCommand { public readonly name = 'deposit' @@ -11,18 +13,38 @@ export class Deposit extends ChequeCommand implements LeafCommand { @Argument({ key: 'amount', + description: 'Amount of tokens to deposit', type: 'bigint', - description: 'Amount of tokens to deposit in PLUR', required: true, minimum: BigInt(1), }) public amount!: bigint + @Option({ + key: 'unit', + type: 'string', + description: 'Unit of the amount', + required: true, + default: 'bzz', + }) + public unit!: string + public async run(): Promise { super.init() - const response = await this.bee.depositTokens(this.amount.toString()) + this.validateUnit() + const amountInPlur = + this.unit === 'bzz' ? BZZ.fromDecimalString(this.amount.toString()).toPLURBigInt() : this.amount + + const response = await this.bee.depositTokens(amountInPlur.toString()) this.console.log(createKeyValue('Tx', response.toHex())) this.console.quiet(response.toHex()) } + + private validateUnit() { + if (!VALID_UNITS.includes(this.unit)) { + this.console.error(errorText(`Invalid unit '${this.unit}'. Valid units are: ${VALID_UNITS.join(', ')}`)) + exit(1) + } + } } diff --git a/src/command/cheque/withdraw.ts b/src/command/cheque/withdraw.ts index 9878cc0b..72ee5c2d 100644 --- a/src/command/cheque/withdraw.ts +++ b/src/command/cheque/withdraw.ts @@ -1,6 +1,8 @@ -import { Argument, LeafCommand } from 'furious-commander' -import { createKeyValue } from '../../utils/text' -import { ChequeCommand } from './cheque-command' +import { Argument, LeafCommand, Option } from 'furious-commander' +import { createKeyValue, errorText } from '../../utils/text' +import { ChequeCommand, VALID_UNITS } from './cheque-command' +import { exit } from 'process' +import { BZZ } from '@ethersphere/bee-js' export class Withdraw extends ChequeCommand implements LeafCommand { public readonly name = 'withdraw' @@ -18,11 +20,31 @@ export class Withdraw extends ChequeCommand implements LeafCommand { }) public amount!: bigint + @Option({ + key: 'unit', + type: 'string', + description: 'Unit of the amount', + required: true, + default: 'bzz', + }) + public unit!: string + public async run(): Promise { super.init() - const response = await this.bee.withdrawTokens(this.amount.toString()) + this.validateUnit() + const amountInPlur = + this.unit === 'bzz' ? BZZ.fromDecimalString(this.amount.toString()).toPLURBigInt() : this.amount + + const response = await this.bee.withdrawTokens(amountInPlur.toString()) this.console.log(createKeyValue('Tx', response.toHex())) this.console.quiet(response.toHex()) } + + private validateUnit() { + if (!VALID_UNITS.includes(this.unit)) { + this.console.error(errorText(`Invalid unit '${this.unit}'. Valid units are: ${VALID_UNITS.join(', ')}`)) + exit(1) + } + } } diff --git a/src/utils/text.ts b/src/utils/text.ts index ba0f90d6..5299cb39 100644 --- a/src/utils/text.ts +++ b/src/utils/text.ts @@ -17,6 +17,10 @@ export function warningText(string: string): string { return chalk.yellow(string) } +export function errorText(string: string): string { + return chalk.red(string) +} + export function deletePreviousLine(): void { process.stdout.write('\r' + goUpOneRow() + deleteWholeRow()) } From bd2259c7b94e3d6762aeeab89b3b58a53673a5c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gergely=20B=C3=A9k=C3=A9si?= Date: Fri, 24 Apr 2026 13:27:06 +0200 Subject: [PATCH 02/21] fix: update spec and improve CLI output --- src/command/cheque/deposit.ts | 3 +-- src/command/cheque/withdraw.ts | 5 ++--- test/misc/monetary-units.spec.ts | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/command/cheque/deposit.ts b/src/command/cheque/deposit.ts index f08093a6..7382c250 100644 --- a/src/command/cheque/deposit.ts +++ b/src/command/cheque/deposit.ts @@ -23,8 +23,7 @@ export class Deposit extends ChequeCommand implements LeafCommand { @Option({ key: 'unit', type: 'string', - description: 'Unit of the amount', - required: true, + description: `Unit of the amount; choices: ${VALID_UNITS.join(', ')}`, default: 'bzz', }) public unit!: string diff --git a/src/command/cheque/withdraw.ts b/src/command/cheque/withdraw.ts index 72ee5c2d..4c52e5dc 100644 --- a/src/command/cheque/withdraw.ts +++ b/src/command/cheque/withdraw.ts @@ -14,7 +14,7 @@ export class Withdraw extends ChequeCommand implements LeafCommand { @Argument({ key: 'amount', type: 'bigint', - description: 'Amount of tokens to withdraw in PLUR', + description: 'Amount of tokens to withdraw', required: true, minimum: BigInt(1), }) @@ -23,8 +23,7 @@ export class Withdraw extends ChequeCommand implements LeafCommand { @Option({ key: 'unit', type: 'string', - description: 'Unit of the amount', - required: true, + description: `Unit of the amount; choices: ${VALID_UNITS.join(', ')}`, default: 'bzz', }) public unit!: string diff --git a/test/misc/monetary-units.spec.ts b/test/misc/monetary-units.spec.ts index 0d7968f8..7138a333 100644 --- a/test/misc/monetary-units.spec.ts +++ b/test/misc/monetary-units.spec.ts @@ -38,12 +38,12 @@ describeCommand('Test Monetary units', ({ consoleMessages }) => { it('should show units in help: cheque withdraw', async () => { await invokeTestCli(['cheque', 'withdraw', '--help']) - expectSubstringsPrinted('amount', 'in PLUR') + expectSubstringsPrinted('amount', 'Amount of tokens to withdraw') }) it('should show units in help: cheque deposit', async () => { await invokeTestCli(['cheque', 'deposit', '--help']) - expectSubstringsPrinted('amount', 'in PLUR') + expectSubstringsPrinted('amount', 'Amount of tokens to deposit') }) it('should show units after running: cheque list', async () => { From 95570bea3d15620537a7477066638d3b5ee13455 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 11:39:35 +0000 Subject: [PATCH 03/21] test: update test coverage --- test/coverage/coverage-summary.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/coverage/coverage-summary.json b/test/coverage/coverage-summary.json index dcf1f5cf..35c0586a 100644 --- a/test/coverage/coverage-summary.json +++ b/test/coverage/coverage-summary.json @@ -1,4 +1,4 @@ -{"total": {"lines":{"total":2774,"covered":2069,"skipped":0,"pct":74.58},"statements":{"total":2795,"covered":2083,"skipped":0,"pct":74.52},"functions":{"total":333,"covered":256,"skipped":0,"pct":76.87},"branches":{"total":583,"covered":313,"skipped":0,"pct":53.68},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} +{"total": {"lines":{"total":2793,"covered":2077,"skipped":0,"pct":74.36},"statements":{"total":2814,"covered":2091,"skipped":0,"pct":74.3},"functions":{"total":336,"covered":256,"skipped":0,"pct":76.19},"branches":{"total":589,"covered":313,"skipped":0,"pct":53.14},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/application.ts": {"lines":{"total":2,"covered":0,"skipped":0,"pct":0},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":2,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/config.ts": {"lines":{"total":33,"covered":32,"skipped":0,"pct":96.96},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":33,"covered":32,"skipped":0,"pct":96.96},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/curl.ts": {"lines":{"total":24,"covered":24,"skipped":0,"pct":100},"functions":{"total":7,"covered":7,"skipped":0,"pct":100},"statements":{"total":25,"covered":25,"skipped":0,"pct":100},"branches":{"total":13,"covered":12,"skipped":0,"pct":92.3}} @@ -11,12 +11,12 @@ ,"/home/runner/work/swarm-cli/swarm-cli/src/command/status.ts": {"lines":{"total":79,"covered":79,"skipped":0,"pct":100},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":79,"covered":79,"skipped":0,"pct":100},"branches":{"total":11,"covered":11,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/upload.ts": {"lines":{"total":223,"covered":157,"skipped":0,"pct":70.4},"functions":{"total":16,"covered":14,"skipped":0,"pct":87.5},"statements":{"total":224,"covered":158,"skipped":0,"pct":70.53},"branches":{"total":99,"covered":56,"skipped":0,"pct":56.56}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/cashout.ts": {"lines":{"total":32,"covered":30,"skipped":0,"pct":93.75},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"statements":{"total":32,"covered":30,"skipped":0,"pct":93.75},"branches":{"total":2,"covered":2,"skipped":0,"pct":100}} -,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/cheque-command.ts": {"lines":{"total":25,"covered":21,"skipped":0,"pct":84},"functions":{"total":5,"covered":5,"skipped":0,"pct":100},"statements":{"total":26,"covered":22,"skipped":0,"pct":84.61},"branches":{"total":2,"covered":0,"skipped":0,"pct":0}} -,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/deposit.ts": {"lines":{"total":12,"covered":8,"skipped":0,"pct":66.66},"functions":{"total":2,"covered":1,"skipped":0,"pct":50},"statements":{"total":12,"covered":8,"skipped":0,"pct":66.66},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} +,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/cheque-command.ts": {"lines":{"total":26,"covered":22,"skipped":0,"pct":84.61},"functions":{"total":5,"covered":5,"skipped":0,"pct":100},"statements":{"total":27,"covered":23,"skipped":0,"pct":85.18},"branches":{"total":2,"covered":0,"skipped":0,"pct":0}} +,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/deposit.ts": {"lines":{"total":20,"covered":11,"skipped":0,"pct":55},"functions":{"total":3,"covered":1,"skipped":0,"pct":33.33},"statements":{"total":20,"covered":11,"skipped":0,"pct":55},"branches":{"total":3,"covered":0,"skipped":0,"pct":0}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/index.ts": {"lines":{"total":9,"covered":9,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":9,"covered":9,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/list.ts": {"lines":{"total":13,"covered":13,"skipped":0,"pct":100},"functions":{"total":3,"covered":3,"skipped":0,"pct":100},"statements":{"total":14,"covered":14,"skipped":0,"pct":100},"branches":{"total":1,"covered":1,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/withdraw-all.ts": {"lines":{"total":15,"covered":6,"skipped":0,"pct":40},"functions":{"total":2,"covered":1,"skipped":0,"pct":50},"statements":{"total":15,"covered":6,"skipped":0,"pct":40},"branches":{"total":1,"covered":0,"skipped":0,"pct":0}} -,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/withdraw.ts": {"lines":{"total":12,"covered":8,"skipped":0,"pct":66.66},"functions":{"total":2,"covered":1,"skipped":0,"pct":50},"statements":{"total":12,"covered":8,"skipped":0,"pct":66.66},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} +,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/withdraw.ts": {"lines":{"total":20,"covered":11,"skipped":0,"pct":55},"functions":{"total":3,"covered":1,"skipped":0,"pct":33.33},"statements":{"total":20,"covered":11,"skipped":0,"pct":55},"branches":{"total":3,"covered":0,"skipped":0,"pct":0}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/feed/feed-command.ts": {"lines":{"total":49,"covered":49,"skipped":0,"pct":100},"functions":{"total":5,"covered":5,"skipped":0,"pct":100},"statements":{"total":49,"covered":49,"skipped":0,"pct":100},"branches":{"total":13,"covered":13,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/feed/index.ts": {"lines":{"total":7,"covered":7,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":7,"covered":7,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/feed/print.ts": {"lines":{"total":80,"covered":26,"skipped":0,"pct":32.5},"functions":{"total":4,"covered":2,"skipped":0,"pct":50},"statements":{"total":81,"covered":26,"skipped":0,"pct":32.09},"branches":{"total":21,"covered":4,"skipped":0,"pct":19.04}} @@ -105,5 +105,5 @@ ,"/home/runner/work/swarm-cli/swarm-cli/src/utils/option.ts": {"lines":{"total":3,"covered":3,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":3,"covered":3,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/utils/rpc.ts": {"lines":{"total":37,"covered":9,"skipped":0,"pct":24.32},"functions":{"total":6,"covered":0,"skipped":0,"pct":0},"statements":{"total":37,"covered":9,"skipped":0,"pct":24.32},"branches":{"total":5,"covered":0,"skipped":0,"pct":0}} ,"/home/runner/work/swarm-cli/swarm-cli/src/utils/spinner.ts": {"lines":{"total":15,"covered":15,"skipped":0,"pct":100},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":15,"covered":15,"skipped":0,"pct":100},"branches":{"total":5,"covered":3,"skipped":0,"pct":60}} -,"/home/runner/work/swarm-cli/swarm-cli/src/utils/text.ts": {"lines":{"total":19,"covered":16,"skipped":0,"pct":84.21},"functions":{"total":8,"covered":6,"skipped":0,"pct":75},"statements":{"total":20,"covered":17,"skipped":0,"pct":85},"branches":{"total":5,"covered":3,"skipped":0,"pct":60}} +,"/home/runner/work/swarm-cli/swarm-cli/src/utils/text.ts": {"lines":{"total":21,"covered":17,"skipped":0,"pct":80.95},"functions":{"total":9,"covered":6,"skipped":0,"pct":66.66},"statements":{"total":22,"covered":18,"skipped":0,"pct":81.81},"branches":{"total":5,"covered":3,"skipped":0,"pct":60}} } From 75a45acf335fefd2a3d06c2d268db8e8a40c1b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gergely=20B=C3=A9k=C3=A9si?= Date: Tue, 28 Apr 2026 09:22:40 +0200 Subject: [PATCH 04/21] feat: make coverage report gen skippable via env --- jest.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jest.config.ts b/jest.config.ts index bb620fc9..1e8940fb 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -55,7 +55,7 @@ export default async (): Promise => { } return { - collectCoverage: true, + collectCoverage: process.env.SKIP_COVERAGE !== 'true', coverageDirectory: 'coverage', coverageReporters: ['lcov', 'json-summary'], collectCoverageFrom: ['src/**/*.ts'], From 83ea6674467f63ff0ef352996bcde6cfc86afb18 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 07:34:15 +0000 Subject: [PATCH 05/21] test: update test coverage --- test/coverage/coverage-summary.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/coverage/coverage-summary.json b/test/coverage/coverage-summary.json index 62e4ff45..c1b83b02 100644 --- a/test/coverage/coverage-summary.json +++ b/test/coverage/coverage-summary.json @@ -1,4 +1,4 @@ -{"total": {"lines":{"total":2834,"covered":2130,"skipped":0,"pct":75.15},"statements":{"total":2855,"covered":2144,"skipped":0,"pct":75.09},"functions":{"total":340,"covered":264,"skipped":0,"pct":77.64},"branches":{"total":603,"covered":333,"skipped":0,"pct":55.22},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} +{"total": {"lines":{"total":2853,"covered":2138,"skipped":0,"pct":74.93},"statements":{"total":2874,"covered":2152,"skipped":0,"pct":74.87},"functions":{"total":343,"covered":264,"skipped":0,"pct":76.96},"branches":{"total":609,"covered":333,"skipped":0,"pct":54.67},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/application.ts": {"lines":{"total":2,"covered":0,"skipped":0,"pct":0},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":2,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/config.ts": {"lines":{"total":33,"covered":32,"skipped":0,"pct":96.96},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":33,"covered":32,"skipped":0,"pct":96.96},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/curl.ts": {"lines":{"total":24,"covered":24,"skipped":0,"pct":100},"functions":{"total":7,"covered":7,"skipped":0,"pct":100},"statements":{"total":25,"covered":25,"skipped":0,"pct":100},"branches":{"total":13,"covered":12,"skipped":0,"pct":92.3}} @@ -108,5 +108,5 @@ ,"/home/runner/work/swarm-cli/swarm-cli/src/utils/option.ts": {"lines":{"total":3,"covered":3,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":3,"covered":3,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/utils/rpc.ts": {"lines":{"total":37,"covered":9,"skipped":0,"pct":24.32},"functions":{"total":6,"covered":0,"skipped":0,"pct":0},"statements":{"total":37,"covered":9,"skipped":0,"pct":24.32},"branches":{"total":5,"covered":0,"skipped":0,"pct":0}} ,"/home/runner/work/swarm-cli/swarm-cli/src/utils/spinner.ts": {"lines":{"total":15,"covered":15,"skipped":0,"pct":100},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":15,"covered":15,"skipped":0,"pct":100},"branches":{"total":5,"covered":3,"skipped":0,"pct":60}} -,"/home/runner/work/swarm-cli/swarm-cli/src/utils/text.ts": {"lines":{"total":19,"covered":17,"skipped":0,"pct":89.47},"functions":{"total":8,"covered":7,"skipped":0,"pct":87.5},"statements":{"total":20,"covered":18,"skipped":0,"pct":90},"branches":{"total":5,"covered":3,"skipped":0,"pct":60}} +,"/home/runner/work/swarm-cli/swarm-cli/src/utils/text.ts": {"lines":{"total":21,"covered":18,"skipped":0,"pct":85.71},"functions":{"total":9,"covered":7,"skipped":0,"pct":77.77},"statements":{"total":22,"covered":19,"skipped":0,"pct":86.36},"branches":{"total":5,"covered":3,"skipped":0,"pct":60}} } From 542a038148b5a5fdac31b8376d73dfc01ba22f17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gergely=20B=C3=A9k=C3=A9si?= Date: Tue, 28 Apr 2026 10:58:12 +0200 Subject: [PATCH 06/21] feat: use validation method and enum --- src/command/cheque/cheque-command.ts | 2 -- src/command/cheque/deposit.ts | 53 ++++++++++++++++++---------- src/command/cheque/withdraw.ts | 49 +++++++++++++++---------- 3 files changed, 65 insertions(+), 39 deletions(-) diff --git a/src/command/cheque/cheque-command.ts b/src/command/cheque/cheque-command.ts index 7f2abab3..33856028 100644 --- a/src/command/cheque/cheque-command.ts +++ b/src/command/cheque/cheque-command.ts @@ -8,8 +8,6 @@ interface Cashable { amount: BZZ } -export const VALID_UNITS = ['bzz', 'plur'] - export class ChequeCommand extends RootCommand { protected async getFilteredCheques(minimum: bigint): Promise { const cheques = await this.getCashableCheques() diff --git a/src/command/cheque/deposit.ts b/src/command/cheque/deposit.ts index 7382c250..29e18044 100644 --- a/src/command/cheque/deposit.ts +++ b/src/command/cheque/deposit.ts @@ -1,8 +1,8 @@ import { Argument, LeafCommand, Option } from 'furious-commander' -import { createKeyValue, errorText } from '../../utils/text' -import { ChequeCommand, VALID_UNITS } from './cheque-command' import { BZZ } from '@ethersphere/bee-js' -import { exit } from 'process' +// import { Context } from 'madlad' +import { createKeyValue } from '../../utils/text' +import { ChequeCommand } from './cheque-command' export class Deposit extends ChequeCommand implements LeafCommand { public readonly name = 'deposit' @@ -14,16 +14,37 @@ export class Deposit extends ChequeCommand implements LeafCommand { @Argument({ key: 'amount', description: 'Amount of tokens to deposit', - type: 'bigint', + type: 'decimal-string', required: true, - minimum: BigInt(1), + // validate: (value: string, context: Context): string[] => { + // if (context.options.unit === 'bzz') { + // const amount = parseFloat(value) + // + // if (isNaN(amount) || amount <= 0) { + // return [`Invalid amount '${value}'. Amount must be a positive number.`] + // } + // } else { + // try { + // const amount = BigInt(value) + // + // if (amount <= BigInt(0)) { + // return [`Invalid amount '${value}'. Amount must be a positive integer.`] + // } + // } catch (e) { + // return [`Invalid amount '${value}'. Amount must be a positive integer.`] + // } + // } + // + // return [] + // }, }) - public amount!: bigint + public amount!: string @Option({ key: 'unit', - type: 'string', - description: `Unit of the amount; choices: ${VALID_UNITS.join(', ')}`, + // type: 'enum', + description: 'Unit of the amount', + // enum: ['bzz', 'plur'], default: 'bzz', }) public unit!: string @@ -31,19 +52,13 @@ export class Deposit extends ChequeCommand implements LeafCommand { public async run(): Promise { super.init() - this.validateUnit() - const amountInPlur = - this.unit === 'bzz' ? BZZ.fromDecimalString(this.amount.toString()).toPLURBigInt() : this.amount + this.console.log(createKeyValue('Amount', this.amount)) + this.console.log(createKeyValue('Unit', this.unit)) - const response = await this.bee.depositTokens(amountInPlur.toString()) + const amountInPlur = this.unit === 'bzz' ? BZZ.fromDecimalString(this.amount) : BZZ.fromPLUR(this.amount) + + const response = await this.bee.depositBZZToChequebook(amountInPlur) this.console.log(createKeyValue('Tx', response.toHex())) this.console.quiet(response.toHex()) } - - private validateUnit() { - if (!VALID_UNITS.includes(this.unit)) { - this.console.error(errorText(`Invalid unit '${this.unit}'. Valid units are: ${VALID_UNITS.join(', ')}`)) - exit(1) - } - } } diff --git a/src/command/cheque/withdraw.ts b/src/command/cheque/withdraw.ts index 4c52e5dc..fbe6a2db 100644 --- a/src/command/cheque/withdraw.ts +++ b/src/command/cheque/withdraw.ts @@ -1,8 +1,8 @@ import { Argument, LeafCommand, Option } from 'furious-commander' -import { createKeyValue, errorText } from '../../utils/text' -import { ChequeCommand, VALID_UNITS } from './cheque-command' -import { exit } from 'process' import { BZZ } from '@ethersphere/bee-js' +// import { Context } from 'madlad' +import { createKeyValue } from '../../utils/text' +import { ChequeCommand } from './cheque-command' export class Withdraw extends ChequeCommand implements LeafCommand { public readonly name = 'withdraw' @@ -13,17 +13,39 @@ export class Withdraw extends ChequeCommand implements LeafCommand { @Argument({ key: 'amount', - type: 'bigint', + type: 'string', description: 'Amount of tokens to withdraw', required: true, - minimum: BigInt(1), + // validate: (value: string, context: Context): string[] => { + // if (context.options.unit === 'bzz') { + // const amount = parseFloat(value) + // + // if (isNaN(amount) || amount <= 0) { + // return [`Invalid amount '${value}'. Amount must be a positive number.`] + // } + // } else { + // try { + // const amount = BigInt(value) + // + // if (amount <= BigInt(0)) { + // return [`Invalid amount '${value}'. Amount must be a positive integer.`] + // } + // } catch (e) { + // return [`Invalid amount '${value}'. Amount must be a positive integer.`] + // } + // } + // + // return [] + // }, }) - public amount!: bigint + public amount!: string @Option({ key: 'unit', + // type: 'enum', type: 'string', - description: `Unit of the amount; choices: ${VALID_UNITS.join(', ')}`, + description: 'Unit of the amount', + // enum: ['bzz', 'plur'], default: 'bzz', }) public unit!: string @@ -31,19 +53,10 @@ export class Withdraw extends ChequeCommand implements LeafCommand { public async run(): Promise { super.init() - this.validateUnit() - const amountInPlur = - this.unit === 'bzz' ? BZZ.fromDecimalString(this.amount.toString()).toPLURBigInt() : this.amount + const amountBZZ = this.unit === 'bzz' ? BZZ.fromDecimalString(this.amount) : BZZ.fromPLUR(this.amount) - const response = await this.bee.withdrawTokens(amountInPlur.toString()) + const response = await this.bee.withdrawBZZFromChequebook(amountBZZ) this.console.log(createKeyValue('Tx', response.toHex())) this.console.quiet(response.toHex()) } - - private validateUnit() { - if (!VALID_UNITS.includes(this.unit)) { - this.console.error(errorText(`Invalid unit '${this.unit}'. Valid units are: ${VALID_UNITS.join(', ')}`)) - exit(1) - } - } } From cdbce622360f464c1858ee6ed3c6f95cc71f5a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gergely=20B=C3=A9k=C3=A9si?= Date: Tue, 28 Apr 2026 10:59:06 +0200 Subject: [PATCH 07/21] chore: madlad update --- package-lock.json | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 49ce685c..d7129b45 100644 --- a/package-lock.json +++ b/package-lock.json @@ -93,7 +93,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz", "integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==", "dev": true, - "peer": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", @@ -2995,7 +2994,6 @@ "integrity": "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -3070,7 +3068,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.44.0.tgz", "integrity": "sha512-j5ULd7FmmekcyWeArx+i8x7sdRHzAtXTkmDPthE4amxZOWKFK7bomoJ4r7PJ8K7PoMzD16U8MmuZFAonr1ERvw==", "dev": true, - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.44.0", "@typescript-eslint/type-utils": "5.44.0", @@ -3104,7 +3101,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz", "integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==", "dev": true, - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.44.0", "@typescript-eslint/types": "5.44.0", @@ -3268,7 +3264,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3666,7 +3661,6 @@ "url": "https://tidelift.com/funding/github/npm/browserslist" } ], - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001400", "electron-to-chromium": "^1.4.251", @@ -4361,7 +4355,6 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz", "integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==", "dev": true, - "peer": true, "dependencies": { "@eslint/eslintrc": "^1.3.3", "@humanwhocodes/config-array": "^0.11.6", @@ -6050,7 +6043,6 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz", "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==", "dev": true, - "peer": true, "dependencies": { "@jest/core": "^29.3.1", "@jest/types": "^29.3.1", @@ -7965,9 +7957,9 @@ } }, "node_modules/madlad": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/madlad/-/madlad-1.4.0.tgz", - "integrity": "sha512-VBHZEiDqIGaKeYRFphAMbhYga34pk+WeZ0hGqKwxZagtIxSuqeiZnr0PvNAvv7preQoIZfs7Nc5lJ1Tpw5Z2cg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/madlad/-/madlad-1.5.0.tgz", + "integrity": "sha512-wvZkAV48esvLI7+ni4+5flCWtgO8MFY+l1LYOzoK3qA4O1IBQ6GntsGb/7jjNPr+O/zZfH5U52uuo7TY4sLf6A==", "license": "MIT" }, "node_modules/make-dir": { @@ -8626,7 +8618,6 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", "dev": true, - "peer": true, "bin": { "prettier": "bin-prettier.js" }, @@ -9535,7 +9526,6 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "dev": true, - "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -9633,7 +9623,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9887,7 +9876,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=10.0.0" }, From 77e03fefb254358a8e0c55325a528129db25df24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gergely=20B=C3=A9k=C3=A9si?= Date: Tue, 28 Apr 2026 13:21:57 +0200 Subject: [PATCH 08/21] feat: use new furious command features --- package-lock.json | 9 +++--- src/command/cheque/deposit.ts | 51 ++++++++++++++++------------------ src/command/cheque/withdraw.ts | 49 ++++++++++++++++---------------- src/config.ts | 2 +- 4 files changed, 54 insertions(+), 57 deletions(-) diff --git a/package-lock.json b/package-lock.json index d7129b45..a6c63f15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5105,11 +5105,12 @@ } }, "node_modules/furious-commander": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/furious-commander/-/furious-commander-1.7.1.tgz", - "integrity": "sha512-EwgVMVU1y1JNpqMdBPezuJRFufGlTumTKKau1eEvOJ6AxYgNkdDiQxl+GD3PBZo6fJo5dpBf+0TohoSdA7oeug==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/furious-commander/-/furious-commander-1.8.0.tgz", + "integrity": "sha512-Hoxuw0UHdWVvsSVEtCxQD41/EUvzPxckdy7C+oGuh9IxH/SUJ31toVTl3u/WPF1iKp+sXGocoeth1QkySPz/xw==", + "license": "MIT", "dependencies": { - "madlad": "^1.2.1", + "madlad": "^1.5.0", "reflect-metadata": "^0.1.13" }, "engines": { diff --git a/src/command/cheque/deposit.ts b/src/command/cheque/deposit.ts index 29e18044..8d79b2bd 100644 --- a/src/command/cheque/deposit.ts +++ b/src/command/cheque/deposit.ts @@ -1,6 +1,6 @@ import { Argument, LeafCommand, Option } from 'furious-commander' import { BZZ } from '@ethersphere/bee-js' -// import { Context } from 'madlad' +import { Context } from 'madlad' import { createKeyValue } from '../../utils/text' import { ChequeCommand } from './cheque-command' @@ -16,35 +16,35 @@ export class Deposit extends ChequeCommand implements LeafCommand { description: 'Amount of tokens to deposit', type: 'decimal-string', required: true, - // validate: (value: string, context: Context): string[] => { - // if (context.options.unit === 'bzz') { - // const amount = parseFloat(value) - // - // if (isNaN(amount) || amount <= 0) { - // return [`Invalid amount '${value}'. Amount must be a positive number.`] - // } - // } else { - // try { - // const amount = BigInt(value) - // - // if (amount <= BigInt(0)) { - // return [`Invalid amount '${value}'. Amount must be a positive integer.`] - // } - // } catch (e) { - // return [`Invalid amount '${value}'. Amount must be a positive integer.`] - // } - // } - // - // return [] - // }, + validate: (value: unknown, context: Context): string[] => { + if (context.options.unit === 'bzz') { + const amount = parseFloat(value as string) + + if (isNaN(amount) || amount <= 0) { + return [`Invalid amount '${value}'. Amount must be a positive number.`] + } + } else { + try { + const amount = BigInt(value as string) + + if (amount <= BigInt(0)) { + return [`Invalid amount '${value}'. Amount must be a positive integer.`] + } + } catch (e) { + return [`Invalid amount '${value}'. Amount must be a positive integer.`] + } + } + + return [] + }, }) public amount!: string @Option({ key: 'unit', - // type: 'enum', + type: 'enum', description: 'Unit of the amount', - // enum: ['bzz', 'plur'], + enum: ['bzz', 'plur'], default: 'bzz', }) public unit!: string @@ -52,9 +52,6 @@ export class Deposit extends ChequeCommand implements LeafCommand { public async run(): Promise { super.init() - this.console.log(createKeyValue('Amount', this.amount)) - this.console.log(createKeyValue('Unit', this.unit)) - const amountInPlur = this.unit === 'bzz' ? BZZ.fromDecimalString(this.amount) : BZZ.fromPLUR(this.amount) const response = await this.bee.depositBZZToChequebook(amountInPlur) diff --git a/src/command/cheque/withdraw.ts b/src/command/cheque/withdraw.ts index fbe6a2db..66fd5654 100644 --- a/src/command/cheque/withdraw.ts +++ b/src/command/cheque/withdraw.ts @@ -1,6 +1,6 @@ import { Argument, LeafCommand, Option } from 'furious-commander' import { BZZ } from '@ethersphere/bee-js' -// import { Context } from 'madlad' +import { Context } from 'madlad' import { createKeyValue } from '../../utils/text' import { ChequeCommand } from './cheque-command' @@ -16,36 +16,35 @@ export class Withdraw extends ChequeCommand implements LeafCommand { type: 'string', description: 'Amount of tokens to withdraw', required: true, - // validate: (value: string, context: Context): string[] => { - // if (context.options.unit === 'bzz') { - // const amount = parseFloat(value) - // - // if (isNaN(amount) || amount <= 0) { - // return [`Invalid amount '${value}'. Amount must be a positive number.`] - // } - // } else { - // try { - // const amount = BigInt(value) - // - // if (amount <= BigInt(0)) { - // return [`Invalid amount '${value}'. Amount must be a positive integer.`] - // } - // } catch (e) { - // return [`Invalid amount '${value}'. Amount must be a positive integer.`] - // } - // } - // - // return [] - // }, + validate: (value: unknown, context: Context): string[] => { + if (context.options.unit === 'bzz') { + const amount = parseFloat(value as string) + + if (isNaN(amount) || amount <= 0) { + return [`Invalid amount '${value}'. Amount must be a positive number.`] + } + } else { + try { + const amount = BigInt(value as string) + + if (amount <= BigInt(0)) { + return [`Invalid amount '${value}'. Amount must be a positive integer.`] + } + } catch (e) { + return [`Invalid amount '${value}'. Amount must be a positive integer.`] + } + } + + return [] + }, }) public amount!: string @Option({ key: 'unit', - // type: 'enum', - type: 'string', + type: 'enum', description: 'Unit of the amount', - // enum: ['bzz', 'plur'], + enum: ['bzz', 'plur'], default: 'bzz', }) public unit!: string diff --git a/src/config.ts b/src/config.ts index 1614f10a..13683d20 100644 --- a/src/config.ts +++ b/src/config.ts @@ -102,7 +102,7 @@ export const dev: IOption = { default: false, } -export const optionParameters: IOption[] = [ +export const optionParameters: IOption[] = [ beeApiUrl, configFolder, configFile, From f92bed9045919ab10cff1371b48f300306142e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gergely=20B=C3=A9k=C3=A9si?= Date: Wed, 29 Apr 2026 10:35:11 +0200 Subject: [PATCH 09/21] test: add more specs for deposit and withdraw --- src/command/cheque/deposit.ts | 4 +- src/command/cheque/withdraw.ts | 5 +- test/command/cheque.spec.ts | 172 ++++++++++++++++++++++----------- 3 files changed, 123 insertions(+), 58 deletions(-) diff --git a/src/command/cheque/deposit.ts b/src/command/cheque/deposit.ts index 8d79b2bd..a516354a 100644 --- a/src/command/cheque/deposit.ts +++ b/src/command/cheque/deposit.ts @@ -52,9 +52,9 @@ export class Deposit extends ChequeCommand implements LeafCommand { public async run(): Promise { super.init() - const amountInPlur = this.unit === 'bzz' ? BZZ.fromDecimalString(this.amount) : BZZ.fromPLUR(this.amount) + const amountBzz = this.unit === 'bzz' ? BZZ.fromDecimalString(this.amount) : BZZ.fromPLUR(this.amount) - const response = await this.bee.depositBZZToChequebook(amountInPlur) + const response = await this.bee.depositBZZToChequebook(amountBzz) this.console.log(createKeyValue('Tx', response.toHex())) this.console.quiet(response.toHex()) } diff --git a/src/command/cheque/withdraw.ts b/src/command/cheque/withdraw.ts index 66fd5654..ba91269c 100644 --- a/src/command/cheque/withdraw.ts +++ b/src/command/cheque/withdraw.ts @@ -52,9 +52,10 @@ export class Withdraw extends ChequeCommand implements LeafCommand { public async run(): Promise { super.init() - const amountBZZ = this.unit === 'bzz' ? BZZ.fromDecimalString(this.amount) : BZZ.fromPLUR(this.amount) + const amountBzz = this.unit === 'bzz' ? BZZ.fromDecimalString(this.amount) : BZZ.fromPLUR(this.amount) - const response = await this.bee.withdrawBZZFromChequebook(amountBZZ) + process.stderr.write(JSON.stringify(amountBzz) + '\n') + const response = await this.bee.withdrawBZZFromChequebook(amountBzz) this.console.log(createKeyValue('Tx', response.toHex())) this.console.quiet(response.toHex()) } diff --git a/test/command/cheque.spec.ts b/test/command/cheque.spec.ts index 1208d30d..0157d658 100644 --- a/test/command/cheque.spec.ts +++ b/test/command/cheque.spec.ts @@ -1,3 +1,4 @@ +import { Bee, BZZ, TransactionId } from '@ethersphere/bee-js' import { describeCommand, invokeTestCli } from '../utility' async function runCommandAndExpectError( @@ -13,79 +14,142 @@ async function runCommandAndExpectError( describeCommand( 'Test Cheque command', ({ consoleMessages, getNthLastMessage, getLastMessage }) => { - it('should print cheques', async () => { - process.env.BEE_API_URL = 'http://localhost:16337' - await invokeTestCli(['cheque', 'list']) - expect(getLastMessage()).toContain('Cheque Value:') - expect(getLastMessage()).toContain('0.0008944000000000 xBZZ') - }) + describe('list', () => { + beforeEach(() => { + process.env.BEE_API_URL = 'http://localhost:16337' + }) + it('should print cheques', async () => { + await invokeTestCli(['cheque', 'list']) + expect(getLastMessage()).toContain('Cheque Value:') + expect(getLastMessage()).toContain('0.0008944000000000 xBZZ') + }) - it('should not print cheques when --minimum is higher', async () => { - process.env.BEE_API_URL = 'http://localhost:16337' - await invokeTestCli(['cheque', 'list', '--minimum', '10000000000000000000']) - expect(getLastMessage()).toContain('No uncashed cheques found') - }) + it('should not print cheques when --minimum is higher', async () => { + await invokeTestCli(['cheque', 'list', '--minimum', '10000000000000000000']) + expect(getLastMessage()).toContain('No uncashed cheques found') + }) - it('should print cheques when --minimum is lower', async () => { - process.env.BEE_API_URL = 'http://localhost:16337' - await invokeTestCli(['cheque', 'list', '--minimum', '1000']) - expect(getLastMessage()).toContain('Cheque Value') + it('should print cheques when --minimum is lower', async () => { + await invokeTestCli(['cheque', 'list', '--minimum', '1000']) + expect(getLastMessage()).toContain('Cheque Value') + }) }) - it('should cashout all cheques', async () => { - process.env.BEE_API_URL = 'http://localhost:16337' - await invokeTestCli(['cheque', 'cashout', '--all']) - expect(getNthLastMessage(3)).toContain('Peer Address:') - expect(getNthLastMessage(3)).toContain('1105536d0f270ecaa9e6e4347e687d1a1afbde7b534354dfd7050d66b3c0faad') - expect(getNthLastMessage(2)).toContain('Cheque Value:') - expect(getNthLastMessage(2)).toContain('0.0008944000000000 xBZZ') - expect(getLastMessage()).toContain('Tx:') - expect(getLastMessage()).toContain('11df9811dc8caaa1ff4389503f2493a8c46b30c0a0b5f8aa54adbb965374c0ae') - }) + describe('cashout', () => { + beforeEach(() => { + process.env.BEE_API_URL = 'http://localhost:16337' + }) + it('should cashout all cheques', async () => { + await invokeTestCli(['cheque', 'cashout', '--all']) + expect(getNthLastMessage(3)).toContain('Peer Address:') + expect(getNthLastMessage(3)).toContain('1105536d0f270ecaa9e6e4347e687d1a1afbde7b534354dfd7050d66b3c0faad') + expect(getNthLastMessage(2)).toContain('Cheque Value:') + expect(getNthLastMessage(2)).toContain('0.0008944000000000 xBZZ') + expect(getLastMessage()).toContain('Tx:') + expect(getLastMessage()).toContain('11df9811dc8caaa1ff4389503f2493a8c46b30c0a0b5f8aa54adbb965374c0ae') + }) - it('should allow specifying gas price and limit for cashout', async () => { - process.env.BEE_API_URL = 'http://localhost:16337' - await invokeTestCli(['cheque', 'cashout', '--all', '--gas-price', '100', '--gas-limit', '100']) - expect(getLastMessage()).toContain('Tx:') - expect(getLastMessage()).toContain('11df9811dc8caaa1ff4389503f2493a8c46b30c0a0b5f8aa54adbb965374c0ae') - }) + it('should allow specifying gas price and limit for cashout', async () => { + await invokeTestCli(['cheque', 'cashout', '--all', '--gas-price', '100', '--gas-limit', '100']) + expect(getLastMessage()).toContain('Tx:') + expect(getLastMessage()).toContain('11df9811dc8caaa1ff4389503f2493a8c46b30c0a0b5f8aa54adbb965374c0ae') + }) - it('should not cashout any cheques when --minimum is higher', async () => { - process.env.BEE_API_URL = 'http://localhost:16337' - await invokeTestCli(['cheque', 'cashout', '--all', '--minimum', '10000000000000000000']) - expect(getLastMessage()).toContain('Found 0 cheques') - }) + it('should not cashout any cheques when --minimum is higher', async () => { + await invokeTestCli(['cheque', 'cashout', '--all', '--minimum', '10000000000000000000']) + expect(getLastMessage()).toContain('Found 0 cheques') + }) - it('should cashout one specific cheque', async () => { - process.env.BEE_API_URL = 'http://localhost:16337' - await invokeTestCli([ - 'cheque', - 'cashout', - '--peer', - '1105536d0f270ecaa9e6e4347e687d1a1afbde7b534354dfd7050d66b3c0faad', - ]) - expect(getNthLastMessage(3)).toContain('Peer Address:') - expect(getNthLastMessage(3)).toContain('1105536d0f270ecaa9e6e4347e687d1a1afbde7b534354dfd7050d66b3c0faad') - expect(getNthLastMessage(2)).toContain('Cheque Value:') - expect(getNthLastMessage(2)).toContain('0.0008944000000000 xBZZ') - expect(getLastMessage()).toContain('Tx:') - expect(getLastMessage()).toContain('11df9811dc8caaa1ff4389503f2493a8c46b30c0a0b5f8aa54adbb965374c0ae') + it('should cashout one specific cheque', async () => { + await invokeTestCli([ + 'cheque', + 'cashout', + '--peer', + '1105536d0f270ecaa9e6e4347e687d1a1afbde7b534354dfd7050d66b3c0faad', + ]) + expect(getNthLastMessage(3)).toContain('Peer Address:') + expect(getNthLastMessage(3)).toContain('1105536d0f270ecaa9e6e4347e687d1a1afbde7b534354dfd7050d66b3c0faad') + expect(getNthLastMessage(2)).toContain('Cheque Value:') + expect(getNthLastMessage(2)).toContain('0.0008944000000000 xBZZ') + expect(getLastMessage()).toContain('Tx:') + expect(getLastMessage()).toContain('11df9811dc8caaa1ff4389503f2493a8c46b30c0a0b5f8aa54adbb965374c0ae') + }) }) it('should raise error when withdrawing negative amount', async () => { - await runCommandAndExpectError(['cheque', 'withdraw', '-1'], '[amount] must be at least 1', consoleMessages) + await runCommandAndExpectError( + ['cheque', 'withdraw', '-1'], + "Invalid amount '-1'. Amount must be a positive number.", + consoleMessages, + ) }) it('should raise error when depositing negative amount', async () => { - await runCommandAndExpectError(['cheque', 'deposit', '-42000000'], '[amount] must be at least 1', consoleMessages) + await runCommandAndExpectError( + ['cheque', 'deposit', '-42000000'], + 'Expected decimal string for amount, got -42000000', + consoleMessages, + ) }) it('should raise error when withdrawing zero', async () => { - await runCommandAndExpectError(['cheque', 'withdraw', '0'], '[amount] must be at least 1', consoleMessages) + await runCommandAndExpectError( + ['cheque', 'withdraw', '0'], + "Invalid amount '-1'. Amount must be a positive number.", + consoleMessages, + ) }) it('should raise error when depositing zero', async () => { - await runCommandAndExpectError(['cheque', 'deposit', '0'], '[amount] must be at least 1', consoleMessages) + await runCommandAndExpectError( + ['cheque', 'deposit', '0'], + "Invalid amount '-1'. Amount must be a positive number.", + consoleMessages, + ) + }) + + describe('deposit', () => { + const fakeTxHash = 'a'.repeat(64) + + it('should deposit {amount} of BZZ to chequebook', async () => { + const spy = jest.spyOn(Bee.prototype, 'depositBZZToChequebook').mockResolvedValue(new TransactionId(fakeTxHash)) + await invokeTestCli(['cheque', 'deposit', '20']) + expect(spy).toHaveBeenCalledWith(BZZ.fromDecimalString('20')) + expect(getLastMessage()).toContain('Tx:') + expect(getLastMessage()).toContain(fakeTxHash) + }) + + it('should deposit {amount} of PLUR to chequebook', async () => { + const spy = jest.spyOn(Bee.prototype, 'depositBZZToChequebook').mockResolvedValue(new TransactionId(fakeTxHash)) + await invokeTestCli(['cheque', 'deposit', '15', '--unit', 'plur']) + expect(spy).toHaveBeenCalledWith(BZZ.fromPLUR('15')) + expect(getLastMessage()).toContain('Tx:') + expect(getLastMessage()).toContain(fakeTxHash) + }) + }) + + describe('withdraw', () => { + const fakeTxHash = 'a'.repeat(64) + + it('should withdraw {amount} of BZZ from chequebook', async () => { + const spy = jest + .spyOn(Bee.prototype, 'withdrawBZZFromChequebook') + .mockResolvedValue(new TransactionId(fakeTxHash)) + await invokeTestCli(['cheque', 'withdraw', '20']) + expect(spy).toHaveBeenCalledWith(BZZ.fromDecimalString('20')) + expect(getLastMessage()).toContain('Tx:') + expect(getLastMessage()).toContain(fakeTxHash) + }) + + it('should withdraw {amount} of PLUR from chequebook', async () => { + const spy = jest + .spyOn(Bee.prototype, 'withdrawBZZFromChequebook') + .mockResolvedValue(new TransactionId(fakeTxHash)) + await invokeTestCli(['cheque', 'withdraw', '15', '--unit', 'plur']) + expect(spy).toHaveBeenCalledWith(BZZ.fromPLUR('15')) + expect(getLastMessage()).toContain('Tx:') + expect(getLastMessage()).toContain(fakeTxHash) + }) }) }, { configFileName: 'cheque' }, From f7b17ae299cc0a86a8a9b3dadd37d51b0fd574a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gergely=20B=C3=A9k=C3=A9si?= Date: Wed, 29 Apr 2026 11:52:30 +0200 Subject: [PATCH 10/21] test: fix --- test/command/cheque.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/command/cheque.spec.ts b/test/command/cheque.spec.ts index 0157d658..4693c872 100644 --- a/test/command/cheque.spec.ts +++ b/test/command/cheque.spec.ts @@ -95,7 +95,7 @@ describeCommand( it('should raise error when withdrawing zero', async () => { await runCommandAndExpectError( ['cheque', 'withdraw', '0'], - "Invalid amount '-1'. Amount must be a positive number.", + "Invalid amount '0'. Amount must be a positive number.", consoleMessages, ) }) @@ -103,7 +103,7 @@ describeCommand( it('should raise error when depositing zero', async () => { await runCommandAndExpectError( ['cheque', 'deposit', '0'], - "Invalid amount '-1'. Amount must be a positive number.", + "Invalid amount '0'. Amount must be a positive number.", consoleMessages, ) }) From 94dc2a4beeb3dbe922947464d082f31b484444f1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 07:26:11 +0000 Subject: [PATCH 11/21] test: update test coverage --- test/coverage/coverage-summary.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/coverage/coverage-summary.json b/test/coverage/coverage-summary.json index 5bc45506..3706ca3d 100644 --- a/test/coverage/coverage-summary.json +++ b/test/coverage/coverage-summary.json @@ -1,4 +1,4 @@ -{"total": {"lines":{"total":2853,"covered":2138,"skipped":0,"pct":74.93},"statements":{"total":2874,"covered":2152,"skipped":0,"pct":74.87},"functions":{"total":343,"covered":264,"skipped":0,"pct":76.96},"branches":{"total":609,"covered":333,"skipped":0,"pct":54.67},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} +{"total": {"lines":{"total":2864,"covered":2187,"skipped":0,"pct":76.36},"statements":{"total":2885,"covered":2201,"skipped":0,"pct":76.29},"functions":{"total":343,"covered":271,"skipped":0,"pct":79},"branches":{"total":619,"covered":352,"skipped":0,"pct":56.86},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/application.ts": {"lines":{"total":2,"covered":0,"skipped":0,"pct":0},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":2,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/config.ts": {"lines":{"total":33,"covered":32,"skipped":0,"pct":96.96},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":33,"covered":32,"skipped":0,"pct":96.96},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/curl.ts": {"lines":{"total":24,"covered":24,"skipped":0,"pct":100},"functions":{"total":7,"covered":7,"skipped":0,"pct":100},"statements":{"total":25,"covered":25,"skipped":0,"pct":100},"branches":{"total":13,"covered":12,"skipped":0,"pct":92.3}} @@ -11,12 +11,12 @@ ,"/home/runner/work/swarm-cli/swarm-cli/src/command/status.ts": {"lines":{"total":79,"covered":79,"skipped":0,"pct":100},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":79,"covered":79,"skipped":0,"pct":100},"branches":{"total":11,"covered":11,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/upload.ts": {"lines":{"total":223,"covered":157,"skipped":0,"pct":70.4},"functions":{"total":16,"covered":14,"skipped":0,"pct":87.5},"statements":{"total":224,"covered":158,"skipped":0,"pct":70.53},"branches":{"total":101,"covered":58,"skipped":0,"pct":57.42}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/cashout.ts": {"lines":{"total":32,"covered":30,"skipped":0,"pct":93.75},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"statements":{"total":32,"covered":30,"skipped":0,"pct":93.75},"branches":{"total":2,"covered":2,"skipped":0,"pct":100}} -,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/cheque-command.ts": {"lines":{"total":26,"covered":22,"skipped":0,"pct":84.61},"functions":{"total":5,"covered":5,"skipped":0,"pct":100},"statements":{"total":27,"covered":23,"skipped":0,"pct":85.18},"branches":{"total":2,"covered":0,"skipped":0,"pct":0}} -,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/deposit.ts": {"lines":{"total":20,"covered":11,"skipped":0,"pct":55},"functions":{"total":3,"covered":1,"skipped":0,"pct":33.33},"statements":{"total":20,"covered":11,"skipped":0,"pct":55},"branches":{"total":3,"covered":0,"skipped":0,"pct":0}} +,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/cheque-command.ts": {"lines":{"total":25,"covered":21,"skipped":0,"pct":84},"functions":{"total":5,"covered":5,"skipped":0,"pct":100},"statements":{"total":26,"covered":22,"skipped":0,"pct":84.61},"branches":{"total":2,"covered":0,"skipped":0,"pct":0}} +,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/deposit.ts": {"lines":{"total":25,"covered":23,"skipped":0,"pct":92},"functions":{"total":3,"covered":3,"skipped":0,"pct":100},"statements":{"total":25,"covered":23,"skipped":0,"pct":92},"branches":{"total":8,"covered":7,"skipped":0,"pct":87.5}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/index.ts": {"lines":{"total":9,"covered":9,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":9,"covered":9,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/list.ts": {"lines":{"total":13,"covered":13,"skipped":0,"pct":100},"functions":{"total":3,"covered":3,"skipped":0,"pct":100},"statements":{"total":14,"covered":14,"skipped":0,"pct":100},"branches":{"total":1,"covered":1,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/withdraw-all.ts": {"lines":{"total":15,"covered":6,"skipped":0,"pct":40},"functions":{"total":2,"covered":1,"skipped":0,"pct":50},"statements":{"total":15,"covered":6,"skipped":0,"pct":40},"branches":{"total":1,"covered":0,"skipped":0,"pct":0}} -,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/withdraw.ts": {"lines":{"total":20,"covered":11,"skipped":0,"pct":55},"functions":{"total":3,"covered":1,"skipped":0,"pct":33.33},"statements":{"total":20,"covered":11,"skipped":0,"pct":55},"branches":{"total":3,"covered":0,"skipped":0,"pct":0}} +,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/withdraw.ts": {"lines":{"total":26,"covered":24,"skipped":0,"pct":92.3},"functions":{"total":3,"covered":3,"skipped":0,"pct":100},"statements":{"total":26,"covered":24,"skipped":0,"pct":92.3},"branches":{"total":8,"covered":7,"skipped":0,"pct":87.5}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/feed/feed-command.ts": {"lines":{"total":49,"covered":49,"skipped":0,"pct":100},"functions":{"total":5,"covered":5,"skipped":0,"pct":100},"statements":{"total":49,"covered":49,"skipped":0,"pct":100},"branches":{"total":13,"covered":13,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/feed/index.ts": {"lines":{"total":7,"covered":7,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":7,"covered":7,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/feed/print.ts": {"lines":{"total":80,"covered":26,"skipped":0,"pct":32.5},"functions":{"total":4,"covered":2,"skipped":0,"pct":50},"statements":{"total":81,"covered":26,"skipped":0,"pct":32.09},"branches":{"total":21,"covered":4,"skipped":0,"pct":19.04}} From d5043d9e5e196d7924e68ce062dcd75d025c95f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gergely=20B=C3=A9k=C3=A9si?= Date: Thu, 30 Apr 2026 13:28:36 +0200 Subject: [PATCH 12/21] test: isolate history specs --- test/command/history.spec.ts | 2 +- test/prompt/history-prompt.spec.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/command/history.spec.ts b/test/command/history.spec.ts index edc66f46..44a3bf53 100644 --- a/test/command/history.spec.ts +++ b/test/command/history.spec.ts @@ -122,4 +122,4 @@ describeCommand('Test History command', ({ consoleMessages }) => { await invokeTestCli(['history', 'disable', '--yes']) }) }) -}) +}, { configFileName: 'history' }) diff --git a/test/prompt/history-prompt.spec.ts b/test/prompt/history-prompt.spec.ts index 6ec91f6d..db2cc1d9 100644 --- a/test/prompt/history-prompt.spec.ts +++ b/test/prompt/history-prompt.spec.ts @@ -43,4 +43,5 @@ describeCommand( }) }) }, + { configFileName: 'history-prompt' }, ) From 4130415ab9ecd822e54e7a1d709c20777579dff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gergely=20B=C3=A9k=C3=A9si?= Date: Thu, 30 Apr 2026 13:32:01 +0200 Subject: [PATCH 13/21] fix: format --- test/command/history.spec.ts | 202 ++++++++++++++++++----------------- 1 file changed, 103 insertions(+), 99 deletions(-) diff --git a/test/command/history.spec.ts b/test/command/history.spec.ts index 44a3bf53..c8bda21f 100644 --- a/test/command/history.spec.ts +++ b/test/command/history.spec.ts @@ -8,118 +8,122 @@ async function uploadTestFile() { await invokeTestCli(['upload', uploadFilePath, ...getStampOption()]) } -describeCommand('Test History command', ({ consoleMessages }) => { - describe('list', () => { - it('should have table header row', async () => { - await invokeTestCli(['history', 'enable']) - await invokeTestCli(['history', 'list']) - expect(consoleMessages[1]).toContain('Timestamp') - expect(consoleMessages[1]).toContain('Reference') - expect(consoleMessages[1]).toContain('Postage stamp batch ID') - expect(consoleMessages[1]).toContain('File path') - expect(consoleMessages[1]).toContain('Upload type') - await invokeTestCli(['history', 'disable', '--yes']) - }) +describeCommand( + 'Test History command', + ({ consoleMessages }) => { + describe('list', () => { + it('should have table header row', async () => { + await invokeTestCli(['history', 'enable']) + await invokeTestCli(['history', 'list']) + expect(consoleMessages[1]).toContain('Timestamp') + expect(consoleMessages[1]).toContain('Reference') + expect(consoleMessages[1]).toContain('Postage stamp batch ID') + expect(consoleMessages[1]).toContain('File path') + expect(consoleMessages[1]).toContain('Upload type') + await invokeTestCli(['history', 'disable', '--yes']) + }) - it('should list history items', async () => { - await invokeTestCli(['history', 'enable']) - await uploadTestFile() - await invokeTestCli(['history', 'list']) + it('should list history items', async () => { + await invokeTestCli(['history', 'enable']) + await uploadTestFile() + await invokeTestCli(['history', 'list']) - const tableString = consoleMessages[consoleMessages.length - 1] - expect(tableString).toContain(' 1 ') - expect(tableString).toContain('b4b1557e29c2') - expect(tableString).toContain('testpage/images/swarm.png') - expect(tableString).toContain('file') - await invokeTestCli(['history', 'disable', '--yes']) - }) + const tableString = consoleMessages[consoleMessages.length - 1] + expect(tableString).toContain(' 1 ') + expect(tableString).toContain('b4b1557e29c2') + expect(tableString).toContain('testpage/images/swarm.png') + expect(tableString).toContain('file') + await invokeTestCli(['history', 'disable', '--yes']) + }) - it('should show warning message if history tracking is not enabled', async () => { - await invokeTestCli(['history', 'disable', '--yes']) - await invokeTestCli(['history', 'list']) - expect(consoleMessages[1]).toContain( - 'Upload history tracking is not enabled. Use "swarm-cli history enable" command to enable it.', - ) + it('should show warning message if history tracking is not enabled', async () => { + await invokeTestCli(['history', 'disable', '--yes']) + await invokeTestCli(['history', 'list']) + expect(consoleMessages[1]).toContain( + 'Upload history tracking is not enabled. Use "swarm-cli history enable" command to enable it.', + ) + }) }) - }) - describe('show', () => { - it('should show all detail for a certain history item', async () => { - const identityName = randomUUID() - await invokeTestCli(['identity', 'create', identityName, '--password', 'test']) - await invokeTestCli(['history', 'enable']) - await invokeTestCli([ - 'feed', - 'upload', - `${__dirname}/../testpage/images`, - '--identity', - identityName, - '--topic-string', - 'test', - '--password', - 'test', - '--quiet', - ...getStampOption(), - ]) - await invokeTestCli(['history', 'show', '1']) + describe('show', () => { + it('should show all detail for a certain history item', async () => { + const identityName = randomUUID() + await invokeTestCli(['identity', 'create', identityName, '--password', 'test']) + await invokeTestCli(['history', 'enable']) + await invokeTestCli([ + 'feed', + 'upload', + `${__dirname}/../testpage/images`, + '--identity', + identityName, + '--topic-string', + 'test', + '--password', + 'test', + '--quiet', + ...getStampOption(), + ]) + await invokeTestCli(['history', 'show', '1']) - expect(consoleMessages[8]).toContain('c86177d67756e097b') - expect(consoleMessages[9]).toMatch(/[a-f0-9]{64}/g) - expect(consoleMessages[10]).toContain('folder') - expect(consoleMessages[11]).toContain('testpage/images') - expect(consoleMessages[12]).toMatch(/[a-f0-9]{64}/g) - expect(consoleMessages[13]).toContain(identityName) - await invokeTestCli(['history', 'disable', '--yes']) - }) + expect(consoleMessages[8]).toContain('c86177d67756e097b') + expect(consoleMessages[9]).toMatch(/[a-f0-9]{64}/g) + expect(consoleMessages[10]).toContain('folder') + expect(consoleMessages[11]).toContain('testpage/images') + expect(consoleMessages[12]).toMatch(/[a-f0-9]{64}/g) + expect(consoleMessages[13]).toContain(identityName) + await invokeTestCli(['history', 'disable', '--yes']) + }) - it('should show warning message if history tracking is not enabled', async () => { - await invokeTestCli(['history', 'show', '1']) - expect(consoleMessages[0]).toContain( - 'Upload history tracking is not enabled. Use "swarm-cli history enable" command to enable it.', - ) + it('should show warning message if history tracking is not enabled', async () => { + await invokeTestCli(['history', 'show', '1']) + expect(consoleMessages[0]).toContain( + 'Upload history tracking is not enabled. Use "swarm-cli history enable" command to enable it.', + ) + }) }) - }) - describe('enable', () => { - it('should enable history tracking', async () => { - await invokeTestCli(['history', 'enable']) - expect(consoleMessages[0]).toContain('Upload history tracking enabled') - }) + describe('enable', () => { + it('should enable history tracking', async () => { + await invokeTestCli(['history', 'enable']) + expect(consoleMessages[0]).toContain('Upload history tracking enabled') + }) - it('should not enable history tracking if it is already enabled', async () => { - await invokeTestCli(['history', 'enable']) - await invokeTestCli(['history', 'enable']) - expect(consoleMessages[1]).toContain('Upload history tracking is already enabled') - await invokeTestCli(['history', 'disable', '--yes']) + it('should not enable history tracking if it is already enabled', async () => { + await invokeTestCli(['history', 'enable']) + await invokeTestCli(['history', 'enable']) + expect(consoleMessages[1]).toContain('Upload history tracking is already enabled') + await invokeTestCli(['history', 'disable', '--yes']) + }) }) - }) - describe('disable', () => { - it('should disable history tracking', async () => { - await invokeTestCli(['history', 'enable']) - await invokeTestCli(['history', 'disable', '--yes']) - expect(consoleMessages[1]).toContain('Upload history file deleted') - expect(consoleMessages[2]).toContain('Upload history tracking disabled') - }) + describe('disable', () => { + it('should disable history tracking', async () => { + await invokeTestCli(['history', 'enable']) + await invokeTestCli(['history', 'disable', '--yes']) + expect(consoleMessages[1]).toContain('Upload history file deleted') + expect(consoleMessages[2]).toContain('Upload history tracking disabled') + }) - it('should not disable history tracking if it is already disabled', async () => { - await invokeTestCli(['history', 'disable', '--yes']) - expect(consoleMessages[0]).toContain('Upload history tracking is already disabled and no history file exists') + it('should not disable history tracking if it is already disabled', async () => { + await invokeTestCli(['history', 'disable', '--yes']) + expect(consoleMessages[0]).toContain('Upload history tracking is already disabled and no history file exists') + }) }) - }) - describe('status', () => { - it('should show history tracking status', async () => { - await invokeTestCli(['history', 'status']) - expect(consoleMessages[0]).toEqual(chalk.green.bold('Upload history tracking status:')) - expect(consoleMessages[1]).toContain('inactive') - await invokeTestCli(['history', 'enable']) - await uploadTestFile() - await invokeTestCli(['history', 'status']) - expect(consoleMessages[9]).toContain('active') - expect(consoleMessages[10]).toContain('/test/testconfig/upload-history.json') - expect(consoleMessages[11]).toEqual('Number of history entries: 1') - await invokeTestCli(['history', 'disable', '--yes']) + describe('status', () => { + it('should show history tracking status', async () => { + await invokeTestCli(['history', 'status']) + expect(consoleMessages[0]).toEqual(chalk.green.bold('Upload history tracking status:')) + expect(consoleMessages[1]).toContain('inactive') + await invokeTestCli(['history', 'enable']) + await uploadTestFile() + await invokeTestCli(['history', 'status']) + expect(consoleMessages[9]).toContain('active') + expect(consoleMessages[10]).toContain('/test/testconfig/upload-history.json') + expect(consoleMessages[11]).toEqual('Number of history entries: 1') + await invokeTestCli(['history', 'disable', '--yes']) + }) }) - }) -}, { configFileName: 'history' }) + }, + { configFileName: 'history' }, +) From c4740ae57b079e8025400c07f07f1a2b6a4917c0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 11:41:05 +0000 Subject: [PATCH 14/21] test: update test coverage From 49c4fd53480edf1d9e64fb3dba535afa8ea88a9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gergely=20B=C3=A9k=C3=A9si?= Date: Thu, 30 Apr 2026 14:04:08 +0200 Subject: [PATCH 15/21] test: use isolated history files --- src/command/root-command/command-config.ts | 2 +- test/command/history.spec.ts | 202 ++++++++++----------- test/prompt/history-prompt.spec.ts | 5 +- test/utility/index.ts | 5 +- 4 files changed, 105 insertions(+), 109 deletions(-) diff --git a/src/command/root-command/command-config.ts b/src/command/root-command/command-config.ts index e7f71974..afd9ea5e 100644 --- a/src/command/root-command/command-config.ts +++ b/src/command/root-command/command-config.ts @@ -55,7 +55,7 @@ export class CommandConfig { } public getHistoryFilePath(): string { - return join(this.configFolderPath, 'upload-history.json') + return process.env.SWARM_CLI_HISTORY_FILE_PATH || join(this.configFolderPath, 'upload-history.json') } public setHistoryEnabled(enabled: boolean): void { diff --git a/test/command/history.spec.ts b/test/command/history.spec.ts index c8bda21f..a83dfb1b 100644 --- a/test/command/history.spec.ts +++ b/test/command/history.spec.ts @@ -8,122 +8,118 @@ async function uploadTestFile() { await invokeTestCli(['upload', uploadFilePath, ...getStampOption()]) } -describeCommand( - 'Test History command', - ({ consoleMessages }) => { - describe('list', () => { - it('should have table header row', async () => { - await invokeTestCli(['history', 'enable']) - await invokeTestCli(['history', 'list']) - expect(consoleMessages[1]).toContain('Timestamp') - expect(consoleMessages[1]).toContain('Reference') - expect(consoleMessages[1]).toContain('Postage stamp batch ID') - expect(consoleMessages[1]).toContain('File path') - expect(consoleMessages[1]).toContain('Upload type') - await invokeTestCli(['history', 'disable', '--yes']) - }) +describeCommand('Test History command', ({ consoleMessages }) => { + describe('list', () => { + it('should have table header row', async () => { + await invokeTestCli(['history', 'enable']) + await invokeTestCli(['history', 'list']) + expect(consoleMessages[1]).toContain('Timestamp') + expect(consoleMessages[1]).toContain('Reference') + expect(consoleMessages[1]).toContain('Postage stamp batch ID') + expect(consoleMessages[1]).toContain('File path') + expect(consoleMessages[1]).toContain('Upload type') + await invokeTestCli(['history', 'disable', '--yes']) + }) - it('should list history items', async () => { - await invokeTestCli(['history', 'enable']) - await uploadTestFile() - await invokeTestCli(['history', 'list']) + it('should list history items', async () => { + await invokeTestCli(['history', 'enable']) + await uploadTestFile() + await invokeTestCli(['history', 'list']) - const tableString = consoleMessages[consoleMessages.length - 1] - expect(tableString).toContain(' 1 ') - expect(tableString).toContain('b4b1557e29c2') - expect(tableString).toContain('testpage/images/swarm.png') - expect(tableString).toContain('file') - await invokeTestCli(['history', 'disable', '--yes']) - }) + const tableString = consoleMessages[consoleMessages.length - 1] + expect(tableString).toContain(' 1 ') + expect(tableString).toContain('b4b1557e29c2') + expect(tableString).toContain('testpage/images/swarm.png') + expect(tableString).toContain('file') + await invokeTestCli(['history', 'disable', '--yes']) + }) - it('should show warning message if history tracking is not enabled', async () => { - await invokeTestCli(['history', 'disable', '--yes']) - await invokeTestCli(['history', 'list']) - expect(consoleMessages[1]).toContain( - 'Upload history tracking is not enabled. Use "swarm-cli history enable" command to enable it.', - ) - }) + it('should show warning message if history tracking is not enabled', async () => { + await invokeTestCli(['history', 'disable', '--yes']) + await invokeTestCli(['history', 'list']) + expect(consoleMessages[1]).toContain( + 'Upload history tracking is not enabled. Use "swarm-cli history enable" command to enable it.', + ) }) + }) - describe('show', () => { - it('should show all detail for a certain history item', async () => { - const identityName = randomUUID() - await invokeTestCli(['identity', 'create', identityName, '--password', 'test']) - await invokeTestCli(['history', 'enable']) - await invokeTestCli([ - 'feed', - 'upload', - `${__dirname}/../testpage/images`, - '--identity', - identityName, - '--topic-string', - 'test', - '--password', - 'test', - '--quiet', - ...getStampOption(), - ]) - await invokeTestCli(['history', 'show', '1']) + describe('show', () => { + it('should show all detail for a certain history item', async () => { + const identityName = randomUUID() + await invokeTestCli(['identity', 'create', identityName, '--password', 'test']) + await invokeTestCli(['history', 'enable']) + await invokeTestCli([ + 'feed', + 'upload', + `${__dirname}/../testpage/images`, + '--identity', + identityName, + '--topic-string', + 'test', + '--password', + 'test', + '--quiet', + ...getStampOption(), + ]) + await invokeTestCli(['history', 'show', '1']) - expect(consoleMessages[8]).toContain('c86177d67756e097b') - expect(consoleMessages[9]).toMatch(/[a-f0-9]{64}/g) - expect(consoleMessages[10]).toContain('folder') - expect(consoleMessages[11]).toContain('testpage/images') - expect(consoleMessages[12]).toMatch(/[a-f0-9]{64}/g) - expect(consoleMessages[13]).toContain(identityName) - await invokeTestCli(['history', 'disable', '--yes']) - }) + expect(consoleMessages[8]).toContain('c86177d67756e097b') + expect(consoleMessages[9]).toMatch(/[a-f0-9]{64}/g) + expect(consoleMessages[10]).toContain('folder') + expect(consoleMessages[11]).toContain('testpage/images') + expect(consoleMessages[12]).toMatch(/[a-f0-9]{64}/g) + expect(consoleMessages[13]).toContain(identityName) + await invokeTestCli(['history', 'disable', '--yes']) + }) - it('should show warning message if history tracking is not enabled', async () => { - await invokeTestCli(['history', 'show', '1']) - expect(consoleMessages[0]).toContain( - 'Upload history tracking is not enabled. Use "swarm-cli history enable" command to enable it.', - ) - }) + it('should show warning message if history tracking is not enabled', async () => { + await invokeTestCli(['history', 'show', '1']) + expect(consoleMessages[0]).toContain( + 'Upload history tracking is not enabled. Use "swarm-cli history enable" command to enable it.', + ) }) + }) - describe('enable', () => { - it('should enable history tracking', async () => { - await invokeTestCli(['history', 'enable']) - expect(consoleMessages[0]).toContain('Upload history tracking enabled') - }) + describe('enable', () => { + it('should enable history tracking', async () => { + await invokeTestCli(['history', 'enable']) + expect(consoleMessages[0]).toContain('Upload history tracking enabled') + }) - it('should not enable history tracking if it is already enabled', async () => { - await invokeTestCli(['history', 'enable']) - await invokeTestCli(['history', 'enable']) - expect(consoleMessages[1]).toContain('Upload history tracking is already enabled') - await invokeTestCli(['history', 'disable', '--yes']) - }) + it('should not enable history tracking if it is already enabled', async () => { + await invokeTestCli(['history', 'enable']) + await invokeTestCli(['history', 'enable']) + expect(consoleMessages[1]).toContain('Upload history tracking is already enabled') + await invokeTestCli(['history', 'disable', '--yes']) }) + }) - describe('disable', () => { - it('should disable history tracking', async () => { - await invokeTestCli(['history', 'enable']) - await invokeTestCli(['history', 'disable', '--yes']) - expect(consoleMessages[1]).toContain('Upload history file deleted') - expect(consoleMessages[2]).toContain('Upload history tracking disabled') - }) + describe('disable', () => { + it('should disable history tracking', async () => { + await invokeTestCli(['history', 'enable']) + await invokeTestCli(['history', 'disable', '--yes']) + expect(consoleMessages[1]).toContain('Upload history file deleted') + expect(consoleMessages[2]).toContain('Upload history tracking disabled') + }) - it('should not disable history tracking if it is already disabled', async () => { - await invokeTestCli(['history', 'disable', '--yes']) - expect(consoleMessages[0]).toContain('Upload history tracking is already disabled and no history file exists') - }) + it('should not disable history tracking if it is already disabled', async () => { + await invokeTestCli(['history', 'disable', '--yes']) + expect(consoleMessages[0]).toContain('Upload history tracking is already disabled and no history file exists') }) + }) - describe('status', () => { - it('should show history tracking status', async () => { - await invokeTestCli(['history', 'status']) - expect(consoleMessages[0]).toEqual(chalk.green.bold('Upload history tracking status:')) - expect(consoleMessages[1]).toContain('inactive') - await invokeTestCli(['history', 'enable']) - await uploadTestFile() - await invokeTestCli(['history', 'status']) - expect(consoleMessages[9]).toContain('active') - expect(consoleMessages[10]).toContain('/test/testconfig/upload-history.json') - expect(consoleMessages[11]).toEqual('Number of history entries: 1') - await invokeTestCli(['history', 'disable', '--yes']) - }) + describe('status', () => { + it('should show history tracking status', async () => { + await invokeTestCli(['history', 'status']) + expect(consoleMessages[0]).toEqual(chalk.green.bold('Upload history tracking status:')) + expect(consoleMessages[1]).toContain('inactive') + await invokeTestCli(['history', 'enable']) + await uploadTestFile() + await invokeTestCli(['history', 'status']) + expect(consoleMessages[9]).toContain('active') + expect(consoleMessages[10]).toContain('upload-history.json') + expect(consoleMessages[11]).toEqual('Number of history entries: 1') + await invokeTestCli(['history', 'disable', '--yes']) }) - }, - { configFileName: 'history' }, -) + }) +}) diff --git a/test/prompt/history-prompt.spec.ts b/test/prompt/history-prompt.spec.ts index db2cc1d9..a91ef97d 100644 --- a/test/prompt/history-prompt.spec.ts +++ b/test/prompt/history-prompt.spec.ts @@ -11,7 +11,7 @@ async function uploadTestFile() { describeCommand( 'Using History Disable Command with Prompts', - ({ consoleMessages, configFolderPath, getLastMessage }) => { + ({ configFolderPath, getLastMessage, hasMessageContaining }) => { it('history disables asks whether the file should be deleted', async () => { await invokeTestCli(['history', 'enable']) await uploadTestFile() @@ -19,7 +19,7 @@ describeCommand( jest.spyOn(inquirer, 'prompt').mockClear().mockResolvedValueOnce({ value: false }) await invokeTestCli(['history', 'disable']) - expect(consoleMessages[6]).toEqual('Upload history tracking disabled') + expect(hasMessageContaining('Upload history tracking disabled')).toBe(true) expect(existsSync(`${configFolderPath}/upload-history.json`)).toEqual(true) expect(inquirer.prompt).toHaveBeenCalledWith({ message: 'Do you want to delete the upload history file? This action cannot be undone.', @@ -43,5 +43,4 @@ describeCommand( }) }) }, - { configFileName: 'history-prompt' }, ) diff --git a/test/utility/index.ts b/test/utility/index.ts index 0a354283..0ab21e7c 100644 --- a/test/utility/index.ts +++ b/test/utility/index.ts @@ -72,6 +72,9 @@ export function describeCommand( jest.spyOn(global.console, 'warn') + const historyFilePath = join(configFolderPath, configFileName ? `${configFileName}-upload-history.json` : 'upload-history.json') + process.env.SWARM_CLI_HISTORY_FILE_PATH = historyFilePath + //if own config is needed if (configFileName) { const fileName = `${configFileName}.json` @@ -90,8 +93,6 @@ export function describeCommand( }) afterEach(() => { - const historyFilePath = join(configFolderPath, 'upload-history.json') - if (existsSync(historyFilePath)) { unlinkSync(historyFilePath) } From e3ae13971f8293279c3e0638823e0bafcc23928d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gergely=20B=C3=A9k=C3=A9si?= Date: Thu, 30 Apr 2026 14:15:59 +0200 Subject: [PATCH 16/21] fix: format --- test/utility/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/utility/index.ts b/test/utility/index.ts index 0ab21e7c..84847640 100644 --- a/test/utility/index.ts +++ b/test/utility/index.ts @@ -72,7 +72,10 @@ export function describeCommand( jest.spyOn(global.console, 'warn') - const historyFilePath = join(configFolderPath, configFileName ? `${configFileName}-upload-history.json` : 'upload-history.json') + const historyFilePath = join( + configFolderPath, + configFileName ? `${configFileName}-upload-history.json` : 'upload-history.json', + ) process.env.SWARM_CLI_HISTORY_FILE_PATH = historyFilePath //if own config is needed From 6fe7f835628f588aabadd0473bcafa0b66f2c53d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 12:28:37 +0000 Subject: [PATCH 17/21] test: update test coverage --- test/coverage/coverage-summary.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/coverage/coverage-summary.json b/test/coverage/coverage-summary.json index 3706ca3d..74f8f95d 100644 --- a/test/coverage/coverage-summary.json +++ b/test/coverage/coverage-summary.json @@ -1,4 +1,4 @@ -{"total": {"lines":{"total":2864,"covered":2187,"skipped":0,"pct":76.36},"statements":{"total":2885,"covered":2201,"skipped":0,"pct":76.29},"functions":{"total":343,"covered":271,"skipped":0,"pct":79},"branches":{"total":619,"covered":352,"skipped":0,"pct":56.86},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} +{"total": {"lines":{"total":2864,"covered":2187,"skipped":0,"pct":76.36},"statements":{"total":2885,"covered":2201,"skipped":0,"pct":76.29},"functions":{"total":343,"covered":271,"skipped":0,"pct":79},"branches":{"total":621,"covered":353,"skipped":0,"pct":56.84},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/application.ts": {"lines":{"total":2,"covered":0,"skipped":0,"pct":0},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":2,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/config.ts": {"lines":{"total":33,"covered":32,"skipped":0,"pct":96.96},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":33,"covered":32,"skipped":0,"pct":96.96},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/curl.ts": {"lines":{"total":24,"covered":24,"skipped":0,"pct":100},"functions":{"total":7,"covered":7,"skipped":0,"pct":100},"statements":{"total":25,"covered":25,"skipped":0,"pct":100},"branches":{"total":13,"covered":12,"skipped":0,"pct":92.3}} @@ -63,7 +63,7 @@ ,"/home/runner/work/swarm-cli/swarm-cli/src/command/pss/receive.ts": {"lines":{"total":24,"covered":18,"skipped":0,"pct":75},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":24,"covered":18,"skipped":0,"pct":75},"branches":{"total":6,"covered":2,"skipped":0,"pct":33.33}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/pss/send.ts": {"lines":{"total":34,"covered":29,"skipped":0,"pct":85.29},"functions":{"total":2,"covered":2,"skipped":0,"pct":100},"statements":{"total":34,"covered":29,"skipped":0,"pct":85.29},"branches":{"total":5,"covered":2,"skipped":0,"pct":40}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/pss/subscribe.ts": {"lines":{"total":18,"covered":8,"skipped":0,"pct":44.44},"functions":{"total":5,"covered":1,"skipped":0,"pct":20},"statements":{"total":18,"covered":8,"skipped":0,"pct":44.44},"branches":{"total":4,"covered":0,"skipped":0,"pct":0}} -,"/home/runner/work/swarm-cli/swarm-cli/src/command/root-command/command-config.ts": {"lines":{"total":39,"covered":33,"skipped":0,"pct":84.61},"functions":{"total":8,"covered":8,"skipped":0,"pct":100},"statements":{"total":42,"covered":35,"skipped":0,"pct":83.33},"branches":{"total":9,"covered":5,"skipped":0,"pct":55.55}} +,"/home/runner/work/swarm-cli/swarm-cli/src/command/root-command/command-config.ts": {"lines":{"total":39,"covered":33,"skipped":0,"pct":84.61},"functions":{"total":8,"covered":8,"skipped":0,"pct":100},"statements":{"total":42,"covered":35,"skipped":0,"pct":83.33},"branches":{"total":11,"covered":6,"skipped":0,"pct":54.54}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/root-command/command-log.ts": {"lines":{"total":78,"covered":60,"skipped":0,"pct":76.92},"functions":{"total":9,"covered":6,"skipped":0,"pct":66.66},"statements":{"total":78,"covered":60,"skipped":0,"pct":76.92},"branches":{"total":11,"covered":7,"skipped":0,"pct":63.63}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/root-command/index.ts": {"lines":{"total":44,"covered":40,"skipped":0,"pct":90.9},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"statements":{"total":44,"covered":40,"skipped":0,"pct":90.9},"branches":{"total":9,"covered":5,"skipped":0,"pct":55.55}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/root-command/printer.ts": {"lines":{"total":9,"covered":9,"skipped":0,"pct":100},"functions":{"total":6,"covered":6,"skipped":0,"pct":100},"statements":{"total":9,"covered":9,"skipped":0,"pct":100},"branches":{"total":1,"covered":1,"skipped":0,"pct":100}} From e64d632fa51d4c61231e31b404be4f45cb88fbea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gergely=20B=C3=A9k=C3=A9si?= Date: Thu, 30 Apr 2026 14:33:51 +0200 Subject: [PATCH 18/21] fix: history specs --- test/command/history.spec.ts | 202 +++++++++++++++-------------- test/prompt/history-prompt.spec.ts | 3 +- 2 files changed, 105 insertions(+), 100 deletions(-) diff --git a/test/command/history.spec.ts b/test/command/history.spec.ts index a83dfb1b..54536551 100644 --- a/test/command/history.spec.ts +++ b/test/command/history.spec.ts @@ -8,118 +8,122 @@ async function uploadTestFile() { await invokeTestCli(['upload', uploadFilePath, ...getStampOption()]) } -describeCommand('Test History command', ({ consoleMessages }) => { - describe('list', () => { - it('should have table header row', async () => { - await invokeTestCli(['history', 'enable']) - await invokeTestCli(['history', 'list']) - expect(consoleMessages[1]).toContain('Timestamp') - expect(consoleMessages[1]).toContain('Reference') - expect(consoleMessages[1]).toContain('Postage stamp batch ID') - expect(consoleMessages[1]).toContain('File path') - expect(consoleMessages[1]).toContain('Upload type') - await invokeTestCli(['history', 'disable', '--yes']) - }) +describeCommand( + 'Test History command', + ({ consoleMessages }) => { + describe('list', () => { + it('should have table header row', async () => { + await invokeTestCli(['history', 'enable']) + await invokeTestCli(['history', 'list']) + expect(consoleMessages[1]).toContain('Timestamp') + expect(consoleMessages[1]).toContain('Reference') + expect(consoleMessages[1]).toContain('Postage stamp batch ID') + expect(consoleMessages[1]).toContain('File path') + expect(consoleMessages[1]).toContain('Upload type') + await invokeTestCli(['history', 'disable', '--yes']) + }) - it('should list history items', async () => { - await invokeTestCli(['history', 'enable']) - await uploadTestFile() - await invokeTestCli(['history', 'list']) + it('should list history items', async () => { + await invokeTestCli(['history', 'enable']) + await uploadTestFile() + await invokeTestCli(['history', 'list']) - const tableString = consoleMessages[consoleMessages.length - 1] - expect(tableString).toContain(' 1 ') - expect(tableString).toContain('b4b1557e29c2') - expect(tableString).toContain('testpage/images/swarm.png') - expect(tableString).toContain('file') - await invokeTestCli(['history', 'disable', '--yes']) - }) + const tableString = consoleMessages[consoleMessages.length - 1] + expect(tableString).toContain(' 1 ') + expect(tableString).toContain('b4b1557e29c2') + expect(tableString).toContain('testpage/images/swarm.png') + expect(tableString).toContain('file') + await invokeTestCli(['history', 'disable', '--yes']) + }) - it('should show warning message if history tracking is not enabled', async () => { - await invokeTestCli(['history', 'disable', '--yes']) - await invokeTestCli(['history', 'list']) - expect(consoleMessages[1]).toContain( - 'Upload history tracking is not enabled. Use "swarm-cli history enable" command to enable it.', - ) + it('should show warning message if history tracking is not enabled', async () => { + await invokeTestCli(['history', 'disable', '--yes']) + await invokeTestCli(['history', 'list']) + expect(consoleMessages[1]).toContain( + 'Upload history tracking is not enabled. Use "swarm-cli history enable" command to enable it.', + ) + }) }) - }) - describe('show', () => { - it('should show all detail for a certain history item', async () => { - const identityName = randomUUID() - await invokeTestCli(['identity', 'create', identityName, '--password', 'test']) - await invokeTestCli(['history', 'enable']) - await invokeTestCli([ - 'feed', - 'upload', - `${__dirname}/../testpage/images`, - '--identity', - identityName, - '--topic-string', - 'test', - '--password', - 'test', - '--quiet', - ...getStampOption(), - ]) - await invokeTestCli(['history', 'show', '1']) + describe('show', () => { + it('should show all detail for a certain history item', async () => { + const identityName = randomUUID() + await invokeTestCli(['identity', 'create', identityName, '--password', 'test']) + await invokeTestCli(['history', 'enable']) + await invokeTestCli([ + 'feed', + 'upload', + `${__dirname}/../testpage/images`, + '--identity', + identityName, + '--topic-string', + 'test', + '--password', + 'test', + '--quiet', + ...getStampOption(), + ]) + await invokeTestCli(['history', 'show', '1']) - expect(consoleMessages[8]).toContain('c86177d67756e097b') - expect(consoleMessages[9]).toMatch(/[a-f0-9]{64}/g) - expect(consoleMessages[10]).toContain('folder') - expect(consoleMessages[11]).toContain('testpage/images') - expect(consoleMessages[12]).toMatch(/[a-f0-9]{64}/g) - expect(consoleMessages[13]).toContain(identityName) - await invokeTestCli(['history', 'disable', '--yes']) - }) + expect(consoleMessages[8]).toContain('c86177d67756e097b') + expect(consoleMessages[9]).toMatch(/[a-f0-9]{64}/g) + expect(consoleMessages[10]).toContain('folder') + expect(consoleMessages[11]).toContain('testpage/images') + expect(consoleMessages[12]).toMatch(/[a-f0-9]{64}/g) + expect(consoleMessages[13]).toContain(identityName) + await invokeTestCli(['history', 'disable', '--yes']) + }) - it('should show warning message if history tracking is not enabled', async () => { - await invokeTestCli(['history', 'show', '1']) - expect(consoleMessages[0]).toContain( - 'Upload history tracking is not enabled. Use "swarm-cli history enable" command to enable it.', - ) + it('should show warning message if history tracking is not enabled', async () => { + await invokeTestCli(['history', 'show', '1']) + expect(consoleMessages[0]).toContain( + 'Upload history tracking is not enabled. Use "swarm-cli history enable" command to enable it.', + ) + }) }) - }) - describe('enable', () => { - it('should enable history tracking', async () => { - await invokeTestCli(['history', 'enable']) - expect(consoleMessages[0]).toContain('Upload history tracking enabled') - }) + describe('enable', () => { + it('should enable history tracking', async () => { + await invokeTestCli(['history', 'enable']) + expect(consoleMessages[0]).toContain('Upload history tracking enabled') + }) - it('should not enable history tracking if it is already enabled', async () => { - await invokeTestCli(['history', 'enable']) - await invokeTestCli(['history', 'enable']) - expect(consoleMessages[1]).toContain('Upload history tracking is already enabled') - await invokeTestCli(['history', 'disable', '--yes']) + it('should not enable history tracking if it is already enabled', async () => { + await invokeTestCli(['history', 'enable']) + await invokeTestCli(['history', 'enable']) + expect(consoleMessages[1]).toContain('Upload history tracking is already enabled') + await invokeTestCli(['history', 'disable', '--yes']) + }) }) - }) - describe('disable', () => { - it('should disable history tracking', async () => { - await invokeTestCli(['history', 'enable']) - await invokeTestCli(['history', 'disable', '--yes']) - expect(consoleMessages[1]).toContain('Upload history file deleted') - expect(consoleMessages[2]).toContain('Upload history tracking disabled') - }) + describe('disable', () => { + it('should disable history tracking', async () => { + await invokeTestCli(['history', 'enable']) + await invokeTestCli(['history', 'disable', '--yes']) + expect(consoleMessages[1]).toContain('Upload history file deleted') + expect(consoleMessages[2]).toContain('Upload history tracking disabled') + }) - it('should not disable history tracking if it is already disabled', async () => { - await invokeTestCli(['history', 'disable', '--yes']) - expect(consoleMessages[0]).toContain('Upload history tracking is already disabled and no history file exists') + it('should not disable history tracking if it is already disabled', async () => { + await invokeTestCli(['history', 'disable', '--yes']) + expect(consoleMessages[0]).toContain('Upload history tracking is already disabled and no history file exists') + }) }) - }) - describe('status', () => { - it('should show history tracking status', async () => { - await invokeTestCli(['history', 'status']) - expect(consoleMessages[0]).toEqual(chalk.green.bold('Upload history tracking status:')) - expect(consoleMessages[1]).toContain('inactive') - await invokeTestCli(['history', 'enable']) - await uploadTestFile() - await invokeTestCli(['history', 'status']) - expect(consoleMessages[9]).toContain('active') - expect(consoleMessages[10]).toContain('upload-history.json') - expect(consoleMessages[11]).toEqual('Number of history entries: 1') - await invokeTestCli(['history', 'disable', '--yes']) + describe('status', () => { + it('should show history tracking status', async () => { + await invokeTestCli(['history', 'status']) + expect(consoleMessages[0]).toEqual(chalk.green.bold('Upload history tracking status:')) + expect(consoleMessages[1]).toContain('inactive') + await invokeTestCli(['history', 'enable']) + await uploadTestFile() + await invokeTestCli(['history', 'status']) + expect(consoleMessages[9]).toContain('active') + expect(consoleMessages[10]).toContain('upload-history.json') + expect(consoleMessages[11]).toEqual('Number of history entries: 1') + await invokeTestCli(['history', 'disable', '--yes']) + }) }) - }) -}) + }, + { configFileName: 'history' }, +) diff --git a/test/prompt/history-prompt.spec.ts b/test/prompt/history-prompt.spec.ts index a91ef97d..8f96f7c8 100644 --- a/test/prompt/history-prompt.spec.ts +++ b/test/prompt/history-prompt.spec.ts @@ -20,7 +20,7 @@ describeCommand( await invokeTestCli(['history', 'disable']) expect(hasMessageContaining('Upload history tracking disabled')).toBe(true) - expect(existsSync(`${configFolderPath}/upload-history.json`)).toEqual(true) + expect(existsSync(`${configFolderPath}/history-prompt-upload-history.json`)).toEqual(true) expect(inquirer.prompt).toHaveBeenCalledWith({ message: 'Do you want to delete the upload history file? This action cannot be undone.', name: 'value', @@ -43,4 +43,5 @@ describeCommand( }) }) }, + { configFileName: 'history-prompt' }, ) From d2580fa329d4cd90cd9b5b4d9ab710a614711252 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 12:46:59 +0000 Subject: [PATCH 19/21] test: update test coverage --- test/coverage/coverage-summary.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/coverage/coverage-summary.json b/test/coverage/coverage-summary.json index 74f8f95d..32223d81 100644 --- a/test/coverage/coverage-summary.json +++ b/test/coverage/coverage-summary.json @@ -1,4 +1,4 @@ -{"total": {"lines":{"total":2864,"covered":2187,"skipped":0,"pct":76.36},"statements":{"total":2885,"covered":2201,"skipped":0,"pct":76.29},"functions":{"total":343,"covered":271,"skipped":0,"pct":79},"branches":{"total":621,"covered":353,"skipped":0,"pct":56.84},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} +{"total": {"lines":{"total":2864,"covered":2187,"skipped":0,"pct":76.36},"statements":{"total":2885,"covered":2201,"skipped":0,"pct":76.29},"functions":{"total":343,"covered":271,"skipped":0,"pct":79},"branches":{"total":621,"covered":354,"skipped":0,"pct":57},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/application.ts": {"lines":{"total":2,"covered":0,"skipped":0,"pct":0},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":2,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/config.ts": {"lines":{"total":33,"covered":32,"skipped":0,"pct":96.96},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":33,"covered":32,"skipped":0,"pct":96.96},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/curl.ts": {"lines":{"total":24,"covered":24,"skipped":0,"pct":100},"functions":{"total":7,"covered":7,"skipped":0,"pct":100},"statements":{"total":25,"covered":25,"skipped":0,"pct":100},"branches":{"total":13,"covered":12,"skipped":0,"pct":92.3}} @@ -96,7 +96,7 @@ ,"/home/runner/work/swarm-cli/swarm-cli/src/service/identity/index.ts": {"lines":{"total":36,"covered":32,"skipped":0,"pct":88.88},"functions":{"total":7,"covered":7,"skipped":0,"pct":100},"statements":{"total":36,"covered":32,"skipped":0,"pct":88.88},"branches":{"total":9,"covered":6,"skipped":0,"pct":66.66}} ,"/home/runner/work/swarm-cli/swarm-cli/src/service/identity/types/identity.ts": {"lines":{"total":4,"covered":4,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":4,"covered":4,"skipped":0,"pct":100},"branches":{"total":2,"covered":2,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/service/identity/types/index.ts": {"lines":{"total":1,"covered":1,"skipped":0,"pct":100},"functions":{"total":2,"covered":1,"skipped":0,"pct":50},"statements":{"total":3,"covered":3,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} -,"/home/runner/work/swarm-cli/swarm-cli/src/service/stamp/index.ts": {"lines":{"total":32,"covered":30,"skipped":0,"pct":93.75},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"statements":{"total":32,"covered":30,"skipped":0,"pct":93.75},"branches":{"total":11,"covered":8,"skipped":0,"pct":72.72}} +,"/home/runner/work/swarm-cli/swarm-cli/src/service/stamp/index.ts": {"lines":{"total":32,"covered":30,"skipped":0,"pct":93.75},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"statements":{"total":32,"covered":30,"skipped":0,"pct":93.75},"branches":{"total":11,"covered":9,"skipped":0,"pct":81.81}} ,"/home/runner/work/swarm-cli/swarm-cli/src/utils/bzz-address.ts": {"lines":{"total":30,"covered":24,"skipped":0,"pct":80},"functions":{"total":3,"covered":2,"skipped":0,"pct":66.66},"statements":{"total":30,"covered":24,"skipped":0,"pct":80},"branches":{"total":6,"covered":3,"skipped":0,"pct":50}} ,"/home/runner/work/swarm-cli/swarm-cli/src/utils/chainsync.ts": {"lines":{"total":4,"covered":4,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":4,"covered":4,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/utils/contracts.ts": {"lines":{"total":3,"covered":3,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":3,"covered":3,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} From 0cb8bee4c86708e29618bc8336430ed680a0d3b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gergely=20B=C3=A9k=C3=A9si?= Date: Mon, 4 May 2026 10:46:16 +0200 Subject: [PATCH 20/21] fix: remove unnecessary stuff --- src/command/cheque/withdraw.ts | 1 - test/misc/monetary-units.spec.ts | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/src/command/cheque/withdraw.ts b/src/command/cheque/withdraw.ts index ba91269c..bf239e78 100644 --- a/src/command/cheque/withdraw.ts +++ b/src/command/cheque/withdraw.ts @@ -54,7 +54,6 @@ export class Withdraw extends ChequeCommand implements LeafCommand { const amountBzz = this.unit === 'bzz' ? BZZ.fromDecimalString(this.amount) : BZZ.fromPLUR(this.amount) - process.stderr.write(JSON.stringify(amountBzz) + '\n') const response = await this.bee.withdrawBZZFromChequebook(amountBzz) this.console.log(createKeyValue('Tx', response.toHex())) this.console.quiet(response.toHex()) diff --git a/test/misc/monetary-units.spec.ts b/test/misc/monetary-units.spec.ts index 7138a333..38d03bbb 100644 --- a/test/misc/monetary-units.spec.ts +++ b/test/misc/monetary-units.spec.ts @@ -36,16 +36,6 @@ describeCommand('Test Monetary units', ({ consoleMessages }) => { expectSubstringsPrinted('--gas-limit', 'in wei') }) - it('should show units in help: cheque withdraw', async () => { - await invokeTestCli(['cheque', 'withdraw', '--help']) - expectSubstringsPrinted('amount', 'Amount of tokens to withdraw') - }) - - it('should show units in help: cheque deposit', async () => { - await invokeTestCli(['cheque', 'deposit', '--help']) - expectSubstringsPrinted('amount', 'Amount of tokens to deposit') - }) - it('should show units after running: cheque list', async () => { await invokeTestCli(['cheque', 'list', '--bee-api-url', 'http://localhost:16337']) expectSubstringsPrinted('Cheque Value', 'xBZZ') From cb4b0f95bcf319143ef11317efeb6b2839be2eed Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 10:38:54 +0000 Subject: [PATCH 21/21] test: update test coverage --- test/coverage/coverage-summary.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/coverage/coverage-summary.json b/test/coverage/coverage-summary.json index 32223d81..ed815663 100644 --- a/test/coverage/coverage-summary.json +++ b/test/coverage/coverage-summary.json @@ -1,4 +1,4 @@ -{"total": {"lines":{"total":2864,"covered":2187,"skipped":0,"pct":76.36},"statements":{"total":2885,"covered":2201,"skipped":0,"pct":76.29},"functions":{"total":343,"covered":271,"skipped":0,"pct":79},"branches":{"total":621,"covered":354,"skipped":0,"pct":57},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} +{"total": {"lines":{"total":2863,"covered":2186,"skipped":0,"pct":76.35},"statements":{"total":2884,"covered":2200,"skipped":0,"pct":76.28},"functions":{"total":343,"covered":271,"skipped":0,"pct":79},"branches":{"total":621,"covered":353,"skipped":0,"pct":56.84},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/application.ts": {"lines":{"total":2,"covered":0,"skipped":0,"pct":0},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":2,"covered":0,"skipped":0,"pct":0},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/config.ts": {"lines":{"total":33,"covered":32,"skipped":0,"pct":96.96},"functions":{"total":1,"covered":0,"skipped":0,"pct":0},"statements":{"total":33,"covered":32,"skipped":0,"pct":96.96},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/curl.ts": {"lines":{"total":24,"covered":24,"skipped":0,"pct":100},"functions":{"total":7,"covered":7,"skipped":0,"pct":100},"statements":{"total":25,"covered":25,"skipped":0,"pct":100},"branches":{"total":13,"covered":12,"skipped":0,"pct":92.3}} @@ -16,7 +16,7 @@ ,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/index.ts": {"lines":{"total":9,"covered":9,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":9,"covered":9,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/list.ts": {"lines":{"total":13,"covered":13,"skipped":0,"pct":100},"functions":{"total":3,"covered":3,"skipped":0,"pct":100},"statements":{"total":14,"covered":14,"skipped":0,"pct":100},"branches":{"total":1,"covered":1,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/withdraw-all.ts": {"lines":{"total":15,"covered":6,"skipped":0,"pct":40},"functions":{"total":2,"covered":1,"skipped":0,"pct":50},"statements":{"total":15,"covered":6,"skipped":0,"pct":40},"branches":{"total":1,"covered":0,"skipped":0,"pct":0}} -,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/withdraw.ts": {"lines":{"total":26,"covered":24,"skipped":0,"pct":92.3},"functions":{"total":3,"covered":3,"skipped":0,"pct":100},"statements":{"total":26,"covered":24,"skipped":0,"pct":92.3},"branches":{"total":8,"covered":7,"skipped":0,"pct":87.5}} +,"/home/runner/work/swarm-cli/swarm-cli/src/command/cheque/withdraw.ts": {"lines":{"total":25,"covered":23,"skipped":0,"pct":92},"functions":{"total":3,"covered":3,"skipped":0,"pct":100},"statements":{"total":25,"covered":23,"skipped":0,"pct":92},"branches":{"total":8,"covered":7,"skipped":0,"pct":87.5}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/feed/feed-command.ts": {"lines":{"total":49,"covered":49,"skipped":0,"pct":100},"functions":{"total":5,"covered":5,"skipped":0,"pct":100},"statements":{"total":49,"covered":49,"skipped":0,"pct":100},"branches":{"total":13,"covered":13,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/feed/index.ts": {"lines":{"total":7,"covered":7,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":7,"covered":7,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/command/feed/print.ts": {"lines":{"total":80,"covered":26,"skipped":0,"pct":32.5},"functions":{"total":4,"covered":2,"skipped":0,"pct":50},"statements":{"total":81,"covered":26,"skipped":0,"pct":32.09},"branches":{"total":21,"covered":4,"skipped":0,"pct":19.04}} @@ -96,7 +96,7 @@ ,"/home/runner/work/swarm-cli/swarm-cli/src/service/identity/index.ts": {"lines":{"total":36,"covered":32,"skipped":0,"pct":88.88},"functions":{"total":7,"covered":7,"skipped":0,"pct":100},"statements":{"total":36,"covered":32,"skipped":0,"pct":88.88},"branches":{"total":9,"covered":6,"skipped":0,"pct":66.66}} ,"/home/runner/work/swarm-cli/swarm-cli/src/service/identity/types/identity.ts": {"lines":{"total":4,"covered":4,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":4,"covered":4,"skipped":0,"pct":100},"branches":{"total":2,"covered":2,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/service/identity/types/index.ts": {"lines":{"total":1,"covered":1,"skipped":0,"pct":100},"functions":{"total":2,"covered":1,"skipped":0,"pct":50},"statements":{"total":3,"covered":3,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} -,"/home/runner/work/swarm-cli/swarm-cli/src/service/stamp/index.ts": {"lines":{"total":32,"covered":30,"skipped":0,"pct":93.75},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"statements":{"total":32,"covered":30,"skipped":0,"pct":93.75},"branches":{"total":11,"covered":9,"skipped":0,"pct":81.81}} +,"/home/runner/work/swarm-cli/swarm-cli/src/service/stamp/index.ts": {"lines":{"total":32,"covered":30,"skipped":0,"pct":93.75},"functions":{"total":4,"covered":4,"skipped":0,"pct":100},"statements":{"total":32,"covered":30,"skipped":0,"pct":93.75},"branches":{"total":11,"covered":8,"skipped":0,"pct":72.72}} ,"/home/runner/work/swarm-cli/swarm-cli/src/utils/bzz-address.ts": {"lines":{"total":30,"covered":24,"skipped":0,"pct":80},"functions":{"total":3,"covered":2,"skipped":0,"pct":66.66},"statements":{"total":30,"covered":24,"skipped":0,"pct":80},"branches":{"total":6,"covered":3,"skipped":0,"pct":50}} ,"/home/runner/work/swarm-cli/swarm-cli/src/utils/chainsync.ts": {"lines":{"total":4,"covered":4,"skipped":0,"pct":100},"functions":{"total":1,"covered":1,"skipped":0,"pct":100},"statements":{"total":4,"covered":4,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}} ,"/home/runner/work/swarm-cli/swarm-cli/src/utils/contracts.ts": {"lines":{"total":3,"covered":3,"skipped":0,"pct":100},"functions":{"total":0,"covered":0,"skipped":0,"pct":100},"statements":{"total":3,"covered":3,"skipped":0,"pct":100},"branches":{"total":0,"covered":0,"skipped":0,"pct":100}}