commit 78ac0beae5ca9d1b91aee388ac7de744fe37644d
parent 119c423765650e10263ce8462e9fbbffd6506eb1
Author: Florian Dold <florian@dold.me>
Date: Mon, 23 Feb 2026 20:10:34 +0100
harness: test for ToS acceptance
Diffstat:
3 files changed, 128 insertions(+), 0 deletions(-)
diff --git a/packages/taler-harness/src/integrationtests/test-tops-merchant-tos.ts b/packages/taler-harness/src/integrationtests/test-tops-merchant-tos.ts
@@ -0,0 +1,123 @@
+/*
+ This file is part of GNU Taler
+ (C) 2025 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 {
+ j2s,
+ Logger,
+ MerchantAccountKycStatus,
+ succeedOrThrow,
+ TalerExchangeHttpClient,
+ TalerMerchantInstanceHttpClient,
+} from "@gnu-taler/taler-util";
+import { GlobalTestState, harnessHttpLib } from "../harness/harness.js";
+import { createTopsEnvironment, doTopsKycAuth } from "../harness/tops.js";
+
+export const logger = new Logger("test-tops-aml.ts");
+
+/**
+ * Test for ToS acceptance by the merchant.
+ * In particular, we test that long-polling works and
+ * we do not manually have to run taler-merchant-kyccheck with the -t option.
+ */
+export async function runTopsMerchantTosTest(t: GlobalTestState) {
+ // Set up test environment
+ const {
+ exchange,
+ officerAcc,
+ merchant,
+ exchangeBankAccount,
+ wireGatewayApi,
+ merchantAdminAccessToken,
+ bank,
+ } = await createTopsEnvironment(t);
+
+ const merchantClient = new TalerMerchantInstanceHttpClient(
+ merchant.makeInstanceBaseUrl(),
+ );
+ const exchangeClient = new TalerExchangeHttpClient(exchange.baseUrl, {
+ httpClient: harnessHttpLib,
+ });
+
+ // Do KYC auth transfer
+ const { accessToken } = await doTopsKycAuth(t, {
+ merchantClient,
+ exchangeBankAccount,
+ wireGatewayApi,
+ merchantAdminAccessToken,
+ bank,
+ });
+
+ {
+ const kycInfo = await exchangeClient.checkKycInfo(
+ accessToken,
+ undefined,
+ undefined,
+ );
+ console.log(j2s(kycInfo));
+
+ t.assertDeepEqual(kycInfo.case, "ok");
+ t.assertDeepEqual(kycInfo.body.requirements.length, 1);
+ t.assertDeepEqual(kycInfo.body.requirements[0].form, "accept-tos");
+ const requirementId = kycInfo.body.requirements[0].id;
+ t.assertTrue(typeof requirementId === "string");
+
+ const uploadRes = await exchangeClient.uploadKycForm(requirementId, {
+ FORM_ID: "accept-tos",
+ FORM_VERSION: 1,
+ ACCEPTED_TERMS_OF_SERVICE: "v1",
+ DOWNLOADED_TERMS_OF_SERVICE: true,
+ });
+ console.log("upload res", uploadRes);
+ t.assertDeepEqual(uploadRes.case, "ok");
+ }
+
+ {
+ const kycInfo = await exchangeClient.checkKycInfo(
+ accessToken,
+ undefined,
+ undefined,
+ );
+ console.log(j2s(kycInfo));
+ }
+
+ {
+ const kycStatus = succeedOrThrow(
+ await merchantClient.getCurrentInstanceKycStatus(
+ merchantAdminAccessToken,
+ {
+ exchangeURL: exchange.baseUrl,
+ longpoll: {
+ type: "state-enter",
+ status: MerchantAccountKycStatus.READY,
+ timeout: 10000,
+ },
+ },
+ ),
+ );
+ logger.info(`kyc status after accept-tos: ${j2s(kycStatus)}`);
+ t.assertDeepEqual(kycStatus.kycRequired, true);
+ const myRow = kycStatus.kyc_data.find(
+ (x) => x.exchange_url === exchange.baseUrl,
+ );
+ t.assertTrue(myRow != null);
+ t.assertDeepEqual(myRow.status, MerchantAccountKycStatus.READY);
+ }
+}
+
+runTopsMerchantTosTest.suites = ["wallet"];
diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts
@@ -164,6 +164,7 @@ import { runTopsAmlLegiTest } from "./test-tops-aml-legi.js";
import { runTopsAmlMeasuresTest } from "./test-tops-aml-measures.js";
import { runTopsAmlPdfTest } from "./test-tops-aml-pdf.js";
import { runTopsChallengerTwiceTest } from "./test-tops-challenger-twice.js";
+import { runTopsMerchantTosTest } from "./test-tops-merchant-tos.js";
import { runTopsPeerTest } from "./test-tops-peer.js";
import { runTermOfServiceFormatTest } from "./test-tos-format.js";
import { runUtilMerchantClientTest } from "./test-util-merchant-client.js";
@@ -425,6 +426,7 @@ const allTests: TestMainFunction[] = [
runMerchantReportsTest,
runExchangeMerchantKycAuthTest,
runMerchantKycAuthMultiTest,
+ runTopsMerchantTosTest,
];
export interface TestRunSpec {
diff --git a/packages/taler-util/src/types-taler-merchant.ts b/packages/taler-util/src/types-taler-merchant.ts
@@ -1445,16 +1445,19 @@ export type KycEtag = string;
export type KycLongPollingReasonWaitForStateEnter = {
type: "state-enter";
status: MerchantAccountKycStatus;
+ // FIXME: Unit!
timeout: number;
};
export type KycLongPollingReasonWaitForStateExit = {
type: "state-exit";
status: MerchantAccountKycStatus;
+ // FIXME: Unit!
timeout: number;
};
export type KycLongPollingReasonWaitForStateChange = {
type: "state-change";
etag: KycEtag;
+ // FIXME: Unit!
timeout: number;
};