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:
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"];