/* This file is part of GNU Taler (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 Foundation; either version 3, or (at your option) any later version. GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ 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 const nullFunction: any = () => null; interface MockHandler { addWalletCallResponse( operation: Op, payload?: Partial>, response?: WalletCoreResponseType, callback?: () => void, ): MockHandler; getCallingQueueState(): "empty" | string; notifyEventFromWallet(notif: WalletNotification): void; } type CallRecord = WalletCallRecord | BackgroundCallRecord; interface WalletCallRecord { source: "wallet"; callback: () => void; operation: WalletCoreOpKeys; payload?: WalletCoreRequestType; response?: WalletCoreResponseType; } 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(); const subscriptions: Subscriptions = {}; const mock: typeof wxApi = { wallet: new Proxy({} 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, ) { 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({} 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, ); } return { handler, TestingContext }; }