pretty
This commit is contained in:
parent
f93bd51499
commit
f1f8f818db
@ -25,7 +25,7 @@ import {
|
||||
LoadingUriView,
|
||||
ShowButtonsAcceptedTosView,
|
||||
ShowButtonsNonAcceptedTosView,
|
||||
ShowTosContentView
|
||||
ShowTosContentView,
|
||||
} from "./views.js";
|
||||
|
||||
export interface Props {
|
||||
|
@ -21,10 +21,8 @@ import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { Props, State } from "./index.js";
|
||||
import { buildTermsOfServiceState } from "./utils.js";
|
||||
|
||||
export function useComponentState(
|
||||
{ exchangeUrl, onChange }: Props,
|
||||
): State {
|
||||
const api = useBackendContext()
|
||||
export function useComponentState({ exchangeUrl, onChange }: Props): State {
|
||||
const api = useBackendContext();
|
||||
const readOnly = !onChange;
|
||||
const [showContent, setShowContent] = useState<boolean>(readOnly);
|
||||
const [errorAccepting, setErrorAccepting] = useState<Error | undefined>(
|
||||
|
@ -23,7 +23,7 @@ import { ComponentChildren, createContext, h, VNode } from "preact";
|
||||
import { useContext } from "preact/hooks";
|
||||
import { wxApi, WxApiType } from "../wxApi.js";
|
||||
|
||||
type Type = WxApiType
|
||||
type Type = WxApiType;
|
||||
|
||||
const initial = wxApi;
|
||||
|
||||
@ -31,7 +31,7 @@ const Context = createContext<Type>(initial);
|
||||
|
||||
type Props = Partial<WxApiType> & {
|
||||
children: ComponentChildren;
|
||||
}
|
||||
};
|
||||
|
||||
export const BackendProvider = ({
|
||||
wallet,
|
||||
@ -39,12 +39,11 @@ export const BackendProvider = ({
|
||||
listener,
|
||||
children,
|
||||
}: Props): VNode => {
|
||||
|
||||
return h(Context.Provider, {
|
||||
value: {
|
||||
wallet: wallet ?? initial.wallet,
|
||||
background: background ?? initial.background,
|
||||
listener: listener ?? initial.listener
|
||||
listener: listener ?? initial.listener,
|
||||
},
|
||||
children,
|
||||
});
|
||||
|
@ -20,10 +20,13 @@ import { useBackendContext } from "../../context/backend.js";
|
||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
{ talerDepositUri, amountStr, cancel, onSuccess }: Props,
|
||||
): State {
|
||||
const api = useBackendContext()
|
||||
export function useComponentState({
|
||||
talerDepositUri,
|
||||
amountStr,
|
||||
cancel,
|
||||
onSuccess,
|
||||
}: Props): 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");
|
||||
|
@ -42,21 +42,26 @@ describe("Deposit CTA states", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [
|
||||
({ status }) => {
|
||||
expect(status).equals("loading");
|
||||
},
|
||||
({ status, error }) => {
|
||||
expect(status).equals("loading-uri");
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(
|
||||
useComponentState,
|
||||
props,
|
||||
[
|
||||
({ status }) => {
|
||||
expect(status).equals("loading");
|
||||
},
|
||||
({ 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-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");
|
||||
},
|
||||
],
|
||||
TestingContext,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -83,21 +88,26 @@ describe("Deposit CTA states", () => {
|
||||
},
|
||||
};
|
||||
|
||||
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)
|
||||
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,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
});
|
||||
|
@ -29,11 +29,13 @@ import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
|
||||
import { RecursiveState } from "../../utils/index.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
{ amount: amountStr, onClose, onSuccess }: Props,
|
||||
): RecursiveState<State> {
|
||||
export function useComponentState({
|
||||
amount: amountStr,
|
||||
onClose,
|
||||
onSuccess,
|
||||
}: Props): RecursiveState<State> {
|
||||
const amount = Amounts.parseOrThrow(amountStr);
|
||||
const api = useBackendContext()
|
||||
const api = useBackendContext();
|
||||
|
||||
const hook = useAsyncAsHook(() =>
|
||||
api.wallet.call(WalletApiOperation.ListExchanges, {}),
|
||||
@ -158,8 +160,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),
|
||||
},
|
||||
|
@ -18,7 +18,7 @@ import {
|
||||
AbsoluteTime,
|
||||
AmountJson,
|
||||
PreparePayResult,
|
||||
TalerErrorDetail
|
||||
TalerErrorDetail,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
|
@ -29,10 +29,13 @@ import { useBackendContext } from "../../context/backend.js";
|
||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
{ talerPayPullUri, onClose, goToWalletManualWithdraw, onSuccess }: Props,
|
||||
): State {
|
||||
const api = useBackendContext()
|
||||
export function useComponentState({
|
||||
talerPayPullUri,
|
||||
onClose,
|
||||
goToWalletManualWithdraw,
|
||||
onSuccess,
|
||||
}: Props): State {
|
||||
const api = useBackendContext();
|
||||
const hook = useAsyncAsHook(async () => {
|
||||
const p2p = await api.wallet.call(WalletApiOperation.CheckPeerPullPayment, {
|
||||
talerUri: talerPayPullUri,
|
||||
|
@ -19,7 +19,7 @@ import {
|
||||
PreparePayResult,
|
||||
PreparePayResultAlreadyConfirmed,
|
||||
PreparePayResultInsufficientBalance,
|
||||
PreparePayResultPaymentPossible
|
||||
PreparePayResultPaymentPossible,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
|
@ -28,11 +28,14 @@ import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { ButtonHandler } from "../../mui/handlers.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
{ talerPayUri, cancel, goToWalletManualWithdraw, onSuccess }: Props,
|
||||
): State {
|
||||
export function useComponentState({
|
||||
talerPayUri,
|
||||
cancel,
|
||||
goToWalletManualWithdraw,
|
||||
onSuccess,
|
||||
}: Props): State {
|
||||
const [payErrMsg, setPayErrMsg] = useState<TalerError | undefined>(undefined);
|
||||
const api = useBackendContext()
|
||||
const api = useBackendContext();
|
||||
|
||||
const hook = useAsyncAsHook(async () => {
|
||||
if (!talerPayUri) throw Error("ERROR_NO-URI-FOR-PAYMENT");
|
||||
|
@ -45,22 +45,26 @@ describe("Payment CTA states", () => {
|
||||
onSuccess: nullFunction,
|
||||
};
|
||||
|
||||
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)
|
||||
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,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
|
||||
});
|
||||
|
||||
it("should response with no balance", async () => {
|
||||
@ -86,22 +90,27 @@ describe("Payment CTA states", () => {
|
||||
{ balances: [] },
|
||||
);
|
||||
|
||||
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)
|
||||
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,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -138,19 +147,24 @@ describe("Payment CTA states", () => {
|
||||
},
|
||||
);
|
||||
|
||||
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)
|
||||
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,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -187,25 +201,29 @@ describe("Payment CTA states", () => {
|
||||
],
|
||||
},
|
||||
);
|
||||
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)
|
||||
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(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
|
||||
});
|
||||
|
||||
it("should be able to pay (with fee)", async () => {
|
||||
@ -241,20 +259,25 @@ describe("Payment CTA states", () => {
|
||||
],
|
||||
},
|
||||
);
|
||||
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)
|
||||
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(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -297,26 +320,30 @@ describe("Payment CTA states", () => {
|
||||
contractTerms: {},
|
||||
} as ConfirmPayResult);
|
||||
|
||||
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)
|
||||
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(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
|
||||
});
|
||||
|
||||
it("should not stay in ready state after pay with error", async () => {
|
||||
@ -357,40 +384,44 @@ describe("Payment CTA states", () => {
|
||||
lastError: { code: 1 },
|
||||
} as ConfirmPayResult);
|
||||
|
||||
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)
|
||||
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(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
|
||||
});
|
||||
|
||||
it("should update balance if a coins is withdraw", async () => {
|
||||
@ -455,30 +486,35 @@ describe("Payment CTA states", () => {
|
||||
},
|
||||
);
|
||||
|
||||
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;
|
||||
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)
|
||||
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(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
});
|
||||
|
@ -19,10 +19,12 @@ import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { useBackendContext } from "../../context/backend.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
{ talerRecoveryUri, onCancel, onSuccess }: Props,
|
||||
): State {
|
||||
const api = useBackendContext()
|
||||
export function useComponentState({
|
||||
talerRecoveryUri,
|
||||
onCancel,
|
||||
onSuccess,
|
||||
}: Props): State {
|
||||
const api = useBackendContext();
|
||||
if (!talerRecoveryUri) {
|
||||
return {
|
||||
status: "loading-uri",
|
||||
|
@ -24,7 +24,7 @@ import {
|
||||
IgnoredView,
|
||||
InProgressView,
|
||||
LoadingUriView,
|
||||
ReadyView
|
||||
ReadyView,
|
||||
} from "./views.js";
|
||||
|
||||
export interface Props {
|
||||
|
@ -21,10 +21,12 @@ import { useBackendContext } from "../../context/backend.js";
|
||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
{ talerRefundUri, cancel, onSuccess }: Props,
|
||||
): State {
|
||||
const api = useBackendContext()
|
||||
export function useComponentState({
|
||||
talerRefundUri,
|
||||
cancel,
|
||||
onSuccess,
|
||||
}: Props): State {
|
||||
const api = useBackendContext();
|
||||
const [ignored, setIgnored] = useState(false);
|
||||
|
||||
const info = useAsyncAsHook(async () => {
|
||||
|
@ -22,12 +22,16 @@
|
||||
import {
|
||||
Amounts,
|
||||
NotificationType,
|
||||
OrderShortInfo
|
||||
OrderShortInfo,
|
||||
} 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 { createWalletApiMock, mountHook, nullFunction } from "../../test-utils.js";
|
||||
import {
|
||||
createWalletApiMock,
|
||||
mountHook,
|
||||
nullFunction,
|
||||
} from "../../test-utils.js";
|
||||
import { useComponentState } from "./state.js";
|
||||
|
||||
describe("Refund CTA states", () => {
|
||||
@ -38,23 +42,28 @@ describe("Refund CTA states", () => {
|
||||
talerRefundUri: undefined,
|
||||
cancel: nullFunction,
|
||||
onSuccess: nullFunction,
|
||||
}
|
||||
};
|
||||
|
||||
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)
|
||||
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,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -83,23 +92,28 @@ describe("Refund CTA states", () => {
|
||||
} as OrderShortInfo,
|
||||
});
|
||||
|
||||
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)
|
||||
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,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -132,30 +146,35 @@ describe("Refund CTA states", () => {
|
||||
} as OrderShortInfo,
|
||||
});
|
||||
|
||||
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;
|
||||
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)
|
||||
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,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -220,42 +239,46 @@ describe("Refund CTA states", () => {
|
||||
} as OrderShortInfo,
|
||||
});
|
||||
|
||||
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)
|
||||
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 !== "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"));
|
||||
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"));
|
||||
},
|
||||
],
|
||||
TestingContext,
|
||||
);
|
||||
|
||||
},
|
||||
], TestingContext)
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
});
|
||||
|
@ -24,7 +24,7 @@ import {
|
||||
AcceptedView,
|
||||
IgnoredView,
|
||||
LoadingUriView,
|
||||
ReadyView
|
||||
ReadyView,
|
||||
} from "./views.js";
|
||||
|
||||
export interface Props {
|
||||
|
@ -20,10 +20,12 @@ import { useBackendContext } from "../../context/backend.js";
|
||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
{ talerTipUri, onCancel, onSuccess }: Props,
|
||||
): State {
|
||||
const api = useBackendContext()
|
||||
export function useComponentState({
|
||||
talerTipUri,
|
||||
onCancel,
|
||||
onSuccess,
|
||||
}: Props): 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, {
|
||||
|
@ -36,23 +36,28 @@ describe("Tip CTA states", () => {
|
||||
talerTipUri: undefined,
|
||||
onCancel: nullFunction,
|
||||
onSuccess: nullFunction,
|
||||
}
|
||||
};
|
||||
|
||||
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)
|
||||
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,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -75,50 +80,58 @@ describe("Tip CTA states", () => {
|
||||
talerTipUri: "taler://tip/asd",
|
||||
onCancel: nullFunction,
|
||||
onSuccess: nullFunction,
|
||||
}
|
||||
};
|
||||
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [
|
||||
({ status, error }) => {
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
},
|
||||
(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();
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(
|
||||
useComponentState,
|
||||
props,
|
||||
[
|
||||
({ status, error }) => {
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
},
|
||||
(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.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: "",
|
||||
});
|
||||
handler.addWalletCallResponse(
|
||||
WalletApiOperation.PrepareTip,
|
||||
undefined,
|
||||
{
|
||||
accepted: true,
|
||||
exchangeBaseUrl: "exchange url",
|
||||
merchantBaseUrl: "merchant url",
|
||||
tipAmountEffective: "EUR:1",
|
||||
walletTipId: "tip_id",
|
||||
expirationTimestamp: {
|
||||
t_s: 1,
|
||||
},
|
||||
tipAmountRaw: "",
|
||||
},
|
||||
);
|
||||
},
|
||||
(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,
|
||||
);
|
||||
|
||||
},
|
||||
(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)
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -140,25 +153,30 @@ describe("Tip CTA states", () => {
|
||||
talerTipUri: "taler://tip/asd",
|
||||
onCancel: nullFunction,
|
||||
onSuccess: nullFunction,
|
||||
}
|
||||
};
|
||||
|
||||
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");
|
||||
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)
|
||||
//FIXME: add ignore button
|
||||
},
|
||||
],
|
||||
TestingContext,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -181,24 +199,28 @@ describe("Tip CTA states", () => {
|
||||
talerTipUri: "taler://tip/asd",
|
||||
onCancel: nullFunction,
|
||||
onSuccess: nullFunction,
|
||||
}
|
||||
};
|
||||
|
||||
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)
|
||||
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,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
|
||||
});
|
||||
});
|
||||
|
@ -17,7 +17,7 @@
|
||||
import {
|
||||
Amounts,
|
||||
TalerErrorDetail,
|
||||
TalerProtocolTimestamp
|
||||
TalerProtocolTimestamp,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { isFuture, parse } from "date-fns";
|
||||
@ -26,10 +26,12 @@ import { useBackendContext } from "../../context/backend.js";
|
||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
{ amount: amountStr, onClose, onSuccess }: Props,
|
||||
): State {
|
||||
const api = useBackendContext()
|
||||
export function useComponentState({
|
||||
amount: amountStr,
|
||||
onClose,
|
||||
onSuccess,
|
||||
}: Props): State {
|
||||
const api = useBackendContext();
|
||||
const amount = Amounts.parseOrThrow(amountStr);
|
||||
|
||||
const [subject, setSubject] = useState<string | undefined>();
|
||||
@ -124,8 +126,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),
|
||||
},
|
||||
|
@ -17,7 +17,7 @@
|
||||
import {
|
||||
AbsoluteTime,
|
||||
AmountJson,
|
||||
TalerErrorDetail
|
||||
TalerErrorDetail,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
|
@ -18,7 +18,7 @@ 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";
|
||||
@ -26,10 +26,12 @@ import { useBackendContext } from "../../context/backend.js";
|
||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
{ talerPayPushUri, onClose, onSuccess }: Props,
|
||||
): State {
|
||||
const api = useBackendContext()
|
||||
export function useComponentState({
|
||||
talerPayPushUri,
|
||||
onClose,
|
||||
onSuccess,
|
||||
}: Props): State {
|
||||
const api = useBackendContext();
|
||||
const hook = useAsyncAsHook(async () => {
|
||||
return await api.wallet.call(WalletApiOperation.CheckPeerPushPayment, {
|
||||
talerUri: talerPayPushUri,
|
||||
|
@ -22,7 +22,7 @@ import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
|
||||
import { compose, StateViewMap } from "../../utils/index.js";
|
||||
import {
|
||||
useComponentStateFromParams,
|
||||
useComponentStateFromURI
|
||||
useComponentStateFromURI,
|
||||
} from "./state.js";
|
||||
|
||||
import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js";
|
||||
|
@ -19,7 +19,7 @@ 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";
|
||||
@ -29,10 +29,12 @@ import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
|
||||
import { RecursiveState } from "../../utils/index.js";
|
||||
import { PropsFromParams, PropsFromURI, State } from "./index.js";
|
||||
|
||||
export function useComponentStateFromParams(
|
||||
{ amount, cancel, onSuccess }: PropsFromParams,
|
||||
): RecursiveState<State> {
|
||||
const api = useBackendContext()
|
||||
export function useComponentStateFromParams({
|
||||
amount,
|
||||
cancel,
|
||||
onSuccess,
|
||||
}: PropsFromParams): RecursiveState<State> {
|
||||
const api = useBackendContext();
|
||||
const uriInfoHook = useAsyncAsHook(async () => {
|
||||
const exchanges = await api.wallet.call(
|
||||
WalletApiOperation.ListExchanges,
|
||||
@ -87,10 +89,12 @@ export function useComponentStateFromParams(
|
||||
);
|
||||
}
|
||||
|
||||
export function useComponentStateFromURI(
|
||||
{ talerWithdrawUri, cancel, onSuccess }: PropsFromURI,
|
||||
): RecursiveState<State> {
|
||||
const api = useBackendContext()
|
||||
export function useComponentStateFromURI({
|
||||
talerWithdrawUri,
|
||||
cancel,
|
||||
onSuccess,
|
||||
}: PropsFromURI): RecursiveState<State> {
|
||||
const api = useBackendContext();
|
||||
/**
|
||||
* Ask the wallet about the withdraw URI
|
||||
*/
|
||||
@ -175,7 +179,7 @@ function exchangeSelectionState(
|
||||
exchangeList: ExchangeListItem[],
|
||||
defaultExchange: string | undefined,
|
||||
): RecursiveState<State> {
|
||||
const api = useBackendContext()
|
||||
const api = useBackendContext();
|
||||
const selectedExchange = useSelectedExchange({
|
||||
currency: chosenAmount.currency,
|
||||
defaultExchange,
|
||||
@ -276,10 +280,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 {
|
||||
|
@ -64,7 +64,7 @@ const exchanges: ExchangeListItem[] = [
|
||||
|
||||
const nullFunction = async (): Promise<void> => {
|
||||
null;
|
||||
}
|
||||
};
|
||||
|
||||
describe("Withdraw CTA states", () => {
|
||||
it("should tell the user that the URI is missing", async () => {
|
||||
@ -76,20 +76,25 @@ describe("Withdraw CTA states", () => {
|
||||
onSuccess: nullFunction,
|
||||
};
|
||||
|
||||
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)
|
||||
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,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -110,17 +115,22 @@ describe("Withdraw CTA states", () => {
|
||||
},
|
||||
);
|
||||
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(useComponentStateFromURI, props, [
|
||||
({ status }) => {
|
||||
expect(status).equals("loading");
|
||||
},
|
||||
({ status, error }) => {
|
||||
expect(status).equals("no-exchange");
|
||||
expect(error).undefined;
|
||||
},
|
||||
], TestingContext)
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(
|
||||
useComponentStateFromURI,
|
||||
props,
|
||||
[
|
||||
({ status }) => {
|
||||
expect(status).equals("loading");
|
||||
},
|
||||
({ status, error }) => {
|
||||
expect(status).equals("no-exchange");
|
||||
expect(error).undefined;
|
||||
},
|
||||
],
|
||||
TestingContext,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -153,27 +163,32 @@ describe("Withdraw CTA states", () => {
|
||||
},
|
||||
);
|
||||
|
||||
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;
|
||||
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;
|
||||
},
|
||||
], TestingContext)
|
||||
expect(state.doWithdrawal.onClick).not.undefined;
|
||||
},
|
||||
],
|
||||
TestingContext,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -221,39 +236,44 @@ describe("Withdraw CTA states", () => {
|
||||
},
|
||||
);
|
||||
|
||||
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;
|
||||
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).undefined;
|
||||
expect(state.doWithdrawal.onClick).undefined;
|
||||
|
||||
state.onTosUpdate();
|
||||
},
|
||||
(state) => {
|
||||
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;
|
||||
},
|
||||
], TestingContext)
|
||||
expect(state.doWithdrawal.onClick).not.undefined;
|
||||
},
|
||||
],
|
||||
TestingContext,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
});
|
||||
|
@ -25,9 +25,11 @@ export function useAutoOpenPermissions(): ToggleHandler {
|
||||
const [enabled, setEnabled] = useState(false);
|
||||
const [error, setError] = useState<TalerError | undefined>();
|
||||
const toggle = async (): Promise<void> => {
|
||||
return handleAutoOpenPerm(enabled, setEnabled, api.background).catch((e) => {
|
||||
setError(TalerError.fromException(e));
|
||||
});
|
||||
return handleAutoOpenPerm(enabled, setEnabled, api.background).catch(
|
||||
(e) => {
|
||||
setError(TalerError.fromException(e));
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -28,7 +28,7 @@ export function useBackupDeviceName(): BackupDeviceName {
|
||||
name: "",
|
||||
update: () => Promise.resolve(),
|
||||
});
|
||||
const api = useBackendContext()
|
||||
const api = useBackendContext();
|
||||
|
||||
useEffect(() => {
|
||||
async function run(): Promise<void> {
|
||||
|
@ -23,12 +23,14 @@ import { platform } from "../platform/api.js";
|
||||
export function useClipboardPermissions(): ToggleHandler {
|
||||
const [enabled, setEnabled] = useState(false);
|
||||
const [error, setError] = useState<TalerError | undefined>();
|
||||
const api = useBackendContext()
|
||||
const api = useBackendContext();
|
||||
|
||||
const toggle = async (): Promise<void> => {
|
||||
return handleClipboardPerm(enabled, setEnabled, api.background).catch((e) => {
|
||||
setError(TalerError.fromException(e));
|
||||
});
|
||||
return handleClipboardPerm(enabled, setEnabled, api.background).catch(
|
||||
(e) => {
|
||||
setError(TalerError.fromException(e));
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -444,8 +444,8 @@ function registerTalerHeaderListener(
|
||||
info: chrome.tabs.TabChangeInfo,
|
||||
): Promise<void> {
|
||||
if (tabId < 0) return;
|
||||
const tabLocationHasBeenUpdated = info.status === "complete"
|
||||
const tabTitleHasBeenUpdated = info.title !== undefined
|
||||
const tabLocationHasBeenUpdated = info.status === "complete";
|
||||
const tabTitleHasBeenUpdated = info.title !== undefined;
|
||||
if (tabLocationHasBeenUpdated || tabTitleHasBeenUpdated) {
|
||||
const uri = await findTalerUriInTab(tabId);
|
||||
if (!uri) return;
|
||||
@ -543,26 +543,26 @@ function setAlertedIcon(): void {
|
||||
|
||||
interface OffscreenCanvasRenderingContext2D
|
||||
extends CanvasState,
|
||||
CanvasTransform,
|
||||
CanvasCompositing,
|
||||
CanvasImageSmoothing,
|
||||
CanvasFillStrokeStyles,
|
||||
CanvasShadowStyles,
|
||||
CanvasFilters,
|
||||
CanvasRect,
|
||||
CanvasDrawPath,
|
||||
CanvasUserInterface,
|
||||
CanvasText,
|
||||
CanvasDrawImage,
|
||||
CanvasImageData,
|
||||
CanvasPathDrawingStyles,
|
||||
CanvasTextDrawingStyles,
|
||||
CanvasPath {
|
||||
CanvasTransform,
|
||||
CanvasCompositing,
|
||||
CanvasImageSmoothing,
|
||||
CanvasFillStrokeStyles,
|
||||
CanvasShadowStyles,
|
||||
CanvasFilters,
|
||||
CanvasRect,
|
||||
CanvasDrawPath,
|
||||
CanvasUserInterface,
|
||||
CanvasText,
|
||||
CanvasDrawImage,
|
||||
CanvasImageData,
|
||||
CanvasPathDrawingStyles,
|
||||
CanvasTextDrawingStyles,
|
||||
CanvasPath {
|
||||
readonly canvas: OffscreenCanvas;
|
||||
}
|
||||
declare const OffscreenCanvasRenderingContext2D: {
|
||||
prototype: OffscreenCanvasRenderingContext2D;
|
||||
new(): OffscreenCanvasRenderingContext2D;
|
||||
new (): OffscreenCanvasRenderingContext2D;
|
||||
};
|
||||
|
||||
interface OffscreenCanvas extends EventTarget {
|
||||
@ -575,7 +575,7 @@ interface OffscreenCanvas extends EventTarget {
|
||||
}
|
||||
declare const OffscreenCanvas: {
|
||||
prototype: OffscreenCanvas;
|
||||
new(width: number, height: number): OffscreenCanvas;
|
||||
new (width: number, height: number): OffscreenCanvas;
|
||||
};
|
||||
|
||||
function createCanvas(size: number): OffscreenCanvas {
|
||||
|
@ -34,18 +34,21 @@ setupI18n("en", { en: {} });
|
||||
setupPlatform(chromeAPI);
|
||||
|
||||
describe("All the examples:", () => {
|
||||
const cms = parseGroupImport({ popup, wallet, cta, mui, components })
|
||||
cms.forEach(group => {
|
||||
const cms = parseGroupImport({ popup, wallet, cta, mui, components });
|
||||
cms.forEach((group) => {
|
||||
describe(`Example for group "${group.title}:"`, () => {
|
||||
group.list.forEach(component => {
|
||||
group.list.forEach((component) => {
|
||||
describe(`Component ${component.name}:`, () => {
|
||||
component.examples.forEach(example => {
|
||||
component.examples.forEach((example) => {
|
||||
it(`should render example: ${example.name}`, () => {
|
||||
renderNodeOrBrowser(example.render.component, example.render.props)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
renderNodeOrBrowser(
|
||||
example.render.component,
|
||||
example.render.props,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -54,7 +54,7 @@ export function createExample<Props>(
|
||||
|
||||
return {
|
||||
component: Render,
|
||||
props: evaluatedProps
|
||||
props: evaluatedProps,
|
||||
};
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ export function createExampleWithCustomContext<Props, ContextProps>(
|
||||
|
||||
return {
|
||||
component: WithContext,
|
||||
props: evaluatedProps
|
||||
props: evaluatedProps,
|
||||
};
|
||||
}
|
||||
|
||||
@ -253,7 +253,7 @@ type Subscriptions = {
|
||||
|
||||
export function createWalletApiMock(): {
|
||||
handler: MockHandler;
|
||||
TestingContext: FunctionalComponent<{ children: ComponentChildren }>
|
||||
TestingContext: FunctionalComponent<{ children: ComponentChildren }>;
|
||||
} {
|
||||
const calls = new Array<CallRecord>();
|
||||
const subscriptions: Subscriptions = {};
|
||||
@ -342,8 +342,8 @@ export function createWalletApiMock(): {
|
||||
callback: cb
|
||||
? cb
|
||||
: () => {
|
||||
null;
|
||||
},
|
||||
null;
|
||||
},
|
||||
});
|
||||
return handler;
|
||||
},
|
||||
@ -358,13 +358,21 @@ export function createWalletApiMock(): {
|
||||
},
|
||||
};
|
||||
|
||||
function TestingContext({ children }: { children: ComponentChildren }): VNode {
|
||||
return create(BackendProvider, {
|
||||
wallet: mock.wallet,
|
||||
background: mock.background,
|
||||
listener: mock.listener,
|
||||
function TestingContext({
|
||||
children,
|
||||
}: {
|
||||
children: ComponentChildren;
|
||||
}): VNode {
|
||||
return create(
|
||||
BackendProvider,
|
||||
{
|
||||
wallet: mock.wallet,
|
||||
background: mock.background,
|
||||
listener: mock.listener,
|
||||
children,
|
||||
},
|
||||
children,
|
||||
}, children)
|
||||
);
|
||||
}
|
||||
|
||||
return { handler, TestingContext };
|
||||
|
@ -14,22 +14,21 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import {
|
||||
TalerErrorDetail
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { TalerErrorDetail } from "@gnu-taler/taler-util";
|
||||
import { SyncTermsOfServiceResponse } from "@gnu-taler/taler-wallet-core";
|
||||
import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
import {
|
||||
ButtonHandler,
|
||||
TextFieldHandler,
|
||||
ToggleHandler
|
||||
ToggleHandler,
|
||||
} from "../../mui/handlers.js";
|
||||
import { compose, StateViewMap } from "../../utils/index.js";
|
||||
import { useComponentState } from "./state.js";
|
||||
import {
|
||||
ConfirmProviderView, LoadingUriView,
|
||||
SelectProviderView
|
||||
ConfirmProviderView,
|
||||
LoadingUriView,
|
||||
SelectProviderView,
|
||||
} from "./views.js";
|
||||
|
||||
export interface Props {
|
||||
|
@ -17,11 +17,11 @@
|
||||
import {
|
||||
canonicalizeBaseUrl,
|
||||
Codec,
|
||||
TalerErrorDetail
|
||||
TalerErrorDetail,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import {
|
||||
codecForSyncTermsOfServiceResponse,
|
||||
WalletApiOperation
|
||||
WalletApiOperation,
|
||||
} from "@gnu-taler/taler-wallet-core";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { useBackendContext } from "../../context/backend.js";
|
||||
@ -106,47 +106,50 @@ function useUrlState<T>(
|
||||
constHref == undefined
|
||||
? undefined
|
||||
: async () => {
|
||||
const req = await fetch(constHref).catch((e) => {
|
||||
return setState({
|
||||
status: "network-error",
|
||||
href: constHref,
|
||||
const req = await fetch(constHref).catch((e) => {
|
||||
return setState({
|
||||
status: "network-error",
|
||||
href: constHref,
|
||||
});
|
||||
});
|
||||
});
|
||||
if (!req) return;
|
||||
if (!req) return;
|
||||
|
||||
if (req.status >= 400 && req.status < 500) {
|
||||
setState({
|
||||
status: "client-error",
|
||||
code: req.status,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (req.status > 500) {
|
||||
setState({
|
||||
status: "server-error",
|
||||
code: req.status,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (req.status >= 400 && req.status < 500) {
|
||||
setState({
|
||||
status: "client-error",
|
||||
code: req.status,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (req.status > 500) {
|
||||
setState({
|
||||
status: "server-error",
|
||||
code: req.status,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const json = await req.json();
|
||||
try {
|
||||
const result = codec.decode(json);
|
||||
setState({ status: "ok", result });
|
||||
} catch (e: any) {
|
||||
setState({ status: "parsing-error", json });
|
||||
}
|
||||
},
|
||||
const json = await req.json();
|
||||
try {
|
||||
const result = codec.decode(json);
|
||||
setState({ status: "ok", result });
|
||||
} catch (e: any) {
|
||||
setState({ status: "parsing-error", json });
|
||||
}
|
||||
},
|
||||
[host, path],
|
||||
);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
export function useComponentState(
|
||||
{ currency, onBack, onComplete, onPaymentRequired }: Props,
|
||||
): State {
|
||||
const api = useBackendContext()
|
||||
export function useComponentState({
|
||||
currency,
|
||||
onBack,
|
||||
onComplete,
|
||||
onPaymentRequired,
|
||||
}: Props): State {
|
||||
const api = useBackendContext();
|
||||
const [url, setHost] = useState<string | undefined>();
|
||||
const [name, setName] = useState<string | undefined>();
|
||||
const [tos, setTos] = useState(false);
|
||||
@ -223,8 +226,8 @@ export function useComponentState(
|
||||
!urlState || urlState.status !== "ok" || !name
|
||||
? undefined
|
||||
: async () => {
|
||||
setShowConfirm(true);
|
||||
},
|
||||
setShowConfirm(true);
|
||||
},
|
||||
},
|
||||
urlOk: urlState?.status === "ok",
|
||||
url: {
|
||||
|
@ -21,9 +21,7 @@
|
||||
|
||||
import { expect } from "chai";
|
||||
import { tests } from "../../../../web-util/src/index.browser.js";
|
||||
import {
|
||||
createWalletApiMock, nullFunction
|
||||
} from "../../test-utils.js";
|
||||
import { createWalletApiMock, nullFunction } from "../../test-utils.js";
|
||||
import { Props } from "./index.js";
|
||||
import { useComponentState } from "./state.js";
|
||||
|
||||
@ -34,21 +32,24 @@ const props: Props = {
|
||||
onPaymentRequired: nullFunction,
|
||||
};
|
||||
describe("AddBackupProvider states", () => {
|
||||
|
||||
it("should start in 'select-provider' state", async () => {
|
||||
const { handler, TestingContext } = createWalletApiMock();
|
||||
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [
|
||||
(state) => {
|
||||
expect(state.status).equal("select-provider");
|
||||
if (state.status !== "select-provider") return;
|
||||
expect(state.name.value).eq("");
|
||||
expect(state.url.value).eq("");
|
||||
},
|
||||
], TestingContext)
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(
|
||||
useComponentState,
|
||||
props,
|
||||
[
|
||||
(state) => {
|
||||
expect(state.status).equal("select-provider");
|
||||
if (state.status !== "select-provider") return;
|
||||
expect(state.name.value).eq("");
|
||||
expect(state.url.value).eq("");
|
||||
},
|
||||
],
|
||||
TestingContext,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
|
||||
});
|
||||
});
|
||||
|
@ -20,7 +20,7 @@ import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
import {
|
||||
AmountFieldHandler,
|
||||
ButtonHandler,
|
||||
SelectFieldHandler
|
||||
SelectFieldHandler,
|
||||
} from "../../mui/handlers.js";
|
||||
import { compose, StateViewMap } from "../../utils/index.js";
|
||||
import { ManageAccountPage } from "../ManageAccount/index.js";
|
||||
@ -30,7 +30,7 @@ import {
|
||||
LoadingErrorView,
|
||||
NoAccountToDepositView,
|
||||
NoEnoughBalanceView,
|
||||
ReadyView
|
||||
ReadyView,
|
||||
} from "./views.js";
|
||||
|
||||
export interface Props {
|
||||
|
@ -21,7 +21,7 @@ import {
|
||||
KnownBankAccountsInfo,
|
||||
parsePaytoUri,
|
||||
PaytoUri,
|
||||
stringifyPaytoUri
|
||||
stringifyPaytoUri,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { useState } from "preact/hooks";
|
||||
@ -29,10 +29,13 @@ import { useBackendContext } from "../../context/backend.js";
|
||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
{ amount: amountStr, currency: currencyStr, onCancel, onSuccess }: Props,
|
||||
): State {
|
||||
const api = useBackendContext()
|
||||
export function useComponentState({
|
||||
amount: amountStr,
|
||||
currency: currencyStr,
|
||||
onCancel,
|
||||
onSuccess,
|
||||
}: Props): State {
|
||||
const api = useBackendContext();
|
||||
const parsed = amountStr === undefined ? undefined : Amounts.parse(amountStr);
|
||||
const currency = parsed !== undefined ? parsed.currency : currencyStr;
|
||||
|
||||
@ -55,8 +58,8 @@ export function useComponentState(
|
||||
parsed !== undefined
|
||||
? parsed
|
||||
: currency !== undefined
|
||||
? Amounts.zeroOfCurrency(currency)
|
||||
: undefined;
|
||||
? Amounts.zeroOfCurrency(currency)
|
||||
: undefined;
|
||||
// const [accountIdx, setAccountIdx] = useState<number>(0);
|
||||
const [amount, setAmount] = useState<AmountJson>(initialValue ?? ({} as any));
|
||||
const [selectedAccount, setSelectedAccount] = useState<PaytoUri>();
|
||||
@ -162,7 +165,11 @@ export function useComponentState(
|
||||
async function updateAmount(newAmount: AmountJson): Promise<void> {
|
||||
// const parsed = Amounts.parse(`${currency}:${numStr}`);
|
||||
try {
|
||||
const result = await getFeeForAmount(currentAccount, newAmount, api.wallet);
|
||||
const result = await getFeeForAmount(
|
||||
currentAccount,
|
||||
newAmount,
|
||||
api.wallet,
|
||||
);
|
||||
setAmount(newAmount);
|
||||
setFee(result);
|
||||
} catch (e) {
|
||||
@ -185,8 +192,8 @@ export function useComponentState(
|
||||
const amountError = !isDirty
|
||||
? undefined
|
||||
: Amounts.cmp(balance, amount) === -1
|
||||
? `Too much, your current balance is ${Amounts.stringifyValue(balance)}`
|
||||
: undefined;
|
||||
? `Too much, your current balance is ${Amounts.stringifyValue(balance)}`
|
||||
: undefined;
|
||||
|
||||
const unableToDeposit =
|
||||
Amounts.isZero(totalToDeposit) || //deposit may be zero because of fee
|
||||
|
@ -23,14 +23,12 @@ import {
|
||||
Amounts,
|
||||
DepositGroupFees,
|
||||
parsePaytoUri,
|
||||
stringifyPaytoUri
|
||||
stringifyPaytoUri,
|
||||
} 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 {
|
||||
createWalletApiMock, nullFunction
|
||||
} from "../../test-utils.js";
|
||||
import { createWalletApiMock, nullFunction } from "../../test-utils.js";
|
||||
|
||||
import { useComponentState } from "./state.js";
|
||||
|
||||
@ -71,16 +69,21 @@ describe("DepositPage states", () => {
|
||||
},
|
||||
);
|
||||
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
({ status }) => {
|
||||
expect(status).equal("no-enough-balance");
|
||||
},
|
||||
], TestingContext)
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(
|
||||
useComponentState,
|
||||
props,
|
||||
[
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
({ status }) => {
|
||||
expect(status).equal("no-enough-balance");
|
||||
},
|
||||
],
|
||||
TestingContext,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -107,16 +110,21 @@ describe("DepositPage states", () => {
|
||||
},
|
||||
);
|
||||
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
({ status }) => {
|
||||
expect(status).equal("no-accounts");
|
||||
},
|
||||
], TestingContext)
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(
|
||||
useComponentState,
|
||||
props,
|
||||
[
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
({ status }) => {
|
||||
expect(status).equal("no-accounts");
|
||||
},
|
||||
],
|
||||
TestingContext,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -161,24 +169,29 @@ describe("DepositPage states", () => {
|
||||
withoutFee(),
|
||||
);
|
||||
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
expect(state.cancelHandler.onClick).not.undefined;
|
||||
expect(state.currency).eq(currency);
|
||||
expect(state.account.value).eq(stringifyPaytoUri(ibanPayto.uri));
|
||||
expect(state.amount.value).deep.eq(Amounts.parseOrThrow("EUR:0"));
|
||||
expect(state.depositHandler.onClick).undefined;
|
||||
},
|
||||
], TestingContext)
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(
|
||||
useComponentState,
|
||||
props,
|
||||
[
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
expect(state.cancelHandler.onClick).not.undefined;
|
||||
expect(state.currency).eq(currency);
|
||||
expect(state.account.value).eq(stringifyPaytoUri(ibanPayto.uri));
|
||||
expect(state.amount.value).deep.eq(Amounts.parseOrThrow("EUR:0"));
|
||||
expect(state.depositHandler.onClick).undefined;
|
||||
},
|
||||
],
|
||||
TestingContext,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -218,37 +231,42 @@ describe("DepositPage states", () => {
|
||||
|
||||
const accountSelected = stringifyPaytoUri(ibanPayto.uri);
|
||||
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
expect(state.cancelHandler.onClick).not.undefined;
|
||||
expect(state.currency).eq(currency);
|
||||
expect(state.account.value).eq(stringifyPaytoUri(talerBankPayto.uri));
|
||||
expect(state.amount.value).deep.eq(Amounts.parseOrThrow("EUR:0"));
|
||||
expect(state.depositHandler.onClick).undefined;
|
||||
expect(state.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
||||
expect(state.account.onChange).not.undefined;
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(
|
||||
useComponentState,
|
||||
props,
|
||||
[
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
expect(state.cancelHandler.onClick).not.undefined;
|
||||
expect(state.currency).eq(currency);
|
||||
expect(state.account.value).eq(stringifyPaytoUri(talerBankPayto.uri));
|
||||
expect(state.amount.value).deep.eq(Amounts.parseOrThrow("EUR:0"));
|
||||
expect(state.depositHandler.onClick).undefined;
|
||||
expect(state.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
||||
expect(state.account.onChange).not.undefined;
|
||||
|
||||
state.account.onChange!(accountSelected);
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
expect(state.cancelHandler.onClick).not.undefined;
|
||||
expect(state.currency).eq(currency);
|
||||
expect(state.account.value).eq(accountSelected);
|
||||
expect(state.amount.value).deep.eq(Amounts.parseOrThrow("EUR:0"));
|
||||
expect(state.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
||||
expect(state.depositHandler.onClick).undefined;
|
||||
},
|
||||
], TestingContext)
|
||||
state.account.onChange!(accountSelected);
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
expect(state.cancelHandler.onClick).not.undefined;
|
||||
expect(state.currency).eq(currency);
|
||||
expect(state.account.value).eq(accountSelected);
|
||||
expect(state.amount.value).deep.eq(Amounts.parseOrThrow("EUR:0"));
|
||||
expect(state.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
||||
expect(state.depositHandler.onClick).undefined;
|
||||
},
|
||||
],
|
||||
TestingContext,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
|
||||
@ -292,52 +310,58 @@ describe("DepositPage states", () => {
|
||||
|
||||
const accountSelected = stringifyPaytoUri(ibanPayto.uri);
|
||||
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
expect(state.cancelHandler.onClick).not.undefined;
|
||||
expect(state.currency).eq(currency);
|
||||
expect(state.account.value).eq(stringifyPaytoUri(talerBankPayto.uri));
|
||||
expect(state.amount.value).deep.eq(Amounts.parseOrThrow("EUR:0"));
|
||||
expect(state.depositHandler.onClick).undefined;
|
||||
expect(state.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
||||
expect(state.account.onChange).not.undefined;
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(
|
||||
useComponentState,
|
||||
props,
|
||||
[
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
expect(state.cancelHandler.onClick).not.undefined;
|
||||
expect(state.currency).eq(currency);
|
||||
expect(state.account.value).eq(stringifyPaytoUri(talerBankPayto.uri));
|
||||
expect(state.amount.value).deep.eq(Amounts.parseOrThrow("EUR:0"));
|
||||
expect(state.depositHandler.onClick).undefined;
|
||||
expect(state.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
||||
expect(state.account.onChange).not.undefined;
|
||||
|
||||
state.account.onChange!(accountSelected);
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
expect(state.cancelHandler.onClick).not.undefined;
|
||||
expect(state.currency).eq(currency);
|
||||
expect(state.account.value).eq(accountSelected);
|
||||
expect(state.amount.value).deep.eq(Amounts.parseOrThrow("EUR:0"));
|
||||
expect(state.depositHandler.onClick).undefined;
|
||||
expect(state.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
|
||||
state.account.onChange!(accountSelected);
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
expect(state.cancelHandler.onClick).not.undefined;
|
||||
expect(state.currency).eq(currency);
|
||||
expect(state.account.value).eq(accountSelected);
|
||||
expect(state.amount.value).deep.eq(Amounts.parseOrThrow("EUR:0"));
|
||||
expect(state.depositHandler.onClick).undefined;
|
||||
expect(state.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
|
||||
|
||||
expect(state.amount.onInput).not.undefined;
|
||||
if (!state.amount.onInput) return;
|
||||
state.amount.onInput(Amounts.parseOrThrow("EUR:10"));
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
expect(state.cancelHandler.onClick).not.undefined;
|
||||
expect(state.currency).eq(currency);
|
||||
expect(state.account.value).eq(accountSelected);
|
||||
expect(state.amount.value).deep.eq(Amounts.parseOrThrow("EUR:10"));
|
||||
expect(state.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
|
||||
expect(state.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`));
|
||||
expect(state.depositHandler.onClick).not.undefined;
|
||||
},
|
||||
], TestingContext)
|
||||
expect(state.amount.onInput).not.undefined;
|
||||
if (!state.amount.onInput) return;
|
||||
state.amount.onInput(Amounts.parseOrThrow("EUR:10"));
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
expect(state.cancelHandler.onClick).not.undefined;
|
||||
expect(state.currency).eq(currency);
|
||||
expect(state.account.value).eq(accountSelected);
|
||||
expect(state.amount.value).deep.eq(Amounts.parseOrThrow("EUR:10"));
|
||||
expect(state.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
|
||||
expect(state.totalToDeposit).deep.eq(
|
||||
Amounts.parseOrThrow(`${currency}:7`),
|
||||
);
|
||||
expect(state.depositHandler.onClick).not.undefined;
|
||||
},
|
||||
],
|
||||
TestingContext,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
|
||||
});
|
||||
});
|
||||
|
@ -22,10 +22,8 @@ import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { assertUnreachable, RecursiveState } from "../../utils/index.js";
|
||||
import { Contact, Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
props: Props,
|
||||
): RecursiveState<State> {
|
||||
const api = useBackendContext()
|
||||
export function useComponentState(props: Props): RecursiveState<State> {
|
||||
const api = useBackendContext();
|
||||
const parsedInitialAmount = !props.amount
|
||||
? undefined
|
||||
: Amounts.parse(props.amount);
|
||||
@ -41,22 +39,22 @@ export function useComponentState(
|
||||
const previous: Contact[] = true
|
||||
? []
|
||||
: [
|
||||
{
|
||||
name: "International Bank",
|
||||
icon_type: 'bank',
|
||||
description: "account ending with 3454",
|
||||
},
|
||||
{
|
||||
name: "Max",
|
||||
icon_type: 'bank',
|
||||
description: "account ending with 3454",
|
||||
},
|
||||
{
|
||||
name: "Alex",
|
||||
icon_type: 'bank',
|
||||
description: "account ending with 3454",
|
||||
},
|
||||
];
|
||||
{
|
||||
name: "International Bank",
|
||||
icon_type: "bank",
|
||||
description: "account ending with 3454",
|
||||
},
|
||||
{
|
||||
name: "Max",
|
||||
icon_type: "bank",
|
||||
description: "account ending with 3454",
|
||||
},
|
||||
{
|
||||
name: "Alex",
|
||||
icon_type: "bank",
|
||||
description: "account ending with 3454",
|
||||
},
|
||||
];
|
||||
|
||||
if (!amount) {
|
||||
return () => {
|
||||
@ -114,15 +112,15 @@ export function useComponentState(
|
||||
onClick: invalid
|
||||
? undefined
|
||||
: async () => {
|
||||
props.goToWalletBankDeposit(currencyAndAmount);
|
||||
},
|
||||
props.goToWalletBankDeposit(currencyAndAmount);
|
||||
},
|
||||
},
|
||||
goToWallet: {
|
||||
onClick: invalid
|
||||
? undefined
|
||||
: async () => {
|
||||
props.goToWalletWalletSend(currencyAndAmount);
|
||||
},
|
||||
props.goToWalletWalletSend(currencyAndAmount);
|
||||
},
|
||||
},
|
||||
amountHandler: {
|
||||
onInput: async (s) => setAmount(s),
|
||||
@ -144,15 +142,15 @@ export function useComponentState(
|
||||
onClick: invalid
|
||||
? undefined
|
||||
: async () => {
|
||||
props.goToWalletManualWithdraw(currencyAndAmount);
|
||||
},
|
||||
props.goToWalletManualWithdraw(currencyAndAmount);
|
||||
},
|
||||
},
|
||||
goToWallet: {
|
||||
onClick: invalid
|
||||
? undefined
|
||||
: async () => {
|
||||
props.goToWalletWalletInvoice(currencyAndAmount);
|
||||
},
|
||||
props.goToWalletWalletInvoice(currencyAndAmount);
|
||||
},
|
||||
},
|
||||
amountHandler: {
|
||||
onInput: async (s) => setAmount(s),
|
||||
|
@ -23,7 +23,7 @@ import {
|
||||
Amounts,
|
||||
ExchangeEntryStatus,
|
||||
ExchangeListItem,
|
||||
ExchangeTosStatus
|
||||
ExchangeTosStatus,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { expect } from "chai";
|
||||
@ -59,33 +59,39 @@ describe("Destination selection states", () => {
|
||||
goToWalletWalletInvoice: nullFunction,
|
||||
};
|
||||
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "select-currency") expect.fail();
|
||||
if (state.error) expect.fail();
|
||||
expect(state.currencies).deep.eq({
|
||||
ARS: "ARS",
|
||||
"": "Select a currency",
|
||||
});
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(
|
||||
useComponentState,
|
||||
props,
|
||||
[
|
||||
({ status }) => {
|
||||
expect(status).equal("loading");
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "select-currency") expect.fail();
|
||||
if (state.error) expect.fail();
|
||||
expect(state.currencies).deep.eq({
|
||||
ARS: "ARS",
|
||||
"": "Select a currency",
|
||||
});
|
||||
|
||||
state.onCurrencySelected(exchangeArs.currency!);
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
if (state.error) expect.fail();
|
||||
expect(state.goToBank.onClick).eq(undefined);
|
||||
expect(state.goToWallet.onClick).eq(undefined);
|
||||
state.onCurrencySelected(exchangeArs.currency!);
|
||||
},
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
if (state.error) expect.fail();
|
||||
expect(state.goToBank.onClick).eq(undefined);
|
||||
expect(state.goToWallet.onClick).eq(undefined);
|
||||
|
||||
expect(state.amountHandler.value).deep.eq(Amounts.parseOrThrow("ARS:0"));
|
||||
},
|
||||
], TestingContext)
|
||||
expect(state.amountHandler.value).deep.eq(
|
||||
Amounts.parseOrThrow("ARS:0"),
|
||||
);
|
||||
},
|
||||
],
|
||||
TestingContext,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
|
||||
});
|
||||
|
||||
it("should be possible to start with an amount specified in request params", async () => {
|
||||
@ -98,22 +104,28 @@ describe("Destination selection states", () => {
|
||||
amount: "ARS:2",
|
||||
};
|
||||
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(useComponentState, props, [
|
||||
// ({ status }) => {
|
||||
// expect(status).equal("loading");
|
||||
// },
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
if (state.error) expect.fail();
|
||||
expect(state.goToBank.onClick).not.eq(undefined);
|
||||
expect(state.goToWallet.onClick).not.eq(undefined);
|
||||
const hookBehavior = await tests.hookBehaveLikeThis(
|
||||
useComponentState,
|
||||
props,
|
||||
[
|
||||
// ({ status }) => {
|
||||
// expect(status).equal("loading");
|
||||
// },
|
||||
(state) => {
|
||||
if (state.status !== "ready") expect.fail();
|
||||
if (state.error) expect.fail();
|
||||
expect(state.goToBank.onClick).not.eq(undefined);
|
||||
expect(state.goToWallet.onClick).not.eq(undefined);
|
||||
|
||||
expect(state.amountHandler.value).deep.eq(Amounts.parseOrThrow("ARS:2"));
|
||||
},
|
||||
], TestingContext)
|
||||
expect(state.amountHandler.value).deep.eq(
|
||||
Amounts.parseOrThrow("ARS:2"),
|
||||
);
|
||||
},
|
||||
],
|
||||
TestingContext,
|
||||
);
|
||||
|
||||
expect(hookBehavior).deep.equal({ result: "ok" })
|
||||
expect(hookBehavior).deep.equal({ result: "ok" });
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
|
||||
});
|
||||
});
|
||||
|
@ -18,7 +18,7 @@ import {
|
||||
DenomOperationMap,
|
||||
ExchangeFullDetails,
|
||||
ExchangeListItem,
|
||||
FeeDescriptionPair
|
||||
FeeDescriptionPair,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
@ -32,7 +32,7 @@ import {
|
||||
NoExchangesView,
|
||||
PrivacyContentView,
|
||||
ReadyView,
|
||||
TosContentView
|
||||
TosContentView,
|
||||
} from "./views.js";
|
||||
|
||||
export interface Props {
|
||||
|
@ -17,17 +17,20 @@
|
||||
import { DenomOperationMap, FeeDescription } from "@gnu-taler/taler-util";
|
||||
import {
|
||||
createPairTimeline,
|
||||
WalletApiOperation
|
||||
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 { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
{ onCancel, onSelection, list: exchanges, currentExchange }: Props,
|
||||
): State {
|
||||
const api = useBackendContext()
|
||||
export function useComponentState({
|
||||
onCancel,
|
||||
onSelection,
|
||||
list: exchanges,
|
||||
currentExchange,
|
||||
}: Props): State {
|
||||
const api = useBackendContext();
|
||||
const initialValue = exchanges.findIndex(
|
||||
(e) => e.exchangeBaseUrl === currentExchange,
|
||||
);
|
||||
@ -52,14 +55,14 @@ export function useComponentState(
|
||||
const selected = !selectedExchange
|
||||
? undefined
|
||||
: await api.wallet.call(WalletApiOperation.GetExchangeDetailedInfo, {
|
||||
exchangeBaseUrl: selectedExchange.exchangeBaseUrl,
|
||||
});
|
||||
exchangeBaseUrl: selectedExchange.exchangeBaseUrl,
|
||||
});
|
||||
|
||||
const original = !initialExchange
|
||||
? undefined
|
||||
: await api.wallet.call(WalletApiOperation.GetExchangeDetailedInfo, {
|
||||
exchangeBaseUrl: initialExchange.exchangeBaseUrl,
|
||||
});
|
||||
exchangeBaseUrl: initialExchange.exchangeBaseUrl,
|
||||
});
|
||||
|
||||
return {
|
||||
exchanges,
|
||||
|
@ -20,7 +20,7 @@ import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
import {
|
||||
ButtonHandler,
|
||||
SelectFieldHandler,
|
||||
TextFieldHandler
|
||||
TextFieldHandler,
|
||||
} from "../../mui/handlers.js";
|
||||
import { compose, StateViewMap } from "../../utils/index.js";
|
||||
import { useComponentState } from "./state.js";
|
||||
|
@ -17,7 +17,7 @@
|
||||
import {
|
||||
KnownBankAccountsInfo,
|
||||
parsePaytoUri,
|
||||
stringifyPaytoUri
|
||||
stringifyPaytoUri,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { useState } from "preact/hooks";
|
||||
@ -25,10 +25,12 @@ import { useBackendContext } from "../../context/backend.js";
|
||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { AccountByType, Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
{ currency, onAccountAdded, onCancel }: Props,
|
||||
): State {
|
||||
const api = useBackendContext()
|
||||
export function useComponentState({
|
||||
currency,
|
||||
onAccountAdded,
|
||||
onCancel,
|
||||
}: Props): State {
|
||||
const api = useBackendContext();
|
||||
const hook = useAsyncAsHook(() =>
|
||||
api.wallet.call(WalletApiOperation.ListKnownBankAccounts, { currency }),
|
||||
);
|
||||
|
@ -21,7 +21,7 @@ import { compose, StateViewMap } from "../../utils/index.js";
|
||||
import { useComponentState } from "./state.js";
|
||||
import { LoadingUriView, ReadyView } from "./views.js";
|
||||
|
||||
export type Props = object
|
||||
export type Props = object;
|
||||
|
||||
export type State = State.Loading | State.LoadingUriError | State.Ready;
|
||||
|
||||
|
@ -20,7 +20,7 @@ import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(p: Props): State {
|
||||
const api = useBackendContext()
|
||||
const api = useBackendContext();
|
||||
const hook = useAsyncAsHook(async () => {
|
||||
return await api.wallet.call(
|
||||
WalletApiOperation.GetUserAttentionRequests,
|
||||
|
@ -156,8 +156,8 @@ export type WxApiType = {
|
||||
background: BackgroundApiClient;
|
||||
listener: {
|
||||
onUpdateNotification: typeof onUpdateNotification;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const wxApi = {
|
||||
wallet: new WxWalletCoreApiClient(),
|
||||
|
Loading…
Reference in New Issue
Block a user