taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 57abe01f3e1bb0849aebc65af825739fc31875fd
parent 8e620b99a35c1b559d9373c1d9ef17c8464d060b
Author: Sebastian <sebasjm@taler-systems.com>
Date:   Wed, 11 Feb 2026 18:10:47 -0300

fix #11030

Diffstat:
Mpackages/taler-harness/README.md | 20++++++++++++--------
Mpackages/taler-harness/src/harness/environments.ts | 66++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mpackages/taler-harness/src/harness/harness.ts | 86++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mpackages/taler-harness/src/integrationtests/test-fee-regression.ts | 2+-
Mpackages/taler-harness/src/integrationtests/test-revocation.ts | 2+-
Mpackages/taler-harness/src/integrationtests/web/test-merchant-self-provision-activation.ts | 14+-------------
6 files changed, 148 insertions(+), 42 deletions(-)

diff --git a/packages/taler-harness/README.md b/packages/taler-harness/README.md @@ -14,7 +14,7 @@ export NODE_OPTIONS=--enable-source-maps ## Headless Web Integration test -1) First you require the browser that you are going to test with +1) First you need the browsers that you are going to use to test Puppeteer scripts can be used to download @@ -34,19 +34,23 @@ Or can be download manually from Firefox: https://archive.mozilla.org/pub/firefox/ Chrome: https://googlechromelabs.github.io/chrome-for-testing/ -let BROWSER_DIR be the directory where the browser was downloaded - 2) Then you need the respective webdriver binaries Firefox: https://github.com/mozilla/geckodriver/ Chrome: https://googlechromelabs.github.io/chrome-for-testing/ -let DRIVER_DIR be the directory where the browser was downloaded - -3) The integration tests will expect the driver+browser available on port 9090 for chrome and 9091 for firefox +3) The integration tests will expect the driver+browser available on PATH -Firefox: $DRIVER_DIR/geckodriver --port 9091 -b $BROWSER_DIR/firefox -Chrome: PATH=$DRIVER_DIR $DRIVER_DIR/chromedriver --port=9090 --verbose +If there are multiple binaries on the system the BROWSER_PATH environment variable +can be used to narrow the search path. This environment will replace the PATH +environment for the driver so it will limit the scope of +search for the driver and the browser. +For example +``` +export BROWSER_PATH=/opt/browsers/chromedriver/linux-145.0.7632.46/chromedriver-linux64/:/opt/browsers/chrome/linux-145.0.7632.45/chrome-linux64/ +taler-harness run-integrationtests web-merchant-self-provision-activation +``` +The default browser is "chrome" unless the env variable DEFAULT_BROWSER is set to either "firefox" or "chrome". diff --git a/packages/taler-harness/src/harness/environments.ts b/packages/taler-harness/src/harness/environments.ts @@ -29,6 +29,7 @@ import { AmlDecisionRequest, AmlDecisionRequestWithoutSignature, AmountString, + assertUnreachable, Configuration, ConfirmPayResultType, decodeCrock, @@ -69,6 +70,7 @@ import { import { BankService, BankServiceHandle, + BrowserService, DbInfo, ExchangeService, ExchangeServiceInterface, @@ -146,7 +148,9 @@ export interface SimpleTestEnvironmentNg3 { merchantAdminAccessToken: AccessToken; walletClient: WalletClient; walletService: WalletService; - createBrowser: (params: { firefox?: boolean }) => Promise<ThenableWebDriver>; + createBrowser: (params: { + browserType?: "chrome" | "firefox"; + }) => Promise<ThenableWebDriver>; } export interface EnvOptions { @@ -486,22 +490,48 @@ export async function createSimpleTestkudosEnvironmentV2( }; } -export async function createBrowser({ firefox }: { firefox?: boolean }): Promise<ThenableWebDriver> { - const chromeOpts = new Chrome.Options(); - chromeOpts.addArguments("--no-sandbox", "-headless"); - - const chromeDriver = new Builder() - .forBrowser(Browser.CHROME) - .setChromeOptions(chromeOpts) - .usingServer("http://127.0.0.1:9090/"); - const firefoxOpts = new Firefox.Options(); - firefoxOpts.addArguments("--headless"); - - const firefoxDriver = new Builder() - .forBrowser(Browser.FIREFOX) - .setFirefoxOptions(firefoxOpts) - .usingServer("http://127.0.0.1:9091/"); - return firefox ? firefoxDriver.build() : chromeDriver.build(); +export function createBrowser(t: GlobalTestState) { + return async function createBrowser({ + browserType, + }: { + browserType?: "firefox" | "chrome"; + }): Promise<ThenableWebDriver> { + const defaultBrowser = + process.env.DEFAULT_BROWSER === "chrome" + ? ("chrome" as const) + : process.env.DEFAULT_BROWSER === "firefox" + ? ("firefox" as const) + : undefined; + + const type = browserType ?? defaultBrowser ?? "chrome"; + const b = new BrowserService(t, type); + await b.start(); + + switch (type) { + case "firefox": { + const firefoxOpts = new Firefox.Options(); + firefoxOpts.addArguments("--headless"); + const driver = new Builder() + .forBrowser(Browser.FIREFOX) + .setFirefoxOptions(firefoxOpts) + .usingServer("http://127.0.0.1:9090/"); + return driver.build(); + } + + case "chrome": { + const chromeOpts = new Chrome.Options(); + chromeOpts.addArguments("--no-sandbox", "-headless"); + + const driver = new Builder() + .forBrowser(Browser.CHROME) + .setChromeOptions(chromeOpts) + .usingServer("http://127.0.0.1:9090/"); + return driver.build(); + } + default: + assertUnreachable(type); + } + }; } /** @@ -670,7 +700,7 @@ export async function createSimpleTestkudosEnvironmentV3( bank, bankClient, exchangeBankAccount, - createBrowser, + createBrowser: createBrowser(t), }; } diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts @@ -54,6 +54,7 @@ import { Transaction, TransactionIdStr, WalletNotification, + assertUnreachable, codecForAccountKycRedirects, codecForQueryInstancesResponse, createEddsaKeyPair, @@ -1187,7 +1188,6 @@ export interface ExchangeServiceInterface { } export class ExchangeService implements ExchangeServiceInterface { - static fromExistingConfig( gc: GlobalTestState, exchangeName: string, @@ -1996,6 +1996,90 @@ export const MERCHANT_DEFAULT_LOGIN_SCOPE: LoginTokenRequest = { duration: { d_us: "forever" }, }; +/** + * FIXME: we may want to have N browsers M drivers and 1 proxy + * proxy = redirect request to drivers + * M = 1 per type of browser (geckodriver, chromedriver,...) + * N = different version of same browser + */ +export class BrowserService { + // browser: ProcessWrapper | undefined; + driver: ProcessWrapper | undefined; + httpPort: number = 9090; + + constructor( + private globalState: GlobalTestState, + private type: "firefox" | "chrome", + ) {} + + async stop(): Promise<void> { + const driver = this.driver; + if (driver) { + logger.info(`killing web driver`); + driver.proc.kill("SIGTERM"); + await driver.wait(); + logger.info(`done killing web driver`); + this.driver = undefined; + } + } + + async pingUntilAvailable(): Promise<void> { + const url = `http://localhost:${this.httpPort}/status`; + await pingProc(this.driver, url, `browser (${this.type})`); + } + + async start(): Promise<void> { + switch (this.type) { + case "firefox": { + const profileDir = path.join( + this.globalState.testDir, + "browser-profile", + ); + fs.mkdirSync(profileDir); + + this.driver = this.globalState.spawnService( + "geckodriver", + [ + "--log", + "debug", + "--port", + "9090", + "--host", + "127.0.0.1", + `--profile-root`, + profileDir, + ], + `web-browser`, + process.env.BROWSER_PATH ? { + PATH : process.env.BROWSER_PATH + } : undefined + ); + break; + } + case "chrome": { + this.driver = this.globalState.spawnService( + "chromedriver", + [ + "--log-level=DEBUG", + "--port=9090", + "--allowed-ips=127.0.0.1", + "--enable-chrome-logs", + `--log-path=${this.globalState.testDir}/browser.log`, + ], + `web-browser`, + process.env.BROWSER_PATH ? { + PATH : process.env.BROWSER_PATH + } : undefined + ); + break; + } + default: + assertUnreachable(this.type); + } + await this.pingUntilAvailable(); + } +} + export class MerchantService implements MerchantServiceInterface { static fromExistingConfig( gc: GlobalTestState, diff --git a/packages/taler-harness/src/integrationtests/test-fee-regression.ts b/packages/taler-harness/src/integrationtests/test-fee-regression.ts @@ -198,7 +198,7 @@ export async function createMyTestkudosEnvironment( walletService, bankClient, bank, - createBrowser, + createBrowser: createBrowser(t), exchangeBankAccount, }; } diff --git a/packages/taler-harness/src/integrationtests/test-revocation.ts b/packages/taler-harness/src/integrationtests/test-revocation.ts @@ -186,7 +186,7 @@ async function createTestEnvironment( bank, bankClient, exchangeBankAccount, - createBrowser + createBrowser: createBrowser(t), }; } diff --git a/packages/taler-harness/src/integrationtests/web/test-merchant-self-provision-activation.ts b/packages/taler-harness/src/integrationtests/web/test-merchant-self-provision-activation.ts @@ -17,24 +17,12 @@ /** * Imports. */ -import { - alternativeOrThrow, - Duration, - HttpStatusCode, - LoginTokenScope, - MerchantAuthMethod, - succeedOrThrow, - TalerMerchantInstanceHttpClient, - TalerMerchantManagementHttpClient, - TanChannel, -} from "@gnu-taler/taler-util"; import { createSimpleTestkudosEnvironmentV3 } from "harness/environments.js"; import { startTanHelper } from "harness/tan-helper.js"; import { randomBytes } from "node:crypto"; import { chmodSync, writeFileSync } from "node:fs"; +import { By } from "selenium-webdriver"; import { GlobalTestState, MERCHANT_DEFAULT_AUTH } from "../../harness/harness.js"; -import { solveMFA } from "../test-merchant-self-provision-inactive-account-permissions.js"; -import { By, locateWith } from "selenium-webdriver"; /** * Do basic checks on instance management and authentication.