appium-cdp-driver 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/adb.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ADB, getSdkRootFromEnv } from 'appium-adb';
1
+ import { ADB, DEFAULT_ADB_PORT, getSdkRootFromEnv } from 'appium-adb';
2
2
  import { fs } from '@appium/support';
3
3
  import getPort from 'get-port';
4
4
  import log from './logger';
@@ -16,14 +16,28 @@ const DEVTOOLS_SOCKET_MAP = {
16
16
  terrance: 'com.sec.android.app.sbrowser_devtools_remote',
17
17
  };
18
18
 
19
- export async function getAdb() {
19
+ /**
20
+ * Resolve the adb server port: explicit value wins, then CDP_ADB_PORT (used by
21
+ * the skip-welcome scripts, which run as separate processes and receive no
22
+ * capabilities), then adb's default.
23
+ */
24
+ export function resolveAdbPort(adbPort) {
25
+ const candidate = adbPort ?? process.env.CDP_ADB_PORT;
26
+ const port = parseInt(candidate, 10);
27
+ return Number.isInteger(port) && port > 0 ? port : DEFAULT_ADB_PORT;
28
+ }
29
+
30
+ export async function getAdb(adbPort) {
20
31
  try {
21
32
  if (!adb) {
22
- adb = await ADB.createADB();
33
+ const port = resolveAdbPort(adbPort);
34
+ log.info(`Using adb server port ${port}`);
35
+ adb = await ADB.createADB({ adbPort: port });
23
36
  }
24
37
  } catch (e) {
25
38
  console.log(e);
26
39
  }
40
+ return adb;
27
41
  }
28
42
 
29
43
  export async function requireSdkRoot() {
@@ -76,7 +90,10 @@ async function getDuckDuckGoPid(browser = 'duckduckgo') {
76
90
  const packageName = 'com.duckduckgo.mobile.android';
77
91
  try {
78
92
  const output = await adb.adbExec(['shell', 'pidof', packageName]);
79
- const pid = output.trim();
93
+ // pidof lists every process of the package; the socket belongs to the first
94
+ // (browser) process, and passing the whole list builds an unusable socket
95
+ // name like webview_devtools_remote_1234 5678
96
+ const pid = String(output).trim().split(/\s+/)[0];
80
97
  return pid || null;
81
98
  } catch (err) {
82
99
  console.error(`Unable to get PID for ${browser}:`, err.message);
@@ -84,66 +101,47 @@ async function getDuckDuckGoPid(browser = 'duckduckgo') {
84
101
  }
85
102
  }
86
103
 
87
- export async function startApplication(browser = 'chrome') {
88
- const common = {
89
- waitDuration: START_APP_WAIT_DURATION,
90
- optionalIntentArguments: '-d www.appium.io',
91
- };
92
- const chrome = {
93
- pkg: 'com.android.chrome',
94
- activity: 'com.google.android.apps.chrome.Main',
95
- };
96
-
97
- const terrance = {
98
- pkg: 'com.sec.android.app.sbrowser',
99
- activity: 'com.sec.android.app.sbrowser.SBrowserMainActivity',
100
- };
101
-
102
- const brave = {
103
- pkg: 'com.brave.browser',
104
- activity: 'com.google.android.apps.chrome.Main',
105
- };
106
-
107
- const opera = {
108
- pkg: 'com.opera.browser',
109
- activity: 'com.opera.android.BrowserActivity',
110
- };
111
-
112
- const duckduckgo = {
113
- pkg: 'com.duckduckgo.mobile.android',
114
- activity: 'com.duckduckgo.app.browser.BrowserActivity',
115
- };
104
+ const BROWSERS = {
105
+ chrome: { pkg: 'com.android.chrome', activity: 'com.google.android.apps.chrome.Main' },
106
+ brave: { pkg: 'com.brave.browser', activity: 'com.google.android.apps.chrome.Main' },
107
+ opera: { pkg: 'com.opera.browser', activity: 'com.opera.android.BrowserActivity' },
108
+ duckduckgo: { pkg: 'com.duckduckgo.mobile.android', activity: 'com.duckduckgo.app.browser.BrowserActivity' },
109
+ samsung: { pkg: 'com.sec.android.app.sbrowser', activity: 'com.sec.android.app.sbrowser.SBrowserMainActivity' },
110
+ terrance: { pkg: 'com.sec.android.app.sbrowser', activity: 'com.sec.android.app.sbrowser.SBrowserMainActivity' },
111
+ edge: { pkg: 'com.microsoft.emmx', activity: 'com.microsoft.ruby.Main' },
112
+ };
116
113
 
117
- const samsung = {
118
- pkg: 'com.sec.android.app.sbrowser',
119
- activity: 'com.sec.android.app.sbrowser.SBrowserMainActivity',
120
- };
121
-
122
- const edge = {
123
- pkg: 'com.microsoft.emmx',
124
- activity: 'com.microsoft.ruby.Main',
125
- };
114
+ /**
115
+ * Open the start URL in an already-running browser.
116
+ *
117
+ * Deliberately a plain VIEW intent rather than startApplication: the latter
118
+ * passes -S, which force-stops the process. That changes the pid, and for
119
+ * WebView-based browsers the devtools socket name carries the pid, so an
120
+ * existing port forward is left pointing at a socket that no longer exists.
121
+ */
122
+ export async function openStartUrl(browser, url = 'https://www.appium.io') {
123
+ const pkg = BROWSERS[browser]?.pkg;
124
+ if (!pkg) {
125
+ return;
126
+ }
127
+ // -n <component>: a bare trailing package is not honoured by am, so the intent
128
+ // would go to whichever browser handles VIEW by default rather than this one
129
+ await adb.adbExec([
130
+ 'shell', 'am', 'start', '-a', 'android.intent.action.VIEW', '-d', url,
131
+ '-n', `${pkg}/${BROWSERS[browser].activity}`,
132
+ ]);
133
+ }
126
134
 
127
- if (browser === 'chrome') {
128
- log.info(`Starting Chrome`);
129
- await adb.startApp(Object.assign({}, chrome, common));
130
- } else if (browser === 'terrance') {
131
- log.info(`Starting Terrance`);
132
- await adb.startApp(Object.assign({}, terrance, common));
133
- } else if (browser === 'brave') {
134
- log.info(`Starting Brave`);
135
- await adb.startApp(Object.assign({}, brave, common));
136
- } else if (browser === 'opera') {
137
- log.info(`Starting Opera`);
138
- await adb.startApp(Object.assign({}, opera, common));
139
- } else if (browser === 'duckduckgo') {
140
- log.info(`Starting DuckDuckGo`);
141
- await adb.startApp(Object.assign({}, duckduckgo, common));
142
- } else if (browser === 'samsung') {
143
- log.info(`Starting Samsung Browser`);
144
- await adb.startApp(Object.assign({}, samsung, common));
145
- } else if (browser === 'edge') {
146
- log.info(`Starting MS Edge`);
147
- await adb.startApp(Object.assign({}, edge, common));
135
+ export async function startApplication(browser = 'chrome') {
136
+ const target = BROWSERS[browser];
137
+ if (!target) {
138
+ return;
148
139
  }
149
- }
140
+ log.info(`Starting ${browser}`);
141
+ await adb.startApp({
142
+ pkg: target.pkg,
143
+ activity: target.activity,
144
+ waitDuration: START_APP_WAIT_DURATION,
145
+ optionalIntentArguments: '-d www.appium.io',
146
+ });
147
+ }
package/src/driver.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BaseDriver, errors } from '@appium/base-driver';
2
- import { getAdb, adbExec, startApplication } from './adb';
2
+ import { getAdb, adbExec, startApplication, openStartUrl } from './adb';
3
3
  import { openBrowser, getConfig, goto } from 'taiko';
4
4
  import commands from './commands';
5
5
  import log from './logger';
@@ -19,6 +19,10 @@ class AppiumCDPDriver extends BaseDriver {
19
19
  presence: true,
20
20
  isString: true,
21
21
  },
22
+ adbPort: {
23
+ isNumber: false,
24
+ presence: false,
25
+ },
22
26
  };
23
27
  }
24
28
 
@@ -26,7 +30,7 @@ class AppiumCDPDriver extends BaseDriver {
26
30
  console.log(await getConfig('local'));
27
31
  const res = await super.createSession(w3cCaps);
28
32
  const browser = w3cCaps.alwaysMatch['browserName'];
29
- await getAdb();
33
+ await getAdb(w3cCaps.alwaysMatch['appium:adbPort']);
30
34
  let port;
31
35
  if (browser === 'duckduckgo') {
32
36
  await startApplication(browser);
@@ -55,6 +59,15 @@ class AppiumCDPDriver extends BaseDriver {
55
59
  log.info(`CDP response: ${JSON.stringify(data)}`);
56
60
 
57
61
  if (!Array.isArray(data) || data.length === 0) {
62
+ // The socket is up but the browser holds no debuggable page — common
63
+ // for WebView-based browsers just after launch. Retrying the fetch
64
+ // alone changes nothing, so nudge the browser into opening one.
65
+ log.info('Debug list is empty, opening the start URL to create a page');
66
+ try {
67
+ await openStartUrl(browser);
68
+ } catch (launchError) {
69
+ log.info(`Could not open the start URL: ${launchError.message}`);
70
+ }
58
71
  throw new Error('Debug list is empty or invalid');
59
72
  }
60
73
 
@@ -71,9 +84,21 @@ class AppiumCDPDriver extends BaseDriver {
71
84
  maxTimeout: 10000,
72
85
  }
73
86
  );
74
- const target = data.find((target) => {
75
- return target.url.includes('appium.io');
76
- });
87
+ // Prefer the page we launched, but do not require it: after a redirect, a
88
+ // new tab, or an onboarding page the list holds other targets, and reading
89
+ // webSocketDebuggerUrl off undefined fails the session with an opaque error.
90
+ let target = data.find((t) => t.url && t.url.includes('appium.io'));
91
+ if (!target) {
92
+ target =
93
+ data.find((t) => t.type === 'page' && t.webSocketDebuggerUrl) ||
94
+ data.find((t) => t.webSocketDebuggerUrl);
95
+ log.info(`No appium.io target; falling back to ${target ? target.url || target.type : 'none'}`);
96
+ }
97
+ if (!target) {
98
+ throw new Error(
99
+ `No CDP target with a webSocketDebuggerUrl in ${JSON.stringify(data)}`
100
+ );
101
+ }
77
102
  log.info(`Target found: ${target.webSocketDebuggerUrl}`);
78
103
  await openBrowser({
79
104
  port: port,