diff options
Diffstat (limited to 'packages/taler-wallet-webextension/src/test-utils.ts')
-rw-r--r-- | packages/taler-wallet-webextension/src/test-utils.ts | 202 |
1 files changed, 194 insertions, 8 deletions
diff --git a/packages/taler-wallet-webextension/src/test-utils.ts b/packages/taler-wallet-webextension/src/test-utils.ts index 6bf1be3ff..452cc578e 100644 --- a/packages/taler-wallet-webextension/src/test-utils.ts +++ b/packages/taler-wallet-webextension/src/test-utils.ts @@ -1,6 +1,6 @@ /* This file is part of GNU Taler - (C) 2021 Taler Systems S.A. + (C) 2022 Taler Systems S.A. GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -14,15 +14,201 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { ComponentChildren, FunctionalComponent, h as render } from 'preact'; +import { NotificationType, TalerBankIntegrationHttpClient, TalerCoreBankHttpClient, TalerRevenueHttpClient, TalerWireGatewayHttpClient, WalletNotification } from "@gnu-taler/taler-util"; +import { + WalletCoreApiClient, + WalletCoreOpKeys, + WalletCoreRequestType, + WalletCoreResponseType, +} from "@gnu-taler/taler-wallet-core"; +import { ApiContextProvider, TranslationProvider, defaultRequestHandler } from "@gnu-taler/web-util/browser"; +import { + ComponentChildren, + FunctionalComponent, + VNode, + h as create, +} from "preact"; +import { AlertProvider } from "./context/alert.js"; +import { BackendProvider } from "./context/backend.js"; +import { strings } from "./i18n/strings.js"; +import { nullFunction } from "./mui/handlers.js"; +import { BackgroundApiClient, wxApi } from "./wxApi.js"; -export function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) { - const r = (args: any) => render(Component, args) - r.args = props - return r +// export const nullFunction: any = () => null; + +interface MockHandler { + addWalletCallResponse<Op extends WalletCoreOpKeys>( + operation: Op, + payload?: Partial<WalletCoreRequestType<Op>>, + response?: WalletCoreResponseType<Op>, + callback?: () => void, + ): MockHandler; + + getCallingQueueState(): "empty" | string; + + notifyEventFromWallet(notif: WalletNotification): void; } +type CallRecord = WalletCallRecord | BackgroundCallRecord; +interface WalletCallRecord { + source: "wallet"; + callback: () => void; + operation: WalletCoreOpKeys; + payload?: WalletCoreRequestType<WalletCoreOpKeys>; + response?: WalletCoreResponseType<WalletCoreOpKeys>; +} +interface BackgroundCallRecord { + source: "background"; + name: string; + args: any; + response: any; +} + +type Subscriptions = { + [key in NotificationType]?: (d: WalletNotification) => void; +}; + +export function createWalletApiMock(): { + handler: MockHandler; + TestingContext: FunctionalComponent<{ children: ComponentChildren }>; +} { + const calls = new Array<CallRecord>(); + const subscriptions: Subscriptions = {}; + + const mock: typeof wxApi = { + wallet: new Proxy<WalletCoreApiClient>({} as any, { + get(target, name, receiver) { + const functionName = String(name); + if (functionName !== "call") { + throw Error( + `the only method in wallet api should be 'call': ${functionName}`, + ); + } + return function ( + operation: WalletCoreOpKeys, + payload: WalletCoreRequestType<WalletCoreOpKeys>, + ) { + const next = calls.shift(); + + if (!next) { + throw Error( + `wallet operation was called but none was expected: ${operation} (${JSON.stringify( + payload, + undefined, + 2, + )})`, + ); + } + if (next.source !== "wallet") { + throw Error(`wallet operation expected`); + } + if (operation !== next.operation) { + //more checks, deep check payload + throw Error( + `wallet operation doesn't match: expected ${next.operation} actual ${operation}`, + ); + } + next.callback(); + + return next.response ?? {}; + }; + }, + }), + listener: { + trigger: () => { + + }, + onUpdateNotification( + mTypes: NotificationType[], + callback: ((d: WalletNotification) => void) | undefined, + ): () => void { + mTypes.forEach((m) => { + subscriptions[m] = callback; + }); + return nullFunction; + }, + }, + background: new Proxy<BackgroundApiClient>({} as any, { + get(target, name, receiver) { + const functionName = String(name); + return function (...args: any) { + const next = calls.shift(); + if (!next) { + throw Error( + `background operation was called but none was expected: ${functionName} (${JSON.stringify( + args, + undefined, + 2, + )})`, + ); + } + if (next.source !== "background" || functionName !== next.name) { + //more checks, deep check args + throw Error(`background operation doesn't match`); + } + return next.response; + }; + }, + }), + }; + + const handler: MockHandler = { + addWalletCallResponse(operation, payload, response, cb) { + calls.push({ + source: "wallet", + operation, + payload, + response, + callback: cb + ? cb + : () => { + null; + }, + }); + return handler; + }, + notifyEventFromWallet(event: WalletNotification): void { + const callback = subscriptions[event.type]; + if (!callback) + throw Error(`Expected to have a subscription for ${event}`); + return callback(event); + }, + getCallingQueueState() { + return calls.length === 0 ? "empty" : `${calls.length} left`; + }, + }; + + function TestingContext({ + children: _cs, + }: { + children: ComponentChildren; + }): VNode { + let children = _cs; + children = create(AlertProvider, { children }, children); + const value = { + request: defaultRequestHandler, + bankCore: new TalerCoreBankHttpClient("/"), + bankIntegration: new TalerBankIntegrationHttpClient("/"), + bankWire: new TalerWireGatewayHttpClient("/",""), + bankRevenue: new TalerRevenueHttpClient("/"), + } + children = create(ApiContextProvider, { value, children }, children); + children = create( + TranslationProvider, + { children, source: strings, initial: "en", forceLang: "en" }, + children, + ); + return create( + BackendProvider, + { + wallet: mock.wallet, + background: mock.background, + listener: mock.listener, + children, + }, + children, + ); + } -export function NullLink({ children }: { children?: ComponentChildren }) { - return render('a', { children, href: 'javascript:void(0);' }) + return { handler, TestingContext }; } |