diff options
Diffstat (limited to 'packages/taler-harness/src/integrationtests/test-payment-share.ts')
-rw-r--r-- | packages/taler-harness/src/integrationtests/test-payment-share.ts | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/packages/taler-harness/src/integrationtests/test-payment-share.ts b/packages/taler-harness/src/integrationtests/test-payment-share.ts new file mode 100644 index 000000000..141faa81e --- /dev/null +++ b/packages/taler-harness/src/integrationtests/test-payment-share.ts @@ -0,0 +1,308 @@ +/* + This file is part of GNU Taler + (C) 2020 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * Imports. + */ +import { + ConfirmPayResultType, + MerchantApiClient, + NotificationType, + PreparePayResultType, + j2s, +} from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { GlobalTestState } from "../harness/harness.js"; +import { + createSimpleTestkudosEnvironmentV2, + createWalletDaemonWithClient, + withdrawViaBankV2, +} from "../harness/helpers.js"; + +/** + * Run test for basic, bank-integrated withdrawal and payment. + */ +export async function runPaymentShareTest(t: GlobalTestState) { + // Set up test environment + const { + walletClient: firstWallet, + bank, + exchange, + merchant, + } = await createSimpleTestkudosEnvironmentV2(t); + + const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); + + // Withdraw digital cash into the wallet. + await withdrawViaBankV2(t, { + walletClient: firstWallet, + bank, + exchange, + amount: "TESTKUDOS:20", + }); + await firstWallet.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); + + const { walletClient: secondWallet } = await createWalletDaemonWithClient(t, { + name: "wallet2", + }); + + await withdrawViaBankV2(t, { + walletClient: secondWallet, + bank, + exchange, + amount: "TESTKUDOS:20", + }); + await secondWallet.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); + + { + const first = await firstWallet.call(WalletApiOperation.GetBalances, {}); + const second = await secondWallet.call(WalletApiOperation.GetBalances, {}); + t.assertAmountEquals(first.balances[0].available, "TESTKUDOS:19.53"); + t.assertAmountEquals(second.balances[0].available, "TESTKUDOS:19.53"); + } + + t.logStep("setup-done"); + + // create two orders to pay + async function createOrder(amount: string) { + const order = { + summary: "Buy me!", + amount, + fulfillment_url: "taler://fulfillment-success/thx", + }; + + const args = { order }; + + const orderResp = await merchantClient.createOrder({ + order: args.order, + }); + + const orderStatus = await merchantClient.queryPrivateOrderStatus({ + orderId: orderResp.order_id, + }); + + t.assertTrue(orderStatus.order_status === "unpaid"); + return { id: orderResp.order_id, uri: orderStatus.taler_pay_uri }; + } + + t.logStep("orders-created"); + + /** + * Case 1: + * - Claim with first wallet and pay in the second wallet. + * - First wallet should be notified. + */ + { + const order = await createOrder("TESTKUDOS:5"); + // Claim the order with the first wallet + const claimFirstWallet = await firstWallet.call( + WalletApiOperation.PreparePayForUri, + { talerPayUri: order.uri }, + ); + + t.assertTrue( + claimFirstWallet.status === PreparePayResultType.PaymentPossible, + ); + + t.logStep("w1-payment-possible"); + + // share order from the first wallet + const { privatePayUri } = await firstWallet.call( + WalletApiOperation.SharePayment, + { + merchantBaseUrl: merchant.makeInstanceBaseUrl(), + orderId: order.id, + }, + ); + + t.logStep("w1-payment-shared"); + + // claim from the second wallet + const claimSecondWallet = await secondWallet.call( + WalletApiOperation.PreparePayForUri, + { talerPayUri: privatePayUri }, + ); + + t.assertTrue( + claimSecondWallet.status === PreparePayResultType.PaymentPossible, + ); + + t.logStep("w2-claimed"); + + // pay from the second wallet + const r2 = await secondWallet.call(WalletApiOperation.ConfirmPay, { + transactionId: claimSecondWallet.transactionId, + }); + + t.assertTrue(r2.type === ConfirmPayResultType.Done); + + t.logStep("w2-confirmed"); + + // Wait for refresh to settle before we do checks + await secondWallet.call( + WalletApiOperation.TestingWaitTransactionsFinal, + {}, + ); + + t.logStep("w2-refresh-settled"); + + { + const first = await firstWallet.call(WalletApiOperation.GetBalances, {}); + const second = await secondWallet.call( + WalletApiOperation.GetBalances, + {}, + ); + t.assertAmountEquals(first.balances[0].available, "TESTKUDOS:19.53"); + t.assertAmountEquals(second.balances[0].available, "TESTKUDOS:14.23"); + } + + t.logStep("wait-for-payment"); + // firstWallet.waitForNotificationCond(n => + // n.type === NotificationType.TransactionStateTransition && + // n.transactionId === claimFirstWallet.transactionId + // ) + // Claim the order with the first wallet + const claimFirstWalletAgain = await firstWallet.call( + WalletApiOperation.PreparePayForUri, + { talerPayUri: order.uri }, + ); + + t.assertTrue( + claimFirstWalletAgain.status === PreparePayResultType.AlreadyConfirmed, + ); + t.assertTrue( claimFirstWalletAgain.paid ); + + t.logStep("w1-prepared-again"); + + const r1 = await firstWallet.call(WalletApiOperation.ConfirmPay, { + transactionId: claimFirstWallet.transactionId, + }); + + //t.assertTrue(r1.type === ConfirmPayResultType.Pending); + + t.logStep("w1-confirmed-shared"); + + await firstWallet.call( + WalletApiOperation.TestingWaitTransactionsFinal, + {}, + ); + + await secondWallet.call( + WalletApiOperation.TestingWaitTransactionsFinal, + {}, + ); + + /** + * only the second wallet balance was affected + */ + { + const first = await firstWallet.call(WalletApiOperation.GetBalances, {}); + const second = await secondWallet.call( + WalletApiOperation.GetBalances, + {}, + ); + t.assertAmountEquals(first.balances[0].available, "TESTKUDOS:19.53"); + t.assertAmountEquals(second.balances[0].available, "TESTKUDOS:14.23"); + } + } + + t.logStep("first-case-done"); + + /** + * Case 2: + * - Claim with first wallet and share with the second wallet + * - Pay with the first wallet, second wallet should be notified + */ + { + const order = await createOrder("TESTKUDOS:3"); + // Claim the order with the first wallet + const claimFirstWallet = await firstWallet.call( + WalletApiOperation.PreparePayForUri, + { talerPayUri: order.uri }, + ); + + t.assertTrue( + claimFirstWallet.status === PreparePayResultType.PaymentPossible, + ); + + t.logStep("case2-w1-claimed"); + + // share order from the first wallet + const { privatePayUri } = await firstWallet.call( + WalletApiOperation.SharePayment, + { + merchantBaseUrl: merchant.makeInstanceBaseUrl(), + orderId: order.id, + }, + ); + + t.logStep("case2-w1-shared"); + + // claim from the second wallet + const claimSecondWallet = await secondWallet.call( + WalletApiOperation.PreparePayForUri, + { talerPayUri: privatePayUri }, + ); + + t.logStep("case2-w2-prepared"); + + t.assertTrue( + claimSecondWallet.status === PreparePayResultType.PaymentPossible, + ); + + // pay from the first wallet + const r2 = await firstWallet.call(WalletApiOperation.ConfirmPay, { + transactionId: claimFirstWallet.transactionId, + }); + + t.assertTrue(r2.type === ConfirmPayResultType.Done); + + // Wait for refreshes to settle before doing checks + await firstWallet.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); + + /** + * only the first wallet balance was affected + */ + const bal1 = await firstWallet.call(WalletApiOperation.GetBalances, {}); + const bal2 = await secondWallet.call(WalletApiOperation.GetBalances, {}); + t.assertAmountEquals(bal1.balances[0].available, "TESTKUDOS:16.18"); + t.assertAmountEquals(bal2.balances[0].available, "TESTKUDOS:14.23"); + + t.logStep("wait-for-payment"); + // secondWallet.waitForNotificationCond(n => + // n.type === NotificationType.TransactionStateTransition && + // n.transactionId === claimSecondWallet.transactionId + // ) + + // Claim the order with the first wallet + const claimSecondWalletAgain = await secondWallet.call( + WalletApiOperation.PreparePayForUri, + { talerPayUri: order.uri }, + ); + + t.assertTrue( + claimSecondWalletAgain.status === PreparePayResultType.AlreadyConfirmed, + ); + t.assertTrue( + claimSecondWalletAgain.paid, + ); + + } + + t.logStep("second-case-done"); +} + +runPaymentShareTest.suites = ["wallet"]; |