aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-webextension')
-rw-r--r--packages/taler-wallet-webextension/package.json2
-rw-r--r--packages/taler-wallet-webextension/src/components/PendingTransactions.tsx13
-rw-r--r--packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx13
-rw-r--r--packages/taler-wallet-webextension/src/components/TermsOfService/index.ts4
-rw-r--r--packages/taler-wallet-webextension/src/components/TermsOfService/state.ts18
-rw-r--r--packages/taler-wallet-webextension/src/cta/Deposit/index.ts2
-rw-r--r--packages/taler-wallet-webextension/src/cta/Deposit/state.ts19
-rw-r--r--packages/taler-wallet-webextension/src/cta/Deposit/test.ts89
-rw-r--r--packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts2
-rw-r--r--packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts8
-rw-r--r--packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts4
-rw-r--r--packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts32
-rw-r--r--packages/taler-wallet-webextension/src/cta/Payment/index.ts13
-rw-r--r--packages/taler-wallet-webextension/src/cta/Payment/state.ts32
-rw-r--r--packages/taler-wallet-webextension/src/cta/Payment/test.ts577
-rw-r--r--packages/taler-wallet-webextension/src/cta/Recovery/index.ts3
-rw-r--r--packages/taler-wallet-webextension/src/cta/Recovery/state.ts5
-rw-r--r--packages/taler-wallet-webextension/src/cta/Refund/index.ts4
-rw-r--r--packages/taler-wallet-webextension/src/cta/Refund/state.ts18
-rw-r--r--packages/taler-wallet-webextension/src/cta/Refund/test.ts389
-rw-r--r--packages/taler-wallet-webextension/src/cta/Tip/index.ts4
-rw-r--r--packages/taler-wallet-webextension/src/cta/Tip/state.ts17
-rw-r--r--packages/taler-wallet-webextension/src/cta/Tip/test.ts163
-rw-r--r--packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts2
-rw-r--r--packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts6
-rw-r--r--packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts4
-rw-r--r--packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts11
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw/index.ts6
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw/state.ts41
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw/test.ts258
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts3
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useAutoOpenPermissions.ts14
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useBackupDeviceName.ts7
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useClipboardPermissions.ts12
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useDiagnostics.ts4
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useProviderStatus.ts14
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useTalerActionURL.test.ts12
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useWalletDevMode.ts6
-rw-r--r--packages/taler-wallet-webextension/src/popup/BalancePage.tsx19
-rw-r--r--packages/taler-wallet-webextension/src/test-utils.ts164
-rw-r--r--packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts10
-rw-r--r--packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts21
-rw-r--r--packages/taler-wallet-webextension/src/wallet/BackupPage.tsx26
-rw-r--r--packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.test.ts66
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts21
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts40
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts498
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx7
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx34
-rw-r--r--packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/index.ts4
-rw-r--r--packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/state.ts2
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx9
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts7
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts12
-rw-r--r--packages/taler-wallet-webextension/src/wallet/History.tsx13
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx23
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx5
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx24
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Settings.tsx6
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Transaction.tsx59
-rw-r--r--packages/taler-wallet-webextension/src/wxApi.ts499
61 files changed, 1515 insertions, 1885 deletions
diff --git a/packages/taler-wallet-webextension/package.json b/packages/taler-wallet-webextension/package.json
index 75c96a17b..f0863df84 100644
--- a/packages/taler-wallet-webextension/package.json
+++ b/packages/taler-wallet-webextension/package.json
@@ -9,7 +9,7 @@
"private": false,
"scripts": {
"clean": "rimraf dist lib tsconfig.tsbuildinfo",
- "test": "pnpm compile && mocha --enable-source-maps 'dist/**/*.test.js' 'dist/**/test.js'",
+ "test": "pnpm compile && mocha 'dist/**/*.test.js' 'dist/**/test.js'",
"test:coverage": "nyc pnpm test",
"compile": "tsc && ./build-fast-with-linaria.mjs",
"prepare": "pnpm compile",
diff --git a/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx b/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx
index e9688da21..5d5dae092 100644
--- a/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx
+++ b/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx
@@ -19,13 +19,14 @@ import {
NotificationType,
Transaction,
} from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { Fragment, h, JSX, VNode } from "preact";
import { useEffect } from "preact/hooks";
import { useTranslationContext } from "../context/translation.js";
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
import { Avatar } from "../mui/Avatar.js";
import { Typography } from "../mui/Typography.js";
-import * as wxApi from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
import Banner from "./Banner.js";
import { Time } from "./Time.js";
@@ -34,14 +35,14 @@ interface Props extends JSX.HTMLAttributes {
}
export function PendingTransactions({ goToTransaction }: Props): VNode {
- const state = useAsyncAsHook(wxApi.getTransactions);
+ const state = useAsyncAsHook(() =>
+ wxApi.wallet.call(WalletApiOperation.GetTransactions, {}),
+ );
useEffect(() => {
- return wxApi.onUpdateNotification(
+ return wxApi.listener.onUpdateNotification(
[NotificationType.WithdrawGroupFinished],
- () => {
- state?.retry();
- },
+ state?.retry,
);
});
diff --git a/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx
index 7c1d2c6fc..6461f76e3 100644
--- a/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx
+++ b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx
@@ -14,7 +14,10 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import { AbsoluteTime, Duration, Location } from "@gnu-taler/taler-util";
-import { WalletContractData } from "@gnu-taler/taler-wallet-core";
+import {
+ WalletApiOperation,
+ WalletContractData,
+} from "@gnu-taler/taler-wallet-core";
import { styled } from "@linaria/react";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
@@ -26,9 +29,9 @@ import { useTranslationContext } from "../context/translation.js";
import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
import { ButtonHandler } from "../mui/handlers.js";
import { compose, StateViewMap } from "../utils/index.js";
-import * as wxApi from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
import { Amount } from "./Amount.js";
-import { Link, LinkPrimary } from "./styled/index.js";
+import { Link } from "./styled/index.js";
const ContractTermsTable = styled.table`
width: 100%;
@@ -99,7 +102,9 @@ function useComponentState({ proposalId }: Props, api: typeof wxApi): State {
const [show, setShow] = useState(false);
const hook = useAsyncAsHook(async () => {
if (!show) return undefined;
- return await api.getContractTermsDetails(proposalId);
+ return await api.wallet.call(WalletApiOperation.GetContractTermsDetails, {
+ proposalId,
+ });
}, [show]);
const hideHandler = {
diff --git a/packages/taler-wallet-webextension/src/components/TermsOfService/index.ts b/packages/taler-wallet-webextension/src/components/TermsOfService/index.ts
index 2c77e5d3c..79778a595 100644
--- a/packages/taler-wallet-webextension/src/components/TermsOfService/index.ts
+++ b/packages/taler-wallet-webextension/src/components/TermsOfService/index.ts
@@ -18,7 +18,7 @@ import { Loading } from "../../components/Loading.js";
import { HookError } from "../../hooks/useAsyncAsHook.js";
import { ToggleHandler } from "../../mui/handlers.js";
import { compose, StateViewMap } from "../../utils/index.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { useComponentState } from "./state.js";
import { TermsState } from "./utils.js";
import {
@@ -26,7 +26,7 @@ import {
LoadingUriView,
ShowButtonsAcceptedTosView,
ShowButtonsNonAcceptedTosView,
- ShowTosContentView,
+ ShowTosContentView
} from "./views.js";
export interface Props {
diff --git a/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts b/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts
index 30322e139..3cad967ae 100644
--- a/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts
+++ b/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts
@@ -14,9 +14,10 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useState } from "preact/hooks";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
import { buildTermsOfServiceState } from "./utils.js";
@@ -34,7 +35,10 @@ export function useComponentState(
* For the exchange selected, bring the status of the terms of service
*/
const terms = useAsyncAsHook(async () => {
- const exchangeTos = await api.getExchangeTos(exchangeUrl, ["text/xml"]);
+ const exchangeTos = await api.wallet.call(WalletApiOperation.GetExchangeTos, {
+ exchangeBaseUrl: exchangeUrl,
+ acceptedFormat: ["text/xml"]
+ })
const state = buildTermsOfServiceState(exchangeTos);
@@ -72,10 +76,16 @@ export function useComponentState(
try {
if (accepted) {
- await api.setExchangeTosAccepted(exchangeUrl, state.version);
+ api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
+ exchangeBaseUrl: exchangeUrl,
+ etag: state.version
+ })
} else {
// mark as not accepted
- await api.setExchangeTosAccepted(exchangeUrl, undefined);
+ api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
+ exchangeBaseUrl: exchangeUrl,
+ etag: undefined
+ })
}
// setAccepted(accepted);
if (!readOnly) onChange(accepted); //external update
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/index.ts b/packages/taler-wallet-webextension/src/cta/Deposit/index.ts
index 0246b6f7c..539709821 100644
--- a/packages/taler-wallet-webextension/src/cta/Deposit/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/index.ts
@@ -19,7 +19,7 @@ import { Loading } from "../../components/Loading.js";
import { HookError } from "../../hooks/useAsyncAsHook.js";
import { ButtonHandler } from "../../mui/handlers.js";
import { compose, StateViewMap } from "../../utils/index.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { useComponentState } from "./state.js";
import { LoadingUriView, ReadyView } from "./views.js";
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/state.ts b/packages/taler-wallet-webextension/src/cta/Deposit/state.ts
index 5662a24c8..ba7bd147b 100644
--- a/packages/taler-wallet-webextension/src/cta/Deposit/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/state.ts
@@ -14,10 +14,10 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { Amounts, CreateDepositGroupResponse } from "@gnu-taler/taler-util";
-import { useState } from "preact/hooks";
+import { Amounts } from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
export function useComponentState(
@@ -29,10 +29,10 @@ export function useComponentState(
if (!amountStr) throw Error("ERROR_NO-AMOUNT-FOR-DEPOSIT");
const amount = Amounts.parse(amountStr);
if (!amount) throw Error("ERROR_INVALID-AMOUNT-FOR-DEPOSIT");
- const deposit = await api.prepareDeposit(
- talerDepositUri,
- Amounts.stringify(amount),
- );
+ const deposit = await api.wallet.call(WalletApiOperation.PrepareDeposit, {
+ amount: Amounts.stringify(amount),
+ depositPaytoUri: talerDepositUri,
+ });
return { deposit, uri: talerDepositUri, amount };
});
@@ -46,7 +46,10 @@ export function useComponentState(
const { deposit, uri, amount } = info.response;
async function doDeposit(): Promise<void> {
- const resp = await api.createDepositGroup(uri, Amounts.stringify(amount));
+ const resp = await api.wallet.call(WalletApiOperation.CreateDepositGroup, {
+ amount: Amounts.stringify(amount),
+ depositPaytoUri: uri,
+ });
onSuccess(resp.transactionId);
}
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/test.ts b/packages/taler-wallet-webextension/src/cta/Deposit/test.ts
index b6e63a796..f628b3287 100644
--- a/packages/taler-wallet-webextension/src/cta/Deposit/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/test.ts
@@ -19,43 +19,40 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { Amounts, PrepareDepositResponse } from "@gnu-taler/taler-util";
+import { Amounts } from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { expect } from "chai";
import { mountHook } from "../../test-utils.js";
+import { createWalletApiMock } from "../../test-utils.js";
import { useComponentState } from "./state.js";
describe("Deposit CTA states", () => {
it("should tell the user that the URI is missing", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerDepositUri: undefined,
+ amountStr: undefined,
+ cancel: async () => {
+ null;
+ },
+ onSuccess: async () => {
+ null;
+ },
+ }
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
- useComponentState(
- {
- talerDepositUri: undefined,
- amountStr: undefined,
- cancel: async () => {
- null;
- },
- onSuccess: async () => {
- null;
- },
- },
- {
- prepareRefund: async () => ({}),
- applyRefund: async () => ({}),
- onUpdateNotification: async () => ({}),
- } as any,
- ),
+ useComponentState(props, mock),
);
{
- const { status } = getLastResultOrThrow();
+ const { status } = pullLastResultOrThrow();
expect(status).equals("loading");
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading-uri");
@@ -64,44 +61,41 @@ describe("Deposit CTA states", () => {
if (error.operational) expect.fail();
expect(error.message).eq("ERROR_NO-URI-FOR-DEPOSIT");
}
-
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should be ready after loading", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ handler.addWalletCallResponse(WalletApiOperation.PrepareDeposit, undefined, {
+ effectiveDepositAmount: Amounts.parseOrThrow("EUR:1"),
+ totalDepositCost: Amounts.parseOrThrow("EUR:1.2"),
+ });
+ const props = {
+ talerDepositUri: "payto://refund/asdasdas",
+ amountStr: "EUR:1",
+ cancel: async () => {
+ null;
+ },
+ onSuccess: async () => {
+ null;
+ },
+ }
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
- useComponentState(
- {
- talerDepositUri: "payto://refund/asdasdas",
- amountStr: "EUR:1",
- cancel: async () => {
- null;
- },
- onSuccess: async () => {
- null;
- },
- },
- {
- prepareDeposit: async () =>
- ({
- effectiveDepositAmount: Amounts.parseOrThrow("EUR:1"),
- totalDepositCost: Amounts.parseOrThrow("EUR:1.2"),
- } as PrepareDepositResponse as any),
- createDepositGroup: async () => ({}),
- } as any,
- ),
+ useComponentState(props, mock),
);
{
- const { status } = getLastResultOrThrow();
+ const { status } = pullLastResultOrThrow();
expect(status).equals("loading");
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const state = getLastResultOrThrow();
+ const state = pullLastResultOrThrow();
if (state.status !== "ready") expect.fail();
if (state.error) expect.fail();
@@ -112,5 +106,6 @@ describe("Deposit CTA states", () => {
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty");
});
});
diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts
index ff04a8247..0389a17fb 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts
@@ -22,7 +22,7 @@ import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js";
import { compose, StateViewMap } from "../../utils/index.js";
import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js";
import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { useComponentState } from "./state.js";
import { LoadingUriView, ReadyView } from "./views.js";
diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
index 205a664e0..d845e121a 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
@@ -16,11 +16,11 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { Amounts, TalerErrorDetail } from "@gnu-taler/taler-util";
-import { TalerError } from "@gnu-taler/taler-wallet-core";
+import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useState } from "preact/hooks";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
@@ -31,7 +31,7 @@ export function useComponentState(
): RecursiveState<State> {
const amount = Amounts.parseOrThrow(amountStr);
- const hook = useAsyncAsHook(api.listExchanges);
+ const hook = useAsyncAsHook(() => api.wallet.call(WalletApiOperation.ListExchanges, {}));
if (!hook) {
return {
@@ -69,7 +69,7 @@ export function useComponentState(
async function accept(): Promise<void> {
try {
- const resp = await api.initiatePeerPullPayment({
+ const resp = await api.wallet.call(WalletApiOperation.InitiatePeerPullPayment, {
amount: Amounts.stringify(amount),
exchangeBaseUrl: exchange.exchangeBaseUrl,
partialContractTerms: {
diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts b/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts
index 7c6f13286..693803587 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts
@@ -18,13 +18,13 @@ import {
AbsoluteTime,
AmountJson,
PreparePayResult,
- TalerErrorDetail,
+ TalerErrorDetail
} from "@gnu-taler/taler-util";
import { Loading } from "../../components/Loading.js";
import { HookError } from "../../hooks/useAsyncAsHook.js";
import { ButtonHandler } from "../../mui/handlers.js";
import { compose, StateViewMap } from "../../utils/index.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { useComponentState } from "./state.js";
import { LoadingUriView, ReadyView } from "./views.js";
diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts b/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts
index c88e80602..457827127 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts
@@ -21,12 +21,12 @@ import {
PreparePayResult,
PreparePayResultType,
TalerErrorDetail,
- TalerProtocolTimestamp,
+ TalerProtocolTimestamp
} from "@gnu-taler/taler-util";
-import { TalerError } from "@gnu-taler/taler-wallet-core";
+import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useEffect, useState } from "preact/hooks";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
export function useComponentState(
@@ -34,18 +34,17 @@ export function useComponentState(
api: typeof wxApi,
): State {
const hook = useAsyncAsHook(async () => {
- const p2p = await api.checkPeerPullPayment({
+ const p2p = await api.wallet.call(WalletApiOperation.CheckPeerPullPayment, {
talerUri: talerPayPullUri,
});
- const balance = await api.getBalance();
+ const balance = await api.wallet.call(WalletApiOperation.GetBalances, {});
return { p2p, balance };
});
- useEffect(() => {
- api.onUpdateNotification([NotificationType.CoinWithdrawn], () => {
- hook?.retry();
- });
- });
+ useEffect(() => api.listener.onUpdateNotification(
+ [NotificationType.CoinWithdrawn],
+ hook?.retry
+ ));
const [operationError, setOperationError] = useState<
TalerErrorDetail | undefined
@@ -64,10 +63,7 @@ export function useComponentState(
};
}
- // const { payStatus } = hook.response.p2p;
-
const {
- amount: purseAmount,
contractTerms,
peerPullPaymentIncomingId,
} = hook.response.p2p;
@@ -136,17 +132,9 @@ export function useComponentState(
};
}
- // if (payStatus.status === PreparePayResultType.AlreadyConfirmed) {
- // return {
- // status: "confirmed",
- // balance: foundAmount,
- // ...baseResult,
- // };
- // }
-
async function accept(): Promise<void> {
try {
- const resp = await api.acceptPeerPullPayment({
+ const resp = await api.wallet.call(WalletApiOperation.AcceptPeerPullPayment, {
peerPullPaymentIncomingId,
});
onSuccess(resp.transactionId);
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/index.ts b/packages/taler-wallet-webextension/src/cta/Payment/index.ts
index 8e446722e..b4e59e666 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Payment/index.ts
@@ -15,21 +15,16 @@
*/
import {
- AmountJson,
- ConfirmPayResult,
- PreparePayResult,
- PreparePayResultAlreadyConfirmed,
- PreparePayResultInsufficientBalance,
- PreparePayResultPaymentPossible,
+ AmountJson, PreparePayResult,
+ PreparePayResultAlreadyConfirmed, PreparePayResultPaymentPossible
} from "@gnu-taler/taler-util";
-import { TalerError } from "@gnu-taler/taler-wallet-core";
import { Loading } from "../../components/Loading.js";
import { HookError } from "../../hooks/useAsyncAsHook.js";
import { ButtonHandler } from "../../mui/handlers.js";
import { compose, StateViewMap } from "../../utils/index.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { useComponentState } from "./state.js";
-import { LoadingUriView, BaseView } from "./views.js";
+import { BaseView, LoadingUriView } from "./views.js";
export interface Props {
talerPayUri?: string;
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/state.ts b/packages/taler-wallet-webextension/src/cta/Payment/state.ts
index 8d388aa60..414bc2000 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Payment/state.ts
@@ -15,19 +15,16 @@
*/
import {
- AmountJson,
- Amounts,
- ConfirmPayResult,
- ConfirmPayResultType,
+ Amounts, ConfirmPayResultType,
NotificationType,
PreparePayResultType,
- TalerErrorCode,
+ TalerErrorCode
} from "@gnu-taler/taler-util";
-import { TalerError } from "@gnu-taler/taler-wallet-core";
+import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useEffect, useState } from "preact/hooks";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
import { ButtonHandler } from "../../mui/handlers.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
export function useComponentState(
@@ -38,16 +35,17 @@ export function useComponentState(
const hook = useAsyncAsHook(async () => {
if (!talerPayUri) throw Error("ERROR_NO-URI-FOR-PAYMENT");
- const payStatus = await api.preparePay(talerPayUri);
- const balance = await api.getBalance();
+ const payStatus = await api.wallet.call(WalletApiOperation.PreparePayForUri, {
+ talerPayUri: talerPayUri
+ });
+ const balance = await api.wallet.call(WalletApiOperation.GetBalances, {});
return { payStatus, balance, uri: talerPayUri };
- });
+ }, []);
- useEffect(() => {
- api.onUpdateNotification([NotificationType.CoinWithdrawn], () => {
- hook?.retry();
- });
- });
+ useEffect(() => api.listener.onUpdateNotification(
+ [NotificationType.CoinWithdrawn],
+ hook?.retry
+ ), [hook]);
const hookResponse = !hook || hook.hasError ? undefined : hook.response;
@@ -127,7 +125,9 @@ export function useComponentState(
hint: `payment is not possible: ${payStatus.status}`,
});
}
- const res = await api.confirmPay(payStatus.proposalId, undefined);
+ const res = await api.wallet.call(WalletApiOperation.ConfirmPay, {
+ proposalId: payStatus.proposalId,
+ });
// handle confirm pay
if (res.type !== ConfirmPayResultType.Done) {
throw TalerError.fromUncheckedDetail({
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/test.ts b/packages/taler-wallet-webextension/src/cta/Payment/test.ts
index f4ce5afb3..8aa099fdc 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Payment/test.ts
@@ -20,81 +20,44 @@
*/
import {
- AmountJson,
- Amounts,
- BalancesResponse,
- ConfirmPayResult,
+ Amounts, ConfirmPayResult,
ConfirmPayResultType,
- NotificationType,
- PreparePayResult,
- PreparePayResultType,
+ NotificationType, PreparePayResultInsufficientBalance,
+ PreparePayResultPaymentPossible,
+ PreparePayResultType
} from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { expect } from "chai";
-import { mountHook } from "../../test-utils.js";
+import { mountHook, nullFunction } from "../../test-utils.js";
+import { createWalletApiMock } from "../../test-utils.js";
import { useComponentState } from "./state.js";
-import * as wxApi from "../../wxApi.js";
-
-const nullFunction: any = () => null;
-type VoidFunction = () => void;
-
-type Subs = {
- [key in NotificationType]?: VoidFunction;
-};
-
-export class SubsHandler {
- private subs: Subs = {};
-
- constructor() {
- this.saveSubscription = this.saveSubscription.bind(this);
- }
-
- saveSubscription(
- messageTypes: NotificationType[],
- callback: VoidFunction,
- ): VoidFunction {
- messageTypes.forEach((m) => {
- this.subs[m] = callback;
- });
- return nullFunction;
- }
-
- notifyEvent(event: NotificationType): void {
- const cb = this.subs[event];
- if (cb === undefined)
- expect.fail(`Expected to have a subscription for ${event}`);
- cb();
- }
-}
describe("Payment CTA states", () => {
it("should tell the user that the URI is missing", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerPayUri: undefined,
+ cancel: nullFunction,
+ goToWalletManualWithdraw: nullFunction,
+ onSuccess: async () => {
+ null;
+ },
+ }
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
- useComponentState(
- {
- talerPayUri: undefined,
- cancel: nullFunction,
- goToWalletManualWithdraw: nullFunction,
- onSuccess: async () => {
- null;
- },
- },
- {
- onUpdateNotification: nullFunction,
- } as Partial<typeof wxApi> as any,
- ),
+ useComponentState(props, mock),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading-uri");
if (error === undefined) expect.fail();
@@ -103,324 +66,312 @@ describe("Payment CTA states", () => {
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should response with no balance", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerPayUri: "taller://pay",
+ cancel: nullFunction,
+ goToWalletManualWithdraw: nullFunction,
+ onSuccess: async () => {
+ null;
+ },
+ }
+
+ handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
+ status: PreparePayResultType.InsufficientBalance,
+ amountRaw: "USD:10",
+ } as PreparePayResultInsufficientBalance)
+ handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, { balances: [] })
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
- useComponentState(
- {
- talerPayUri: "taller://pay",
- cancel: nullFunction,
- goToWalletManualWithdraw: nullFunction,
- onSuccess: async () => {
- null;
- },
- },
- {
- onUpdateNotification: nullFunction,
- preparePay: async () =>
- ({
- amountRaw: "USD:10",
- status: PreparePayResultType.InsufficientBalance,
- } as Partial<PreparePayResult>),
- getBalance: async () =>
- ({
- balances: [],
- } as Partial<BalancesResponse>),
- } as Partial<typeof wxApi> as any,
- ),
+ useComponentState(props, mock),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const r = getLastResultOrThrow();
- if (r.status !== "no-balance-for-currency") expect.fail();
+ const r = pullLastResultOrThrow();
+ if (r.status !== "no-balance-for-currency") {
+ expect(r).eq({})
+ return;
+ }
expect(r.balance).undefined;
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:10"));
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should not be able to pay if there is no enough balance", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerPayUri: "taller://pay",
+ cancel: nullFunction,
+ goToWalletManualWithdraw: nullFunction,
+ onSuccess: async () => {
+ null;
+ },
+ }
+ handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
+ status: PreparePayResultType.InsufficientBalance,
+ amountRaw: "USD:10",
+ } as PreparePayResultInsufficientBalance)
+ handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
+ balances: [{
+ available: "USD:5",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ }]
+ })
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
- useComponentState(
- {
- talerPayUri: "taller://pay",
- cancel: nullFunction,
- goToWalletManualWithdraw: nullFunction,
- onSuccess: async () => {
- null;
- },
- },
- {
- onUpdateNotification: nullFunction,
- preparePay: async () =>
- ({
- amountRaw: "USD:10",
- status: PreparePayResultType.InsufficientBalance,
- } as Partial<PreparePayResult>),
- getBalance: async () =>
- ({
- balances: [
- {
- available: "USD:5",
- },
- ],
- } as Partial<BalancesResponse>),
- } as Partial<typeof wxApi> as any,
- ),
+ useComponentState(props, mock),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const r = getLastResultOrThrow();
+ const r = pullLastResultOrThrow();
if (r.status !== "no-enough-balance") expect.fail();
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:5"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:10"));
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should be able to pay (without fee)", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerPayUri: "taller://pay",
+ cancel: nullFunction,
+ goToWalletManualWithdraw: nullFunction,
+ onSuccess: async () => {
+ null;
+ },
+ }
+ handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
+ status: PreparePayResultType.PaymentPossible,
+ amountRaw: "USD:10",
+ amountEffective: "USD:10",
+ } as PreparePayResultPaymentPossible)
+ handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
+ balances: [{
+ available: "USD:15",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ }]
+ })
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
- useComponentState(
- {
- talerPayUri: "taller://pay",
- cancel: nullFunction,
- goToWalletManualWithdraw: nullFunction,
- onSuccess: async () => {
- null;
- },
- },
- {
- onUpdateNotification: nullFunction,
- preparePay: async () =>
- ({
- amountRaw: "USD:10",
- amountEffective: "USD:10",
- status: PreparePayResultType.PaymentPossible,
- } as Partial<PreparePayResult>),
- getBalance: async () =>
- ({
- balances: [
- {
- available: "USD:15",
- },
- ],
- } as Partial<BalancesResponse>),
- } as Partial<typeof wxApi> as any,
- ),
+ useComponentState(props, mock),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
+ const r = pullLastResultOrThrow();
+ if (r.status !== "ready") {
+ expect(r).eq({})
+ return
+ }
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:10"));
- // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:0"));
expect(r.payHandler.onClick).not.undefined;
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should be able to pay (with fee)", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerPayUri: "taller://pay",
+ cancel: nullFunction,
+ goToWalletManualWithdraw: nullFunction,
+ onSuccess: async () => {
+ null;
+ },
+ }
+ handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
+ status: PreparePayResultType.PaymentPossible,
+ amountRaw: "USD:9",
+ amountEffective: "USD:10",
+ } as PreparePayResultPaymentPossible)
+ handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
+ balances: [{
+ available: "USD:15",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ }]
+ })
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
- {
- talerPayUri: "taller://pay",
- cancel: nullFunction,
- goToWalletManualWithdraw: nullFunction,
- onSuccess: async () => {
- null;
- },
- },
- {
- onUpdateNotification: nullFunction,
- preparePay: async () =>
- ({
- amountRaw: "USD:9",
- amountEffective: "USD:10",
- status: PreparePayResultType.PaymentPossible,
- } as Partial<PreparePayResult>),
- getBalance: async () =>
- ({
- balances: [
- {
- available: "USD:15",
- },
- ],
- } as Partial<BalancesResponse>),
- } as Partial<typeof wxApi> as any,
+ props,
+ mock
+
),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const r = getLastResultOrThrow();
+ const r = pullLastResultOrThrow();
if (r.status !== "ready") expect.fail();
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
- // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
expect(r.payHandler.onClick).not.undefined;
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should get confirmation done after pay successfully", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerPayUri: "taller://pay",
+ cancel: nullFunction,
+ goToWalletManualWithdraw: nullFunction,
+ onSuccess: async () => {
+ null;
+ },
+ }
+ handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
+ status: PreparePayResultType.PaymentPossible,
+ amountRaw: "USD:9",
+ amountEffective: "USD:10",
+ } as PreparePayResultPaymentPossible)
+
+ handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
+ balances: [{
+ available: "USD:15",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ }]
+ })
+ handler.addWalletCallResponse(WalletApiOperation.ConfirmPay, undefined, {
+ type: ConfirmPayResultType.Done,
+ contractTerms: {},
+ } as ConfirmPayResult)
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
- {
- talerPayUri: "taller://pay",
- cancel: nullFunction,
- goToWalletManualWithdraw: nullFunction,
- onSuccess: async () => {
- null;
- },
- },
- {
- onUpdateNotification: nullFunction,
- preparePay: async () =>
- ({
- amountRaw: "USD:9",
- amountEffective: "USD:10",
- status: PreparePayResultType.PaymentPossible,
- } as Partial<PreparePayResult>),
- getBalance: async () =>
- ({
- balances: [
- {
- available: "USD:15",
- },
- ],
- } as Partial<BalancesResponse>),
- confirmPay: async () =>
- ({
- type: ConfirmPayResultType.Done,
- contractTerms: {},
- } as Partial<ConfirmPayResult>),
- } as Partial<typeof wxApi> as any,
+ props, mock
),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
+ const r = pullLastResultOrThrow();
+ if (r.status !== "ready") {
+ expect(r).eq({})
+ return;
+ }
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
- // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
if (r.payHandler.onClick === undefined) expect.fail();
r.payHandler.onClick();
}
- // await waitNextUpdate();
-
- // {
- // const r = getLastResultOrThrow();
- // if (r.status !== "completed") expect.fail();
- // expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
- // expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
- // // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
- // // if (r.payResult.type !== ConfirmPayResultType.Done) expect.fail();
- // // expect(r.payResult.contractTerms).not.undefined;
- // // expect(r.payHandler.onClick).undefined;
- // }
-
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should not stay in ready state after pay with error", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerPayUri: "taller://pay",
+ cancel: nullFunction,
+ goToWalletManualWithdraw: nullFunction,
+ onSuccess: nullFunction,
+ };
+ handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
+ status: PreparePayResultType.PaymentPossible,
+ amountRaw: "USD:9",
+ amountEffective: "USD:10",
+ } as PreparePayResultPaymentPossible)
+
+ handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
+ balances: [{
+ available: "USD:15",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ }]
+ })
+ handler.addWalletCallResponse(WalletApiOperation.ConfirmPay, undefined, {
+ type: ConfirmPayResultType.Pending,
+ lastError: { code: 1 },
+ } as ConfirmPayResult)
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
- {
- talerPayUri: "taller://pay",
- cancel: nullFunction,
- goToWalletManualWithdraw: nullFunction,
- onSuccess: async () => {
- null;
- },
- },
- {
- onUpdateNotification: nullFunction,
- preparePay: async () =>
- ({
- amountRaw: "USD:9",
- amountEffective: "USD:10",
- status: PreparePayResultType.PaymentPossible,
- } as Partial<PreparePayResult>),
- getBalance: async () =>
- ({
- balances: [
- {
- available: "USD:15",
- },
- ],
- } as Partial<BalancesResponse>),
- confirmPay: async () =>
- ({
- type: ConfirmPayResultType.Pending,
- lastError: { code: 1 },
- } as Partial<ConfirmPayResult>),
- } as Partial<typeof wxApi> as any,
+ props, mock
),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true
{
- const r = getLastResultOrThrow();
+ const r = pullLastResultOrThrow();
if (r.status !== "ready") expect.fail();
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
@@ -429,10 +380,10 @@ describe("Payment CTA states", () => {
r.payHandler.onClick();
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true
{
- const r = getLastResultOrThrow();
+ const r = pullLastResultOrThrow();
if (r.status !== "ready") expect.fail();
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
@@ -450,72 +401,91 @@ describe("Payment CTA states", () => {
}
await assertNoPendingUpdate();
+
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should update balance if a coins is withdraw", async () => {
- const subscriptions = new SubsHandler();
- let availableBalance = Amounts.parseOrThrow("USD:10");
-
- function notifyCoinWithdrawn(newAmount: AmountJson): void {
- availableBalance = Amounts.add(availableBalance, newAmount).amount;
- subscriptions.notifyEvent(NotificationType.CoinWithdrawn);
+ const { handler, mock } = createWalletApiMock();
+
+ const props = {
+ talerPayUri: "taller://pay",
+ cancel: nullFunction,
+ goToWalletManualWithdraw: nullFunction,
+ onSuccess: async () => {
+ null;
+ },
}
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
+ status: PreparePayResultType.PaymentPossible,
+ amountRaw: "USD:9",
+ amountEffective: "USD:10",
+ } as PreparePayResultPaymentPossible)
+
+ handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
+ balances: [{
+ available: "USD:10",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ }]
+ })
+
+ handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
+ status: PreparePayResultType.PaymentPossible,
+ amountRaw: "USD:9",
+ amountEffective: "USD:10",
+ } as PreparePayResultPaymentPossible)
+
+ handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
+ balances: [{
+ available: "USD:15",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ }]
+ })
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
- {
- talerPayUri: "taller://pay",
- cancel: nullFunction,
- goToWalletManualWithdraw: nullFunction,
- onSuccess: async () => {
- null;
- },
- },
- {
- onUpdateNotification: subscriptions.saveSubscription,
- preparePay: async () =>
- ({
- amountRaw: "USD:9",
- amountEffective: "USD:10",
- status: PreparePayResultType.PaymentPossible,
- } as Partial<PreparePayResult>),
- getBalance: async () =>
- ({
- balances: [
- {
- available: Amounts.stringify(availableBalance),
- },
- ],
- } as Partial<BalancesResponse>),
- } as Partial<typeof wxApi> as any,
+ props, mock
),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
+ const r = pullLastResultOrThrow();
+ if (r.status !== "ready") {
+ expect(r).eq({})
+ return
+ }
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:10"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
expect(r.payHandler.onClick).not.undefined;
- notifyCoinWithdrawn(Amounts.parseOrThrow("USD:5"));
+ handler.notifyEventFromWallet(NotificationType.CoinWithdrawn);
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
+ const r = pullLastResultOrThrow();
+ if (r.status !== "ready") {
+ expect(r).eq({})
+ return
+ }
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
@@ -523,5 +493,6 @@ describe("Payment CTA states", () => {
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
});
diff --git a/packages/taler-wallet-webextension/src/cta/Recovery/index.ts b/packages/taler-wallet-webextension/src/cta/Recovery/index.ts
index 013e9c041..4a65c571b 100644
--- a/packages/taler-wallet-webextension/src/cta/Recovery/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Recovery/index.ts
@@ -14,12 +14,11 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { AmountJson } from "@gnu-taler/taler-util";
import { Loading } from "../../components/Loading.js";
import { HookError } from "../../hooks/useAsyncAsHook.js";
import { ButtonHandler } from "../../mui/handlers.js";
import { compose, StateViewMap } from "../../utils/index.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { useComponentState } from "./state.js";
import { LoadingUriView, ReadyView } from "./views.js";
diff --git a/packages/taler-wallet-webextension/src/cta/Recovery/state.ts b/packages/taler-wallet-webextension/src/cta/Recovery/state.ts
index 965a64e69..750fd22f7 100644
--- a/packages/taler-wallet-webextension/src/cta/Recovery/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Recovery/state.ts
@@ -16,8 +16,7 @@
import { parseRecoveryUri } from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
-import * as wxApi from "../../wxApi.js";
-import { wxClient } from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
export function useComponentState(
@@ -49,7 +48,7 @@ export function useComponentState(
const recovery = info;
async function recoverBackup(): Promise<void> {
- await wxClient.call(WalletApiOperation.ImportBackupRecovery, { recovery });
+ await wxApi.wallet.call(WalletApiOperation.ImportBackupRecovery, { recovery });
onSuccess();
}
diff --git a/packages/taler-wallet-webextension/src/cta/Refund/index.ts b/packages/taler-wallet-webextension/src/cta/Refund/index.ts
index be9e3499b..6bd976aab 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Refund/index.ts
@@ -19,13 +19,13 @@ import { Loading } from "../../components/Loading.js";
import { HookError } from "../../hooks/useAsyncAsHook.js";
import { ButtonHandler } from "../../mui/handlers.js";
import { compose, StateViewMap } from "../../utils/index.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { useComponentState } from "./state.js";
import {
IgnoredView,
InProgressView,
LoadingUriView,
- ReadyView,
+ ReadyView
} from "./views.js";
export interface Props {
diff --git a/packages/taler-wallet-webextension/src/cta/Refund/state.ts b/packages/taler-wallet-webextension/src/cta/Refund/state.ts
index 16dbbf70d..65a895fc3 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Refund/state.ts
@@ -15,9 +15,10 @@
*/
import { Amounts, NotificationType } from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useEffect, useState } from "preact/hooks";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
export function useComponentState(
@@ -28,15 +29,14 @@ export function useComponentState(
const info = useAsyncAsHook(async () => {
if (!talerRefundUri) throw Error("ERROR_NO-URI-FOR-REFUND");
- const refund = await api.prepareRefund({ talerRefundUri });
+ const refund = await api.wallet.call(WalletApiOperation.PrepareRefund, { talerRefundUri });
return { refund, uri: talerRefundUri };
});
- useEffect(() => {
- api.onUpdateNotification([NotificationType.RefreshMelted], () => {
- info?.retry();
- });
- });
+ useEffect(() => api.listener.onUpdateNotification(
+ [NotificationType.RefreshMelted],
+ info?.retry)
+ );
if (!info) {
return { status: "loading", error: undefined };
@@ -51,7 +51,9 @@ export function useComponentState(
const { refund, uri } = info.response;
const doAccept = async (): Promise<void> => {
- const res = await api.applyRefund(uri);
+ const res = await api.wallet.call(WalletApiOperation.ApplyRefund, {
+ talerRefundUri: uri
+ });
onSuccess(res.transactionId);
};
diff --git a/packages/taler-wallet-webextension/src/cta/Refund/test.ts b/packages/taler-wallet-webextension/src/cta/Refund/test.ts
index 3111a85c6..41996c133 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Refund/test.ts
@@ -21,18 +21,19 @@
import {
AmountJson,
- Amounts,
- NotificationType,
- PrepareRefundResult,
+ Amounts, NotificationType, OrderShortInfo, PrepareRefundResult
} from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { expect } from "chai";
import { mountHook } from "../../test-utils.js";
-import { SubsHandler } from "../Payment/test.js";
+import { createWalletApiMock } from "../../test-utils.js";
import { useComponentState } from "./state.js";
describe("Refund CTA states", () => {
it("should tell the user that the URI is missing", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
{
@@ -44,24 +45,25 @@ describe("Refund CTA states", () => {
null;
},
},
- {
- prepareRefund: async () => ({}),
- applyRefund: async () => ({}),
- onUpdateNotification: async () => ({}),
- } as any,
+ mock
+ // {
+ // prepareRefund: async () => ({}),
+ // applyRefund: async () => ({}),
+ // onUpdateNotification: async () => ({}),
+ // } as any,
),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading-uri");
if (!error) expect.fail();
@@ -71,55 +73,76 @@ describe("Refund CTA states", () => {
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should be ready after loading", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerRefundUri: "taler://refund/asdasdas",
+ cancel: async () => {
+ null;
+ },
+ onSuccess: async () => {
+ null;
+ },
+ }
+
+ handler.addWalletCallResponse(WalletApiOperation.PrepareRefund, undefined, {
+ awaiting: "EUR:2",
+ effectivePaid: "EUR:2",
+ gone: "EUR:0",
+ granted: "EUR:0",
+ pending: false,
+ proposalId: "1",
+ info: {
+ contractTermsHash: "123",
+ merchant: {
+ name: "the merchant name",
+ },
+ orderId: "orderId1",
+ summary: "the summary",
+ } as OrderShortInfo,
+ })
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
- {
- talerRefundUri: "taler://refund/asdasdas",
- cancel: async () => {
- null;
- },
- onSuccess: async () => {
- null;
- },
- },
- {
- prepareRefund: async () =>
- ({
- effectivePaid: "EUR:2",
- awaiting: "EUR:2",
- gone: "EUR:0",
- granted: "EUR:0",
- pending: false,
- proposalId: "1",
- info: {
- contractTermsHash: "123",
- merchant: {
- name: "the merchant name",
- },
- orderId: "orderId1",
- summary: "the summary",
- },
- } as PrepareRefundResult as any),
- applyRefund: async () => ({}),
- onUpdateNotification: async () => ({}),
- } as any,
+ props, mock
+ // {
+ // prepareRefund: async () =>
+ // ({
+ // effectivePaid: "EUR:2",
+ // awaiting: "EUR:2",
+ // gone: "EUR:0",
+ // granted: "EUR:0",
+ // pending: false,
+ // proposalId: "1",
+ // info: {
+ // contractTermsHash: "123",
+ // merchant: {
+ // name: "the merchant name",
+ // },
+ // orderId: "orderId1",
+ // summary: "the summary",
+ // },
+ // } as PrepareRefundResult as any),
+ // applyRefund: async () => ({}),
+ // onUpdateNotification: async () => ({}),
+ // } as any,
),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const state = getLastResultOrThrow();
+ const state = pullLastResultOrThrow();
if (state.status !== "ready") expect.fail();
if (state.error) expect.fail();
@@ -131,58 +154,101 @@ describe("Refund CTA states", () => {
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should be ignored after clicking the ignore button", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerRefundUri: "taler://refund/asdasdas",
+ cancel: async () => {
+ null;
+ },
+ onSuccess: async () => {
+ null;
+ },
+ }
+
+ handler.addWalletCallResponse(WalletApiOperation.PrepareRefund, undefined, {
+ awaiting: "EUR:2",
+ effectivePaid: "EUR:2",
+ gone: "EUR:0",
+ granted: "EUR:0",
+ pending: false,
+ proposalId: "1",
+ info: {
+ contractTermsHash: "123",
+ merchant: {
+ name: "the merchant name",
+ },
+ orderId: "orderId1",
+ summary: "the summary",
+ } as OrderShortInfo,
+ })
+ // handler.addWalletCall(WalletApiOperation.ApplyRefund)
+ // handler.addWalletCall(WalletApiOperation.PrepareRefund, undefined, {
+ // awaiting: "EUR:1",
+ // effectivePaid: "EUR:2",
+ // gone: "EUR:0",
+ // granted: "EUR:1",
+ // pending: true,
+ // proposalId: "1",
+ // info: {
+ // contractTermsHash: "123",
+ // merchant: {
+ // name: "the merchant name",
+ // },
+ // orderId: "orderId1",
+ // summary: "the summary",
+ // } as OrderShortInfo,
+ // })
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
- {
- talerRefundUri: "taler://refund/asdasdas",
- cancel: async () => {
- null;
- },
- onSuccess: async () => {
- null;
- },
- },
- {
- prepareRefund: async () =>
- ({
- effectivePaid: "EUR:2",
- awaiting: "EUR:2",
- gone: "EUR:0",
- granted: "EUR:0",
- pending: false,
- proposalId: "1",
- info: {
- contractTermsHash: "123",
- merchant: {
- name: "the merchant name",
- },
- orderId: "orderId1",
- summary: "the summary",
- },
- } as PrepareRefundResult as any),
- applyRefund: async () => ({}),
- onUpdateNotification: async () => ({}),
- } as any,
+ props, mock
+ // {
+ // prepareRefund: async () =>
+ // ({
+ // effectivePaid: "EUR:2",
+ // awaiting: "EUR:2",
+ // gone: "EUR:0",
+ // granted: "EUR:0",
+ // pending: false,
+ // proposalId: "1",
+ // info: {
+ // contractTermsHash: "123",
+ // merchant: {
+ // name: "the merchant name",
+ // },
+ // orderId: "orderId1",
+ // summary: "the summary",
+ // },
+ // } as PrepareRefundResult as any),
+ // applyRefund: async () => ({}),
+ // onUpdateNotification: async () => ({}),
+ // } as any,
),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const state = getLastResultOrThrow();
-
- if (state.status !== "ready") expect.fail();
- if (state.error) expect.fail();
+ const state = pullLastResultOrThrow();
+
+ if (state.status !== "ready") {
+ expect(state).eq({})
+ return;
+ }
+ if (state.error) {
+ expect(state).eq({})
+ return;
+ }
expect(state.accept.onClick).not.undefined;
expect(state.merchantName).eq("the merchant name");
expect(state.orderId).eq("orderId1");
@@ -192,113 +258,145 @@ describe("Refund CTA states", () => {
state.ignore.onClick();
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const state = getLastResultOrThrow();
-
- if (state.status !== "ignored") expect.fail();
- if (state.error) expect.fail();
+ const state = pullLastResultOrThrow();
+
+ if (state.status !== "ignored") {
+ expect(state).eq({})
+ return;
+ }
+ if (state.error) {
+ expect(state).eq({})
+ return;
+ }
expect(state.merchantName).eq("the merchant name");
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should be in progress when doing refresh", async () => {
- let granted = Amounts.getZero("EUR");
- const unit: AmountJson = { currency: "EUR", value: 1, fraction: 0 };
- const refunded: AmountJson = { currency: "EUR", value: 2, fraction: 0 };
- let awaiting: AmountJson = refunded;
- let pending = true;
-
- const subscriptions = new SubsHandler();
-
- function notifyMelt(): void {
- granted = Amounts.add(granted, unit).amount;
- pending = granted.value < refunded.value;
- awaiting = Amounts.sub(refunded, granted).amount;
- subscriptions.notifyEvent(NotificationType.RefreshMelted);
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerRefundUri: "taler://refund/asdasdas",
+ cancel: async () => {
+ null;
+ },
+ onSuccess: async () => {
+ null;
+ },
}
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ handler.addWalletCallResponse(WalletApiOperation.PrepareRefund, undefined, {
+ awaiting: "EUR:2",
+ effectivePaid: "EUR:2",
+ gone: "EUR:0",
+ granted: "EUR:0",
+ pending: true,
+ proposalId: "1",
+ info: {
+ contractTermsHash: "123",
+ merchant: {
+ name: "the merchant name",
+ },
+ orderId: "orderId1",
+ summary: "the summary",
+ } as OrderShortInfo,
+ })
+ handler.addWalletCallResponse(WalletApiOperation.PrepareRefund, undefined, {
+ awaiting: "EUR:1",
+ effectivePaid: "EUR:2",
+ gone: "EUR:0",
+ granted: "EUR:1",
+ pending: true,
+ proposalId: "1",
+ info: {
+ contractTermsHash: "123",
+ merchant: {
+ name: "the merchant name",
+ },
+ orderId: "orderId1",
+ summary: "the summary",
+ } as OrderShortInfo,
+ })
+ handler.addWalletCallResponse(WalletApiOperation.PrepareRefund, undefined, {
+ awaiting: "EUR:0",
+ effectivePaid: "EUR:2",
+ gone: "EUR:0",
+ granted: "EUR:2",
+ pending: false,
+ proposalId: "1",
+ info: {
+ contractTermsHash: "123",
+ merchant: {
+ name: "the merchant name",
+ },
+ orderId: "orderId1",
+ summary: "the summary",
+ } as OrderShortInfo,
+ })
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
- {
- talerRefundUri: "taler://refund/asdasdas",
- cancel: async () => {
- null;
- },
- onSuccess: async () => {
- null;
- },
- },
- {
- prepareRefund: async () =>
- ({
- awaiting: Amounts.stringify(awaiting),
- effectivePaid: "EUR:2",
- gone: "EUR:0",
- granted: Amounts.stringify(granted),
- pending,
- proposalId: "1",
- info: {
- contractTermsHash: "123",
- merchant: {
- name: "the merchant name",
- },
- orderId: "orderId1",
- summary: "the summary",
- },
- } as PrepareRefundResult as any),
- applyRefund: async () => ({}),
- onUpdateNotification: subscriptions.saveSubscription,
- } as any,
+ props, mock
),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const state = getLastResultOrThrow();
+ const state = pullLastResultOrThrow();
- if (state.status !== "in-progress") expect.fail("1");
+ if (state.status !== "in-progress") {
+ expect(state).eq({})
+ return;
+ }
if (state.error) expect.fail();
expect(state.merchantName).eq("the merchant name");
expect(state.products).undefined;
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2"));
// expect(state.progress).closeTo(1 / 3, 0.01)
- notifyMelt();
+ handler.notifyEventFromWallet(NotificationType.RefreshMelted)
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const state = getLastResultOrThrow();
+ const state = pullLastResultOrThrow();
- if (state.status !== "in-progress") expect.fail("2");
+ if (state.status !== "in-progress") {
+ expect(state).eq({})
+ return;
+ }
if (state.error) expect.fail();
expect(state.merchantName).eq("the merchant name");
expect(state.products).undefined;
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2"));
// expect(state.progress).closeTo(2 / 3, 0.01)
- notifyMelt();
+ handler.notifyEventFromWallet(NotificationType.RefreshMelted)
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const state = getLastResultOrThrow();
+ const state = pullLastResultOrThrow();
- if (state.status !== "ready") expect.fail("3");
+ if (state.status !== "ready") {
+ expect(state).eq({})
+ return;
+ }
if (state.error) expect.fail();
expect(state.merchantName).eq("the merchant name");
expect(state.products).undefined;
@@ -306,5 +404,6 @@ describe("Refund CTA states", () => {
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
});
diff --git a/packages/taler-wallet-webextension/src/cta/Tip/index.ts b/packages/taler-wallet-webextension/src/cta/Tip/index.ts
index 03cbd2196..520d854f2 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Tip/index.ts
@@ -19,13 +19,13 @@ import { Loading } from "../../components/Loading.js";
import { HookError } from "../../hooks/useAsyncAsHook.js";
import { ButtonHandler } from "../../mui/handlers.js";
import { compose, StateViewMap } from "../../utils/index.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { useComponentState } from "./state.js";
import {
AcceptedView,
IgnoredView,
LoadingUriView,
- ReadyView,
+ ReadyView
} from "./views.js";
export interface Props {
diff --git a/packages/taler-wallet-webextension/src/cta/Tip/state.ts b/packages/taler-wallet-webextension/src/cta/Tip/state.ts
index f6721d504..00e1fddad 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Tip/state.ts
@@ -15,20 +15,18 @@
*/
import { Amounts } from "@gnu-taler/taler-util";
-import { useState } from "preact/hooks";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
export function useComponentState(
{ talerTipUri, onCancel, onSuccess }: Props,
api: typeof wxApi,
): State {
- const [tipIgnored, setTipIgnored] = useState(false);
-
const tipInfo = useAsyncAsHook(async () => {
if (!talerTipUri) throw Error("ERROR_NO-URI-FOR-TIP");
- const tip = await api.prepareTip({ talerTipUri });
+ const tip = await api.wallet.call(WalletApiOperation.PrepareTip, { talerTipUri });
return { tip };
});
@@ -48,7 +46,7 @@ export function useComponentState(
const { tip } = tipInfo.response;
const doAccept = async (): Promise<void> => {
- const res = await api.acceptTip({ walletTipId: tip.walletTipId });
+ const res = await api.wallet.call(WalletApiOperation.AcceptTip, { walletTipId: tip.walletTipId });
//FIX: this may not be seen since we are moving to the success also
tipInfo.retry();
@@ -65,13 +63,6 @@ export function useComponentState(
},
};
- if (tipIgnored) {
- return {
- status: "ignored",
- ...baseInfo,
- };
- }
-
if (tip.accepted) {
return {
status: "accepted",
diff --git a/packages/taler-wallet-webextension/src/cta/Tip/test.ts b/packages/taler-wallet-webextension/src/cta/Tip/test.ts
index 47d9aa8db..69badbede 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Tip/test.ts
@@ -19,14 +19,18 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { Amounts, PrepareTipResult } from "@gnu-taler/taler-util";
+import { Amounts } from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { expect } from "chai";
import { mountHook } from "../../test-utils.js";
+import { createWalletApiMock } from "../../test-utils.js";
import { useComponentState } from "./state.js";
describe("Tip CTA states", () => {
it("should tell the user that the URI is missing", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
{
@@ -38,23 +42,20 @@ describe("Tip CTA states", () => {
null;
},
},
- {
- prepareTip: async () => ({}),
- acceptTip: async () => ({}),
- } as any,
+ mock,
),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading-uri");
if (!error) expect.fail();
@@ -64,12 +65,26 @@ describe("Tip CTA states", () => {
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should be ready for accepting the tip", async () => {
- let tipAccepted = false;
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+
+ handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, {
+ accepted: false,
+ exchangeBaseUrl: "exchange url",
+ merchantBaseUrl: "merchant url",
+ tipAmountEffective: "EUR:1",
+ walletTipId: "tip_id",
+ expirationTimestamp: {
+ t_s: 1
+ },
+ tipAmountRaw: ""
+ });
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
{
@@ -81,58 +96,79 @@ describe("Tip CTA states", () => {
null;
},
},
- {
- prepareTip: async () =>
- ({
- accepted: tipAccepted,
- exchangeBaseUrl: "exchange url",
- merchantBaseUrl: "merchant url",
- tipAmountEffective: "EUR:1",
- walletTipId: "tip_id",
- } as PrepareTipResult as any),
- acceptTip: async () => {
- tipAccepted = true;
- },
- } as any,
+ mock,
),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const state = getLastResultOrThrow();
+ const state = pullLastResultOrThrow();
- if (state.status !== "ready") expect.fail();
+ if (state.status !== "ready") {
+ expect(state).eq({ status: "ready" })
+ return;
+ }
if (state.error) expect.fail();
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1"));
expect(state.merchantBaseUrl).eq("merchant url");
expect(state.exchangeBaseUrl).eq("exchange url");
if (state.accept.onClick === undefined) expect.fail();
+ handler.addWalletCallResponse(WalletApiOperation.AcceptTip);
state.accept.onClick();
}
- await waitNextUpdate();
+ handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, {
+ accepted: true,
+ exchangeBaseUrl: "exchange url",
+ merchantBaseUrl: "merchant url",
+ tipAmountEffective: "EUR:1",
+ walletTipId: "tip_id",
+ expirationTimestamp: {
+ t_s: 1
+ },
+ tipAmountRaw: ""
+ });
+ expect(await waitForStateUpdate()).true;
+
{
- const state = getLastResultOrThrow();
+ const state = pullLastResultOrThrow();
- if (state.status !== "accepted") expect.fail();
+ if (state.status !== "accepted") {
+ expect(state).eq({ status: "accepted" })
+ return;
+ }
if (state.error) expect.fail();
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1"));
expect(state.merchantBaseUrl).eq("merchant url");
expect(state.exchangeBaseUrl).eq("exchange url");
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should be ignored after clicking the ignore button", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, {
+ exchangeBaseUrl: "exchange url",
+ merchantBaseUrl: "merchant url",
+ tipAmountEffective: "EUR:1",
+ walletTipId: "tip_id",
+ accepted: false,
+ expirationTimestamp: {
+ t_s: 1,
+ },
+ tipAmountRaw: ""
+ });
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
{
@@ -144,52 +180,48 @@ describe("Tip CTA states", () => {
null;
},
},
- {
- prepareTip: async () =>
- ({
- exchangeBaseUrl: "exchange url",
- merchantBaseUrl: "merchant url",
- tipAmountEffective: "EUR:1",
- walletTipId: "tip_id",
- } as PrepareTipResult as any),
- acceptTip: async () => ({}),
- } as any,
+ mock,
),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const state = getLastResultOrThrow();
+ const state = pullLastResultOrThrow();
if (state.status !== "ready") expect.fail();
if (state.error) expect.fail();
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1"));
expect(state.merchantBaseUrl).eq("merchant url");
expect(state.exchangeBaseUrl).eq("exchange url");
- // if (state.ignore.onClick === undefined) expect.fail();
-
- // state.ignore.onClick();
}
- // await waitNextUpdate();
- // {
- // const state = getLastResultOrThrow();
-
- // if (state.status !== "ignored") expect.fail();
- // if (state.error) expect.fail();
- // }
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should render accepted if the tip has been used previously", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+
+ handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, {
+ accepted: true,
+ exchangeBaseUrl: "exchange url",
+ merchantBaseUrl: "merchant url",
+ tipAmountEffective: "EUR:1",
+ walletTipId: "tip_id",
+ expirationTimestamp: {
+ t_s: 1,
+ },
+ tipAmountRaw: "",
+ });
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
{
@@ -201,30 +233,20 @@ describe("Tip CTA states", () => {
null;
},
},
- {
- prepareTip: async () =>
- ({
- accepted: true,
- exchangeBaseUrl: "exchange url",
- merchantBaseUrl: "merchant url",
- tipAmountEffective: "EUR:1",
- walletTipId: "tip_id",
- } as PrepareTipResult as any),
- acceptTip: async () => ({}),
- } as any,
+ mock,
),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const state = getLastResultOrThrow();
+ const state = pullLastResultOrThrow();
if (state.status !== "accepted") expect.fail();
if (state.error) expect.fail();
@@ -233,5 +255,6 @@ describe("Tip CTA states", () => {
expect(state.exchangeBaseUrl).eq("exchange url");
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
});
diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts b/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts
index 820bffdea..83293438f 100644
--- a/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts
@@ -19,7 +19,7 @@ import { Loading } from "../../components/Loading.js";
import { HookError } from "../../hooks/useAsyncAsHook.js";
import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js";
import { compose, StateViewMap } from "../../utils/index.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { useComponentState } from "./state.js";
import { LoadingUriView, ReadyView } from "./views.js";
diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts b/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts
index d4ba18c12..b229924b2 100644
--- a/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts
@@ -15,9 +15,9 @@
*/
import { Amounts, TalerErrorDetail } from "@gnu-taler/taler-util";
-import { TalerError } from "@gnu-taler/taler-wallet-core";
+import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useState } from "preact/hooks";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
export function useComponentState(
@@ -33,7 +33,7 @@ export function useComponentState(
async function accept(): Promise<void> {
try {
- const resp = await api.initiatePeerPushPayment({
+ const resp = await api.wallet.call(WalletApiOperation.InitiatePeerPushPayment, {
amount: Amounts.stringify(amount),
partialContractTerms: {
summary: subject,
diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts b/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts
index 0ffdb1b95..954243fe8 100644
--- a/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts
@@ -17,13 +17,13 @@
import {
AbsoluteTime,
AmountJson,
- TalerErrorDetail,
+ TalerErrorDetail
} from "@gnu-taler/taler-util";
import { Loading } from "../../components/Loading.js";
import { HookError } from "../../hooks/useAsyncAsHook.js";
import { ButtonHandler } from "../../mui/handlers.js";
import { compose, StateViewMap } from "../../utils/index.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { useComponentState } from "./state.js";
import { LoadingUriView, ReadyView } from "./views.js";
diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts
index 0095910b5..4b860559e 100644
--- a/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts
@@ -18,12 +18,12 @@ import {
AbsoluteTime,
Amounts,
TalerErrorDetail,
- TalerProtocolTimestamp,
+ TalerProtocolTimestamp
} from "@gnu-taler/taler-util";
-import { TalerError } from "@gnu-taler/taler-wallet-core";
+import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useState } from "preact/hooks";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
export function useComponentState(
@@ -31,7 +31,7 @@ export function useComponentState(
api: typeof wxApi,
): State {
const hook = useAsyncAsHook(async () => {
- return await api.checkPeerPushPayment({
+ return await api.wallet.call(WalletApiOperation.CheckPeerPushPayment, {
talerUri: talerPayPushUri,
});
}, []);
@@ -53,7 +53,6 @@ export function useComponentState(
}
const {
- amount: purseAmount,
contractTerms,
peerPushPaymentIncomingId,
} = hook.response;
@@ -65,7 +64,7 @@ export function useComponentState(
async function accept(): Promise<void> {
try {
- const resp = await api.acceptPeerPushPayment({
+ const resp = await api.wallet.call(WalletApiOperation.AcceptPeerPushPayment, {
peerPushPaymentIncomingId,
});
onSuccess(resp.transactionId);
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
index a3b3df8b3..9a7acf9f1 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
@@ -20,15 +20,15 @@ import { HookError } from "../../hooks/useAsyncAsHook.js";
import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js";
import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
import { compose, StateViewMap } from "../../utils/index.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import {
useComponentStateFromParams,
- useComponentStateFromURI,
+ useComponentStateFromURI
} from "./state.js";
import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js";
-import { LoadingInfoView, LoadingUriView, SuccessView } from "./views.js";
import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
+import { LoadingInfoView, LoadingUriView, SuccessView } from "./views.js";
export interface PropsFromURI {
talerWithdrawUri: string | undefined;
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
index c542d8aae..704ef1ac3 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
@@ -19,13 +19,13 @@ import {
AmountJson,
Amounts,
ExchangeListItem,
- ExchangeTosStatus,
+ ExchangeTosStatus
} from "@gnu-taler/taler-util";
-import { TalerError } from "@gnu-taler/taler-wallet-core";
+import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useState } from "preact/hooks";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { PropsFromParams, PropsFromURI, State } from "./index.js";
type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
@@ -35,7 +35,7 @@ export function useComponentStateFromParams(
api: typeof wxApi,
): RecursiveState<State> {
const uriInfoHook = useAsyncAsHook(async () => {
- const exchanges = await api.listExchanges();
+ const exchanges = await api.wallet.call(WalletApiOperation.ListExchanges, {});
return { amount: Amounts.parseOrThrow(amount), exchanges };
});
@@ -58,11 +58,11 @@ export function useComponentStateFromParams(
transactionId: string;
confirmTransferUrl: string | undefined;
}> {
- const res = await api.acceptManualWithdrawal(
- exchange,
- Amounts.stringify(chosenAmount),
- ageRestricted,
- );
+ const res = await api.wallet.call(WalletApiOperation.AcceptManualWithdrawal, {
+ exchangeBaseUrl: exchange,
+ amount: Amounts.stringify(chosenAmount),
+ restrictAge: ageRestricted,
+ });
return {
confirmTransferUrl: undefined,
transactionId: res.transactionId,
@@ -93,16 +93,15 @@ export function useComponentStateFromURI(
const uriInfoHook = useAsyncAsHook(async () => {
if (!talerWithdrawUri) throw Error("ERROR_NO-URI-FOR-WITHDRAWAL");
- const uriInfo = await api.getWithdrawalDetailsForUri({
+ const uriInfo = await api.wallet.call(WalletApiOperation.GetWithdrawalDetailsForUri, {
talerWithdrawUri,
});
- const exchanges = await api.listExchanges();
const { amount, defaultExchangeBaseUrl } = uriInfo;
return {
talerWithdrawUri,
amount: Amounts.parseOrThrow(amount),
thisExchange: defaultExchangeBaseUrl,
- exchanges,
+ exchanges: uriInfo.possibleExchanges,
};
});
@@ -118,7 +117,7 @@ export function useComponentStateFromURI(
const uri = uriInfoHook.response.talerWithdrawUri;
const chosenAmount = uriInfoHook.response.amount;
const defaultExchange = uriInfoHook.response.thisExchange;
- const exchangeList = uriInfoHook.response.exchanges.exchanges;
+ const exchangeList = uriInfoHook.response.exchanges;
async function doManagedWithdraw(
exchange: string,
@@ -127,7 +126,11 @@ export function useComponentStateFromURI(
transactionId: string;
confirmTransferUrl: string | undefined;
}> {
- const res = await api.acceptWithdrawal(uri, exchange, ageRestricted);
+ const res = await api.wallet.call(WalletApiOperation.AcceptBankIntegratedWithdrawal, {
+ exchangeBaseUrl: exchange,
+ talerWithdrawUri: uri,
+ restrictAge: ageRestricted
+ });
return {
confirmTransferUrl: res.confirmTransferUrl,
transactionId: res.transactionId,
@@ -186,7 +189,7 @@ function exchangeSelectionState(
* about the withdrawal
*/
const amountHook = useAsyncAsHook(async () => {
- const info = await api.getWithdrawalDetailsForAmount({
+ const info = await api.wallet.call(WalletApiOperation.GetWithdrawalDetailsForAmount, {
exchangeBaseUrl: currentExchange.exchangeBaseUrl,
amount: Amounts.stringify(chosenAmount),
restrictAge: ageRestricted,
@@ -261,10 +264,10 @@ function exchangeSelectionState(
//TODO: calculate based on exchange info
const ageRestriction = ageRestrictionEnabled
? {
- list: ageRestrictionOptions,
- value: String(ageRestricted),
- onChange: async (v: string) => setAgeRestricted(parseInt(v, 10)),
- }
+ list: ageRestrictionOptions,
+ value: String(ageRestricted),
+ onChange: async (v: string) => setAgeRestricted(parseInt(v, 10)),
+ }
: undefined;
return {
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
index 977faa03a..b4ba32f8a 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
@@ -21,16 +21,12 @@
import {
Amounts,
- ExchangeEntryStatus,
- ExchangeFullDetails,
- ExchangeListItem,
- ExchangesListResponse,
- ExchangeTosStatus,
- GetExchangeTosResult,
- ManualWithdrawalDetails,
+ ExchangeEntryStatus, ExchangeListItem, ExchangeTosStatus
} from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { expect } from "chai";
import { mountHook } from "../../test-utils.js";
+import { createWalletApiMock } from "../../test-utils.js";
import { useComponentStateFromURI } from "./state.js";
const exchanges: ExchangeListItem[] = [
@@ -65,39 +61,32 @@ const exchanges: ExchangeListItem[] = [
describe("Withdraw CTA states", () => {
it("should tell the user that the URI is missing", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerWithdrawUri: undefined,
+ cancel: async () => {
+ null;
+ },
+ onSuccess: async () => {
+ null;
+ },
+ }
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentStateFromURI(
- {
- talerWithdrawUri: undefined,
- cancel: async () => {
- null;
- },
- onSuccess: async () => {
- null;
- },
- },
- {
- listExchanges: async () => ({ exchanges }),
- getWithdrawalDetailsForAmount: async ({
- talerWithdrawUri,
- }: any) => ({
- amount: "ARS:2",
- possibleExchanges: exchanges,
- }),
- } as any,
+ props, mock
),
);
{
- const { status } = getLastResultOrThrow();
+ const { status } = pullLastResultOrThrow();
expect(status).equals("loading");
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
if (status != "uri-error") expect.fail();
if (!error) expect.fail();
@@ -107,40 +96,41 @@ describe("Withdraw CTA states", () => {
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should tell the user that there is not known exchange", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerWithdrawUri: "taler-withdraw://",
+ cancel: async () => {
+ null;
+ },
+ onSuccess: async () => {
+ null;
+ },
+ }
+ handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForUri, undefined, {
+ amount: "EUR:2",
+ possibleExchanges: [],
+ })
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentStateFromURI(
- {
- talerWithdrawUri: "taler-withdraw://",
- cancel: async () => {
- null;
- },
- onSuccess: async () => {
- null;
- },
- },
- {
- listExchanges: async () => ({ exchanges }),
- getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
- amount: "EUR:2",
- possibleExchanges: [],
- }),
- } as any,
+ props, mock
),
);
{
- const { status } = getLastResultOrThrow();
+ const { status } = pullLastResultOrThrow();
expect(status).equals("loading", "1");
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("no-exchange", "3");
@@ -148,65 +138,60 @@ describe("Withdraw CTA states", () => {
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
it("should be able to withdraw if tos are ok", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerWithdrawUri: "taler-withdraw://",
+ cancel: async () => {
+ null;
+ },
+ onSuccess: async () => {
+ null;
+ },
+ }
+ handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForUri, undefined, {
+ amount: "ARS:2",
+ possibleExchanges: exchanges,
+ defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl
+ })
+ handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForAmount, undefined, {
+ amountRaw: "ARS:2",
+ amountEffective: "ARS:2",
+ paytoUris: ["payto://"],
+ tosAccepted: true,
+ ageRestrictionOptions: []
+ })
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentStateFromURI(
- {
- talerWithdrawUri: "taler-withdraw://",
- cancel: async () => {
- null;
- },
- onSuccess: async () => {
- null;
- },
- },
- {
- listExchanges: async () => ({ exchanges }),
- getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
- amount: "ARS:2",
- possibleExchanges: exchanges,
- defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl,
- }),
- getWithdrawalDetailsForAmount:
- async (): Promise<ManualWithdrawalDetails> =>
- ({
- amountRaw: "ARS:2",
- amountEffective: "ARS:2",
- } as any),
- getExchangeTos: async (): Promise<GetExchangeTosResult> => ({
- contentType: "text",
- content: "just accept",
- acceptedEtag: "v1",
- currentEtag: "v1",
- tosStatus: ExchangeTosStatus.Accepted,
- }),
- } as any,
+ props, mock
),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const state = getLastResultOrThrow();
+ const state = pullLastResultOrThrow();
expect(state.status).equals("success");
if (state.status !== "success") return;
@@ -218,82 +203,72 @@ describe("Withdraw CTA states", () => {
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
- it("should be accept the tos before withdraw", async () => {
- const listExchangesResponse: ExchangesListResponse = {
- exchanges: exchanges.map((e) => ({
- ...e,
- tosStatus: ExchangeTosStatus.New,
- })),
- };
-
- function updateAcceptedVersionToCurrentVersion(): void {
- listExchangesResponse.exchanges = listExchangesResponse.exchanges.map(
- (e) => ({
- ...e,
- tosStatus: ExchangeTosStatus.Accepted,
- }),
- );
+ it("should accept the tos before withdraw", async () => {
+ const { handler, mock } = createWalletApiMock();
+ const props = {
+ talerWithdrawUri: "taler-withdraw://",
+ cancel: async () => {
+ null;
+ },
+ onSuccess: async () => {
+ null;
+ },
}
-
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const exchangeWithNewTos = exchanges.map((e) => ({
+ ...e,
+ tosStatus: ExchangeTosStatus.New,
+ }));
+
+ handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForUri, undefined, {
+ amount: "ARS:2",
+ possibleExchanges: exchangeWithNewTos,
+ defaultExchangeBaseUrl: exchangeWithNewTos[0].exchangeBaseUrl
+ })
+ handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForAmount, undefined, {
+ amountRaw: "ARS:2",
+ amountEffective: "ARS:2",
+ paytoUris: ["payto://"],
+ tosAccepted: false,
+ ageRestrictionOptions: []
+ })
+
+
+ handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForUri, undefined, {
+ amount: "ARS:2",
+ possibleExchanges: exchanges,
+ defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl
+ })
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentStateFromURI(
- {
- talerWithdrawUri: "taler-withdraw://",
- cancel: async () => {
- null;
- },
- onSuccess: async () => {
- null;
- },
- },
- {
- listExchanges: async () => listExchangesResponse,
- getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
- amount: "ARS:2",
- possibleExchanges: exchanges,
- defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl,
- }),
- getWithdrawalDetailsForAmount:
- async (): Promise<ManualWithdrawalDetails> =>
- ({
- amountRaw: "ARS:2",
- amountEffective: "ARS:2",
- } as any),
- getExchangeTos: async (): Promise<GetExchangeTosResult> => ({
- contentType: "text",
- content: "just accept",
- acceptedEtag: "v1",
- currentEtag: "v2",
- tosStatus: ExchangeTosStatus.Changed,
- }),
- setExchangeTosAccepted: async () => ({}),
- } as any,
+ props, mock
),
);
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const { status, error } = getLastResultOrThrow();
+ const { status, error } = pullLastResultOrThrow();
expect(status).equals("loading");
expect(error).undefined;
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const state = getLastResultOrThrow();
+ const state = pullLastResultOrThrow();
expect(state.status).equals("success");
if (state.status !== "success") return;
@@ -303,14 +278,14 @@ describe("Withdraw CTA states", () => {
expect(state.doWithdrawal.onClick).undefined;
- updateAcceptedVersionToCurrentVersion();
+ // updateAcceptedVersionToCurrentVersion();
state.onTosUpdate();
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const state = getLastResultOrThrow();
+ const state = pullLastResultOrThrow();
expect(state.status).equals("success");
if (state.status !== "success") return;
@@ -322,5 +297,6 @@ describe("Withdraw CTA states", () => {
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
});
diff --git a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
index f24896bf3..1b2929317 100644
--- a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
@@ -13,10 +13,9 @@
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/>
*/
-import { NotificationType, TalerErrorDetail } from "@gnu-taler/taler-util";
+import { TalerErrorDetail } from "@gnu-taler/taler-util";
import { TalerError } from "@gnu-taler/taler-wallet-core";
import { useEffect, useMemo, useState } from "preact/hooks";
-import * as wxApi from "../wxApi.js";
export interface HookOk<T> {
hasError: false;
diff --git a/packages/taler-wallet-webextension/src/hooks/useAutoOpenPermissions.ts b/packages/taler-wallet-webextension/src/hooks/useAutoOpenPermissions.ts
index 727d653af..5a0194db8 100644
--- a/packages/taler-wallet-webextension/src/hooks/useAutoOpenPermissions.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useAutoOpenPermissions.ts
@@ -14,11 +14,11 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { useState, useEffect } from "preact/hooks";
-import * as wxApi from "../wxApi.js";
-import { platform } from "../platform/api.js";
-import { ToggleHandler } from "../mui/handlers.js";
import { TalerError } from "@gnu-taler/taler-wallet-core";
+import { useEffect, useState } from "preact/hooks";
+import { ToggleHandler } from "../mui/handlers.js";
+import { platform } from "../platform/api.js";
+import { wxApi } from "../wxApi.js";
export function useAutoOpenPermissions(): ToggleHandler {
const [enabled, setEnabled] = useState(false);
@@ -31,7 +31,7 @@ export function useAutoOpenPermissions(): ToggleHandler {
useEffect(() => {
async function getValue(): Promise<void> {
- const res = await wxApi.containsHeaderListener();
+ const res = await wxApi.background.containsHeaderListener();
setEnabled(res.newValue);
}
getValue();
@@ -59,11 +59,11 @@ async function handleAutoOpenPerm(
onChange(false);
throw lastError;
}
- const res = await wxApi.toggleHeaderListener(granted);
+ const res = await wxApi.background.toggleHeaderListener(granted);
onChange(res.newValue);
} else {
try {
- await wxApi.toggleHeaderListener(false).then((r) => onChange(r.newValue));
+ await wxApi.background.toggleHeaderListener(false).then((r) => onChange(r.newValue));
} catch (e) {
console.log(e);
}
diff --git a/packages/taler-wallet-webextension/src/hooks/useBackupDeviceName.ts b/packages/taler-wallet-webextension/src/hooks/useBackupDeviceName.ts
index da3b05df4..7339a876a 100644
--- a/packages/taler-wallet-webextension/src/hooks/useBackupDeviceName.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useBackupDeviceName.ts
@@ -14,8 +14,9 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useEffect, useState } from "preact/hooks";
-import * as wxApi from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
export interface BackupDeviceName {
name: string;
@@ -31,10 +32,10 @@ export function useBackupDeviceName(): BackupDeviceName {
useEffect(() => {
async function run(): Promise<void> {
//create a first list of backup info by currency
- const status = await wxApi.getBackupInfo();
+ const status = await wxApi.wallet.call(WalletApiOperation.GetBackupInfo, {});
async function update(newName: string): Promise<void> {
- await wxApi.setWalletDeviceId(newName);
+ await wxApi.wallet.call(WalletApiOperation.SetWalletDeviceId, { walletDeviceId: newName });
setStatus((old) => ({ ...old, name: newName }));
}
diff --git a/packages/taler-wallet-webextension/src/hooks/useClipboardPermissions.ts b/packages/taler-wallet-webextension/src/hooks/useClipboardPermissions.ts
index 3e9629dcb..3d284fb5a 100644
--- a/packages/taler-wallet-webextension/src/hooks/useClipboardPermissions.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useClipboardPermissions.ts
@@ -14,11 +14,11 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { useState, useEffect } from "preact/hooks";
-import * as wxApi from "../wxApi.js";
-import { platform } from "../platform/api.js";
-import { ToggleHandler } from "../mui/handlers.js";
import { TalerError } from "@gnu-taler/taler-wallet-core";
+import { useEffect, useState } from "preact/hooks";
+import { ToggleHandler } from "../mui/handlers.js";
+import { platform } from "../platform/api.js";
+import { wxApi } from "../wxApi.js";
export function useClipboardPermissions(): ToggleHandler {
const [enabled, setEnabled] = useState(false);
@@ -31,7 +31,7 @@ export function useClipboardPermissions(): ToggleHandler {
useEffect(() => {
async function getValue(): Promise<void> {
- const res = await wxApi.containsHeaderListener();
+ const res = await wxApi.background.containsHeaderListener();
setEnabled(res.newValue);
}
getValue();
@@ -66,7 +66,7 @@ async function handleClipboardPerm(
onChange(granted);
} else {
try {
- await wxApi.toggleHeaderListener(false).then((r) => onChange(r.newValue));
+ await wxApi.background.toggleHeaderListener(false).then((r) => onChange(r.newValue));
} catch (e) {
console.log(e);
}
diff --git a/packages/taler-wallet-webextension/src/hooks/useDiagnostics.ts b/packages/taler-wallet-webextension/src/hooks/useDiagnostics.ts
index a61fe7965..a8564fddb 100644
--- a/packages/taler-wallet-webextension/src/hooks/useDiagnostics.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useDiagnostics.ts
@@ -16,7 +16,7 @@
import { WalletDiagnostics } from "@gnu-taler/taler-util";
import { useEffect, useState } from "preact/hooks";
-import * as wxApi from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
export function useDiagnostics(): [WalletDiagnostics | undefined, boolean] {
const [timedOut, setTimedOut] = useState(false);
@@ -33,7 +33,7 @@ export function useDiagnostics(): [WalletDiagnostics | undefined, boolean] {
}
}, 1000);
const doFetch = async (): Promise<void> => {
- const d = await wxApi.getDiagnostics();
+ const d = await wxApi.background.getDiagnostics();
gotDiagnostics = true;
setDiagnostics(d);
};
diff --git a/packages/taler-wallet-webextension/src/hooks/useProviderStatus.ts b/packages/taler-wallet-webextension/src/hooks/useProviderStatus.ts
index 187517b41..b73c9fc16 100644
--- a/packages/taler-wallet-webextension/src/hooks/useProviderStatus.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useProviderStatus.ts
@@ -14,9 +14,9 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { ProviderInfo } from "@gnu-taler/taler-wallet-core";
+import { ProviderInfo, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useEffect, useState } from "preact/hooks";
-import * as wxApi from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
export interface ProviderStatus {
info?: ProviderInfo;
@@ -30,7 +30,7 @@ export function useProviderStatus(url: string): ProviderStatus | undefined {
useEffect(() => {
async function run(): Promise<void> {
//create a first list of backup info by currency
- const status = await wxApi.getBackupInfo();
+ const status = await wxApi.wallet.call(WalletApiOperation.GetBackupInfo, {});
const providers = status.providers.filter(
(p) => p.syncProviderBaseUrl === url,
@@ -39,13 +39,17 @@ export function useProviderStatus(url: string): ProviderStatus | undefined {
async function sync(): Promise<void> {
if (info) {
- await wxApi.syncOneProvider(info.syncProviderBaseUrl);
+ await wxApi.wallet.call(WalletApiOperation.RunBackupCycle, {
+ providers: [info.syncProviderBaseUrl]
+ });
}
}
async function remove(): Promise<void> {
if (info) {
- await wxApi.removeProvider(info.syncProviderBaseUrl);
+ await wxApi.wallet.call(WalletApiOperation.RemoveBackupProvider, {
+ provider: info.syncProviderBaseUrl
+ });
}
}
diff --git a/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.test.ts b/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.test.ts
index a7ad3e81b..8aabb8adf 100644
--- a/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.test.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.test.ts
@@ -31,18 +31,18 @@ describe("useTalerActionURL hook", () => {
});
};
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(useTalerActionURL, ctx);
{
- const [url] = getLastResultOrThrow();
+ const [url] = pullLastResultOrThrow();
expect(url).undefined;
}
- await waitNextUpdate("waiting for useEffect");
+ expect(await waitForStateUpdate()).true;
{
- const [url, setDismissed] = getLastResultOrThrow();
+ const [url, setDismissed] = pullLastResultOrThrow();
expect(url).deep.equals({
location: "clipboard",
uri: "qwe",
@@ -50,10 +50,10 @@ describe("useTalerActionURL hook", () => {
setDismissed(true);
}
- await waitNextUpdate("after dismiss");
+ expect(await waitForStateUpdate()).true;
{
- const [url] = getLastResultOrThrow();
+ const [url] = pullLastResultOrThrow();
if (url !== undefined) throw Error("invalid");
expect(url).undefined;
}
diff --git a/packages/taler-wallet-webextension/src/hooks/useWalletDevMode.ts b/packages/taler-wallet-webextension/src/hooks/useWalletDevMode.ts
index 8021db686..8d4921392 100644
--- a/packages/taler-wallet-webextension/src/hooks/useWalletDevMode.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useWalletDevMode.ts
@@ -15,7 +15,7 @@
*/
import { useState, useEffect } from "preact/hooks";
-import { wxClient } from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
import { ToggleHandler } from "../mui/handlers.js";
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
@@ -30,7 +30,7 @@ export function useWalletDevMode(): ToggleHandler {
useEffect(() => {
async function getValue(): Promise<void> {
- const res = await wxClient.call(WalletApiOperation.GetVersion, {});
+ const res = await wxApi.wallet.call(WalletApiOperation.GetVersion, {});
setEnabled(res.devMode);
}
getValue();
@@ -49,7 +49,7 @@ async function handleOpen(
onChange: (value: boolean) => void,
): Promise<void> {
const nextValue = !currentValue
- await wxClient.call(WalletApiOperation.SetDevMode, { devModeEnabled: nextValue });
+ await wxApi.wallet.call(WalletApiOperation.SetDevMode, { devModeEnabled: nextValue });
onChange(nextValue);
return;
}
diff --git a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
index 94d5d1e16..98c6d166c 100644
--- a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
+++ b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
@@ -15,6 +15,7 @@
*/
import { Amounts, Balance, NotificationType } from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { Fragment, h, VNode } from "preact";
import { useEffect, useState } from "preact/hooks";
import { BalanceTable } from "../components/BalanceTable.js";
@@ -27,7 +28,7 @@ import { Button } from "../mui/Button.js";
import { ButtonHandler } from "../mui/handlers.js";
import { compose, StateViewMap } from "../utils/index.js";
import { AddNewActionView } from "../wallet/AddNewActionView.js";
-import * as wxApi from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
import { NoBalanceHelp } from "./NoBalanceHelp.js";
export interface Props {
@@ -71,16 +72,16 @@ function useComponentState(
api: typeof wxApi,
): State {
const [addingAction, setAddingAction] = useState(false);
- const state = useAsyncAsHook(api.getBalance);
+ const state = useAsyncAsHook(() =>
+ api.wallet.call(WalletApiOperation.GetBalances, {}),
+ );
- useEffect(() => {
- return api.onUpdateNotification(
+ useEffect(() =>
+ api.listener.onUpdateNotification(
[NotificationType.WithdrawGroupFinished],
- () => {
- state?.retry();
- },
- );
- });
+ state?.retry,
+ ),
+ );
if (!state) {
return {
diff --git a/packages/taler-wallet-webextension/src/test-utils.ts b/packages/taler-wallet-webextension/src/test-utils.ts
index e2339bff3..695fec201 100644
--- a/packages/taler-wallet-webextension/src/test-utils.ts
+++ b/packages/taler-wallet-webextension/src/test-utils.ts
@@ -14,6 +14,8 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+import { NotificationType } from "@gnu-taler/taler-util";
+import { WalletCoreApiClient, WalletCoreOpKeys, WalletCoreRequestType, WalletCoreResponseType } from "@gnu-taler/taler-wallet-core";
import {
ComponentChildren,
Fragment,
@@ -24,6 +26,7 @@ import {
VNode,
} from "preact";
import { render as renderToString } from "preact-render-to-string";
+import { BackgroundApiClient, wxApi } from "./wxApi.js";
// When doing tests we want the requestAnimationFrame to be as fast as possible.
// without this option the RAF will timeout after 100ms making the tests slower
@@ -86,9 +89,10 @@ type RecursiveState<S> = S | (() => RecursiveState<S>);
interface Mounted<T> {
unmount: () => void;
- getLastResultOrThrow: () => Exclude<T, VoidFunction>;
+ pullLastResultOrThrow: () => Exclude<T, VoidFunction>;
assertNoPendingUpdate: () => void;
- waitNextUpdate: (s?: string) => Promise<void>;
+ // waitNextUpdate: (s?: string) => Promise<void>;
+ waitForStateUpdate: () => Promise<boolean>;
}
const isNode = typeof window === "undefined";
@@ -97,9 +101,6 @@ export function mountHook<T extends object>(
callback: () => RecursiveState<T>,
Context?: ({ children }: { children: any }) => VNode,
): Mounted<T> {
- // const result: { current: T | null } = {
- // current: null
- // }
let lastResult: Exclude<T, VoidFunction> | Error | null = null;
const listener: Array<() => void> = [];
@@ -132,23 +133,6 @@ export function mountHook<T extends object>(
? create(Component, {})
: create(Context, { children: [create(Component, {})] });
- // waiter callback
- async function waitNextUpdate(_label = ""): Promise<void> {
- if (_label) _label = `. label: "${_label}"`;
- await new Promise((res, rej) => {
- const tid = setTimeout(() => {
- rej(
- Error(`waiting for an update but the hook didn't make one${_label}`),
- );
- }, 100);
-
- listener.push(() => {
- clearTimeout(tid);
- res(undefined);
- });
- });
- }
-
const customElement = {} as Element;
const parentElement = isNode ? customElement : document.createElement("div");
if (!isNode) {
@@ -164,14 +148,14 @@ export function mountHook<T extends object>(
}
}
- function getLastResult(): Exclude<T | Error | null, VoidFunction> {
+ function pullLastResult(): Exclude<T | Error | null, VoidFunction> {
const copy: Exclude<T | Error | null, VoidFunction> = lastResult;
lastResult = null;
return copy;
}
- function getLastResultOrThrow(): Exclude<T, VoidFunction> {
- const r = getLastResult();
+ function pullLastResultOrThrow(): Exclude<T, VoidFunction> {
+ const r = pullLastResult();
if (r instanceof Error) throw r;
if (!r) throw Error("there was no last result");
return r;
@@ -194,15 +178,137 @@ export function mountHook<T extends object>(
});
});
- const r = getLastResult();
+ const r = pullLastResult();
if (r)
throw Error(`There are still pending results.
- This may happen because the hook did a new update but the test didn't consume the result using getLastResult`);
+ This may happen because the hook did a new update but the test didn't consume the result using pullLastResult`);
}
+ async function waitForStateUpdate(): Promise<boolean> {
+ return await new Promise((res, rej) => {
+ const tid = setTimeout(() => {
+ res(false);
+ }, 10);
+
+ listener.push(() => {
+ clearTimeout(tid);
+ res(true);
+ });
+ });
+ }
+
return {
unmount,
- getLastResultOrThrow,
- waitNextUpdate,
+ pullLastResultOrThrow,
+ waitForStateUpdate,
assertNoPendingUpdate,
};
}
+
+export const nullFunction: any = () => null;
+
+interface MockHandler {
+ addWalletCallResponse<Op extends WalletCoreOpKeys>(operation: Op,
+ payload?: Partial<WalletCoreRequestType<Op>>,
+ response?: WalletCoreResponseType<Op>,
+ callback?: () => void,
+ ): MockHandler;
+
+ getCallingQueueState(): "empty" | string;
+
+ notifyEventFromWallet(event: NotificationType): void;
+}
+
+type CallRecord = WalletCallRecord | BackgroundCallRecord;
+interface WalletCallRecord {
+ source: "wallet"
+ callback: () => void;
+ operation: WalletCoreOpKeys,
+ payload?: WalletCoreRequestType<WalletCoreOpKeys>,
+ response?: WalletCoreResponseType<WalletCoreOpKeys>,
+}
+interface BackgroundCallRecord {
+ source: "background"
+ name: string,
+ args: any,
+ response: any;
+}
+
+type Subscriptions = {
+ [key in NotificationType]?: VoidFunction;
+};
+
+export function createWalletApiMock(): { handler: MockHandler, mock: typeof wxApi } {
+ const calls = new Array<CallRecord>()
+ const subscriptions: Subscriptions = {};
+
+
+ const mock: typeof wxApi = {
+ wallet: new Proxy<WalletCoreApiClient>({} as any, {
+ get(target, name, receiver) {
+ const functionName = String(name)
+ if (functionName !== "call") {
+ throw Error(`the only method in wallet api should be 'call': ${functionName}`)
+ }
+ return function (operation: WalletCoreOpKeys, payload: WalletCoreRequestType<WalletCoreOpKeys>) {
+ const next = calls.shift()
+
+ if (!next) {
+ throw Error(`wallet operation was called but none was expected: ${operation} (${JSON.stringify(payload, undefined, 2)})`)
+ }
+ if (next.source !== "wallet") {
+ throw Error(`wallet operation expected`)
+ }
+ if (operation !== next.operation) {
+ //more checks, deep check payload
+ throw Error(`wallet operation doesn't match: expected ${next.operation} actual ${operation}`)
+ }
+ next.callback()
+
+ return next.response ?? {}
+ }
+ }
+ }),
+ listener: {
+ onUpdateNotification(mTypes: NotificationType[], callback: (() => void) | undefined): (() => void) {
+ mTypes.forEach(m => {
+ subscriptions[m] = callback
+ })
+ return nullFunction
+ }
+ },
+ background: new Proxy<BackgroundApiClient>({} as any, {
+ get(target, name, receiver) {
+ const functionName = String(name);
+ return function (...args: any) {
+ const next = calls.shift()
+ if (!next) {
+ throw Error(`background operation was called but none was expected: ${functionName} (${JSON.stringify(args, undefined, 2)})`)
+ }
+ if (next.source !== "background" || functionName !== next.name) {
+ //more checks, deep check args
+ throw Error(`background operation doesn't match`)
+ }
+ return next.response
+ }
+ }
+ }),
+ }
+
+
+ const handler: MockHandler = {
+ addWalletCallResponse(operation, payload, response, cb) {
+ calls.push({ source: "wallet", operation, payload, response, callback: cb ? cb : () => { null } })
+ return handler
+ },
+ notifyEventFromWallet(event: NotificationType): void {
+ const callback = subscriptions[event]
+ if (!callback) throw Error(`Expected to have a subscription for ${event}`);
+ return callback();
+ },
+ getCallingQueueState() {
+ return calls.length === 0 ? "empty" : `${calls.length} left`;
+ },
+ }
+
+ return { handler, mock }
+}
diff --git a/packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts b/packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts
index 0b50d9d85..09609a8a1 100644
--- a/packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts
@@ -16,15 +16,15 @@
import { Loading } from "../../components/Loading.js";
import { HookError } from "../../hooks/useAsyncAsHook.js";
-import { compose, StateViewMap } from "../../utils/index.js";
-import { LoadingUriView, ReadyView } from "./views.js";
-import * as wxApi from "../../wxApi.js";
-import { useComponentState } from "./state.js";
import {
ButtonHandler,
SelectFieldHandler,
- TextFieldHandler,
+ TextFieldHandler
} from "../../mui/handlers.js";
+import { compose, StateViewMap } from "../../utils/index.js";
+import { wxApi } from "../../wxApi.js";
+import { useComponentState } from "./state.js";
+import { LoadingUriView, ReadyView } from "./views.js";
export interface Props {
currency: string;
diff --git a/packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts b/packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts
index f14c4c1bb..a9e8dfb30 100644
--- a/packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts
@@ -15,19 +15,17 @@
*/
import { parsePaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useState } from "preact/hooks";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
export function useComponentState(
{ currency, onAccountAdded, onCancel }: Props,
api: typeof wxApi,
): State {
- const hook = useAsyncAsHook(async () => {
- const { accounts } = await api.listKnownBankAccounts(currency);
- return { accounts };
- });
+ const hook = useAsyncAsHook(() => api.wallet.call(WalletApiOperation.ListKnownBankAccounts, { currency }));
const [payto, setPayto] = useState("");
const [alias, setAlias] = useState("");
@@ -61,7 +59,10 @@ export function useComponentState(
async function addAccount(): Promise<void> {
if (!uri || found) return;
- await api.addKnownBankAccounts(uri, currency, alias);
+ const normalizedPayto = stringifyPaytoUri(uri);
+ await api.wallet.call(WalletApiOperation.AddKnownBankAccounts, {
+ alias, currency, payto: normalizedPayto
+ });
onAccountAdded(payto);
}
@@ -69,10 +70,10 @@ export function useComponentState(
payto === ""
? undefined
: !uri
- ? "the uri is not ok"
- : found
- ? "that account is already present"
- : undefined;
+ ? "the uri is not ok"
+ : found
+ ? "that account is already present"
+ : undefined;
const unableToAdd = !type || !alias || paytoUriError;
diff --git a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
index bba8b5964..c9dbfb64d 100644
--- a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
@@ -14,11 +14,7 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import {
- AbsoluteTime,
- BackupRecovery,
- constructRecoveryUri,
-} from "@gnu-taler/taler-util";
+import { AbsoluteTime, constructRecoveryUri } from "@gnu-taler/taler-util";
import {
ProviderInfo,
ProviderPaymentPaid,
@@ -32,8 +28,10 @@ import {
intervalToDuration,
} from "date-fns";
import { Fragment, h, VNode } from "preact";
+import { useEffect, useState } from "preact/hooks";
import { Loading } from "../components/Loading.js";
import { LoadingError } from "../components/LoadingError.js";
+import { QR } from "../components/QR.js";
import {
BoldLight,
Centered,
@@ -48,10 +46,7 @@ import { useTranslationContext } from "../context/translation.js";
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
import { Button } from "../mui/Button.js";
import { Pages } from "../NavigationBar.js";
-import * as wxApi from "../wxApi.js";
-import { wxClient } from "../wxApi.js";
-import { useEffect, useState } from "preact/hooks";
-import { QR } from "../components/QR.js";
+import { wxApi } from "../wxApi.js";
interface Props {
onAddProvider: () => Promise<void>;
@@ -112,7 +107,9 @@ export function ShowRecoveryInfo({
export function BackupPage({ onAddProvider }: Props): VNode {
const { i18n } = useTranslationContext();
- const status = useAsyncAsHook(wxApi.getBackupInfo);
+ const status = useAsyncAsHook(() =>
+ wxApi.wallet.call(WalletApiOperation.GetBackupInfo, {}),
+ );
const [recoveryInfo, setRecoveryInfo] = useState<string>("");
if (!status) {
return <Loading />;
@@ -127,7 +124,10 @@ export function BackupPage({ onAddProvider }: Props): VNode {
}
async function getRecoveryInfo(): Promise<void> {
- const r = await wxClient.call(WalletApiOperation.ExportBackupRecovery, {});
+ const r = await wxApi.wallet.call(
+ WalletApiOperation.ExportBackupRecovery,
+ {},
+ );
const str = constructRecoveryUri(r);
setRecoveryInfo(str);
}
@@ -157,7 +157,9 @@ export function BackupPage({ onAddProvider }: Props): VNode {
<BackupView
providers={providers}
onAddProvider={onAddProvider}
- onSyncAll={wxApi.syncAllProviders}
+ onSyncAll={async () =>
+ wxApi.wallet.call(WalletApiOperation.RunBackupCycle, {}).then()
+ }
onShowInfo={getRecoveryInfo}
/>
);
diff --git a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.test.ts b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.test.ts
index 374d6639f..c757610fc 100644
--- a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.test.ts
+++ b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.test.ts
@@ -34,73 +34,73 @@ const exchangeListEmpty = {};
describe("CreateManualWithdraw states", () => {
it("should set noExchangeFound when exchange list is empty", () => {
- const { getLastResultOrThrow } = mountHook(() =>
+ const { pullLastResultOrThrow } = mountHook(() =>
useComponentState(exchangeListEmpty, undefined, undefined),
);
- const { noExchangeFound } = getLastResultOrThrow();
+ const { noExchangeFound } = pullLastResultOrThrow();
expect(noExchangeFound).equal(true);
});
it("should set noExchangeFound when exchange list doesn't include selected currency", () => {
- const { getLastResultOrThrow } = mountHook(() =>
+ const { pullLastResultOrThrow } = mountHook(() =>
useComponentState(exchangeListWithARSandUSD, undefined, "COL"),
);
- const { noExchangeFound } = getLastResultOrThrow();
+ const { noExchangeFound } = pullLastResultOrThrow();
expect(noExchangeFound).equal(true);
});
it("should select the first exchange from the list", () => {
- const { getLastResultOrThrow } = mountHook(() =>
+ const { pullLastResultOrThrow } = mountHook(() =>
useComponentState(exchangeListWithARSandUSD, undefined, undefined),
);
- const { exchange } = getLastResultOrThrow();
+ const { exchange } = pullLastResultOrThrow();
expect(exchange.value).equal("url1");
});
it("should select the first exchange with the selected currency", () => {
- const { getLastResultOrThrow } = mountHook(() =>
+ const { pullLastResultOrThrow } = mountHook(() =>
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
);
- const { exchange } = getLastResultOrThrow();
+ const { exchange } = pullLastResultOrThrow();
expect(exchange.value).equal("url2");
});
it("should change the exchange when currency change", async () => {
- const { getLastResultOrThrow, waitNextUpdate } = mountHook(() =>
+ const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() =>
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
);
{
- const { exchange, currency } = getLastResultOrThrow();
+ const { exchange, currency } = pullLastResultOrThrow();
expect(exchange.value).equal("url2");
if (currency.onChange === undefined) expect.fail();
currency.onChange("USD");
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const { exchange } = getLastResultOrThrow();
+ const { exchange } = pullLastResultOrThrow();
expect(exchange.value).equal("url1");
}
});
it("should change the currency when exchange change", async () => {
- const { getLastResultOrThrow, waitNextUpdate } = mountHook(() =>
+ const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() =>
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
);
{
- const { exchange, currency } = getLastResultOrThrow();
+ const { exchange, currency } = pullLastResultOrThrow();
expect(exchange.value).equal("url2");
expect(currency.value).equal("ARS");
@@ -109,10 +109,10 @@ describe("CreateManualWithdraw states", () => {
exchange.onChange("url1");
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const { exchange, currency } = getLastResultOrThrow();
+ const { exchange, currency } = pullLastResultOrThrow();
expect(exchange.value).equal("url1");
expect(currency.value).equal("USD");
@@ -120,22 +120,22 @@ describe("CreateManualWithdraw states", () => {
});
it("should update parsed amount when amount change", async () => {
- const { getLastResultOrThrow, waitNextUpdate } = mountHook(() =>
+ const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() =>
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
);
{
- const { amount, parsedAmount } = getLastResultOrThrow();
+ const { amount, parsedAmount } = pullLastResultOrThrow();
expect(parsedAmount).equal(undefined);
amount.onInput("12");
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const { parsedAmount } = getLastResultOrThrow();
+ const { parsedAmount } = pullLastResultOrThrow();
expect(parsedAmount).deep.equals({
value: 12,
@@ -146,41 +146,41 @@ describe("CreateManualWithdraw states", () => {
});
it("should have an amount field", async () => {
- const { getLastResultOrThrow, waitNextUpdate } = mountHook(() =>
+ const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() =>
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
);
await defaultTestForInputText(
- waitNextUpdate,
- () => getLastResultOrThrow().amount,
+ waitForStateUpdate,
+ () => pullLastResultOrThrow().amount,
);
});
it("should have an exchange selector ", async () => {
- const { getLastResultOrThrow, waitNextUpdate } = mountHook(() =>
+ const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() =>
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
);
await defaultTestForInputSelect(
- waitNextUpdate,
- () => getLastResultOrThrow().exchange,
+ waitForStateUpdate,
+ () => pullLastResultOrThrow().exchange,
);
});
it("should have a currency selector ", async () => {
- const { getLastResultOrThrow, waitNextUpdate } = mountHook(() =>
+ const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() =>
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
);
await defaultTestForInputSelect(
- waitNextUpdate,
- () => getLastResultOrThrow().currency,
+ waitForStateUpdate,
+ () => pullLastResultOrThrow().currency,
);
});
});
async function defaultTestForInputText(
- awaiter: () => Promise<void>,
+ awaiter: () => Promise<boolean>,
getField: () => TextFieldHandler,
): Promise<void> {
let nextValue = "";
@@ -191,7 +191,7 @@ async function defaultTestForInputText(
field.onInput(nextValue);
}
- await awaiter();
+ expect(await awaiter()).true;
{
const field = getField();
@@ -200,7 +200,7 @@ async function defaultTestForInputText(
}
async function defaultTestForInputSelect(
- awaiter: () => Promise<void>,
+ awaiter: () => Promise<boolean>,
getField: () => SelectFieldHandler,
): Promise<void> {
let nextValue = "";
@@ -218,7 +218,7 @@ async function defaultTestForInputSelect(
field.onChange(nextValue);
}
- await awaiter();
+ expect(await awaiter()).true;
{
const field = getField();
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts b/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts
index 81d401a70..77661fe15 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts
@@ -14,26 +14,25 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+import { AmountJson, PaytoUri } from "@gnu-taler/taler-util";
import { Loading } from "../../components/Loading.js";
import { HookError } from "../../hooks/useAsyncAsHook.js";
+import {
+ ButtonHandler,
+ SelectFieldHandler,
+ TextFieldHandler
+} from "../../mui/handlers.js";
import { compose, StateViewMap } from "../../utils/index.js";
+import { wxApi } from "../../wxApi.js";
+import { AddAccountPage } from "../AddAccount/index.js";
+import { useComponentState } from "./state.js";
import {
AmountOrCurrencyErrorView,
LoadingErrorView,
NoAccountToDepositView,
NoEnoughBalanceView,
- ReadyView,
+ ReadyView
} from "./views.js";
-import * as wxApi from "../../wxApi.js";
-import { useComponentState } from "./state.js";
-import { AmountJson, PaytoUri } from "@gnu-taler/taler-util";
-import {
- ButtonHandler,
- SelectFieldHandler,
- TextFieldHandler,
- ToggleHandler,
-} from "../../mui/handlers.js";
-import { AddAccountPage } from "../AddAccount/index.js";
export interface Props {
amount?: string;
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
index 57380a632..686cfb4b4 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
@@ -21,11 +21,12 @@ import {
KnownBankAccountsInfo,
parsePaytoUri,
PaytoUri,
- stringifyPaytoUri,
+ stringifyPaytoUri
} from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useState } from "preact/hooks";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
export function useComponentState(
@@ -36,8 +37,10 @@ export function useComponentState(
const currency = parsed !== undefined ? parsed.currency : currencyStr;
const hook = useAsyncAsHook(async () => {
- const { balances } = await api.getBalance();
- const { accounts } = await api.listKnownBankAccounts(currency);
+ const { balances } = await api.wallet.call(WalletApiOperation.GetBalances, {});
+ const { accounts } = await api.wallet.call(WalletApiOperation.ListKnownBankAccounts, {
+ currency
+ });
return { accounts, balances };
});
@@ -127,25 +130,29 @@ export function useComponentState(
// const newSelected = !accountMap[accountStr] ? undefined : accountMap[accountStr];
// if (!newSelected) return;
const uri = !accountStr ? undefined : parsePaytoUri(accountStr);
- setSelectedAccount(uri);
if (uri && parsedAmount) {
try {
const result = await getFeeForAmount(uri, parsedAmount, api);
+ setSelectedAccount(uri);
setFee(result);
} catch (e) {
+ console.error(e)
+ setSelectedAccount(uri);
setFee(undefined);
}
}
}
async function updateAmount(numStr: string): Promise<void> {
- setAmount(numStr);
const parsed = Amounts.parse(`${currency}:${numStr}`);
if (parsed && selectedAccount) {
try {
const result = await getFeeForAmount(selectedAccount, parsed, api);
+ setAmount(numStr);
setFee(result);
} catch (e) {
+ console.error(e)
+ setAmount(numStr);
setFee(undefined);
}
}
@@ -165,10 +172,10 @@ export function useComponentState(
const amountError = !isDirty
? undefined
: !parsedAmount
- ? "Invalid amount"
- : Amounts.cmp(balance, parsedAmount) === -1
- ? `Too much, your current balance is ${Amounts.stringifyValue(balance)}`
- : undefined;
+ ? "Invalid amount"
+ : Amounts.cmp(balance, parsedAmount) === -1
+ ? `Too much, your current balance is ${Amounts.stringifyValue(balance)}`
+ : undefined;
const unableToDeposit =
!parsedAmount ||
@@ -176,13 +183,16 @@ export function useComponentState(
Amounts.isZero(totalToDeposit) ||
fee === undefined ||
amountError !== undefined;
+ // console.log(parsedAmount, selectedAccount, fee, totalToDeposit, amountError)
async function doSend(): Promise<void> {
if (!selectedAccount || !parsedAmount || !currency) return;
- const account = `payto://${selectedAccount.targetType}/${selectedAccount.targetPath}`;
+ const depositPaytoUri = `payto://${selectedAccount.targetType}/${selectedAccount.targetPath}`;
const amount = Amounts.stringify(parsedAmount);
- await api.createDepositGroup(account, amount);
+ await api.wallet.call(WalletApiOperation.CreateDepositGroup, {
+ amount, depositPaytoUri
+ })
onSuccess(currency);
}
@@ -226,9 +236,11 @@ async function getFeeForAmount(
a: AmountJson,
api: typeof wxApi,
): Promise<DepositGroupFees> {
- const account = `payto://${p.targetType}/${p.targetPath}`;
+ const depositPaytoUri = `payto://${p.targetType}/${p.targetPath}`;
const amount = Amounts.stringify(a);
- return await api.getFeeForDeposit(account, amount);
+ return await api.wallet.call(WalletApiOperation.GetFeeForDeposit, {
+ amount, depositPaytoUri
+ })
}
export function labelForAccountType(id: string) {
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts b/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts
index 68df5e402..4d36bc740 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts
@@ -20,101 +20,108 @@
*/
import {
- Amounts,
- Balance,
- BalancesResponse,
- DepositGroupFees,
+ Amounts, DepositGroupFees,
parsePaytoUri,
- stringifyPaytoUri,
+ stringifyPaytoUri
} from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { expect } from "chai";
-import { mountHook } from "../../test-utils.js";
+import { createWalletApiMock, mountHook, nullFunction } from "../../test-utils.js";
-import * as wxApi from "../../wxApi.js";
import { useComponentState } from "./state.js";
const currency = "EUR";
-const withoutFee = async (): Promise<DepositGroupFees> => ({
+const withoutFee = (): DepositGroupFees => ({
coin: Amounts.parseOrThrow(`${currency}:0`),
wire: Amounts.parseOrThrow(`${currency}:0`),
refresh: Amounts.parseOrThrow(`${currency}:0`),
});
-const withSomeFee = async (): Promise<DepositGroupFees> => ({
+const withSomeFee = (): DepositGroupFees => ({
coin: Amounts.parseOrThrow(`${currency}:1`),
wire: Amounts.parseOrThrow(`${currency}:1`),
refresh: Amounts.parseOrThrow(`${currency}:1`),
});
-const freeJustForIBAN = async (account: string): Promise<DepositGroupFees> =>
- /IBAN/i.test(account) ? withSomeFee() : withoutFee();
-
-const someBalance = [
- {
- available: "EUR:10",
- } as Balance,
-];
-
-const nullFunction: any = () => null;
-type VoidFunction = () => void;
-
describe("DepositPage states", () => {
it("should have status 'no-enough-balance' when balance is empty", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = { currency, onCancel: nullFunction, onSuccess: nullFunction }
+
+ handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, {
+ balances: [{
+ available: `${currency}:0`,
+ hasPendingTransactions: false,
+ pendingIncoming: `${currency}:0`,
+ pendingOutgoing: `${currency}:0`,
+ requiresUserInput: false,
+ }],
+ })
+ handler.addWalletCallResponse(WalletApiOperation.ListKnownBankAccounts, undefined, {
+ accounts: []
+ });
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
- { currency, onCancel: nullFunction, onSuccess: nullFunction },
- {
- getBalance: async () =>
- ({
- balances: [{ available: `${currency}:0` }],
- } as Partial<BalancesResponse>),
- listKnownBankAccounts: async () => ({ accounts: {} }),
- } as Partial<typeof wxApi> as any,
+ props, mock
),
);
{
- const { status } = getLastResultOrThrow();
+ const { status } = pullLastResultOrThrow();
expect(status).equal("loading");
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const { status } = getLastResultOrThrow();
+ const { status } = pullLastResultOrThrow();
expect(status).equal("no-enough-balance");
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
- // it("should have status 'no-accounts' when balance is not empty and accounts is empty", async () => {
- // const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
- // mountHook(() =>
- // useComponentState({ currency, onCancel: nullFunction, onSuccess: nullFunction }, {
- // getBalance: async () =>
- // ({
- // balances: [{ available: `${currency}:1` }],
- // } as Partial<BalancesResponse>),
- // listKnownBankAccounts: async () => ({ accounts: {} }),
- // } as Partial<typeof wxApi> as any),
- // );
-
- // {
- // const { status } = getLastResultOrThrow();
- // expect(status).equal("loading");
- // }
-
- // await waitNextUpdate();
- // {
- // const r = getLastResultOrThrow();
- // if (r.status !== "no-accounts") expect.fail();
- // expect(r.cancelHandler.onClick).not.undefined;
- // }
-
- // await assertNoPendingUpdate();
- // });
+ it("should have status 'no-accounts' when balance is not empty and accounts is empty", async () => {
+ const { handler, mock } = createWalletApiMock();
+ const props = { currency, onCancel: nullFunction, onSuccess: nullFunction }
+
+ handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, {
+ balances: [{
+ available: `${currency}:1`,
+ hasPendingTransactions: false,
+ pendingIncoming: `${currency}:0`,
+ pendingOutgoing: `${currency}:0`,
+ requiresUserInput: false,
+ }],
+ })
+ handler.addWalletCallResponse(WalletApiOperation.ListKnownBankAccounts, undefined, {
+ accounts: []
+ });
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
+ mountHook(() =>
+ useComponentState(
+ props, mock
+ )
+ );
+
+ {
+ const { status } = pullLastResultOrThrow();
+ expect(status).equal("loading");
+ }
+
+ expect(await waitForStateUpdate()).true;
+ {
+ const r = pullLastResultOrThrow();
+ if (r.status !== "no-accounts") expect.fail();
+ // expect(r.cancelHandler.onClick).not.undefined;
+ }
+
+ await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
+ });
const ibanPayto = {
uri: parsePaytoUri("payto://iban/ES8877998399652238")!,
@@ -130,29 +137,38 @@ describe("DepositPage states", () => {
};
it("should have status 'ready' but unable to deposit ", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ const { handler, mock } = createWalletApiMock();
+ const props = { currency, onCancel: nullFunction, onSuccess: nullFunction }
+
+ handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, {
+ balances: [{
+ available: `${currency}:1`,
+ hasPendingTransactions: false,
+ pendingIncoming: `${currency}:0`,
+ pendingOutgoing: `${currency}:0`,
+ requiresUserInput: false,
+ }],
+ })
+ handler.addWalletCallResponse(WalletApiOperation.ListKnownBankAccounts, undefined, {
+ accounts: [ibanPayto]
+ });
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
- { currency, onCancel: nullFunction, onSuccess: nullFunction },
- {
- getBalance: async () =>
- ({
- balances: [{ available: `${currency}:1` }],
- } as Partial<BalancesResponse>),
- listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
- } as Partial<typeof wxApi> as any,
+ props, mock
),
);
{
- const { status } = getLastResultOrThrow();
+ const { status } = pullLastResultOrThrow();
expect(status).equal("loading");
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const r = getLastResultOrThrow();
+ const r = pullLastResultOrThrow();
if (r.status !== "ready") expect.fail();
expect(r.cancelHandler.onClick).not.undefined;
expect(r.currency).eq(currency);
@@ -162,33 +178,46 @@ describe("DepositPage states", () => {
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
- it.skip("should not be able to deposit more than the balance ", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ it("should not be able to deposit more than the balance ", async () => {
+ const { handler, mock } = createWalletApiMock();
+ const props = { currency, onCancel: nullFunction, onSuccess: nullFunction }
+
+ handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, {
+ balances: [{
+ available: `${currency}:5`,
+ hasPendingTransactions: false,
+ pendingIncoming: `${currency}:0`,
+ pendingOutgoing: `${currency}:0`,
+ requiresUserInput: false,
+ }],
+ })
+ handler.addWalletCallResponse(WalletApiOperation.ListKnownBankAccounts, undefined, {
+ accounts: [ibanPayto]
+ });
+ handler.addWalletCallResponse(WalletApiOperation.GetFeeForDeposit, undefined, withoutFee())
+ handler.addWalletCallResponse(WalletApiOperation.GetFeeForDeposit, undefined, withoutFee())
+ handler.addWalletCallResponse(WalletApiOperation.GetFeeForDeposit, undefined, withoutFee())
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
- { currency, onCancel: nullFunction, onSuccess: nullFunction },
- {
- getBalance: async () =>
- ({
- balances: [{ available: `${currency}:1` }],
- } as Partial<BalancesResponse>),
- listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
- getFeeForDeposit: withoutFee,
- } as Partial<typeof wxApi> as any,
+ props, mock
),
);
{
- const { status } = getLastResultOrThrow();
+ const { status } = pullLastResultOrThrow();
expect(status).equal("loading");
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
+ const accountSelected = stringifyPaytoUri(ibanPayto.uri)
{
- const r = getLastResultOrThrow();
+ const r = pullLastResultOrThrow();
if (r.status !== "ready") expect.fail();
expect(r.cancelHandler.onClick).not.undefined;
expect(r.currency).eq(currency);
@@ -196,68 +225,19 @@ describe("DepositPage states", () => {
expect(r.amount.value).eq("0");
expect(r.depositHandler.onClick).undefined;
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
+ expect(r.account.onChange).not.undefined;
- r.amount.onInput("10");
- }
-
- await waitNextUpdate();
-
- {
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
- expect(r.cancelHandler.onClick).not.undefined;
- expect(r.currency).eq(currency);
- expect(r.account.value).eq("");
- expect(r.amount.value).eq("10");
- expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
- expect(r.depositHandler.onClick).undefined;
+ r.account.onChange!(accountSelected)
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const r = getLastResultOrThrow();
+ const r = pullLastResultOrThrow();
if (r.status !== "ready") expect.fail();
expect(r.cancelHandler.onClick).not.undefined;
expect(r.currency).eq(currency);
- expect(r.account.value).eq("");
- expect(r.amount.value).eq("10");
- expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
- expect(r.depositHandler.onClick).undefined;
- }
-
- await assertNoPendingUpdate();
- });
-
- it.skip("should calculate the fee upon entering amount ", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
- mountHook(() =>
- useComponentState(
- { currency, onCancel: nullFunction, onSuccess: nullFunction },
- {
- getBalance: async () =>
- ({
- balances: [{ available: `${currency}:1` }],
- } as Partial<BalancesResponse>),
- listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
- getFeeForDeposit: withSomeFee,
- } as Partial<typeof wxApi> as any,
- ),
- );
-
- {
- const { status } = getLastResultOrThrow();
- expect(status).equal("loading");
- }
-
- await waitNextUpdate();
-
- {
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
- expect(r.cancelHandler.onClick).not.undefined;
- expect(r.currency).eq(currency);
- expect(r.account.value).eq("");
+ expect(r.account.value).eq(accountSelected);
expect(r.amount.value).eq("0");
expect(r.depositHandler.onClick).undefined;
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
@@ -265,64 +245,74 @@ describe("DepositPage states", () => {
r.amount.onInput("10");
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const r = getLastResultOrThrow();
+ const r = pullLastResultOrThrow();
if (r.status !== "ready") expect.fail();
expect(r.cancelHandler.onClick).not.undefined;
expect(r.currency).eq(currency);
- expect(r.account.value).eq("");
+ expect(r.account.value).eq(accountSelected);
expect(r.amount.value).eq("10");
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
- expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:10`));
expect(r.depositHandler.onClick).undefined;
+
+ r.amount.onInput("3");
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const r = getLastResultOrThrow();
+ const r = pullLastResultOrThrow();
if (r.status !== "ready") expect.fail();
expect(r.cancelHandler.onClick).not.undefined;
expect(r.currency).eq(currency);
- expect(r.account.value).eq("");
- expect(r.amount.value).eq("10");
- expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
- expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`));
- expect(r.depositHandler.onClick).undefined;
+ expect(r.account.value).eq(accountSelected);
+ expect(r.amount.value).eq("3");
+ expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
+ expect(r.depositHandler.onClick).not.undefined;
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
- it("should calculate the fee upon selecting account ", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
+ it("should calculate the fee upon entering amount ", async () => {
+ const { handler, mock } = createWalletApiMock();
+ const props = { currency, onCancel: nullFunction, onSuccess: nullFunction }
+
+ handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, {
+ balances: [{
+ available: `${currency}:10`,
+ hasPendingTransactions: false,
+ pendingIncoming: `${currency}:0`,
+ pendingOutgoing: `${currency}:0`,
+ requiresUserInput: false,
+ }],
+ })
+ handler.addWalletCallResponse(WalletApiOperation.ListKnownBankAccounts, undefined, {
+ accounts: [ibanPayto]
+ });
+ handler.addWalletCallResponse(WalletApiOperation.GetFeeForDeposit, undefined, withSomeFee())
+ handler.addWalletCallResponse(WalletApiOperation.GetFeeForDeposit, undefined, withSomeFee())
+
+ const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
mountHook(() =>
useComponentState(
- { currency, onCancel: nullFunction, onSuccess: nullFunction },
- {
- getBalance: async () =>
- ({
- balances: [{ available: `${currency}:1` }],
- } as Partial<BalancesResponse>),
- listKnownBankAccounts: async () => ({
- accounts: [ibanPayto, talerBankPayto],
- }),
- getFeeForDeposit: freeJustForIBAN,
- } as Partial<typeof wxApi> as any,
+ props, mock
),
);
{
- const { status } = getLastResultOrThrow();
+ const { status } = pullLastResultOrThrow();
expect(status).equal("loading");
}
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
+ const accountSelected = stringifyPaytoUri(ibanPayto.uri)
{
- const r = getLastResultOrThrow();
+ const r = pullLastResultOrThrow();
if (r.status !== "ready") expect.fail();
expect(r.cancelHandler.onClick).not.undefined;
expect(r.currency).eq(currency);
@@ -330,198 +320,42 @@ describe("DepositPage states", () => {
expect(r.amount.value).eq("0");
expect(r.depositHandler.onClick).undefined;
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
- expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
+ expect(r.account.onChange).not.undefined;
- if (r.account.onChange === undefined) expect.fail();
- r.account.onChange(stringifyPaytoUri(ibanPayto.uri));
+ r.account.onChange!(accountSelected)
}
- await waitNextUpdate("");
+ expect(await waitForStateUpdate()).true;
{
- const r = getLastResultOrThrow();
+ const r = pullLastResultOrThrow();
if (r.status !== "ready") expect.fail();
expect(r.cancelHandler.onClick).not.undefined;
expect(r.currency).eq(currency);
- expect(r.account.value).eq(stringifyPaytoUri(ibanPayto.uri));
+ expect(r.account.value).eq(accountSelected);
expect(r.amount.value).eq("0");
- expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
- expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
- expect(r.depositHandler.onClick).undefined;
- }
-
- await waitNextUpdate("");
-
- {
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
- expect(r.cancelHandler.onClick).not.undefined;
- expect(r.currency).eq(currency);
- expect(r.account.value).eq(stringifyPaytoUri(ibanPayto.uri));
- expect(r.amount.value).eq("0");
- expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
- expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
- expect(r.depositHandler.onClick).undefined;
-
- r.amount.onInput("10");
- }
-
- await waitNextUpdate("");
-
- {
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
- expect(r.cancelHandler.onClick).not.undefined;
- expect(r.currency).eq(currency);
- expect(r.account.value).eq(stringifyPaytoUri(ibanPayto.uri));
- expect(r.amount.value).eq("10");
- expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
- expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`));
- expect(r.depositHandler.onClick).undefined;
- }
-
- await waitNextUpdate("");
-
- {
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
- expect(r.cancelHandler.onClick).not.undefined;
- expect(r.currency).eq(currency);
- expect(r.account.value).eq(stringifyPaytoUri(ibanPayto.uri));
- expect(r.amount.value).eq("10");
- expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
- expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`));
expect(r.depositHandler.onClick).undefined;
-
- if (r.account.onChange === undefined) expect.fail();
- r.account.onChange(stringifyPaytoUri(talerBankPayto.uri));
- }
-
- await waitNextUpdate("");
-
- {
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
- expect(r.cancelHandler.onClick).not.undefined;
- expect(r.currency).eq(currency);
- expect(r.account.value).eq(stringifyPaytoUri(talerBankPayto.uri));
- expect(r.amount.value).eq("10");
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
- expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`));
- expect(r.depositHandler.onClick).undefined;
- }
-
- await waitNextUpdate("");
-
- {
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
- expect(r.cancelHandler.onClick).not.undefined;
- expect(r.currency).eq(currency);
- expect(r.account.value).eq(stringifyPaytoUri(talerBankPayto.uri));
- expect(r.amount.value).eq("10");
- expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
- expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:10`));
- expect(r.depositHandler.onClick).undefined;
- }
-
- await assertNoPendingUpdate();
- });
-
- it.skip("should be able to deposit if has the enough balance ", async () => {
- const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
- mountHook(() =>
- useComponentState(
- { currency, onCancel: nullFunction, onSuccess: nullFunction },
- {
- getBalance: async () =>
- ({
- balances: [{ available: `${currency}:15` }],
- } as Partial<BalancesResponse>),
- listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
- getFeeForDeposit: withSomeFee,
- } as Partial<typeof wxApi> as any,
- ),
- );
-
- {
- const { status } = getLastResultOrThrow();
- expect(status).equal("loading");
- }
-
- await waitNextUpdate();
-
- {
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
- expect(r.cancelHandler.onClick).not.undefined;
- expect(r.currency).eq(currency);
- expect(r.account.value).eq("");
- expect(r.amount.value).eq("0");
- expect(r.depositHandler.onClick).undefined;
- expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
r.amount.onInput("10");
}
- await waitNextUpdate();
-
- {
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
- expect(r.cancelHandler.onClick).not.undefined;
- expect(r.currency).eq(currency);
- expect(r.account.value).eq("");
- expect(r.amount.value).eq("10");
- expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
- expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:10`));
- expect(r.depositHandler.onClick).undefined;
- }
-
- await waitNextUpdate();
+ expect(await waitForStateUpdate()).true;
{
- const r = getLastResultOrThrow();
+ const r = pullLastResultOrThrow();
if (r.status !== "ready") expect.fail();
expect(r.cancelHandler.onClick).not.undefined;
expect(r.currency).eq(currency);
- expect(r.account.value).eq("");
+ expect(r.account.value).eq(accountSelected);
expect(r.amount.value).eq("10");
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`));
expect(r.depositHandler.onClick).not.undefined;
-
- r.amount.onInput("13");
- }
-
- await waitNextUpdate();
-
- {
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
- expect(r.cancelHandler.onClick).not.undefined;
- expect(r.currency).eq(currency);
- expect(r.account.value).eq("");
- expect(r.amount.value).eq("13");
- expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
- expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:10`));
- expect(r.depositHandler.onClick).not.undefined;
- }
-
- await waitNextUpdate();
-
- {
- const r = getLastResultOrThrow();
- if (r.status !== "ready") expect.fail();
- expect(r.cancelHandler.onClick).not.undefined;
- expect(r.currency).eq(currency);
- expect(r.account.value).eq("");
- expect(r.amount.value).eq("13");
- expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
- expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:10`));
- expect(r.depositHandler.onClick).not.undefined;
}
await assertNoPendingUpdate();
+ expect(handler.getCallingQueueState()).eq("empty")
});
+
});
diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx b/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx
index 94e6ab442..1e52f11bc 100644
--- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx
@@ -15,6 +15,7 @@
*/
import { Amounts } from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { styled } from "@linaria/react";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
@@ -36,7 +37,7 @@ import { TextField } from "../mui/TextField.js";
import { Pages } from "../NavigationBar.js";
import arrowIcon from "../svg/chevron-down.svg";
import bankIcon from "../svg/ri-bank-line.svg";
-import * as wxApi from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
const Container = styled.div`
display: flex;
@@ -171,7 +172,9 @@ export function SelectCurrency({
}): VNode {
const { i18n } = useTranslationContext();
- const hook = useAsyncAsHook(wxApi.listExchanges);
+ const hook = useAsyncAsHook(() =>
+ wxApi.wallet.call(WalletApiOperation.ListExchanges, {}),
+ );
if (!hook) {
return <Loading />;
diff --git a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
index c0e35b17b..2333fd3c1 100644
--- a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
@@ -21,7 +21,10 @@ import {
ExchangeListItem,
NotificationType,
} from "@gnu-taler/taler-util";
-import { PendingTaskInfo } from "@gnu-taler/taler-wallet-core";
+import {
+ PendingTaskInfo,
+ WalletApiOperation,
+} from "@gnu-taler/taler-wallet-core";
import { format } from "date-fns";
import { Fragment, h, VNode } from "preact";
import { useEffect, useRef, useState } from "preact/hooks";
@@ -33,8 +36,7 @@ import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
import { useDiagnostics } from "../hooks/useDiagnostics.js";
import { Button } from "../mui/Button.js";
import { Grid } from "../mui/Grid.js";
-import { Paper } from "../mui/Paper.js";
-import * as wxApi from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
export function DeveloperPage(): VNode {
const [status, timedOut] = useDiagnostics();
@@ -44,9 +46,12 @@ export function DeveloperPage(): VNode {
listenAllEvents.includes = (e) => e !== "waiting-for-retry"; // includes every event
const response = useAsyncAsHook(async () => {
- const op = await wxApi.getPendingOperations();
- const c = await wxApi.dumpCoins();
- const ex = await wxApi.listExchanges();
+ const op = await wxApi.wallet.call(
+ WalletApiOperation.GetPendingOperations,
+ {},
+ );
+ const c = await wxApi.wallet.call(WalletApiOperation.DumpCoins, {});
+ const ex = await wxApi.wallet.call(WalletApiOperation.ListExchanges, {});
return {
operations: op.pendingOperations,
coins: c.coins,
@@ -55,9 +60,10 @@ export function DeveloperPage(): VNode {
});
useEffect(() => {
- return wxApi.onUpdateNotification(listenAllEvents, () => {
- response?.retry();
- });
+ return wxApi.listener.onUpdateNotification(
+ listenAllEvents,
+ response?.retry,
+ );
});
const nonResponse = { operations: [], coins: [], exchanges: [] };
@@ -76,7 +82,7 @@ export function DeveloperPage(): VNode {
coins={coins}
exchanges={exchanges}
onDownloadDatabase={async () => {
- const db = await wxApi.exportDB();
+ const db = await wxApi.wallet.call(WalletApiOperation.ExportDb, {});
return JSON.stringify(db);
}}
/>
@@ -131,7 +137,9 @@ export function View({
}
const fileRef = useRef<HTMLInputElement>(null);
async function onImportDatabase(str: string): Promise<void> {
- return wxApi.importDB(JSON.parse(str));
+ return wxApi.wallet.call(WalletApiOperation.ImportDb, {
+ dump: JSON.parse(str),
+ });
}
const currencies: { [ex: string]: string } = {};
const money_by_exchange = coins.reduce(
@@ -169,7 +177,7 @@ export function View({
onClick={() =>
confirmReset(
i18n.str`Do you want to IRREVOCABLY DESTROY everything inside your wallet and LOSE ALL YOUR COINS?`,
- wxApi.resetDb,
+ () => wxApi.background.resetDb(),
)
}
>
@@ -182,7 +190,7 @@ export function View({
onClick={() =>
confirmReset(
i18n.str`TESTING: This may delete all your coin, proceed with caution`,
- wxApi.runGarbageCollector,
+ () => wxApi.background.runGarbageCollector(),
)
}
>
diff --git a/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/index.ts b/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/index.ts
index 605c71e80..4b7725264 100644
--- a/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/index.ts
@@ -17,9 +17,9 @@
import { Loading } from "../../components/Loading.js";
import { HookError } from "../../hooks/useAsyncAsHook.js";
import { compose, StateViewMap } from "../../utils/index.js";
-import { LoadingUriView, ReadyView } from "./views.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { useComponentState } from "./state.js";
+import { LoadingUriView, ReadyView } from "./views.js";
export interface Props {
p: string;
diff --git a/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/state.ts b/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/state.ts
index 2c5ac95c0..d194b3f97 100644
--- a/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/state.ts
@@ -14,7 +14,7 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
export function useComponentState({ p }: Props, api: typeof wxApi): State {
diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx
index 859a7f86b..a0c62787a 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx
@@ -18,11 +18,12 @@ import {
canonicalizeBaseUrl,
TalerConfigResponse,
} from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
import { queryToSlashKeys } from "../utils/index.js";
-import * as wxApi from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
import { ExchangeAddConfirmPage } from "./ExchangeAddConfirm.js";
import { ExchangeSetUrlPage } from "./ExchangeSetUrl.js";
@@ -36,7 +37,9 @@ export function ExchangeAddPage({ currency, onBack }: Props): VNode {
{ url: string; config: TalerConfigResponse } | undefined
>(undefined);
- const knownExchangesResponse = useAsyncAsHook(wxApi.listExchanges);
+ const knownExchangesResponse = useAsyncAsHook(() =>
+ wxApi.wallet.call(WalletApiOperation.ListExchanges, {}),
+ );
const knownExchanges = !knownExchangesResponse
? []
: knownExchangesResponse.hasError
@@ -72,7 +75,7 @@ export function ExchangeAddPage({ currency, onBack }: Props): VNode {
url={verifying.url}
onCancel={onBack}
onConfirm={async () => {
- await wxApi.addExchange({
+ await wxApi.wallet.call(WalletApiOperation.AddExchange, {
exchangeBaseUrl: canonicalizeBaseUrl(verifying.url),
forceUpdate: true,
});
diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts
index 2ea73d310..ddfaa71f9 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts
@@ -18,15 +18,14 @@ import {
DenomOperationMap,
ExchangeFullDetails,
ExchangeListItem,
- FeeDescriptionPair,
+ FeeDescriptionPair
} from "@gnu-taler/taler-util";
import { Loading } from "../../components/Loading.js";
-import { TermsState } from "../../components/TermsOfService/utils.js";
import { HookError } from "../../hooks/useAsyncAsHook.js";
import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js";
import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
import { compose, StateViewMap } from "../../utils/index.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { useComponentState } from "./state.js";
import {
ComparingView,
@@ -34,7 +33,7 @@ import {
NoExchangesView,
PrivacyContentView,
ReadyView,
- TosContentView,
+ TosContentView
} from "./views.js";
export interface Props {
diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
index 2450a90ca..ee839cad7 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
@@ -15,10 +15,10 @@
*/
import { DenomOperationMap, FeeDescription } from "@gnu-taler/taler-util";
-import { createPairTimeline } from "@gnu-taler/taler-wallet-core";
+import { createPairTimeline, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useState } from "preact/hooks";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
-import * as wxApi from "../../wxApi.js";
+import { wxApi } from "../../wxApi.js";
import { Props, State } from "./index.js";
export function useComponentState(
@@ -36,22 +36,20 @@ export function useComponentState(
const [value, setValue] = useState(String(initialValue));
const hook = useAsyncAsHook(async () => {
- // const { exchanges } = await api.listExchanges();
-
const selectedIdx = parseInt(value, 10);
const selectedExchange =
exchanges.length == 0 ? undefined : exchanges[selectedIdx];
const selected = !selectedExchange
? undefined
- : await api.getExchangeDetailedInfo(selectedExchange.exchangeBaseUrl);
+ : await api.wallet.call(WalletApiOperation.GetExchangeDetailedInfo, { exchangeBaseUrl: selectedExchange.exchangeBaseUrl });
const initialExchange =
selectedIdx === initialValue ? undefined : exchanges[initialValue];
const original = !initialExchange
? undefined
- : await api.getExchangeDetailedInfo(initialExchange.exchangeBaseUrl);
+ : await api.wallet.call(WalletApiOperation.GetExchangeDetailedInfo, { exchangeBaseUrl: initialExchange.exchangeBaseUrl });
- return { exchanges, selected, original };
+ return { exchanges, selected: selected?.exchange, original: original?.exchange };
}, [value]);
const [showingTos, setShowingTos] = useState<string | undefined>(undefined);
diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx b/packages/taler-wallet-webextension/src/wallet/History.tsx
index 53913501d..4b9c5c711 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.tsx
@@ -20,6 +20,7 @@ import {
NotificationType,
Transaction,
} from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { Fragment, h, VNode } from "preact";
import { useEffect, useState } from "preact/hooks";
import { Loading } from "../components/Loading.js";
@@ -38,7 +39,7 @@ import { Button } from "../mui/Button.js";
import { NoBalanceHelp } from "../popup/NoBalanceHelp.js";
import DownloadIcon from "../svg/download_24px.svg";
import UploadIcon from "../svg/upload_24px.svg";
-import * as wxApi from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
interface Props {
currency?: string;
@@ -52,16 +53,14 @@ export function HistoryPage({
}: Props): VNode {
const { i18n } = useTranslationContext();
const state = useAsyncAsHook(async () => ({
- b: await wxApi.getBalance(),
- tx: await wxApi.getTransactions(),
+ b: await wxApi.wallet.call(WalletApiOperation.GetBalances, {}),
+ tx: await wxApi.wallet.call(WalletApiOperation.GetTransactions, {}),
}));
useEffect(() => {
- return wxApi.onUpdateNotification(
+ return wxApi.listener.onUpdateNotification(
[NotificationType.WithdrawGroupFinished],
- () => {
- state?.retry();
- },
+ state?.retry,
);
});
diff --git a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
index 3714ae538..e2284a466 100644
--- a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
@@ -22,13 +22,14 @@ import {
parsePaytoUri,
PaytoUri,
} from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { h, VNode } from "preact";
import { useEffect, useState } from "preact/hooks";
import { Loading } from "../components/Loading.js";
import { LoadingError } from "../components/LoadingError.js";
import { useTranslationContext } from "../context/translation.js";
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
-import * as wxApi from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
import { CreateManualWithdraw } from "./CreateManualWithdraw.js";
import { ReserveCreated } from "./ReserveCreated.js";
@@ -50,11 +51,14 @@ export function ManualWithdrawPage({ amount, onCancel }: Props): VNode {
>(undefined);
const [error, setError] = useState<string | undefined>(undefined);
- const state = useAsyncAsHook(wxApi.listExchanges);
+ const state = useAsyncAsHook(() =>
+ wxApi.wallet.call(WalletApiOperation.ListExchanges, {}),
+ );
useEffect(() => {
- return wxApi.onUpdateNotification([NotificationType.ExchangeAdded], () => {
- state?.retry();
- });
+ return wxApi.listener.onUpdateNotification(
+ [NotificationType.ExchangeAdded],
+ state?.retry,
+ );
});
const { i18n } = useTranslationContext();
@@ -63,9 +67,12 @@ export function ManualWithdrawPage({ amount, onCancel }: Props): VNode {
amount: AmountJson,
): Promise<void> {
try {
- const response = await wxApi.acceptManualWithdrawal(
- exchangeBaseUrl,
- Amounts.stringify(amount),
+ const response = await wxApi.wallet.call(
+ WalletApiOperation.AcceptManualWithdrawal,
+ {
+ exchangeBaseUrl: exchangeBaseUrl,
+ amount: Amounts.stringify(amount),
+ },
);
const payto = response.exchangePaytoUris[0];
const paytoURI = parsePaytoUri(payto);
diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx
index e0bdeec5f..d5f072828 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx
@@ -34,8 +34,7 @@ import {
import { useTranslationContext } from "../context/translation.js";
import { Button } from "../mui/Button.js";
import { queryToSlashConfig } from "../utils/index.js";
-import * as wxApi from "../wxApi.js";
-import { wxClient } from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
interface Props {
currency: string;
@@ -71,7 +70,7 @@ export function ProviderAddPage({ onBack }: Props): VNode {
setVerifying(undefined);
}}
onConfirm={() => {
- return wxClient
+ return wxApi.wallet
.call(WalletApiOperation.AddBackupProvider, {
backupProviderBaseUrl: verifying.url,
name: verifying.name,
diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
index 5378f4b93..d9dd1d746 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
@@ -20,6 +20,7 @@ import {
ProviderInfo,
ProviderPaymentStatus,
ProviderPaymentType,
+ WalletApiOperation,
} from "@gnu-taler/taler-wallet-core";
import { Fragment, h, VNode } from "preact";
import { ErrorMessage } from "../components/ErrorMessage.js";
@@ -30,7 +31,7 @@ import { Time } from "../components/Time.js";
import { useTranslationContext } from "../context/translation.js";
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
import { Button } from "../mui/Button.js";
-import * as wxApi from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
interface Props {
pid: string;
@@ -41,7 +42,10 @@ export function ProviderDetailPage({ pid: providerURL, onBack }: Props): VNode {
const { i18n } = useTranslationContext();
async function getProviderInfo(): Promise<ProviderInfo | null> {
//create a first list of backup info by currency
- const status = await wxApi.getBackupInfo();
+ const status = await wxApi.wallet.call(
+ WalletApiOperation.GetBackupInfo,
+ {},
+ );
const providers = status.providers.filter(
(p) => p.syncProviderBaseUrl === providerURL,
@@ -72,8 +76,20 @@ export function ProviderDetailPage({ pid: providerURL, onBack }: Props): VNode {
<ProviderView
url={providerURL}
info={state.response}
- onSync={() => wxApi.syncOneProvider(providerURL)}
- onDelete={() => wxApi.removeProvider(providerURL).then(onBack)}
+ onSync={async () =>
+ wxApi.wallet
+ .call(WalletApiOperation.RunBackupCycle, {
+ providers: [providerURL],
+ })
+ .then()
+ }
+ onDelete={() =>
+ wxApi.wallet
+ .call(WalletApiOperation.RemoveBackupProvider, {
+ provider: providerURL,
+ })
+ .then(onBack)
+ }
onBack={onBack}
onExtend={async () => {
null;
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
index 8f6807d46..a4f51de29 100644
--- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
@@ -43,7 +43,7 @@ import { useClipboardPermissions } from "../hooks/useClipboardPermissions.js";
import { ToggleHandler } from "../mui/handlers.js";
import { Pages } from "../NavigationBar.js";
import { platform } from "../platform/api.js";
-import { wxClient } from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined;
@@ -55,8 +55,8 @@ export function SettingsPage(): VNode {
const webex = platform.getWalletWebExVersion();
const exchangesHook = useAsyncAsHook(async () => {
- const list = await wxClient.call(WalletApiOperation.ListExchanges, {});
- const version = await wxClient.call(WalletApiOperation.GetVersion, {});
+ const list = await wxApi.wallet.call(WalletApiOperation.ListExchanges, {});
+ const version = await wxApi.wallet.call(WalletApiOperation.GetVersion, {});
return { exchanges: list.exchanges, version };
});
const { exchanges, version } =
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index c95b79fbc..d7b6e3b1c 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -34,6 +34,7 @@ import {
TransactionType,
WithdrawalType,
} from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { styled } from "@linaria/react";
import { differenceInSeconds } from "date-fns";
import { ComponentChildren, Fragment, h, VNode } from "preact";
@@ -62,31 +63,33 @@ import { useTranslationContext } from "../context/translation.js";
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
import { Button } from "../mui/Button.js";
import { Pages } from "../NavigationBar.js";
-import * as wxApi from "../wxApi.js";
+import { wxApi } from "../wxApi.js";
interface Props {
tid: string;
goToWalletHistory: (currency?: string) => Promise<void>;
}
-async function getTransaction(tid: string): Promise<Transaction> {
- const res = await wxApi.getTransactionById(tid);
- return res;
-}
-
-export function TransactionPage({ tid, goToWalletHistory }: Props): VNode {
+export function TransactionPage({
+ tid: transactionId,
+ goToWalletHistory,
+}: Props): VNode {
const { i18n } = useTranslationContext();
- const state = useAsyncAsHook(() => getTransaction(tid), [tid]);
+ const state = useAsyncAsHook(
+ () =>
+ wxApi.wallet.call(WalletApiOperation.GetTransactionById, {
+ transactionId,
+ }),
+ [transactionId],
+ );
- useEffect(() => {
- return wxApi.onUpdateNotification(
+ useEffect(() =>
+ wxApi.listener.onUpdateNotification(
[NotificationType.WithdrawGroupFinished],
- () => {
- state?.retry();
- },
- );
- });
+ state?.retry,
+ ),
+ );
if (!state) {
return <Loading />;
@@ -113,15 +116,23 @@ export function TransactionPage({ tid, goToWalletHistory }: Props): VNode {
onSend={async () => {
null;
}}
- onDelete={() =>
- wxApi.deleteTransaction(tid).then(() => goToWalletHistory(currency))
- }
- onRetry={async () =>
- await wxApi
- .retryTransaction(tid)
- .then(() => goToWalletHistory(currency))
- }
- onRefund={(id) => wxApi.applyRefundFromPurchaseId(id).then()}
+ onDelete={async () => {
+ await wxApi.wallet.call(WalletApiOperation.DeleteTransaction, {
+ transactionId,
+ });
+ goToWalletHistory(currency);
+ }}
+ onRetry={async () => {
+ await wxApi.wallet.call(WalletApiOperation.RetryTransaction, {
+ transactionId,
+ });
+ goToWalletHistory(currency);
+ }}
+ onRefund={async (purchaseId) => {
+ await wxApi.wallet.call(WalletApiOperation.ApplyRefundFromPurchaseId, {
+ purchaseId,
+ });
+ }}
onBack={() => goToWalletHistory(currency)}
/>
);
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts b/packages/taler-wallet-webextension/src/wxApi.ts
index cb333f1dc..bd1184d46 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -22,77 +22,16 @@
* Imports.
*/
import {
- AcceptExchangeTosRequest,
- AcceptManualWithdrawalResult,
- AcceptPeerPullPaymentRequest,
- AcceptPeerPullPaymentResponse,
- AcceptPeerPushPaymentRequest,
- AcceptPeerPushPaymentResponse,
- AcceptTipRequest,
- AcceptTipResponse,
- AcceptWithdrawalResponse,
- AddExchangeRequest,
- AddKnownBankAccountsRequest,
- AmountString,
- ApplyRefundResponse,
- BalancesResponse,
- CheckPeerPullPaymentRequest,
- CheckPeerPullPaymentResponse,
- CheckPeerPushPaymentRequest,
- CheckPeerPushPaymentResponse,
- CoinDumpJson,
- ConfirmPayResult,
- CoreApiResponse,
- CreateDepositGroupRequest,
- CreateDepositGroupResponse,
- DeleteTransactionRequest,
- DepositGroupFees,
- ExchangeFullDetails,
- ExchangesListResponse,
- ForgetKnownBankAccountsRequest,
- GetExchangeTosResult,
- GetFeeForDepositRequest,
- GetWithdrawalDetailsForAmountRequest,
- GetWithdrawalDetailsForUriRequest,
- InitiatePeerPullPaymentRequest,
- InitiatePeerPullPaymentResponse,
- InitiatePeerPushPaymentRequest,
- InitiatePeerPushPaymentResponse,
- KnownBankAccounts,
- Logger,
- ManualWithdrawalDetails,
- NotificationType,
- PaytoUri,
- PrepareDepositRequest,
- PrepareDepositResponse,
- PreparePayResult,
- PrepareRefundRequest,
- PrepareRefundResult,
- PrepareTipRequest,
- PrepareTipResult,
- RetryTransactionRequest,
- SetWalletDeviceIdRequest,
- stringifyPaytoUri,
- Transaction,
- TransactionsResponse,
- WalletCoreVersion,
- WalletDiagnostics,
- WithdrawUriInfoResponse,
+ CoreApiResponse, Logger, NotificationType, WalletDiagnostics
} from "@gnu-taler/taler-util";
import {
- AddBackupProviderRequest,
- BackupInfo,
- PendingOperationsResponse,
- RemoveBackupProviderRequest,
- TalerError,
- WalletApiOperation,
- WalletContractData,
- WalletCoreApiClient,
+ TalerError, WalletCoreApiClient,
WalletCoreOpKeys,
WalletCoreRequestType,
- WalletCoreResponseType,
+ WalletCoreResponseType
} from "@gnu-taler/taler-wallet-core";
import { MessageFromBackend, platform } from "./platform/api.js";
+import { nullFunction } from "./test-utils.js";
/**
*
@@ -167,381 +106,39 @@ export class WxWalletCoreApiClient implements WalletCoreApiClient {
}
}
-export const wxClient = new WxWalletCoreApiClient();
+export class BackgroundApiClient {
-/**
- * Pay for a proposal.
- */
-export function confirmPay(
- proposalId: string,
- sessionId: string | undefined,
-): Promise<ConfirmPayResult> {
- return wxClient.call(WalletApiOperation.ConfirmPay, {
- proposalId,
- sessionId,
- });
-}
-
-/**
- * Check upgrade information
- */
-export function checkUpgrade(): Promise<UpgradeResponse> {
- return callBackend("check-upgrade", {});
-}
-
-/**
- * Reset database
- */
-export function resetDb(): Promise<void> {
- return callBackend("reset-db", {});
-}
-
-/**
- * Reset database
- */
-export function runGarbageCollector(): Promise<void> {
- return callBackend("run-gc", {});
-}
-
-export function getFeeForDeposit(
- depositPaytoUri: string,
- amount: AmountString,
-): Promise<DepositGroupFees> {
- return callBackend("getFeeForDeposit", {
- depositPaytoUri,
- amount,
- } as GetFeeForDepositRequest);
-}
-
-export function prepareDeposit(
- depositPaytoUri: string,
- amount: AmountString,
-): Promise<PrepareDepositResponse> {
- return callBackend("prepareDeposit", {
- depositPaytoUri,
- amount,
- } as PrepareDepositRequest);
-}
-
-export function createDepositGroup(
- depositPaytoUri: string,
- amount: AmountString,
-): Promise<CreateDepositGroupResponse> {
- return callBackend("createDepositGroup", {
- depositPaytoUri,
- amount,
- } as CreateDepositGroupRequest);
-}
-
-/**
- * Get balances for all currencies/exchanges.
- */
-export function getBalance(): Promise<BalancesResponse> {
- return callBackend("getBalances", {});
-}
-
-export function getContractTermsDetails(
- proposalId: string,
-): Promise<WalletContractData> {
- return callBackend("getContractTermsDetails", { proposalId });
-}
-
-/**
- * Retrieve the full event history for this wallet.
- */
-export function getTransactions(): Promise<TransactionsResponse> {
- return callBackend("getTransactions", {});
-}
-
-interface CurrencyInfo {
- name: string;
- baseUrl: string;
- pub: string;
-}
-interface ListOfKnownCurrencies {
- auditors: CurrencyInfo[];
- exchanges: CurrencyInfo[];
-}
-
-/**
- * Get a list of currencies from known auditors and exchanges
- */
-export function listKnownCurrencies(): Promise<ListOfKnownCurrencies> {
- return callBackend("listCurrencies", {}).then((result) => {
- const auditors = result.trustedAuditors.map(
- (a: Record<string, string>) => ({
- name: a.currency,
- baseUrl: a.auditorBaseUrl,
- pub: a.auditorPub,
- }),
- );
- const exchanges = result.trustedExchanges.map(
- (a: Record<string, string>) => ({
- name: a.currency,
- baseUrl: a.exchangeBaseUrl,
- pub: a.exchangeMasterPub,
- }),
- );
- return { auditors, exchanges };
- });
-}
-
-export function listExchanges(): Promise<ExchangesListResponse> {
- return callBackend("listExchanges", {});
-}
-
-export function getExchangeDetailedInfo(
- exchangeBaseUrl: string,
-): Promise<ExchangeFullDetails> {
- return callBackend("getExchangeDetailedInfo", {
- exchangeBaseUrl,
- });
-}
-
-export function getVersion(): Promise<WalletCoreVersion> {
- return callBackend("getVersion", {});
-}
-
-export function listKnownBankAccounts(
- currency?: string,
-): Promise<KnownBankAccounts> {
- return callBackend("listKnownBankAccounts", { currency });
-}
-
-export function addKnownBankAccounts(
- payto: PaytoUri,
- currency: string,
- alias: string,
-): Promise<void> {
- return callBackend("addKnownBankAccounts", {
- payto: stringifyPaytoUri(payto),
- currency,
- alias,
- } as AddKnownBankAccountsRequest);
-}
-export function forgetKnownBankAccounts(payto: string): Promise<void> {
- return callBackend("forgetKnownBankAccounts", {
- payto,
- } as ForgetKnownBankAccountsRequest);
-}
-
-/**
- * Get information about the current state of wallet backups.
- */
-export function getBackupInfo(): Promise<BackupInfo> {
- return callBackend("getBackupInfo", {});
-}
-
-/**
- * Add a backup provider and activate it
- */
-export function addBackupProvider(
- backupProviderBaseUrl: string,
- name: string,
-): Promise<void> {
- return callBackend("addBackupProvider", {
- backupProviderBaseUrl,
- activate: true,
- name,
- } as AddBackupProviderRequest);
-}
-
-export function setWalletDeviceId(walletDeviceId: string): Promise<void> {
- return callBackend("setWalletDeviceId", {
- walletDeviceId,
- } as SetWalletDeviceIdRequest);
-}
-
-export function syncAllProviders(): Promise<void> {
- return callBackend("runBackupCycle", {});
-}
-
-export function syncOneProvider(url: string): Promise<void> {
- return callBackend("runBackupCycle", { providers: [url] });
-}
-export function removeProvider(url: string): Promise<void> {
- return callBackend("removeBackupProvider", {
- provider: url,
- } as RemoveBackupProviderRequest);
-}
-export function extendedProvider(url: string): Promise<void> {
- return callBackend("extendBackupProvider", { provider: url });
-}
-
-/**
- * Retry a transaction
- * @param transactionId
- * @returns
- */
-export function retryTransaction(transactionId: string): Promise<void> {
- return callBackend("retryTransaction", {
- transactionId,
- } as RetryTransactionRequest);
-}
-
-/**
- * Permanently delete a transaction from the transaction list
- */
-export function deleteTransaction(transactionId: string): Promise<void> {
- return callBackend("deleteTransaction", {
- transactionId,
- } as DeleteTransactionRequest);
-}
-
-/**
- * Download a refund and accept it.
- */
-export function applyRefund(
- talerRefundUri: string,
-): Promise<ApplyRefundResponse> {
- return callBackend("applyRefund", { talerRefundUri });
-}
-
-/**
- * Do refund for purchase.
- */
-export function applyRefundFromPurchaseId(
- purchaseId: string,
-): Promise<ApplyRefundResponse> {
- return callBackend("applyRefundFromPurchaseId", { purchaseId });
-}
-
-/**
- * Get details about a pay operation.
- */
-export function preparePay(talerPayUri: string): Promise<PreparePayResult> {
- return callBackend("preparePayForUri", { talerPayUri });
-}
-
-/**
- * Get details about a withdraw operation.
- */
-export function acceptWithdrawal(
- talerWithdrawUri: string,
- selectedExchange: string,
- restrictAge?: number,
-): Promise<AcceptWithdrawalResponse> {
- return callBackend("acceptBankIntegratedWithdrawal", {
- talerWithdrawUri,
- exchangeBaseUrl: selectedExchange,
- restrictAge,
- });
-}
-
-/**
- * Create a reserve into the exchange that expect the amount indicated
- * @param exchangeBaseUrl
- * @param amount
- * @returns
- */
-export function acceptManualWithdrawal(
- exchangeBaseUrl: string,
- amount: string,
- restrictAge?: number,
-): Promise<AcceptManualWithdrawalResult> {
- return callBackend("acceptManualWithdrawal", {
- amount,
- exchangeBaseUrl,
- restrictAge,
- });
-}
-
-export function setExchangeTosAccepted(
- exchangeBaseUrl: string,
- etag: string | undefined,
-): Promise<void> {
- return callBackend("setExchangeTosAccepted", {
- exchangeBaseUrl,
- etag,
- } as AcceptExchangeTosRequest);
-}
-
-/**
- * Get diagnostics information
- */
-export function getDiagnostics(): Promise<WalletDiagnostics> {
- return callBackend("wxGetDiagnostics", {});
-}
-
-/**
- * Get diagnostics information
- */
-export function toggleHeaderListener(
- value: boolean,
-): Promise<ExtendedPermissionsResponse> {
- return callBackend("toggleHeaderListener", { value });
-}
-
-/**
- * Get diagnostics information
- */
-export function containsHeaderListener(): Promise<ExtendedPermissionsResponse> {
- return callBackend("containsHeaderListener", {});
-}
-
-/**
- * Get diagnostics information
- */
-export function getWithdrawalDetailsForUri(
- req: GetWithdrawalDetailsForUriRequest,
-): Promise<WithdrawUriInfoResponse> {
- return callBackend("getWithdrawalDetailsForUri", req);
-}
-
-export function getWithdrawalDetailsForAmount(
- req: GetWithdrawalDetailsForAmountRequest,
-): Promise<ManualWithdrawalDetails> {
- return callBackend("getWithdrawalDetailsForAmount", req);
-}
-
-export function getExchangeTos(
- exchangeBaseUrl: string,
- acceptedFormat: string[],
-): Promise<GetExchangeTosResult> {
- return callBackend("getExchangeTos", {
- exchangeBaseUrl,
- acceptedFormat,
- });
-}
-
-export function dumpCoins(): Promise<CoinDumpJson> {
- return callBackend("dumpCoins", {});
-}
-
-export function getPendingOperations(): Promise<PendingOperationsResponse> {
- return callBackend("getPendingOperations", {});
-}
-
-export function addExchange(req: AddExchangeRequest): Promise<void> {
- return callBackend("addExchange", req);
-}
+ public resetDb(): Promise<void> {
+ return callBackend("reset-db", {});
+ }
-export function prepareRefund(
- req: PrepareRefundRequest,
-): Promise<PrepareRefundResult> {
- return callBackend("prepareRefund", req);
-}
+ public containsHeaderListener(): Promise<ExtendedPermissionsResponse> {
+ return callBackend("containsHeaderListener", {});
+ }
-export function prepareTip(req: PrepareTipRequest): Promise<PrepareTipResult> {
- return callBackend("prepareTip", req);
-}
+ public getDiagnostics(): Promise<WalletDiagnostics> {
+ return callBackend("wxGetDiagnostics", {});
+ }
-export function acceptTip(req: AcceptTipRequest): Promise<AcceptTipResponse> {
- return callBackend("acceptTip", req);
-}
+ public toggleHeaderListener(
+ value: boolean,
+ ): Promise<ExtendedPermissionsResponse> {
+ return callBackend("toggleHeaderListener", { value });
+ }
-export function exportDB(): Promise<any> {
- return callBackend("exportDb", {});
-}
+ public runGarbageCollector(): Promise<void> {
+ return callBackend("run-gc", {});
+ }
-export function importDB(dump: any): Promise<void> {
- return callBackend("importDb", { dump });
}
-
-export function onUpdateNotification(
+function onUpdateNotification(
messageTypes: Array<NotificationType>,
- doCallback: () => void,
+ doCallback: undefined | (() => void),
): () => void {
+ //if no callback, then ignore
+ if (!doCallback) return () => {
+ return
+ };
const onNewMessage = (message: MessageFromBackend): void => {
const shouldNotify = messageTypes.includes(message.type);
if (shouldNotify) {
@@ -551,39 +148,11 @@ export function onUpdateNotification(
return platform.listenToWalletBackground(onNewMessage);
}
-export function initiatePeerPushPayment(
- req: InitiatePeerPushPaymentRequest,
-): Promise<InitiatePeerPushPaymentResponse> {
- return callBackend("initiatePeerPushPayment", req);
-}
-export function checkPeerPushPayment(
- req: CheckPeerPushPaymentRequest,
-): Promise<CheckPeerPushPaymentResponse> {
- return callBackend("checkPeerPushPayment", req);
-}
-export function acceptPeerPushPayment(
- req: AcceptPeerPushPaymentRequest,
-): Promise<AcceptPeerPushPaymentResponse> {
- return callBackend("acceptPeerPushPayment", req);
-}
-export function initiatePeerPullPayment(
- req: InitiatePeerPullPaymentRequest,
-): Promise<InitiatePeerPullPaymentResponse> {
- return callBackend("initiatePeerPullPayment", req);
-}
-export function checkPeerPullPayment(
- req: CheckPeerPullPaymentRequest,
-): Promise<CheckPeerPullPaymentResponse> {
- return callBackend("checkPeerPullPayment", req);
-}
-export function acceptPeerPullPayment(
- req: AcceptPeerPullPaymentRequest,
-): Promise<AcceptPeerPullPaymentResponse> {
- return callBackend("acceptPeerPullPayment", req);
+export const wxApi = {
+ wallet: new WxWalletCoreApiClient(),
+ background: new BackgroundApiClient(),
+ listener: {
+ onUpdateNotification
+ }
}
-export function getTransactionById(tid: string): Promise<Transaction> {
- return callBackend("getTransactionById", {
- transactionId: tid,
- });
-}