Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/commands/transactions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export function initializeTransactionsCommands(program: Command) {
.option("--retries <retries>", "Number of retries", (value) => parseIntOption(value, 100), 100)
.option("--interval <interval>", "Interval between retries in milliseconds", (value) => parseIntOption(value, 5000), 5000)
.option("--rpc <rpcUrl>", "RPC URL for the network")
.option("--stdout", "Print only stdout from the receipt")
.option("--stderr", "Print only stderr from the receipt")
.action(async (txId: TransactionHash, options: ReceiptOptions) => {
const receiptAction = new ReceiptAction();

Expand Down
28 changes: 27 additions & 1 deletion src/commands/transactions/receipt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export interface ReceiptParams {
retries?: number;
interval?: number;
rpc?: string;
stdout?: boolean;
stderr?: boolean;
}

export interface ReceiptOptions extends Omit<ReceiptParams, 'txId'> {}
Expand Down Expand Up @@ -37,6 +39,8 @@ export class ReceiptAction extends BaseAction {
retries,
interval,
rpc,
stdout,
stderr,
}: ReceiptParams): Promise<void> {
const client = await this.getClient(rpc);
await client.initializeConsensusSmartContract();
Expand All @@ -55,7 +59,29 @@ export class ReceiptAction extends BaseAction {
retries,
interval,
});


// If specific output flags are provided, print only those fields
if (stdout || stderr) {
const stdoutValue = (result as any)?.consensus_data?.leader_receipt[0]?.genvm_result?.stdout;
const stderrValue = (result as any)?.consensus_data?.leader_receipt[0]?.genvm_result?.stderr;

if (stdout && stderr) {
this.succeedSpinner("Transaction stdout and stderr", { stdout: stdoutValue, stderr: stderrValue });
return;
}

if (stdout) {
this.succeedSpinner("Transaction stdout retrieved successfully", stdoutValue);
return;
}

if (stderr) {
this.succeedSpinner("Transaction stderr retrieved successfully", stderrValue);
return;
}
}

// Default behavior (no flags): show full receipt result
this.succeedSpinner("Transaction receipt retrieved successfully", result);
} catch (error) {
this.failSpinner("Error retrieving transaction receipt", error);
Expand Down
88 changes: 88 additions & 0 deletions tests/actions/receipt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,92 @@ describe("ReceiptAction", () => {
}
});

test("prints only stdout when --stdout is provided", async () => {
const mockReceipt = {
consensus_data: {
leader_receipt: [
{
genvm_result: {
stdout: "program stdout",
stderr: "program stderr",
},
},
],
},
};

vi.mocked(mockClient.waitForTransactionReceipt).mockResolvedValue(mockReceipt as any);

await receiptAction.receipt({
txId: mockTxId,
retries: defaultRetries,
interval: defaultInterval,
stdout: true,
} as ReceiptParams);

expect(receiptAction["succeedSpinner"]).toHaveBeenCalledWith(
"Transaction stdout retrieved successfully",
"program stdout",
);
});

test("prints only stderr when --stderr is provided", async () => {
const mockReceipt = {
consensus_data: {
leader_receipt: [
{
genvm_result: {
stdout: "program stdout",
stderr: "program stderr",
},
},
],
},
};

vi.mocked(mockClient.waitForTransactionReceipt).mockResolvedValue(mockReceipt as any);

await receiptAction.receipt({
txId: mockTxId,
retries: defaultRetries,
interval: defaultInterval,
stderr: true,
} as ReceiptParams);

expect(receiptAction["succeedSpinner"]).toHaveBeenCalledWith(
"Transaction stderr retrieved successfully",
"program stderr",
);
});

test("prints both stdout and stderr when both flags are provided", async () => {
const mockReceipt = {
consensus_data: {
leader_receipt: [
{
genvm_result: {
stdout: "program stdout",
stderr: "program stderr",
},
},
],
},
};

vi.mocked(mockClient.waitForTransactionReceipt).mockResolvedValue(mockReceipt as any);

await receiptAction.receipt({
txId: mockTxId,
retries: defaultRetries,
interval: defaultInterval,
stdout: true,
stderr: true,
} as ReceiptParams);

expect(receiptAction["succeedSpinner"]).toHaveBeenCalledWith(
"Transaction stdout and stderr",
{ stdout: "program stdout", stderr: "program stderr" },
);
});

});
34 changes: 34 additions & 0 deletions tests/commands/receipt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,38 @@ describe("receipt command", () => {
interval: 5000,
});
});

test("parses --stdout flag", async () => {
program.parse(["node", "test", "receipt", mockTxId, "--stdout"]);
expect(ReceiptAction.prototype.receipt).toHaveBeenCalledWith({
txId: mockTxId,
status: "FINALIZED",
retries: 100,
interval: 5000,
stdout: true,
});
});

test("parses --stderr flag", async () => {
program.parse(["node", "test", "receipt", mockTxId, "--stderr"]);
expect(ReceiptAction.prototype.receipt).toHaveBeenCalledWith({
txId: mockTxId,
status: "FINALIZED",
retries: 100,
interval: 5000,
stderr: true,
});
});

test("parses both --stdout and --stderr flags", async () => {
program.parse(["node", "test", "receipt", mockTxId, "--stdout", "--stderr"]);
expect(ReceiptAction.prototype.receipt).toHaveBeenCalledWith({
txId: mockTxId,
status: "FINALIZED",
retries: 100,
interval: 5000,
stdout: true,
stderr: true,
});
});
});