diff --git a/scripts/brave.js b/scripts/brave.js index aaee196..18760cd 100755 --- a/scripts/brave.js +++ b/scripts/brave.js @@ -2,6 +2,7 @@ import { AndroidUiautomator2Driver } from 'appium-uiautomator2-driver'; import { ADB } from 'appium-adb'; +import { resolveAdbPort } from '../src/adb.js'; import log from '../src/logger.js'; import { waitForCondition } from 'asyncbox'; @@ -18,7 +19,8 @@ const common = { }; async function skipWelcomeBrave() { - const adb = await ADB.createADB(); + const adbPort = resolveAdbPort(); + const adb = await ADB.createADB({ adbPort }); await adb.adbExec(['shell', 'pm', 'clear', 'com.brave.browser']); // Suppress the first-run Welcome walkthrough (honored on emulators/debuggable builds; // harmless no-op elsewhere, where the UI walkthrough below still handles it) @@ -30,6 +32,7 @@ async function skipWelcomeBrave() { const caps = { platformName: "Android", "appium:automationName": "UiAutomator2", + "appium:adbPort": adbPort, "appium:deviceName": "Android Device", "appium:appPackage": "com.brave.browser", "appium:appActivity": "com.google.android.apps.chrome.Main", diff --git a/scripts/duckduckgo.js b/scripts/duckduckgo.js index 4eb0ae2..85e1029 100755 --- a/scripts/duckduckgo.js +++ b/scripts/duckduckgo.js @@ -2,6 +2,7 @@ import { AndroidUiautomator2Driver } from 'appium-uiautomator2-driver'; import { ADB } from 'appium-adb'; +import { resolveAdbPort } from '../src/adb.js'; import log from '../src/logger.js'; import { waitForCondition } from 'asyncbox'; @@ -18,12 +19,14 @@ const common = { }; async function skipWelcomeDuckDuckGo() { - const adb = await ADB.createADB(); + const adbPort = resolveAdbPort(); + const adb = await ADB.createADB({ adbPort }); await adb.adbExec(['shell', 'pm', 'clear', 'com.duckduckgo.mobile.android']); const driver = new AndroidUiautomator2Driver(); const caps = { platformName: "Android", "appium:automationName": "UiAutomator2", + "appium:adbPort": adbPort, "appium:deviceName": "Android Device", "appium:appPackage": "com.duckduckgo.mobile.android", "appium:appActivity": "com.duckduckgo.app.browser.BrowserActivity", diff --git a/scripts/edge.js b/scripts/edge.js index b32fe28..1aa0135 100755 --- a/scripts/edge.js +++ b/scripts/edge.js @@ -2,6 +2,7 @@ import { AndroidUiautomator2Driver } from 'appium-uiautomator2-driver'; import { ADB } from 'appium-adb'; +import { resolveAdbPort } from '../src/adb.js'; import log from '../src/logger.js'; import { waitForCondition } from 'asyncbox'; @@ -18,12 +19,14 @@ const common = { }; async function skipWelcomeEdge() { - const adb = await ADB.createADB(); + const adbPort = resolveAdbPort(); + const adb = await ADB.createADB({ adbPort }); await adb.adbExec(['shell', 'pm', 'clear', edge.pkg]); const driver = new AndroidUiautomator2Driver(); const caps = { platformName: "Android", "appium:automationName": "UiAutomator2", + "appium:adbPort": adbPort, "appium:deviceName": "Android Device", "appium:appPackage": edge.pkg, "appium:appActivity": edge.activity, diff --git a/scripts/opera.js b/scripts/opera.js index a6b36f0..9eda233 100755 --- a/scripts/opera.js +++ b/scripts/opera.js @@ -2,6 +2,7 @@ import { AndroidUiautomator2Driver } from 'appium-uiautomator2-driver'; import { ADB } from 'appium-adb'; +import { resolveAdbPort } from '../src/adb.js'; import log from '../src/logger.js'; import { waitForCondition } from 'asyncbox'; @@ -18,13 +19,15 @@ const common = { }; async function skipWelcomeOpera() { - const adb = await ADB.createADB(); + const adbPort = resolveAdbPort(); + const adb = await ADB.createADB({ adbPort }); await adb.adbExec(['shell', 'pm', 'clear', 'com.opera.browser']); //await adb.startApp(Object.assign({}, opera, common)); const driver = new AndroidUiautomator2Driver(); const caps = { platformName: "Android", "appium:automationName": "UiAutomator2", + "appium:adbPort": adbPort, "appium:deviceName": "Android Device", "appium:appPackage": "com.opera.browser", "appium:appActivity": "com.opera.android.BrowserActivity", diff --git a/scripts/samsung.js b/scripts/samsung.js index a37e54c..388f37c 100755 --- a/scripts/samsung.js +++ b/scripts/samsung.js @@ -2,6 +2,7 @@ import { AndroidUiautomator2Driver } from 'appium-uiautomator2-driver'; import { ADB } from 'appium-adb'; +import { resolveAdbPort } from '../src/adb.js'; import log from '../src/logger.js'; import { waitForCondition } from 'asyncbox'; @@ -18,12 +19,14 @@ const common = { }; async function skipWelcomeSamsung() { - const adb = await ADB.createADB(); + const adbPort = resolveAdbPort(); + const adb = await ADB.createADB({ adbPort }); await adb.adbExec(['shell', 'pm', 'clear', samsung.pkg]); const driver = new AndroidUiautomator2Driver(); const caps = { platformName: "Android", "appium:automationName": "UiAutomator2", + "appium:adbPort": adbPort, "appium:deviceName": "Android Device", "appium:appPackage": samsung.pkg, "appium:appActivity": samsung.activity, diff --git a/src/adb.js b/src/adb.js index 94ee16d..e7aa915 100644 --- a/src/adb.js +++ b/src/adb.js @@ -1,4 +1,4 @@ -import { ADB, getSdkRootFromEnv } from 'appium-adb'; +import { ADB, DEFAULT_ADB_PORT, getSdkRootFromEnv } from 'appium-adb'; import { fs } from '@appium/support'; import getPort from 'get-port'; import log from './logger'; @@ -16,14 +16,28 @@ const DEVTOOLS_SOCKET_MAP = { terrance: 'com.sec.android.app.sbrowser_devtools_remote', }; -export async function getAdb() { +/** + * Resolve the adb server port: explicit value wins, then CDP_ADB_PORT (used by + * the skip-welcome scripts, which run as separate processes and receive no + * capabilities), then adb's default. + */ +export function resolveAdbPort(adbPort) { + const candidate = adbPort ?? process.env.CDP_ADB_PORT; + const port = parseInt(candidate, 10); + return Number.isInteger(port) && port > 0 ? port : DEFAULT_ADB_PORT; +} + +export async function getAdb(adbPort) { try { if (!adb) { - adb = await ADB.createADB(); + const port = resolveAdbPort(adbPort); + log.info(`Using adb server port ${port}`); + adb = await ADB.createADB({ adbPort: port }); } } catch (e) { console.log(e); } + return adb; } export async function requireSdkRoot() { diff --git a/src/driver.js b/src/driver.js index 7dd86fc..9596eab 100644 --- a/src/driver.js +++ b/src/driver.js @@ -19,6 +19,10 @@ class AppiumCDPDriver extends BaseDriver { presence: true, isString: true, }, + adbPort: { + isNumber: false, + presence: false, + }, }; } @@ -26,7 +30,7 @@ class AppiumCDPDriver extends BaseDriver { console.log(await getConfig('local')); const res = await super.createSession(w3cCaps); const browser = w3cCaps.alwaysMatch['browserName']; - await getAdb(); + await getAdb(w3cCaps.alwaysMatch['appium:adbPort']); let port; if (browser === 'duckduckgo') { await startApplication(browser); diff --git a/test/adb-port.spec.js b/test/adb-port.spec.js new file mode 100644 index 0000000..2921d80 --- /dev/null +++ b/test/adb-port.spec.js @@ -0,0 +1,51 @@ +const { expect } = require('chai'); +const { resolveAdbPort } = require('../build/src/adb.js'); + +const DEFAULT = 5037; + +describe('resolveAdbPort', function () { + let previous; + + beforeEach(function () { + previous = process.env.CDP_ADB_PORT; + delete process.env.CDP_ADB_PORT; + }); + + afterEach(function () { + if (previous === undefined) { + delete process.env.CDP_ADB_PORT; + } else { + process.env.CDP_ADB_PORT = previous; + } + }); + + it('defaults to 5037 when nothing is supplied', function () { + expect(resolveAdbPort(undefined)).to.equal(DEFAULT); + }); + + it('defaults to 5037 for unusable values', function () { + for (const value of [null, '', 'abc', 0, -1]) { + expect(resolveAdbPort(value)).to.equal(DEFAULT); + } + }); + + it('accepts the capability as a number or a string', function () { + expect(resolveAdbPort(5038)).to.equal(5038); + expect(resolveAdbPort('5038')).to.equal(5038); + }); + + it('falls back to CDP_ADB_PORT when no capability is given', function () { + process.env.CDP_ADB_PORT = '5040'; + expect(resolveAdbPort(undefined)).to.equal(5040); + }); + + it('prefers the capability over the environment variable', function () { + process.env.CDP_ADB_PORT = '5040'; + expect(resolveAdbPort(5041)).to.equal(5041); + }); + + it('ignores an unusable environment variable', function () { + process.env.CDP_ADB_PORT = 'nope'; + expect(resolveAdbPort(undefined)).to.equal(DEFAULT); + }); +});