commit 57abe01f3e1bb0849aebc65af825739fc31875fd
parent 8e620b99a35c1b559d9373c1d9ef17c8464d060b
Author: Sebastian <sebasjm@taler-systems.com>
Date: Wed, 11 Feb 2026 18:10:47 -0300
fix #11030
Diffstat:
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.