diff options
| author | Sebastian <sebasjm@gmail.com> | 2023-01-09 20:20:09 -0300 |
|---|---|---|
| committer | Sebastian <sebasjm@gmail.com> | 2023-01-09 20:20:09 -0300 |
| commit | 4a781bd0dd8828ce152f6ab2c3f1bbd6b5e826f7 (patch) | |
| tree | 5c16976f99eb973ff62d78ed64107ca01df57b99 /packages/taler-wallet-webextension/src/hooks | |
| parent | 8a70edb2f8e235c3462127b0aa4e1b65aa1aee0b (diff) | |
fix #7153: more error handling
if handler do not trap error then fail at compile time,
all safe handlers push alert on error
errors are typed so they render good information
Diffstat (limited to 'packages/taler-wallet-webextension/src/hooks')
6 files changed, 109 insertions, 143 deletions
diff --git a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts index 978ea90e1..cf9409bad 100644 --- a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts +++ b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts @@ -16,7 +16,7 @@ import { TalerErrorDetail } from "@gnu-taler/taler-util"; import { TalerError } from "@gnu-taler/taler-wallet-core"; import { useEffect, useMemo, useState } from "preact/hooks"; -import { WalletError } from "../wxApi.js"; +import { BackgroundError } from "../wxApi.js"; export interface HookOk<T> { hasError: false; @@ -74,12 +74,12 @@ export function useAsyncAsHook<T>( message: e.message, details: e.errorDetail, }); - } else if (e instanceof WalletError) { + } else if (e instanceof BackgroundError) { setHookResponse({ hasError: true, type: "taler", message: e.message, - details: e.errorDetail.errorDetail, + details: e.errorDetail, }); } else if (e instanceof Error) { setHookResponse({ diff --git a/packages/taler-wallet-webextension/src/hooks/useAutoOpenPermissions.ts b/packages/taler-wallet-webextension/src/hooks/useAutoOpenPermissions.ts index cf2fd880e..e0a34f690 100644 --- a/packages/taler-wallet-webextension/src/hooks/useAutoOpenPermissions.ts +++ b/packages/taler-wallet-webextension/src/hooks/useAutoOpenPermissions.ts @@ -14,23 +14,41 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { TalerError } from "@gnu-taler/taler-wallet-core"; import { useEffect, useState } from "preact/hooks"; +import { useAlertContext } from "../context/alert.js"; import { useBackendContext } from "../context/backend.js"; import { ToggleHandler } from "../mui/handlers.js"; import { platform } from "../platform/foreground.js"; export function useAutoOpenPermissions(): ToggleHandler { const api = useBackendContext(); + const { pushAlertOnError } = useAlertContext(); 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)); - }, - ); - }; + + async function handleAutoOpenPerm(): Promise<void> { + if (!enabled) { + // We set permissions here, since apparently FF wants this to be done + // as the result of an input event ... + let granted: boolean; + try { + granted = await platform.getPermissionsApi().requestHostPermissions(); + } catch (lastError) { + setEnabled(false); + throw lastError; + } + const res = await api.background.call("toggleHeaderListener", granted); + setEnabled(res.newValue); + } else { + try { + await api.background + .call("toggleHeaderListener", false) + .then((r) => setEnabled(r.newValue)); + } catch (e) { + console.log(e); + } + } + return; + } useEffect(() => { async function getValue(): Promise<void> { @@ -42,40 +60,11 @@ export function useAutoOpenPermissions(): ToggleHandler { } getValue(); }, []); + return { value: enabled, button: { - onClick: toggle, - error, + onClick: pushAlertOnError(handleAutoOpenPerm), }, }; } - -async function handleAutoOpenPerm( - isEnabled: boolean, - onChange: (value: boolean) => void, - background: ReturnType<typeof useBackendContext>["background"], -): Promise<void> { - if (!isEnabled) { - // We set permissions here, since apparently FF wants this to be done - // as the result of an input event ... - let granted: boolean; - try { - granted = await platform.getPermissionsApi().requestHostPermissions(); - } catch (lastError) { - onChange(false); - throw lastError; - } - const res = await background.call("toggleHeaderListener", granted); - onChange(res.newValue); - } else { - try { - await background - .call("toggleHeaderListener", false) - .then((r) => onChange(r.newValue)); - } catch (e) { - console.log(e); - } - } - return; -} diff --git a/packages/taler-wallet-webextension/src/hooks/useClipboardPermissions.ts b/packages/taler-wallet-webextension/src/hooks/useClipboardPermissions.ts index 0f035d0f2..25757f473 100644 --- a/packages/taler-wallet-webextension/src/hooks/useClipboardPermissions.ts +++ b/packages/taler-wallet-webextension/src/hooks/useClipboardPermissions.ts @@ -14,24 +14,42 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { TalerError } from "@gnu-taler/taler-wallet-core"; import { useEffect, useState } from "preact/hooks"; +import { useAlertContext } from "../context/alert.js"; import { useBackendContext } from "../context/backend.js"; import { ToggleHandler } from "../mui/handlers.js"; import { platform } from "../platform/foreground.js"; export function useClipboardPermissions(): ToggleHandler { const [enabled, setEnabled] = useState(false); - const [error, setError] = useState<TalerError | undefined>(); const api = useBackendContext(); + const { pushAlertOnError } = useAlertContext(); - const toggle = async (): Promise<void> => { - return handleClipboardPerm(enabled, setEnabled, api.background).catch( - (e) => { - setError(TalerError.fromException(e)); - }, - ); - }; + async function handleClipboardPerm(): Promise<void> { + if (!enabled) { + // We set permissions here, since apparently FF wants this to be done + // as the result of an input event ... + let granted: boolean; + try { + granted = await platform + .getPermissionsApi() + .requestClipboardPermissions(); + } catch (lastError) { + setEnabled(false); + throw lastError; + } + setEnabled(granted); + } else { + try { + await api.background + .call("toggleHeaderListener", false) + .then((r) => setEnabled(r.newValue)); + } catch (e) { + console.log(e); + } + } + return; + } useEffect(() => { async function getValue(): Promise<void> { @@ -47,38 +65,7 @@ export function useClipboardPermissions(): ToggleHandler { return { value: enabled, button: { - onClick: toggle, - error, + onClick: pushAlertOnError(handleClipboardPerm), }, }; } - -async function handleClipboardPerm( - isEnabled: boolean, - onChange: (value: boolean) => void, - background: ReturnType<typeof useBackendContext>["background"], -): Promise<void> { - if (!isEnabled) { - // We set permissions here, since apparently FF wants this to be done - // as the result of an input event ... - let granted: boolean; - try { - granted = await platform - .getPermissionsApi() - .requestClipboardPermissions(); - } catch (lastError) { - onChange(false); - throw lastError; - } - onChange(granted); - } else { - try { - await background - .call("toggleHeaderListener", false) - .then((r) => onChange(r.newValue)); - } catch (e) { - console.log(e); - } - } - return; -} diff --git a/packages/taler-wallet-webextension/src/hooks/useSelectedExchange.ts b/packages/taler-wallet-webextension/src/hooks/useSelectedExchange.ts index c04dcce84..6ceae2d47 100644 --- a/packages/taler-wallet-webextension/src/hooks/useSelectedExchange.ts +++ b/packages/taler-wallet-webextension/src/hooks/useSelectedExchange.ts @@ -16,6 +16,7 @@ import { ExchangeListItem } from "@gnu-taler/taler-util"; import { useState } from "preact/hooks"; +import { useAlertContext } from "../context/alert.js"; import { ButtonHandler } from "../mui/handlers.js"; type State = State.Ready | State.NoExchange | State.Selecting; @@ -59,6 +60,7 @@ export function useSelectedExchange({ const [selectedExchange, setSelectedExchange] = useState<string | undefined>( undefined, ); + const { pushAlertOnError } = useAlertContext(); if (!list.length) { return { @@ -105,7 +107,7 @@ export function useSelectedExchange({ return { status: "ready", doSelect: { - onClick: async () => setIsSelecting(true), + onClick: pushAlertOnError(async () => setIsSelecting(true)), }, selected: found, }; @@ -118,7 +120,7 @@ export function useSelectedExchange({ return { status: "ready", doSelect: { - onClick: async () => setIsSelecting(true), + onClick: pushAlertOnError(async () => setIsSelecting(true)), }, selected: found, }; @@ -127,7 +129,7 @@ export function useSelectedExchange({ return { status: "ready", doSelect: { - onClick: async () => setIsSelecting(true), + onClick: pushAlertOnError(async () => setIsSelecting(true)), }, selected: listCurrency[0], }; diff --git a/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.test.ts b/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.test.ts index 8aabb8adf..e70f7f9be 100644 --- a/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.test.ts +++ b/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.test.ts @@ -13,11 +13,11 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { useTalerActionURL } from "./useTalerActionURL.js"; -import { mountHook } from "../test-utils.js"; -import { IoCProviderForTesting } from "../context/iocContext.js"; -import { h, VNode } from "preact"; import { expect } from "chai"; +import { h, VNode } from "preact"; +import { IoCProviderForTesting } from "../context/iocContext.js"; +import { useTalerActionURL } from "./useTalerActionURL.js"; +import { tests } from "@gnu-taler/web-util/lib/index.browser"; describe("useTalerActionURL hook", () => { it("should be set url to undefined when dismiss", async () => { @@ -31,32 +31,28 @@ describe("useTalerActionURL hook", () => { }); }; - const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = - mountHook(useTalerActionURL, ctx); - - { - const [url] = pullLastResultOrThrow(); - expect(url).undefined; - } - - expect(await waitForStateUpdate()).true; - - { - const [url, setDismissed] = pullLastResultOrThrow(); - expect(url).deep.equals({ - location: "clipboard", - uri: "qwe", - }); - setDismissed(true); - } - - expect(await waitForStateUpdate()).true; + const hookBehavior = await tests.hookBehaveLikeThis( + useTalerActionURL, + {}, + [ + ([url]) => { + expect(url).undefined; + }, + ([url, setDismissed]) => { + expect(url).deep.equals({ + location: "clipboard", + uri: "qwe", + }); + setDismissed(true); + }, + ([url]) => { + if (url !== undefined) throw Error("invalid"); + expect(url).undefined; + }, + ], + ctx, + ); - { - const [url] = pullLastResultOrThrow(); - if (url !== undefined) throw Error("invalid"); - expect(url).undefined; - } - await assertNoPendingUpdate(); + expect(hookBehavior).deep.equal({ result: "ok" }); }); }); diff --git a/packages/taler-wallet-webextension/src/hooks/useWalletDevMode.ts b/packages/taler-wallet-webextension/src/hooks/useWalletDevMode.ts index 6ae55da61..db7effe96 100644 --- a/packages/taler-wallet-webextension/src/hooks/useWalletDevMode.ts +++ b/packages/taler-wallet-webextension/src/hooks/useWalletDevMode.ts @@ -14,21 +14,28 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { useState, useEffect } from "preact/hooks"; -import { ToggleHandler } from "../mui/handlers.js"; -import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { useEffect, useState } from "preact/hooks"; import { useBackendContext } from "../context/backend.js"; -export function useWalletDevMode(): ToggleHandler { +type Result = { + value: boolean | undefined; + toggle: () => Promise<void>; +}; + +export function useWalletDevMode(): Result { const [enabled, setEnabled] = useState<undefined | boolean>(undefined); - const [error, setError] = useState<TalerError | undefined>(); const api = useBackendContext(); + // const { pushAlertOnError } = useAlertContext(); - const toggle = async (): Promise<void> => { - return handleOpen(enabled, setEnabled, api).catch((e) => { - setError(TalerError.fromException(e)); + async function handleOpen(): Promise<void> { + const nextValue = !enabled; + await api.wallet.call(WalletApiOperation.SetDevMode, { + devModeEnabled: nextValue, }); - }; + setEnabled(nextValue); + return; + } useEffect(() => { async function getValue(): Promise<void> { @@ -37,24 +44,9 @@ export function useWalletDevMode(): ToggleHandler { } getValue(); }, []); + return { value: enabled, - button: { - onClick: enabled === undefined ? undefined : toggle, - error, - }, + toggle: handleOpen, }; } - -async function handleOpen( - currentValue: undefined | boolean, - onChange: (value: boolean) => void, - api: ReturnType<typeof useBackendContext>, -): Promise<void> { - const nextValue = !currentValue; - await api.wallet.call(WalletApiOperation.SetDevMode, { - devModeEnabled: nextValue, - }); - onChange(nextValue); - return; -} |
