diff options
Diffstat (limited to 'packages/taler-wallet-webextension/src/cta')
25 files changed, 553 insertions, 897 deletions
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/index.ts b/packages/taler-wallet-webextension/src/cta/Deposit/index.ts index 539709821..9ff3ddd1d 100644 --- a/packages/taler-wallet-webextension/src/cta/Deposit/index.ts +++ b/packages/taler-wallet-webextension/src/cta/Deposit/index.ts @@ -19,7 +19,6 @@ 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 { wxApi } from "../../wxApi.js"; import { useComponentState } from "./state.js"; import { LoadingUriView, ReadyView } from "./views.js"; @@ -64,6 +63,6 @@ const viewMapping: StateViewMap<State> = { export const DepositPage = compose( "Deposit", - (p: Props) => useComponentState(p, wxApi), + (p: Props) => useComponentState(p), viewMapping, ); diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/state.ts b/packages/taler-wallet-webextension/src/cta/Deposit/state.ts index 77e918ca9..fbcd107ef 100644 --- a/packages/taler-wallet-webextension/src/cta/Deposit/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Deposit/state.ts @@ -16,14 +16,14 @@ import { Amounts } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { useBackendContext } from "../../context/backend.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; -import { wxApi } from "../../wxApi.js"; import { Props, State } from "./index.js"; export function useComponentState( { talerDepositUri, amountStr, cancel, onSuccess }: Props, - api: typeof wxApi, ): State { + const api = useBackendContext() const info = useAsyncAsHook(async () => { if (!talerDepositUri) throw Error("ERROR_NO-URI-FOR-DEPOSIT"); if (!amountStr) throw Error("ERROR_NO-AMOUNT-FOR-DEPOSIT"); diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/test.ts b/packages/taler-wallet-webextension/src/cta/Deposit/test.ts index a5bfed4a8..1c8d4708d 100644 --- a/packages/taler-wallet-webextension/src/cta/Deposit/test.ts +++ b/packages/taler-wallet-webextension/src/cta/Deposit/test.ts @@ -20,16 +20,18 @@ */ 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"; +import { tests } from "@gnu-taler/web-util/lib/index.browser"; +import { Props } from "./index.js"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; describe("Deposit CTA states", () => { it("should tell the user that the URI is missing", async () => { - const { handler, mock } = createWalletApiMock(); - const props = { + const { handler, TestingContext } = createWalletApiMock(); + + const props: Props = { talerDepositUri: undefined, amountStr: undefined, cancel: async () => { @@ -39,32 +41,28 @@ describe("Deposit CTA states", () => { null; }, }; - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentState(props, mock)); - { - const { status } = pullLastResultOrThrow(); - expect(status).equals("loading"); - } - - expect(await waitForStateUpdate()).true; - - { - const { status, error } = pullLastResultOrThrow(); + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status }) => { + expect(status).equals("loading"); + }, + ({ status, error }) => { + expect(status).equals("loading-uri"); - expect(status).equals("loading-uri"); + if (!error) expect.fail(); + if (!error.hasError) expect.fail(); + if (error.operational) expect.fail(); + expect(error.message).eq("ERROR_NO-URI-FOR-DEPOSIT"); + }, + ], TestingContext) - if (!error) expect.fail(); - if (!error.hasError) expect.fail(); - if (error.operational) expect.fail(); - expect(error.message).eq("ERROR_NO-URI-FOR-DEPOSIT"); - } - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); }); it("should be ready after loading", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); + handler.addWalletCallResponse( WalletApiOperation.PrepareDeposit, undefined, @@ -73,6 +71,7 @@ describe("Deposit CTA states", () => { totalDepositCost: "EUR:1.2", }, ); + const props = { talerDepositUri: "payto://refund/asdasdas", amountStr: "EUR:1", @@ -84,28 +83,21 @@ describe("Deposit CTA states", () => { }, }; - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentState(props, mock)); - - { - const { status } = pullLastResultOrThrow(); - expect(status).equals("loading"); - } - - expect(await waitForStateUpdate()).true; - - { - const state = pullLastResultOrThrow(); - - if (state.status !== "ready") expect.fail(); - if (state.error) expect.fail(); - expect(state.confirm.onClick).not.undefined; - expect(state.cost).deep.eq(Amounts.parseOrThrow("EUR:1.2")); - expect(state.fee).deep.eq(Amounts.parseOrThrow("EUR:0.2")); - expect(state.effective).deep.eq(Amounts.parseOrThrow("EUR:1")); - } + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status }) => { + expect(status).equals("loading"); + }, + (state) => { + if (state.status !== "ready") expect.fail(); + if (state.error) expect.fail(); + expect(state.confirm.onClick).not.undefined; + expect(state.cost).deep.eq(Amounts.parseOrThrow("EUR:1.2")); + expect(state.fee).deep.eq(Amounts.parseOrThrow("EUR:0.2")); + expect(state.effective).deep.eq(Amounts.parseOrThrow("EUR:1")); + }, + ], TestingContext) - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) 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 01dbb6d6d..0569e8e5f 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts @@ -22,7 +22,6 @@ 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 { wxApi } from "../../wxApi.js"; import { useComponentState } from "./state.js"; import { LoadingUriView, ReadyView } from "./views.js"; @@ -78,6 +77,6 @@ const viewMapping: StateViewMap<State> = { export const InvoiceCreatePage = compose( "InvoiceCreatePage", - (p: Props) => useComponentState(p, wxApi), + (p: Props) => useComponentState(p), viewMapping, ); diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts index 6007b5193..a26167f8e 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts @@ -23,17 +23,17 @@ import { import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { isFuture, parse } from "date-fns"; import { useState } from "preact/hooks"; +import { useBackendContext } from "../../context/backend.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; import { useSelectedExchange } from "../../hooks/useSelectedExchange.js"; import { RecursiveState } from "../../utils/index.js"; -import { wxApi } from "../../wxApi.js"; import { Props, State } from "./index.js"; export function useComponentState( { amount: amountStr, onClose, onSuccess }: Props, - api: typeof wxApi, ): RecursiveState<State> { const amount = Amounts.parseOrThrow(amountStr); + const api = useBackendContext() const hook = useAsyncAsHook(() => api.wallet.call(WalletApiOperation.ListExchanges, {}), @@ -158,8 +158,8 @@ export function useComponentState( subject === undefined ? undefined : !subject - ? "Can't be empty" - : undefined, + ? "Can't be empty" + : undefined, value: subject ?? "", onInput: async (e) => setSubject(e), }, diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts b/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts index 6e16b528c..78f244964 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts @@ -18,13 +18,12 @@ 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 { wxApi } from "../../wxApi.js"; import { useComponentState } from "./state.js"; import { LoadingUriView, ReadyView } from "./views.js"; @@ -92,6 +91,6 @@ const viewMapping: StateViewMap<State> = { export const InvoicePayPage = compose( "InvoicePayPage", - (p: Props) => useComponentState(p, wxApi), + (p: Props) => useComponentState(p), viewMapping, ); diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts b/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts index c7fb48958..eb50ba748 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts @@ -25,14 +25,14 @@ import { } from "@gnu-taler/taler-util"; import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useEffect, useState } from "preact/hooks"; +import { useBackendContext } from "../../context/backend.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; -import { wxApi } from "../../wxApi.js"; import { Props, State } from "./index.js"; export function useComponentState( { talerPayPullUri, onClose, goToWalletManualWithdraw, onSuccess }: Props, - api: typeof wxApi, ): State { + const api = useBackendContext() const hook = useAsyncAsHook(async () => { const p2p = await api.wallet.call(WalletApiOperation.CheckPeerPullPayment, { talerUri: talerPayPullUri, diff --git a/packages/taler-wallet-webextension/src/cta/Payment/index.ts b/packages/taler-wallet-webextension/src/cta/Payment/index.ts index 9bca8f74f..45e4a5b88 100644 --- a/packages/taler-wallet-webextension/src/cta/Payment/index.ts +++ b/packages/taler-wallet-webextension/src/cta/Payment/index.ts @@ -19,13 +19,12 @@ import { PreparePayResult, PreparePayResultAlreadyConfirmed, PreparePayResultInsufficientBalance, - PreparePayResultPaymentPossible, + PreparePayResultPaymentPossible } 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 { wxApi } from "../../wxApi.js"; import { useComponentState } from "./state.js"; import { BaseView, LoadingUriView } from "./views.js"; @@ -96,6 +95,6 @@ const viewMapping: StateViewMap<State> = { export const PaymentPage = compose( "Payment", - (p: Props) => useComponentState(p, wxApi), + (p: Props) => useComponentState(p), viewMapping, ); diff --git a/packages/taler-wallet-webextension/src/cta/Payment/state.ts b/packages/taler-wallet-webextension/src/cta/Payment/state.ts index 970af5b81..7690910e6 100644 --- a/packages/taler-wallet-webextension/src/cta/Payment/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Payment/state.ts @@ -23,16 +23,16 @@ import { } from "@gnu-taler/taler-util"; import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useEffect, useState } from "preact/hooks"; +import { useBackendContext } from "../../context/backend.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; import { ButtonHandler } from "../../mui/handlers.js"; -import { wxApi } from "../../wxApi.js"; import { Props, State } from "./index.js"; export function useComponentState( { talerPayUri, cancel, goToWalletManualWithdraw, onSuccess }: Props, - api: typeof wxApi, ): State { const [payErrMsg, setPayErrMsg] = useState<TalerError | undefined>(undefined); + const api = useBackendContext() const hook = useAsyncAsHook(async () => { if (!talerPayUri) throw Error("ERROR_NO-URI-FOR-PAYMENT"); diff --git a/packages/taler-wallet-webextension/src/cta/Payment/test.ts b/packages/taler-wallet-webextension/src/cta/Payment/test.ts index b02ac6274..aba76fcf4 100644 --- a/packages/taler-wallet-webextension/src/cta/Payment/test.ts +++ b/packages/taler-wallet-webextension/src/cta/Payment/test.ts @@ -30,54 +30,46 @@ import { } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { expect } from "chai"; +import { tests } from "../../../../web-util/src/index.browser.js"; import { mountHook, nullFunction } from "../../test-utils.js"; import { createWalletApiMock } from "../../test-utils.js"; import { useComponentState } from "./state.js"; describe("Payment CTA states", () => { it("should tell the user that the URI is missing", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); const props = { talerPayUri: undefined, cancel: nullFunction, goToWalletManualWithdraw: nullFunction, - onSuccess: async () => { - null; - }, + onSuccess: nullFunction, }; - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentState(props, mock)); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - { - const { status, error } = pullLastResultOrThrow(); - - expect(status).equals("loading-uri"); - if (error === undefined) expect.fail(); - expect(error.hasError).true; - expect(error.operational).false; - } + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + ({ status, error }) => { + expect(status).equals("loading-uri"); + if (error === undefined) expect.fail(); + expect(error.hasError).true; + expect(error.operational).false; + }, + ], TestingContext) - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); + }); it("should response with no balance", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); const props = { talerPayUri: "taller://pay", cancel: nullFunction, goToWalletManualWithdraw: nullFunction, - onSuccess: async () => { - null; - }, + onSuccess: nullFunction, }; handler.addWalletCallResponse( @@ -94,41 +86,34 @@ describe("Payment CTA states", () => { { balances: [] }, ); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentState(props, mock)); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - 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")); - } + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + if (state.status !== "no-balance-for-currency") { + expect(state).eq({}); + return; + } + expect(state.balance).undefined; + expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:10")); + }, + ], TestingContext) - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); }); it("should not be able to pay if there is no enough balance", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); const props = { talerPayUri: "taller://pay", cancel: nullFunction, goToWalletManualWithdraw: nullFunction, - onSuccess: async () => { - null; - }, + onSuccess: nullFunction, }; + handler.addWalletCallResponse( WalletApiOperation.PreparePayForUri, undefined, @@ -153,38 +138,31 @@ describe("Payment CTA states", () => { }, ); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentState(props, mock)); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - 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")); - } + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + if (state.status !== "no-enough-balance") expect.fail(); + expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:5")); + expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:10")); + }, + ], TestingContext) - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); }); it("should be able to pay (without fee)", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); const props = { talerPayUri: "taller://pay", cancel: nullFunction, goToWalletManualWithdraw: nullFunction, - onSuccess: async () => { - null; - }, + onSuccess: nullFunction, }; + handler.addWalletCallResponse( WalletApiOperation.PreparePayForUri, undefined, @@ -209,42 +187,36 @@ describe("Payment CTA states", () => { ], }, ); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentState(props, mock)); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - 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.payHandler.onClick).not.undefined; - } - - await assertNoPendingUpdate(); + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + if (state.status !== "ready") { + expect(state).eq({}); + return; + } + expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:15")); + expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:10")); + expect(state.payHandler.onClick).not.undefined; + }, + ], TestingContext) + + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); + }); it("should be able to pay (with fee)", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); const props = { talerPayUri: "taller://pay", cancel: nullFunction, goToWalletManualWithdraw: nullFunction, - onSuccess: async () => { - null; - }, + onSuccess: nullFunction, }; + handler.addWalletCallResponse( WalletApiOperation.PreparePayForUri, undefined, @@ -269,39 +241,32 @@ describe("Payment CTA states", () => { ], }, ); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentState(props, mock)); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - 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.payHandler.onClick).not.undefined; - } - - await assertNoPendingUpdate(); + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + if (state.status !== "ready") expect.fail(); + expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:15")); + expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:9")); + expect(state.payHandler.onClick).not.undefined; + }, + ], TestingContext) + + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); }); it("should get confirmation done after pay successfully", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); const props = { talerPayUri: "taller://pay", cancel: nullFunction, goToWalletManualWithdraw: nullFunction, - onSuccess: async () => { - null; - }, + onSuccess: nullFunction, }; + handler.addWalletCallResponse( WalletApiOperation.PreparePayForUri, undefined, @@ -332,35 +297,30 @@ describe("Payment CTA states", () => { contractTerms: {}, } as ConfirmPayResult); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentState(props, mock)); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - 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")); - if (r.payHandler.onClick === undefined) expect.fail(); - r.payHandler.onClick(); - } - - await assertNoPendingUpdate(); + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + if (state.status !== "ready") { + expect(state).eq({}); + return; + } + expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:15")); + expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:9")); + if (state.payHandler.onClick === undefined) expect.fail(); + state.payHandler.onClick(); + }, + ], TestingContext) + + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); + }); it("should not stay in ready state after pay with error", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); const props = { talerPayUri: "taller://pay", cancel: nullFunction, @@ -397,62 +357,50 @@ describe("Payment CTA states", () => { lastError: { code: 1 }, } as ConfirmPayResult); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentState(props, mock)); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - 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")); - if (r.payHandler.onClick === undefined) expect.fail(); - r.payHandler.onClick(); - } - - expect(await waitForStateUpdate()).true; - - { - 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).undefined; - if (r.payHandler.error === undefined) expect.fail(); - //FIXME: error message here is bad - expect(r.payHandler.error.errorDetail.hint).eq( - "could not confirm payment", - ); - expect(r.payHandler.error.errorDetail.payResult).deep.equal({ - type: ConfirmPayResultType.Pending, - lastError: { code: 1 }, - }); - } - - await assertNoPendingUpdate(); + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + if (state.status !== "ready") expect.fail(); + expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:15")); + expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:9")); + // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1")); + if (state.payHandler.onClick === undefined) expect.fail(); + state.payHandler.onClick(); + }, + (state) => { + if (state.status !== "ready") expect.fail(); + expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:15")); + expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:9")); + // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1")); + expect(state.payHandler.onClick).undefined; + if (state.payHandler.error === undefined) expect.fail(); + //FIXME: error message here is bad + expect(state.payHandler.error.errorDetail.hint).eq( + "could not confirm payment", + ); + expect(state.payHandler.error.errorDetail.payResult).deep.equal({ + type: ConfirmPayResultType.Pending, + lastError: { code: 1 }, + }); + }, + ], TestingContext) + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); + }); it("should update balance if a coins is withdraw", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); const props = { talerPayUri: "taller://pay", cancel: nullFunction, goToWalletManualWithdraw: nullFunction, - onSuccess: async () => { - null; - }, + onSuccess: nullFunction, }; handler.addWalletCallResponse( @@ -507,46 +455,30 @@ describe("Payment CTA states", () => { }, ); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentState(props, mock)); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - 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; - - handler.notifyEventFromWallet(NotificationType.CoinWithdrawn); - } - - expect(await waitForStateUpdate()).true; - - { - 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")); - expect(r.payHandler.onClick).not.undefined; - } - - await assertNoPendingUpdate(); + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + if (state.status !== "ready") expect.fail() + expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:10")); + expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:9")); + // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1")); + expect(state.payHandler.onClick).not.undefined; + + handler.notifyEventFromWallet(NotificationType.CoinWithdrawn); + }, + (state) => { + if (state.status !== "ready") expect.fail() + expect(state.balance).deep.equal(Amounts.parseOrThrow("USD:15")); + expect(state.amount).deep.equal(Amounts.parseOrThrow("USD:9")); + // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1")); + expect(state.payHandler.onClick).not.undefined; + }, + ], TestingContext) + + expect(hookBehavior).deep.equal({ result: "ok" }) 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 4a65c571b..4a6fc79c9 100644 --- a/packages/taler-wallet-webextension/src/cta/Recovery/index.ts +++ b/packages/taler-wallet-webextension/src/cta/Recovery/index.ts @@ -18,7 +18,6 @@ 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 { wxApi } from "../../wxApi.js"; import { useComponentState } from "./state.js"; import { LoadingUriView, ReadyView } from "./views.js"; @@ -60,6 +59,6 @@ const viewMapping: StateViewMap<State> = { export const RecoveryPage = compose( "Recovery", - (p: Props) => useComponentState(p, wxApi), + (p: Props) => useComponentState(p), viewMapping, ); diff --git a/packages/taler-wallet-webextension/src/cta/Recovery/state.ts b/packages/taler-wallet-webextension/src/cta/Recovery/state.ts index 3a5d94e2e..018d61c03 100644 --- a/packages/taler-wallet-webextension/src/cta/Recovery/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Recovery/state.ts @@ -16,13 +16,13 @@ import { parseRecoveryUri } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { wxApi } from "../../wxApi.js"; +import { useBackendContext } from "../../context/backend.js"; import { Props, State } from "./index.js"; export function useComponentState( { talerRecoveryUri, onCancel, onSuccess }: Props, - api: typeof wxApi, ): State { + const api = useBackendContext() if (!talerRecoveryUri) { return { status: "loading-uri", @@ -48,7 +48,7 @@ export function useComponentState( const recovery = info; async function recoverBackup(): Promise<void> { - await wxApi.wallet.call(WalletApiOperation.ImportBackupRecovery, { + await api.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 099f72919..158f5c179 100644 --- a/packages/taler-wallet-webextension/src/cta/Refund/index.ts +++ b/packages/taler-wallet-webextension/src/cta/Refund/index.ts @@ -19,13 +19,12 @@ 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 { wxApi } from "../../wxApi.js"; import { useComponentState } from "./state.js"; import { IgnoredView, InProgressView, LoadingUriView, - ReadyView, + ReadyView } from "./views.js"; export interface Props { @@ -90,6 +89,6 @@ const viewMapping: StateViewMap<State> = { export const RefundPage = compose( "Refund", - (p: Props) => useComponentState(p, wxApi), + (p: Props) => useComponentState(p), viewMapping, ); diff --git a/packages/taler-wallet-webextension/src/cta/Refund/state.ts b/packages/taler-wallet-webextension/src/cta/Refund/state.ts index 94c5567d6..624ab2fb2 100644 --- a/packages/taler-wallet-webextension/src/cta/Refund/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Refund/state.ts @@ -17,14 +17,14 @@ import { Amounts, NotificationType } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useEffect, useState } from "preact/hooks"; +import { useBackendContext } from "../../context/backend.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; -import { wxApi } from "../../wxApi.js"; import { Props, State } from "./index.js"; export function useComponentState( { talerRefundUri, cancel, onSuccess }: Props, - api: typeof wxApi, ): State { + const api = useBackendContext() const [ignored, setIgnored] = useState(false); const info = useAsyncAsHook(async () => { diff --git a/packages/taler-wallet-webextension/src/cta/Refund/test.ts b/packages/taler-wallet-webextension/src/cta/Refund/test.ts index 927c45981..5fbf3743e 100644 --- a/packages/taler-wallet-webextension/src/cta/Refund/test.ts +++ b/packages/taler-wallet-webextension/src/cta/Refund/test.ts @@ -20,75 +20,50 @@ */ import { - AmountJson, Amounts, NotificationType, - OrderShortInfo, - PrepareRefundResult, + OrderShortInfo } 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 { tests } from "../../../../web-util/src/index.browser.js"; +import { createWalletApiMock, mountHook, nullFunction } 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 { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => - useComponentState( - { - talerRefundUri: undefined, - cancel: async () => { - null; - }, - onSuccess: async () => { - null; - }, - }, - mock, - // { - // prepareRefund: async () => ({}), - // applyRefund: async () => ({}), - // onUpdateNotification: async () => ({}), - // } as any, - ), - ); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; + const props = { + talerRefundUri: undefined, + cancel: nullFunction, + onSuccess: nullFunction, } - expect(await waitForStateUpdate()).true; - - { - const { status, error } = pullLastResultOrThrow(); - - expect(status).equals("loading-uri"); - if (!error) expect.fail(); - if (!error.hasError) expect.fail(); - if (error.operational) expect.fail(); - expect(error.message).eq("ERROR_NO-URI-FOR-REFUND"); - } + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + ({ status, error }) => { + expect(status).equals("loading-uri"); + if (!error) expect.fail(); + if (!error.hasError) expect.fail(); + if (error.operational) expect.fail(); + expect(error.message).eq("ERROR_NO-URI-FOR-REFUND"); + }, + ], TestingContext) - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); }); it("should be ready after loading", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); const props = { talerRefundUri: "taler://refund/asdasdas", - cancel: async () => { - null; - }, - onSuccess: async () => { - null; - }, + cancel: nullFunction, + onSuccess: nullFunction, }; handler.addWalletCallResponse(WalletApiOperation.PrepareRefund, undefined, { @@ -108,61 +83,28 @@ describe("Refund CTA states", () => { } as OrderShortInfo, }); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => - useComponentState( - 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 } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - const state = pullLastResultOrThrow(); - - if (state.status !== "ready") expect.fail(); - if (state.error) expect.fail(); - expect(state.accept.onClick).not.undefined; - expect(state.ignore.onClick).not.undefined; - expect(state.merchantName).eq("the merchant name"); - expect(state.orderId).eq("orderId1"); - expect(state.products).undefined; - } + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + if (state.status !== "ready") expect.fail(); + if (state.error) expect.fail(); + expect(state.accept.onClick).not.undefined; + expect(state.ignore.onClick).not.undefined; + expect(state.merchantName).eq("the merchant name"); + expect(state.orderId).eq("orderId1"); + expect(state.products).undefined; + }, + ], TestingContext) - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); }); it("should be ignored after clicking the ignore button", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); const props = { talerRefundUri: "taler://refund/asdasdas", cancel: async () => { @@ -189,102 +131,36 @@ describe("Refund CTA states", () => { 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( - 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 } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - 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"); - expect(state.products).undefined; - - if (state.ignore.onClick === undefined) expect.fail(); - state.ignore.onClick(); - } - - expect(await waitForStateUpdate()).true; - - { - 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"); - } + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + if (state.status !== "ready") expect.fail() + if (state.error) expect.fail() + expect(state.accept.onClick).not.undefined; + expect(state.merchantName).eq("the merchant name"); + expect(state.orderId).eq("orderId1"); + expect(state.products).undefined; + + if (state.ignore.onClick === undefined) expect.fail(); + state.ignore.onClick(); + }, + (state) => { + if (state.status !== "ignored") expect.fail() + if (state.error) expect.fail() + expect(state.merchantName).eq("the merchant name"); + }, + ], TestingContext) - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); }); it("should be in progress when doing refresh", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); const props = { talerRefundUri: "taler://refund/asdasdas", cancel: async () => { @@ -344,67 +220,42 @@ describe("Refund CTA states", () => { } as OrderShortInfo, }); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentState(props, mock)); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - const state = pullLastResultOrThrow(); - - 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) - - handler.notifyEventFromWallet(NotificationType.RefreshMelted); - } - - expect(await waitForStateUpdate()).true; - - { - const state = pullLastResultOrThrow(); - - 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) - - handler.notifyEventFromWallet(NotificationType.RefreshMelted); - } - - expect(await waitForStateUpdate()).true; - - { - const state = pullLastResultOrThrow(); + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + if (state.status !== "in-progress") expect.fail() + 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) + + handler.notifyEventFromWallet(NotificationType.RefreshMelted); + }, + (state) => { + if (state.status !== "in-progress") expect.fail() + 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) + + handler.notifyEventFromWallet(NotificationType.RefreshMelted); + }, + (state) => { + if (state.status !== "ready") expect.fail() + 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")); - if (state.status !== "ready") { - 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")); - } + }, + ], TestingContext) - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) 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 ff917008f..a29a3eadb 100644 --- a/packages/taler-wallet-webextension/src/cta/Tip/index.ts +++ b/packages/taler-wallet-webextension/src/cta/Tip/index.ts @@ -19,13 +19,12 @@ 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 { wxApi } from "../../wxApi.js"; import { useComponentState } from "./state.js"; import { AcceptedView, IgnoredView, LoadingUriView, - ReadyView, + ReadyView } from "./views.js"; export interface Props { @@ -84,6 +83,6 @@ const viewMapping: StateViewMap<State> = { export const TipPage = compose( "Tip", - (p: Props) => useComponentState(p, wxApi), + (p: Props) => useComponentState(p), viewMapping, ); diff --git a/packages/taler-wallet-webextension/src/cta/Tip/state.ts b/packages/taler-wallet-webextension/src/cta/Tip/state.ts index ea9ba1b37..0ca213b01 100644 --- a/packages/taler-wallet-webextension/src/cta/Tip/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Tip/state.ts @@ -16,14 +16,14 @@ import { Amounts } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { useBackendContext } from "../../context/backend.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; -import { wxApi } from "../../wxApi.js"; import { Props, State } from "./index.js"; export function useComponentState( { talerTipUri, onCancel, onSuccess }: Props, - api: typeof wxApi, ): State { + const api = useBackendContext() const tipInfo = useAsyncAsHook(async () => { if (!talerTipUri) throw Error("ERROR_NO-URI-FOR-TIP"); const tip = await api.wallet.call(WalletApiOperation.PrepareTip, { diff --git a/packages/taler-wallet-webextension/src/cta/Tip/test.ts b/packages/taler-wallet-webextension/src/cta/Tip/test.ts index e57b9ec4d..21ed95218 100644 --- a/packages/taler-wallet-webextension/src/cta/Tip/test.ts +++ b/packages/taler-wallet-webextension/src/cta/Tip/test.ts @@ -22,54 +22,42 @@ 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 { tests } from "../../../../web-util/src/index.browser.js"; +import { mountHook, nullFunction } from "../../test-utils.js"; import { createWalletApiMock } from "../../test-utils.js"; +import { Props } from "./index.js"; import { useComponentState } from "./state.js"; describe("Tip CTA states", () => { it("should tell the user that the URI is missing", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => - useComponentState( - { - talerTipUri: undefined, - onCancel: async () => { - null; - }, - onSuccess: async () => { - null; - }, - }, - mock, - ), - ); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; + const props: Props = { + talerTipUri: undefined, + onCancel: nullFunction, + onSuccess: nullFunction, } - expect(await waitForStateUpdate()).true; - - { - const { status, error } = pullLastResultOrThrow(); - - expect(status).equals("loading-uri"); - if (!error) expect.fail(); - if (!error.hasError) expect.fail(); - if (error.operational) expect.fail(); - expect(error.message).eq("ERROR_NO-URI-FOR-TIP"); - } + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + ({ status, error }) => { + expect(status).equals("loading-uri"); + if (!error) expect.fail(); + if (!error.hasError) expect.fail(); + if (error.operational) expect.fail(); + expect(error.message).eq("ERROR_NO-URI-FOR-TIP"); + }, + ], TestingContext) - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); }); it("should be ready for accepting the tip", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, { accepted: false, @@ -83,78 +71,59 @@ describe("Tip CTA states", () => { tipAmountRaw: "", }); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => - useComponentState( - { - talerTipUri: "taler://tip/asd", - onCancel: async () => { - null; - }, - onSuccess: async () => { - null; - }, - }, - mock, - ), - ); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; + const props: Props = { + talerTipUri: "taler://tip/asd", + onCancel: nullFunction, + onSuccess: nullFunction, } - expect(await waitForStateUpdate()).true; - - { - const state = pullLastResultOrThrow(); - - 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(); - } - - handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, { - accepted: true, - exchangeBaseUrl: "exchange url", - merchantBaseUrl: "merchant url", - tipAmountEffective: "EUR:1", - walletTipId: "tip_id", - expirationTimestamp: { - t_s: 1, + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; }, - tipAmountRaw: "", - }); - expect(await waitForStateUpdate()).true; + (state) => { + 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(); + + 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 state = pullLastResultOrThrow(); + }, + (state) => { + if (state.status !== "accepted") 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"); + }, + ], TestingContext) - 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(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); }); - it("should be ignored after clicking the ignore button", async () => { - const { handler, mock } = createWalletApiMock(); + it.skip("should be ignored after clicking the ignore button", async () => { + const { handler, TestingContext } = createWalletApiMock(); handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, { exchangeBaseUrl: "exchange url", merchantBaseUrl: "merchant url", @@ -167,46 +136,34 @@ describe("Tip CTA states", () => { tipAmountRaw: "", }); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => - useComponentState( - { - talerTipUri: "taler://tip/asd", - onCancel: async () => { - null; - }, - onSuccess: async () => { - null; - }, - }, - mock, - ), - ); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; + const props: Props = { + talerTipUri: "taler://tip/asd", + onCancel: nullFunction, + onSuccess: nullFunction, } - expect(await waitForStateUpdate()).true; - - { - 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"); - } + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + 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"); + + //FIXME: add ignore button + }, + ], TestingContext) - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); }); it("should render accepted if the tip has been used previously", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, { accepted: true, @@ -220,40 +177,28 @@ describe("Tip CTA states", () => { tipAmountRaw: "", }); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => - useComponentState( - { - talerTipUri: "taler://tip/asd", - onCancel: async () => { - null; - }, - onSuccess: async () => { - null; - }, - }, - mock, - ), - ); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; + const props: Props = { + talerTipUri: "taler://tip/asd", + onCancel: nullFunction, + onSuccess: nullFunction, } - expect(await waitForStateUpdate()).true; - - { - const state = pullLastResultOrThrow(); + const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [ + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + if (state.status !== "accepted") 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"); + }, + ], TestingContext) - if (state.status !== "accepted") 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"); - } - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) 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 8d51ff3e0..0715bb60e 100644 --- a/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts +++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts @@ -19,7 +19,6 @@ 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 { wxApi } from "../../wxApi.js"; import { useComponentState } from "./state.js"; import { LoadingUriView, ReadyView } from "./views.js"; @@ -66,6 +65,6 @@ const viewMapping: StateViewMap<State> = { export const TransferCreatePage = compose( "TransferCreatePage", - (p: Props) => useComponentState(p, wxApi), + (p: Props) => useComponentState(p), viewMapping, ); diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts b/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts index c5e143f42..3536014da 100644 --- a/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts +++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts @@ -17,19 +17,19 @@ import { Amounts, TalerErrorDetail, - TalerProtocolTimestamp, + TalerProtocolTimestamp } from "@gnu-taler/taler-util"; import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { format, isFuture, parse } from "date-fns"; +import { isFuture, parse } from "date-fns"; import { useState } from "preact/hooks"; +import { useBackendContext } from "../../context/backend.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; -import { wxApi } from "../../wxApi.js"; import { Props, State } from "./index.js"; export function useComponentState( { amount: amountStr, onClose, onSuccess }: Props, - api: typeof wxApi, ): State { + const api = useBackendContext() const amount = Amounts.parseOrThrow(amountStr); const [subject, setSubject] = useState<string | undefined>(); @@ -124,8 +124,8 @@ export function useComponentState( subject === undefined ? undefined : !subject - ? "Can't be empty" - : undefined, + ? "Can't be empty" + : undefined, value: subject ?? "", onInput: async (e) => setSubject(e), }, diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts b/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts index 399f1e290..de6ad3b79 100644 --- a/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts +++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts @@ -17,13 +17,12 @@ 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 { wxApi } from "../../wxApi.js"; import { useComponentState } from "./state.js"; import { LoadingUriView, ReadyView } from "./views.js"; @@ -69,6 +68,6 @@ const viewMapping: StateViewMap<State> = { export const TransferPickupPage = compose( "TransferPickupPage", - (p: Props) => useComponentState(p, wxApi), + (p: Props) => useComponentState(p), viewMapping, ); diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts index e8fb99ab7..45bec28fb 100644 --- a/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts +++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts @@ -18,18 +18,18 @@ import { AbsoluteTime, Amounts, TalerErrorDetail, - TalerProtocolTimestamp, + TalerProtocolTimestamp } from "@gnu-taler/taler-util"; import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useState } from "preact/hooks"; +import { useBackendContext } from "../../context/backend.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; -import { wxApi } from "../../wxApi.js"; import { Props, State } from "./index.js"; export function useComponentState( { talerPayPushUri, onClose, onSuccess }: Props, - api: typeof wxApi, ): State { + const api = useBackendContext() const hook = useAsyncAsHook(async () => { return await api.wallet.call(WalletApiOperation.CheckPeerPushPayment, { talerUri: talerPayPushUri, diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts index 68b314c07..9e5943161 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts @@ -20,10 +20,9 @@ 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 { wxApi } from "../../wxApi.js"; import { useComponentStateFromParams, - useComponentStateFromURI, + useComponentStateFromURI } from "./state.js"; import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js"; @@ -96,11 +95,11 @@ const viewMapping: StateViewMap<State> = { export const WithdrawPageFromURI = compose( "WithdrawPageFromURI", - (p: PropsFromURI) => useComponentStateFromURI(p, wxApi), + (p: PropsFromURI) => useComponentStateFromURI(p), viewMapping, ); export const WithdrawPageFromParams = compose( "WithdrawPageFromParams", - (p: PropsFromParams) => useComponentStateFromParams(p, wxApi), + (p: PropsFromParams) => useComponentStateFromParams(p), viewMapping, ); diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts index 9bb29fbd6..4420221fc 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts @@ -19,20 +19,20 @@ import { AmountJson, Amounts, ExchangeListItem, - ExchangeTosStatus, + ExchangeTosStatus } from "@gnu-taler/taler-util"; import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useState } from "preact/hooks"; +import { useBackendContext } from "../../context/backend.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; import { useSelectedExchange } from "../../hooks/useSelectedExchange.js"; import { RecursiveState } from "../../utils/index.js"; -import { wxApi } from "../../wxApi.js"; import { PropsFromParams, PropsFromURI, State } from "./index.js"; export function useComponentStateFromParams( { amount, cancel, onSuccess }: PropsFromParams, - api: typeof wxApi, ): RecursiveState<State> { + const api = useBackendContext() const uriInfoHook = useAsyncAsHook(async () => { const exchanges = await api.wallet.call( WalletApiOperation.ListExchanges, @@ -84,14 +84,13 @@ export function useComponentStateFromParams( chosenAmount, exchangeList, undefined, - api, ); } export function useComponentStateFromURI( { talerWithdrawUri, cancel, onSuccess }: PropsFromURI, - api: typeof wxApi, ): RecursiveState<State> { + const api = useBackendContext() /** * Ask the wallet about the withdraw URI */ @@ -158,7 +157,6 @@ export function useComponentStateFromURI( chosenAmount, exchangeList, defaultExchange, - api, ); } @@ -176,8 +174,8 @@ function exchangeSelectionState( chosenAmount: AmountJson, exchangeList: ExchangeListItem[], defaultExchange: string | undefined, - api: typeof wxApi, ): RecursiveState<State> { + const api = useBackendContext() const selectedExchange = useSelectedExchange({ currency: chosenAmount.currency, defaultExchange, @@ -278,10 +276,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 7fd8188ce..084b4368c 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts @@ -27,6 +27,7 @@ import { } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { expect } from "chai"; +import { tests } from "../../../../web-util/src/index.browser.js"; import { mountHook } from "../../test-utils.js"; import { createWalletApiMock } from "../../test-utils.js"; import { useComponentStateFromURI } from "./state.js"; @@ -61,53 +62,45 @@ const exchanges: ExchangeListItem[] = [ } as Partial<ExchangeListItem> as ExchangeListItem, ]; +const nullFunction = async (): Promise<void> => { + null; +} + describe("Withdraw CTA states", () => { it("should tell the user that the URI is missing", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); + const props = { talerWithdrawUri: undefined, - cancel: async () => { - null; - }, - onSuccess: async () => { - null; - }, + cancel: nullFunction, + onSuccess: nullFunction, }; - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentStateFromURI(props, mock)); - - { - const { status } = pullLastResultOrThrow(); - expect(status).equals("loading"); - } - - expect(await waitForStateUpdate()).true; - { - const { status, error } = pullLastResultOrThrow(); - - if (status != "uri-error") expect.fail(); - if (!error) expect.fail(); - if (!error.hasError) expect.fail(); - if (error.operational) expect.fail(); - expect(error.message).eq("ERROR_NO-URI-FOR-WITHDRAWAL"); - } + const hookBehavior = await tests.hookBehaveLikeThis(useComponentStateFromURI, props, [ + ({ status }) => { + expect(status).equals("loading"); + }, + ({ status, error }) => { + if (status != "uri-error") expect.fail(); + if (!error) expect.fail(); + if (!error.hasError) expect.fail(); + if (error.operational) expect.fail(); + expect(error.message).eq("ERROR_NO-URI-FOR-WITHDRAWAL"); + }, + ], TestingContext) - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); }); it("should tell the user that there is not known exchange", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); const props = { talerWithdrawUri: "taler-withdraw://", - cancel: async () => { - null; - }, - onSuccess: async () => { - null; - }, + cancel: nullFunction, + onSuccess: nullFunction, }; + handler.addWalletCallResponse( WalletApiOperation.GetWithdrawalDetailsForUri, undefined, @@ -117,39 +110,28 @@ describe("Withdraw CTA states", () => { }, ); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentStateFromURI(props, mock)); - - { - const { status } = pullLastResultOrThrow(); - expect(status).equals("loading", "1"); - } - - expect(await waitForStateUpdate()).true; - - { - const { status, error } = pullLastResultOrThrow(); - - expect(status).equals("no-exchange", "3"); - - expect(error).undefined; - } + const hookBehavior = await tests.hookBehaveLikeThis(useComponentStateFromURI, props, [ + ({ status }) => { + expect(status).equals("loading"); + }, + ({ status, error }) => { + expect(status).equals("no-exchange"); + expect(error).undefined; + }, + ], TestingContext) - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); }); it("should be able to withdraw if tos are ok", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); const props = { talerWithdrawUri: "taler-withdraw://", - cancel: async () => { - null; - }, - onSuccess: async () => { - null; - }, + cancel: nullFunction, + onSuccess: nullFunction, }; + handler.addWalletCallResponse( WalletApiOperation.GetWithdrawalDetailsForUri, undefined, @@ -171,54 +153,38 @@ describe("Withdraw CTA states", () => { }, ); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentStateFromURI(props, mock)); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - const { status, error } = pullLastResultOrThrow(); - - expect(status).equals("loading"); - - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - const state = pullLastResultOrThrow(); - expect(state.status).equals("success"); - if (state.status !== "success") return; + const hookBehavior = await tests.hookBehaveLikeThis(useComponentStateFromURI, props, [ + ({ status }) => { + expect(status).equals("loading"); + }, + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + expect(state.status).equals("success"); + if (state.status !== "success") return; - expect(state.toBeReceived).deep.equal(Amounts.parseOrThrow("ARS:2")); - expect(state.withdrawalFee).deep.equal(Amounts.parseOrThrow("ARS:0")); - expect(state.chosenAmount).deep.equal(Amounts.parseOrThrow("ARS:2")); + expect(state.toBeReceived).deep.equal(Amounts.parseOrThrow("ARS:2")); + expect(state.withdrawalFee).deep.equal(Amounts.parseOrThrow("ARS:0")); + expect(state.chosenAmount).deep.equal(Amounts.parseOrThrow("ARS:2")); - expect(state.doWithdrawal.onClick).not.undefined; - } + expect(state.doWithdrawal.onClick).not.undefined; + }, + ], TestingContext) - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); }); it("should accept the tos before withdraw", async () => { - const { handler, mock } = createWalletApiMock(); + const { handler, TestingContext } = createWalletApiMock(); const props = { talerWithdrawUri: "taler-withdraw://", - cancel: async () => { - null; - }, - onSuccess: async () => { - null; - }, + cancel: nullFunction, + onSuccess: nullFunction, }; + const exchangeWithNewTos = exchanges.map((e) => ({ ...e, tosStatus: ExchangeTosStatus.New, @@ -255,57 +221,39 @@ describe("Withdraw CTA states", () => { }, ); - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(() => useComponentStateFromURI(props, mock)); - - { - const { status, error } = pullLastResultOrThrow(); - expect(status).equals("loading"); - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - const { status, error } = pullLastResultOrThrow(); - - expect(status).equals("loading"); - - expect(error).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - const state = pullLastResultOrThrow(); - expect(state.status).equals("success"); - if (state.status !== "success") return; - - expect(state.toBeReceived).deep.equal(Amounts.parseOrThrow("ARS:2")); - expect(state.withdrawalFee).deep.equal(Amounts.parseOrThrow("ARS:0")); - expect(state.chosenAmount).deep.equal(Amounts.parseOrThrow("ARS:2")); - - expect(state.doWithdrawal.onClick).undefined; + const hookBehavior = await tests.hookBehaveLikeThis(useComponentStateFromURI, props, [ + ({ status }) => { + expect(status).equals("loading"); + }, + ({ status, error }) => { + expect(status).equals("loading"); + expect(error).undefined; + }, + (state) => { + expect(state.status).equals("success"); + if (state.status !== "success") return; - // updateAcceptedVersionToCurrentVersion(); - state.onTosUpdate(); - } + expect(state.toBeReceived).deep.equal(Amounts.parseOrThrow("ARS:2")); + expect(state.withdrawalFee).deep.equal(Amounts.parseOrThrow("ARS:0")); + expect(state.chosenAmount).deep.equal(Amounts.parseOrThrow("ARS:2")); - expect(await waitForStateUpdate()).true; + expect(state.doWithdrawal.onClick).undefined; - { - const state = pullLastResultOrThrow(); - expect(state.status).equals("success"); - if (state.status !== "success") return; + state.onTosUpdate(); + }, + (state) => { + expect(state.status).equals("success"); + if (state.status !== "success") return; - expect(state.toBeReceived).deep.equal(Amounts.parseOrThrow("ARS:2")); - expect(state.withdrawalFee).deep.equal(Amounts.parseOrThrow("ARS:0")); - expect(state.chosenAmount).deep.equal(Amounts.parseOrThrow("ARS:2")); + expect(state.toBeReceived).deep.equal(Amounts.parseOrThrow("ARS:2")); + expect(state.withdrawalFee).deep.equal(Amounts.parseOrThrow("ARS:0")); + expect(state.chosenAmount).deep.equal(Amounts.parseOrThrow("ARS:2")); - expect(state.doWithdrawal.onClick).not.undefined; - } + expect(state.doWithdrawal.onClick).not.undefined; + }, + ], TestingContext) - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }) expect(handler.getCallingQueueState()).eq("empty"); }); }); |