taler-typescript-core

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

commit 208fcb920418497497870c4971fedbe38d880cc9
parent abab81ab46481725129cc52a8522dd6832058a86
Author: Iván Ávalos <avalos@disroot.org>
Date:   Mon, 30 Jun 2025 15:21:47 +0200

harness: extend wallet-tokens test

Diffstat:
Mpackages/taler-harness/src/integrationtests/test-wallet-tokens.ts | 408++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
1 file changed, 278 insertions(+), 130 deletions(-)

diff --git a/packages/taler-harness/src/integrationtests/test-wallet-tokens.ts b/packages/taler-harness/src/integrationtests/test-wallet-tokens.ts @@ -36,6 +36,7 @@ import { TalerProtocolTimestamp, TokenFamilyKind, } from "@gnu-taler/taler-util"; +import { logger } from "./test-tops-challenger-twice.js"; export async function runWalletTokensTest(t: GlobalTestState) { let { bankClient, exchange, merchant, walletClient } = @@ -50,11 +51,11 @@ export async function runWalletTokensTest(t: GlobalTestState) { walletClient, bankClient, exchange, - amount: "TESTKUDOS:20", + amount: "TESTKUDOS:40", }); await wres.withdrawalFinishedCond; - // setup token family + // setup discount token family succeedOrThrow( await merchantApi.createTokenFamily(undefined, { kind: TokenFamilyKind.Discount, @@ -77,66 +78,30 @@ export async function runWalletTokensTest(t: GlobalTestState) { }), ); - // setup order with token output - let orderResp = succeedOrThrow( - await merchantApi.createOrder(undefined, { - order: { - version: 1, - summary: "Test order", - timestamp: TalerProtocolTimestamp.now(), - pay_deadline: AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.addDuration( - AbsoluteTime.now(), - Duration.fromSpec({days: 1}), - ), + // setup subscription token family + succeedOrThrow( + await merchantApi.createTokenFamily(undefined, { + kind: TokenFamilyKind.Subscription, + slug: "test_subscription", + name: "Test subscription", + description: "This is a test subscription", + valid_after: TalerProtocolTimestamp.now(), + valid_before: AbsoluteTime.toProtocolTimestamp( + AbsoluteTime.addDuration( + AbsoluteTime.now(), + Duration.fromSpec({years: 1}), ), - choices: [ - { - amount: "TESTKUDOS:1", - inputs: [], - outputs: [{ - type: OrderOutputType.Token, - token_family_slug: "test_discount", - }], - }, - ], - }, + ), + duration: Duration.toTalerProtocolDuration( + Duration.fromSpec({days: 90}), + ), + validity_granularity: Duration.toTalerProtocolDuration( + Duration.fromSpec({days: 1}), + ), }), ); - let orderStatus = succeedOrThrow( - await merchantApi.getOrderDetails(undefined, orderResp.order_id), - ); - - t.assertTrue(orderStatus.order_status === "unpaid"); - - let talerPayUri = orderStatus.taler_pay_uri; - let orderId = orderResp.order_id; - - let preparePayResult = await walletClient.call( - WalletApiOperation.PreparePayForUri, - { - talerPayUri, - }, - ); - - t.assertTrue( - preparePayResult.status === PreparePayResultType.ChoiceSelection, - ); - - await walletClient.call(WalletApiOperation.ConfirmPay, { - transactionId: preparePayResult.transactionId, - choiceIndex: 0, - }); - - orderStatus = succeedOrThrow( - await merchantApi.getOrderDetails(undefined, orderId), - ); - - t.assertTrue(orderStatus.order_status === "paid"); - - // setup order with token input - const order: Order = { + let orderJsonDiscount: Order = { version: 1, summary: "Test order", timestamp: TalerProtocolTimestamp.now(), @@ -150,7 +115,10 @@ export async function runWalletTokensTest(t: GlobalTestState) { { amount: "TESTKUDOS:2", inputs: [], - outputs: [], + outputs: [{ + type: OrderOutputType.Token, + token_family_slug: "test_discount", + }], }, { amount: "TESTKUDOS:1", @@ -158,117 +126,297 @@ export async function runWalletTokensTest(t: GlobalTestState) { type: OrderInputType.Token, token_family_slug: "test_discount", }], + outputs: [], }, ], }; - orderResp = succeedOrThrow( - await merchantApi.createOrder(undefined, { order }), - ); + let orderJsonSubscription: Order = { + version: 1, + summary: "Test order", + timestamp: TalerProtocolTimestamp.now(), + pay_deadline: AbsoluteTime.toProtocolTimestamp( + AbsoluteTime.addDuration( + AbsoluteTime.now(), + Duration.fromSpec({days: 1}), + ), + ), + choices: [ + { + amount: "TESTKUDOS:10", + inputs: [], + outputs: [{ + type: OrderOutputType.Token, + token_family_slug: "test_subscription", + count: 1, + }], + }, + { + amount: "TESTKUDOS:0", + inputs: [{ + type: OrderInputType.Token, + token_family_slug: "test_subscription", + count: 1, + }], + outputs: [{ + type: OrderOutputType.Token, + token_family_slug: "test_subscription", + count: 1, + }], + }, + ], + } - orderStatus = succeedOrThrow( - await merchantApi.getOrderDetails(undefined, orderResp.order_id), - ); + { + logger.info("Payment with discount token output..."); + const orderResp = succeedOrThrow( + await merchantApi.createOrder(undefined, { + order: orderJsonDiscount, + }), + ); - t.assertTrue(orderStatus.order_status === "unpaid"); + let orderStatus = succeedOrThrow( + await merchantApi.getOrderDetails(undefined, orderResp.order_id), + ); - talerPayUri = orderStatus.taler_pay_uri; - orderId = orderResp.order_id; + t.assertTrue(orderStatus.order_status === "unpaid"); - preparePayResult = await walletClient.call( - WalletApiOperation.PreparePayForUri, - { - talerPayUri, - } - ); + const talerPayUri = orderStatus.taler_pay_uri; + const orderId = orderResp.order_id; - t.assertTrue( - preparePayResult.status === PreparePayResultType.ChoiceSelection, - ); + const preparePayResult = await walletClient.call( + WalletApiOperation.PreparePayForUri, + { + talerPayUri, + }, + ); - { - const choicesRes = await walletClient.call(WalletApiOperation.GetChoicesForPayment, { + t.assertTrue( + preparePayResult.status === PreparePayResultType.ChoiceSelection, + ); + + await walletClient.call(WalletApiOperation.ConfirmPay, { transactionId: preparePayResult.transactionId, + choiceIndex: 0, }); - t.assertTrue(choicesRes.defaultChoiceIndex === 1); - t.assertTrue(choicesRes.automaticExecution === false); - - t.assertTrue(choicesRes.choices[0].status === - ChoiceSelectionDetailType.PaymentPossible, + orderStatus = succeedOrThrow( + await merchantApi.getOrderDetails(undefined, orderId), ); - const tokenDetails = choicesRes.choices[1].tokenDetails; - t.assertTrue(tokenDetails?.tokensAvailable === 1); - t.assertTrue(tokenDetails?.tokensRequested === 1); + t.assertTrue(orderStatus.order_status === "paid"); } - await walletClient.call(WalletApiOperation.ConfirmPay, { - transactionId: preparePayResult.transactionId, - choiceIndex: 1, - }); + { + logger.info("Payment with discount token input..."); + const orderResp = succeedOrThrow( + await merchantApi.createOrder(undefined, { + order: orderJsonDiscount, + }), + ); - orderStatus = succeedOrThrow( - await merchantApi.getOrderDetails(undefined, orderId), - ); + let orderStatus = succeedOrThrow( + await merchantApi.getOrderDetails(undefined, orderResp.order_id), + ); - t.assertTrue(orderStatus.order_status === "paid"); + t.assertTrue(orderStatus.order_status === "unpaid"); - // setup another order with token input - orderResp = succeedOrThrow( - await merchantApi.createOrder(undefined, { order }), - ); + const talerPayUri = orderStatus.taler_pay_uri; + const orderId = orderResp.order_id; - orderStatus = succeedOrThrow( - await merchantApi.getOrderDetails(undefined, orderResp.order_id), - ); + const preparePayResult = await walletClient.call( + WalletApiOperation.PreparePayForUri, + { + talerPayUri, + } + ); + + t.assertTrue( + preparePayResult.status === PreparePayResultType.ChoiceSelection, + ); + + { + const choicesRes = await walletClient.call(WalletApiOperation.GetChoicesForPayment, { + transactionId: preparePayResult.transactionId, + }); + + t.assertTrue(choicesRes.defaultChoiceIndex === 1); + t.assertTrue(choicesRes.automaticExecution === false); + + t.assertTrue(choicesRes.choices[0].status === + ChoiceSelectionDetailType.PaymentPossible, + ); + + const tokenDetails = choicesRes.choices[1].tokenDetails; + t.assertTrue(tokenDetails?.tokensAvailable === 1); + t.assertTrue(tokenDetails?.tokensRequested === 1); + } + + await walletClient.call(WalletApiOperation.ConfirmPay, { + transactionId: preparePayResult.transactionId, + choiceIndex: 1, + }); - t.assertTrue(orderStatus.order_status === "unpaid"); + orderStatus = succeedOrThrow( + await merchantApi.getOrderDetails(undefined, orderId), + ); + } - talerPayUri = orderStatus.taler_pay_uri; - orderId = orderResp.order_id; + { + logger.info("Payment with discount token input, insufficient tokens..."); + const orderResp = succeedOrThrow( + await merchantApi.createOrder(undefined, { + order: orderJsonDiscount, + }), + ); + + let orderStatus = succeedOrThrow( + await merchantApi.getOrderDetails(undefined, orderResp.order_id), + ); + + t.assertTrue(orderStatus.order_status === "unpaid"); + + const talerPayUri = orderStatus.taler_pay_uri; + const orderId = orderResp.order_id; + + const preparePayResult = await walletClient.call( + WalletApiOperation.PreparePayForUri, + { + talerPayUri, + }, + ); + + t.assertTrue( + preparePayResult.status === PreparePayResultType.ChoiceSelection, + ); - preparePayResult = await walletClient.call( - WalletApiOperation.PreparePayForUri, { - talerPayUri, - }, - ); + const choicesRes = await walletClient.call(WalletApiOperation.GetChoicesForPayment, { + transactionId: preparePayResult.transactionId, + }); - t.assertTrue( - preparePayResult.status === PreparePayResultType.ChoiceSelection, - ); + t.assertTrue(choicesRes.defaultChoiceIndex === 0); + t.assertTrue(choicesRes.automaticExecution === false); + + t.assertTrue(choicesRes.choices[1].status === + ChoiceSelectionDetailType.InsufficientBalance, + ); + + const tokenDetails = choicesRes.choices[1].tokenDetails; + t.assertTrue(tokenDetails?.tokensAvailable === 0); + t.assertTrue(tokenDetails?.tokensRequested === 1); + } + + // should fail because we have no tokens left + t.assertThrowsAsync(async () => { + await walletClient.call(WalletApiOperation.ConfirmPay, { + transactionId: preparePayResult.transactionId, + choiceIndex: 1, + }); + }); + + orderStatus = succeedOrThrow( + await merchantApi.getOrderDetails(undefined, orderId), + ); + + t.assertTrue(orderStatus.order_status === "claimed"); + } { - const choicesRes = await walletClient.call(WalletApiOperation.GetChoicesForPayment, { + logger.info("Payment with subscription token output..."); + const orderResp = succeedOrThrow( + await merchantApi.createOrder(undefined, { + order: orderJsonSubscription, + }), + ); + + let orderStatus = succeedOrThrow( + await merchantApi.getOrderDetails(undefined, orderResp.order_id), + ); + + t.assertTrue(orderStatus.order_status === "unpaid"); + + const talerPayUri = orderStatus.taler_pay_uri; + const orderId = orderResp.order_id; + + const preparePayResult = await walletClient.call( + WalletApiOperation.PreparePayForUri, + { + talerPayUri, + }, + ); + + t.assertTrue( + preparePayResult.status === PreparePayResultType.ChoiceSelection, + ); + + await walletClient.call(WalletApiOperation.ConfirmPay, { transactionId: preparePayResult.transactionId, + choiceIndex: 0, }); - t.assertTrue(choicesRes.defaultChoiceIndex === 0); - t.assertTrue(choicesRes.automaticExecution === false); - - t.assertTrue(choicesRes.choices[1].status === - ChoiceSelectionDetailType.InsufficientBalance, + orderStatus = succeedOrThrow( + await merchantApi.getOrderDetails(undefined, orderId), ); - const tokenDetails = choicesRes.choices[1].tokenDetails; - t.assertTrue(tokenDetails?.tokensAvailable === 0); - t.assertTrue(tokenDetails?.tokensRequested === 1); + t.assertTrue(orderStatus.order_status === "paid"); } - // should fail because we have no tokens left - t.assertThrowsAsync(async () => { + { + logger.info("Payment with subscription token input..."); + const orderResp = succeedOrThrow( + await merchantApi.createOrder(undefined, { + order: orderJsonSubscription, + }), + ); + + let orderStatus = succeedOrThrow( + await merchantApi.getOrderDetails(undefined, orderResp.order_id), + ); + + t.assertTrue(orderStatus.order_status === "unpaid"); + + const talerPayUri = orderStatus.taler_pay_uri; + const orderId = orderResp.order_id; + + const preparePayResult = await walletClient.call( + WalletApiOperation.PreparePayForUri, + { + talerPayUri, + } + ); + + t.assertTrue( + preparePayResult.status === PreparePayResultType.ChoiceSelection, + ); + + { + logger.info("Payment with subscription token input and output..."); + const choicesRes = await walletClient.call(WalletApiOperation.GetChoicesForPayment, { + transactionId: preparePayResult.transactionId, + }); + + t.assertTrue(choicesRes.defaultChoiceIndex === 1); + t.assertTrue(choicesRes.automaticExecution === true); + + t.assertTrue(choicesRes.choices[1].status === + ChoiceSelectionDetailType.PaymentPossible, + ); + + const tokenDetails = choicesRes.choices[1].tokenDetails; + t.assertTrue(tokenDetails?.tokensAvailable === 1); + t.assertTrue(tokenDetails?.tokensRequested === 1); + } + await walletClient.call(WalletApiOperation.ConfirmPay, { transactionId: preparePayResult.transactionId, choiceIndex: 1, }); - }); - orderStatus = succeedOrThrow( - await merchantApi.getOrderDetails(undefined, orderId), - ); - - t.assertTrue(orderStatus.order_status === "claimed"); + orderStatus = succeedOrThrow( + await merchantApi.getOrderDetails(undefined, orderId), + ); + } } runWalletTokensTest.suites = ["merchant", "wallet"];