taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 6fb290a4e8663c7fa72a869d01c51f1ef440bfc2
parent 8e5feef9ff2cd986f9f8e403a702a82001987030
Author: Florian Dold <dold@taler.net>
Date:   Thu, 13 Aug 2026 12:17:37 +0200

taler-harness: add expiring orders playground

Diffstat:
Mpackages/taler-harness/README.md | 15++++++++++++++-
Mpackages/taler-harness/src/index.ts | 18++++++++++++++++++
Mpackages/taler-harness/src/playground.ts | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 92 insertions(+), 1 deletion(-)

diff --git a/packages/taler-harness/README.md b/packages/taler-harness/README.md @@ -4,6 +4,20 @@ This package implements the `taler-harness` CLI tool. It contains integration tests for GNU Taler and GNU anastasis, as well as various helpers for managing deployments of GNU Taler. +## Quickly expiring payments + +Create a payment that expires after one minute with: + +``` +taler-harness playground expiring-orders \ + --merchant-url "$MERCHANT_URL" \ + --merchant-pw "$MERCHANT_PASSWORD" +``` + +Open the printed `taler://pay/` URI in a wallet and leave the payment +confirmation open until it expires. The deadline can be changed with +`--pay-delay`, for example `--pay-delay 30s`. + ## Debugging To get more actionable stack traces, enable source maps for node: @@ -120,4 +134,3 @@ taler-harness run-integrationtests web-merchant-login ``` The default browser is "chrome" unless the env variable DEFAULT_BROWSER is set to either "firefox" or "chrome". - diff --git a/packages/taler-harness/src/index.ts b/packages/taler-harness/src/index.ts @@ -115,6 +115,7 @@ import { lintExchangeDeployment, lintExchangeUrl } from "./lint.js"; import { runPlaygroundAdvancedTokens1, runPlaygroundBlog, + runPlaygroundExpiringOrders, } from "./playground.js"; import { MYTOPS_STAGE_BASE_URL, @@ -2054,6 +2055,23 @@ export const playgroundCli = talerHarnessCli.subcommand( ); playgroundCli + .subcommand("exp", "expiring-orders", { + help: "Create a payment that expires quickly for wallet UI testing.", + }) + .requiredOption("merchantUrl", ["--merchant-url"], clk.STRING) + .requiredOption("merchantPw", ["--merchant-pw"], clk.STRING) + .maybeOption("payDelay", ["--pay-delay"], clk.STRING, { + help: "Time until the order expires (default: 1m).", + }) + .action(async (args) => { + await runPlaygroundExpiringOrders({ + merchantPw: args.exp.merchantPw, + merchantUrl: args.exp.merchantUrl, + payDelay: args.exp.payDelay, + }); + }); + +playgroundCli .subcommand("exp", "blog", {}) .requiredOption("merchantUrl", ["--merchant-url"], clk.STRING) .requiredOption("merchantPw", ["--merchant-pw"], clk.STRING) diff --git a/packages/taler-harness/src/playground.ts b/packages/taler-harness/src/playground.ts @@ -38,6 +38,66 @@ export interface PlaygroundBlogArgs { payDelay?: string; } +export interface PlaygroundExpiringOrdersArgs { + merchantUrl: string; + merchantPw: string; + payDelay?: string; +} + +/** + * Create a plain payment order that expires soon after it is opened. + * + * The short deadline makes it possible to leave the wallet on the payment + * confirmation screen until the order expires and then inspect the expired + * transaction in the wallet's history. + */ +export async function runPlaygroundExpiringOrders( + args: PlaygroundExpiringOrdersArgs, +): Promise<void> { + const payDelay = args.payDelay ?? "1m"; + const payDuration = Duration.fromPrettyString(payDelay); + if (payDuration.d_ms === "forever" || payDuration.d_ms <= 0) { + throw Error("pay delay must be a positive, finite duration"); + } + + const merchantClient = new TalerMerchantInstanceHttpClient(args.merchantUrl); + const config = succeedOrThrow(await merchantClient.getConfig()); + const tok = succeedOrThrow( + await merchantClient.createAccessToken( + merchantClient.guessInstanceName(), + args.merchantPw, + { + scope: LoginTokenScope.All, + duration: Duration.toTalerProtocolDuration( + Duration.fromSpec({ hours: 1 }), + ), + }, + ), + ); + + const payDeadline = AbsoluteTime.toProtocolTimestamp( + AbsoluteTime.addDuration(AbsoluteTime.now(), payDuration), + ); + const createResp = succeedOrThrow( + await merchantClient.createOrder(tok.access_token, { + order: { + amount: `${config.currency}:1` as AmountString, + fulfillment_message: "The quickly expiring test payment succeeded.", + pay_deadline: payDeadline, + summary: `Test payment expiring in ${payDelay}`, + }, + }), + ); + const st = succeedOrThrow( + await merchantClient.getOrderDetails(tok.access_token, createResp.order_id), + ); + + if (st.order_status !== "unpaid") { + throw Error(`new order unexpectedly has status ${st.order_status}`); + } + console.log(st.taler_pay_uri); +} + export async function runPlaygroundBlog( args: PlaygroundBlogArgs, ): Promise<void> {