commit fb5b0be16750f7c5a11778a82ebb638938314100
parent 8dbf7d74d69703049bdcfd754a698f79165e93fd
Author: Florian Dold <florian@dold.me>
Date: Mon, 25 Aug 2025 01:58:59 +0200
harness: add test for merchant account selection
Diffstat:
2 files changed, 203 insertions(+), 0 deletions(-)
diff --git a/packages/taler-harness/src/integrationtests/test-merchant-acctsel.ts b/packages/taler-harness/src/integrationtests/test-merchant-acctsel.ts
@@ -0,0 +1,201 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 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 {
+ Duration,
+ j2s,
+ succeedOrThrow,
+ TalerMerchantInstanceHttpClient,
+} from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import { defaultCoinConfig } from "../harness/denomStructures.js";
+import { createWalletDaemonWithClient } from "../harness/environments.js";
+import {
+ ExchangeService,
+ GlobalTestState,
+ MerchantService,
+ setupDb,
+} from "../harness/harness.js";
+
+export async function runMerchantAcctselTest(t: GlobalTestState) {
+ // Set up test environment
+
+ const db = await setupDb(t);
+
+ const { walletClient } = await createWalletDaemonWithClient(t, {
+ name: "wallet",
+ });
+
+ const exchange1 = ExchangeService.create(t, {
+ name: "testexchange-1",
+ currency: "TESTKUDOS",
+ httpPort: 8081,
+ database: db.connStr,
+ });
+
+ exchange1.addCoinConfigList(defaultCoinConfig.map((x) => x("TESTKUDOS")));
+
+ const paytoXtb =
+ "payto://x-taler-bank/localhost/exchange?receiver-name=exchange";
+
+ const paytoIban =
+ "payto://iban/DE76500202009817493529?receiver-name=exchange";
+
+ await exchange1.addBankAccount("1", {
+ accountPaytoUri: paytoXtb,
+ wireGatewayApiBaseUrl: "http://localhost:8082/",
+ wireGatewayAuth: {
+ password: "test",
+ username: "test",
+ },
+ });
+
+ const exchange2 = ExchangeService.create(t, {
+ name: "testexchange-2",
+ currency: "TESTKUDOS",
+ httpPort: 8181,
+ database: db.connStr,
+ });
+
+ await exchange2.addBankAccount("1", {
+ accountPaytoUri: paytoIban,
+ wireGatewayApiBaseUrl: "http://localhost:8082/",
+ wireGatewayAuth: {
+ password: "test",
+ username: "test",
+ },
+ });
+
+ exchange2.addCoinConfigList(defaultCoinConfig.map((x) => x("TESTKUDOS")));
+
+ const merchant = await MerchantService.create(t, {
+ name: "testmerchant-1",
+ httpPort: 8083,
+ database: db.connStr,
+ });
+
+ merchant.addExchange(exchange1);
+ merchant.addExchange(exchange2);
+
+ await exchange1.start();
+ await exchange2.start();
+
+ await merchant.start();
+ await merchant.pingUntilAvailable();
+
+ const { accessToken: adminAccessToken } =
+ await merchant.addInstanceWithWireAccount({
+ id: "admin",
+ name: "Default Instance",
+ paytoUris: [paytoIban, paytoXtb],
+ defaultWireTransferDelay: Duration.toTalerProtocolDuration(
+ Duration.fromSpec({ minutes: 1 }),
+ ),
+ });
+
+ const merchApi = new TalerMerchantInstanceHttpClient(
+ merchant.makeInstanceBaseUrl(),
+ );
+
+ {
+ const ordResp1 = succeedOrThrow(
+ await merchApi.createOrder(adminAccessToken, {
+ payment_target: "iban",
+ order: {
+ amount: "TESTKUDOS:5",
+ summary: "Test!",
+ },
+ }),
+ );
+
+ console.log(j2s(ordResp1));
+
+ const ordDet1 = succeedOrThrow(
+ await merchApi.getOrderDetails(adminAccessToken, ordResp1.order_id),
+ );
+
+ t.assertDeepEqual(ordDet1.order_status, "unpaid");
+
+ await walletClient.call(WalletApiOperation.PreparePayForUri, {
+ talerPayUri: ordDet1.taler_pay_uri,
+ });
+
+ const ordDet2 = succeedOrThrow(
+ await merchApi.getOrderDetails(adminAccessToken, ordResp1.order_id),
+ );
+
+ console.log(j2s(ordDet2));
+
+ t.assertDeepEqual(ordDet2.order_status, "claimed");
+
+ const numExch1 = ordDet2.contract_terms.exchanges.filter(
+ (x) => x.url === exchange1.baseUrl,
+ ).length;
+ const numExch2 = ordDet2.contract_terms.exchanges.filter(
+ (x) => x.url === exchange2.baseUrl,
+ ).length;
+
+ t.assertDeepEqual(numExch1, 0);
+ t.assertDeepEqual(numExch2, 1);
+ }
+
+ {
+ const ordResp1 = succeedOrThrow(
+ await merchApi.createOrder(adminAccessToken, {
+ payment_target: "x-taler-bank",
+ order: {
+ amount: "TESTKUDOS:5",
+ summary: "Test!",
+ },
+ }),
+ );
+
+ console.log(j2s(ordResp1));
+
+ const ordDet1 = succeedOrThrow(
+ await merchApi.getOrderDetails(adminAccessToken, ordResp1.order_id),
+ );
+
+ t.assertDeepEqual(ordDet1.order_status, "unpaid");
+
+ await walletClient.call(WalletApiOperation.PreparePayForUri, {
+ talerPayUri: ordDet1.taler_pay_uri,
+ });
+
+ const ordDet2 = succeedOrThrow(
+ await merchApi.getOrderDetails(adminAccessToken, ordResp1.order_id),
+ );
+
+ console.log(j2s(ordDet2));
+
+ t.assertDeepEqual(ordDet2.order_status, "claimed");
+
+ const numExch1 = ordDet2.contract_terms.exchanges.filter(
+ (x) => x.url === exchange1.baseUrl,
+ ).length;
+ const numExch2 = ordDet2.contract_terms.exchanges.filter(
+ (x) => x.url === exchange2.baseUrl,
+ ).length;
+
+ t.assertDeepEqual(numExch1, 1);
+ t.assertDeepEqual(numExch2, 0);
+ }
+}
+
+runMerchantAcctselTest.suites = ["merchant"];
diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts
@@ -93,6 +93,7 @@ import { runKycTwoFormsTest } from "./test-kyc-two-forms.js";
import { runKycWalletDepositAbortTest } from "./test-kyc-wallet-deposit-abort.js";
import { runKycWithdrawalVerbotenTest } from "./test-kyc-withdrawal-verboten.js";
import { runLibeufinBankTest } from "./test-libeufin-bank.js";
+import { runMerchantAcctselTest } from "./test-merchant-acctsel.js";
import { runMerchantCategoriesTest } from "./test-merchant-categories.js";
import { runMerchantExchangeConfusionTest } from "./test-merchant-exchange-confusion.js";
import { runMerchantInstancesDeleteTest } from "./test-merchant-instances-delete.js";
@@ -371,6 +372,7 @@ const allTests: TestMainFunction[] = [
runKycFormCompressionTest,
runDepositLargeTest,
runDepositTooLargeTest,
+ runMerchantAcctselTest,
];
export interface TestRunSpec {