appium-cdp-driver 1.0.7 → 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.
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
12
+ var __importDefault = (this && this.__importDefault) || function (mod) {
13
+ return (mod && mod.__esModule) ? mod : { "default": mod };
14
+ };
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ const appium_uiautomator2_driver_1 = require("appium-uiautomator2-driver");
17
+ const appium_adb_1 = require("appium-adb");
18
+ const adb_js_1 = require("../src/adb.js");
19
+ const logger_js_1 = __importDefault(require("../src/logger.js"));
20
+ const asyncbox_1 = require("asyncbox");
21
+ const browserReady_js_1 = require("./browserReady.js");
22
+ const START_APP_WAIT_DURATION = 60000;
23
+ const brave = {
24
+ pkg: 'com.brave.browser',
25
+ activity: 'com.google.android.apps.chrome.Main',
26
+ };
27
+ const common = {
28
+ waitDuration: START_APP_WAIT_DURATION,
29
+ optionalIntentArguments: '-d www.appium.io',
30
+ };
31
+ function skipWelcomeBrave() {
32
+ return __awaiter(this, void 0, void 0, function* () {
33
+ const adbPort = (0, adb_js_1.resolveAdbPort)();
34
+ const adb = yield appium_adb_1.ADB.createADB({ adbPort });
35
+ yield adb.adbExec(['shell', 'pm', 'clear', 'com.brave.browser']);
36
+ // Optional: suppress Chromium's first-run experience. Off by default because
37
+ // /data/local/tmp/chrome-command-line is shared with Chrome and chromedriver,
38
+ // which writes its own chromeOptions.args there — clobbering it would change
39
+ // an unrelated Chrome session on the same device. Set CDP_SUPPRESS_FIRST_RUN=1
40
+ // to opt in; without it the readiness pass dismisses onboarding instead.
41
+ if (process.env.CDP_SUPPRESS_FIRST_RUN === '1') {
42
+ yield adb.adbExec([
43
+ 'shell',
44
+ "echo '_ --disable-fre --no-first-run' > /data/local/tmp/chrome-command-line",
45
+ ]);
46
+ }
47
+ const driver = new appium_uiautomator2_driver_1.AndroidUiautomator2Driver();
48
+ const caps = {
49
+ platformName: "Android",
50
+ "appium:automationName": "UiAutomator2",
51
+ "appium:adbPort": adbPort,
52
+ "appium:deviceName": "Android Device",
53
+ "appium:appPackage": "com.brave.browser",
54
+ "appium:appActivity": "com.google.android.apps.chrome.Main",
55
+ };
56
+ try {
57
+ yield driver.createSession(null, {
58
+ alwaysMatch: caps,
59
+ firstMatch: [{}],
60
+ });
61
+ const activity = yield driver.getCurrentActivity();
62
+ logger_js_1.default.info(`Activity is ${activity}`);
63
+ if (activity.includes('Welcome')) {
64
+ const findElementWithWaitForCondition = (strategy_1, selector_1, ...args_1) => __awaiter(this, [strategy_1, selector_1, ...args_1], void 0, function* (strategy, selector, timeout = 20000) {
65
+ try {
66
+ return yield (0, asyncbox_1.waitForCondition)(() => __awaiter(this, void 0, void 0, function* () {
67
+ try {
68
+ logger_js_1.default.info(`Attempting to find element (${strategy}: ${selector})`);
69
+ const element = yield driver.findElement(strategy, selector);
70
+ logger_js_1.default.info(`Successfully found element (${strategy}: ${selector})`);
71
+ return element;
72
+ }
73
+ catch (error) {
74
+ // Return false to continue waiting
75
+ return false;
76
+ }
77
+ }), {
78
+ waitMs: timeout,
79
+ intervalMs: 1000,
80
+ });
81
+ }
82
+ catch (error) {
83
+ throw new Error(`Failed to find element (${strategy}: ${selector}) within ${timeout}ms timeout: ${error.message}`);
84
+ }
85
+ });
86
+ const cancelButton = yield findElementWithWaitForCondition('id', 'android:id/button2');
87
+ logger_js_1.default.info(`Cancel button is ${JSON.stringify(cancelButton, null, 2)}`);
88
+ yield driver.click(cancelButton.ELEMENT);
89
+ try {
90
+ yield findElementWithWaitForCondition('xpath', '//android.widget.TextView[@text="Allow Brave to send you notifications?"]');
91
+ const allowButton = yield findElementWithWaitForCondition('id', 'com.android.permissioncontroller:id/permission_allow_button');
92
+ yield driver.click(allowButton.ELEMENT);
93
+ }
94
+ catch (error) {
95
+ logger_js_1.default.info(`Help make Brave better text not found, skipping`);
96
+ }
97
+ const laterButton = yield findElementWithWaitForCondition('id', 'com.brave.browser:id/btn_negative');
98
+ yield driver.click(laterButton.ELEMENT);
99
+ yield findElementWithWaitForCondition('xpath', '//android.widget.TextView[@text="Help make Brave better."]');
100
+ const continueButton = yield findElementWithWaitForCondition('id', 'com.brave.browser:id/btn_positive');
101
+ yield driver.click(continueButton.ELEMENT);
102
+ }
103
+ }
104
+ catch (error) {
105
+ logger_js_1.default.info(`walkthrough did not complete (${error.message}) — checking readiness anyway`);
106
+ }
107
+ finally {
108
+ yield (0, browserReady_js_1.finishSession)(driver, { adb, pkg: brave.pkg, component: `${brave.pkg}/${brave.activity}`, socket: 'chrome_devtools_remote' });
109
+ }
110
+ });
111
+ }
112
+ (() => __awaiter(void 0, void 0, void 0, function* () {
113
+ yield skipWelcomeBrave();
114
+ process.exit(0);
115
+ }))();
116
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJhdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zY3JpcHRzL2JyYXZlLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7OztBQUVBLDJFQUF1RTtBQUN2RSwyQ0FBaUM7QUFDakMsMENBQStDO0FBQy9DLGlFQUFtQztBQUNuQyx1Q0FBNEM7QUFDNUMsdURBQWtEO0FBRWxELE1BQU0sdUJBQXVCLEdBQUcsS0FBSyxDQUFDO0FBRXRDLE1BQU0sS0FBSyxHQUFHO0lBQ1osR0FBRyxFQUFFLG1CQUFtQjtJQUN4QixRQUFRLEVBQUUscUNBQXFDO0NBQ2hELENBQUM7QUFFRixNQUFNLE1BQU0sR0FBRztJQUNiLFlBQVksRUFBRSx1QkFBdUI7SUFDckMsdUJBQXVCLEVBQUUsa0JBQWtCO0NBQzVDLENBQUM7QUFFRixTQUFlLGdCQUFnQjs7UUFDN0IsTUFBTSxPQUFPLEdBQUcsSUFBQSx1QkFBYyxHQUFFLENBQUM7UUFDakMsTUFBTSxHQUFHLEdBQUcsTUFBTSxnQkFBRyxDQUFDLFNBQVMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFDN0MsTUFBTSxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsbUJBQW1CLENBQUMsQ0FBQyxDQUFDO1FBQ2pFLDZFQUE2RTtRQUM3RSw4RUFBOEU7UUFDOUUsNkVBQTZFO1FBQzdFLCtFQUErRTtRQUMvRSx5RUFBeUU7UUFDekUsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLHNCQUFzQixLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQy9DLE1BQU0sR0FBRyxDQUFDLE9BQU8sQ0FBQztnQkFDaEIsT0FBTztnQkFDUCw2RUFBNkU7YUFDOUUsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUNELE1BQU0sTUFBTSxHQUFHLElBQUksc0RBQXlCLEVBQUUsQ0FBQztRQUMvQyxNQUFNLElBQUksR0FBRztZQUNYLFlBQVksRUFBRSxTQUFTO1lBQ3ZC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
@@ -0,0 +1,302 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.pickPageTargets = pickPageTargets;
16
+ exports.browserPid = browserPid;
17
+ exports.ensureBrowserReady = ensureBrowserReady;
18
+ exports.clickSafely = clickSafely;
19
+ exports.finishSession = finishSession;
20
+ const node_fetch_1 = __importDefault(require("node-fetch"));
21
+ const get_port_1 = __importDefault(require("get-port"));
22
+ const logger_js_1 = __importDefault(require("../src/logger.js"));
23
+ /**
24
+ * Shared readiness helper for the skip-welcome-* scripts.
25
+ *
26
+ * The scripts clear the browser profile and then click through first-run
27
+ * onboarding. That choreography is inherently racy: dialog order and content
28
+ * vary per launch, some stages are conditional, and an Android system dialog
29
+ * (e.g. "System UI isn't responding") can cover the screen entirely. When it
30
+ * goes wrong the browser never opens its devtools socket and session creation
31
+ * fails later with "socket hang up" or "Debug list is empty or invalid".
32
+ *
33
+ * Instead of requiring a fixed sequence, converge on the end state the driver
34
+ * actually needs: the browser's own devtools socket, with onboarding gone and a
35
+ * page open. Dismiss whatever happens to be on screen, relaunch when stuck, and
36
+ * report honestly if it never becomes ready.
37
+ */
38
+ const ONBOARDING_ACTIVITY = /Welcome|FirstRun|firstrun|Onboarding|HelpIntro/i;
39
+ // Safe to click on first-run and system dialogs, in priority order. "Wait" is
40
+ // first so an ANR dialog is cleared before anything underneath it is touched.
41
+ const COMMON_SELECTORS = [
42
+ '//android.widget.Button[@text="Wait"]',
43
+ '//android.widget.Button[@text="OK"]',
44
+ '//android.widget.Button[@text="Continue"]',
45
+ '//android.widget.Button[@text="Next"]',
46
+ '//android.widget.Button[@text="Skip"]',
47
+ '//android.widget.Button[@text="Not now"]',
48
+ '//android.widget.Button[@text="Allow"]',
49
+ ];
50
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
51
+ /**
52
+ * Targets the driver can actually attach to. Workers also carry a
53
+ * webSocketDebuggerUrl, so filtering on that field alone would accept a browser
54
+ * that has no page open — the state this check exists to reject.
55
+ */
56
+ function pickPageTargets(targets) {
57
+ return (Array.isArray(targets) ? targets : []).filter((t) => t && t.type === 'page' && t.webSocketDebuggerUrl);
58
+ }
59
+ /**
60
+ * Resolve the devtools socket name, or null if the browser has not opened it.
61
+ * WebView-based browsers expose webview_devtools_remote_<pid>; the bare prefix
62
+ * also matches other apps' WebViews, so scope it to this package's pid.
63
+ */
64
+ function resolveSocket(adb, socket, pkg, pidScoped) {
65
+ return __awaiter(this, void 0, void 0, function* () {
66
+ const unix = String(yield adb.adbExec(['shell', 'cat', '/proc/net/unix']));
67
+ if (!pidScoped) {
68
+ // Several browsers share a socket name (chrome, brave and edge all use
69
+ // chrome_devtools_remote). Abstract names are unique per owner, so seeing
70
+ // the name proves *someone* opened it, not that we did — verifyReady()
71
+ // confirms ownership before trusting it.
72
+ return unix.includes(socket) ? socket : null;
73
+ }
74
+ const pid = yield browserPid(adb, pkg);
75
+ if (!pid) {
76
+ return null;
77
+ }
78
+ const scoped = `${socket}_${pid}`;
79
+ return unix.includes(scoped) ? scoped : null;
80
+ });
81
+ }
82
+ /**
83
+ * First pid of the package. pidof returns a space-separated list when the app
84
+ * has several processes, and only the first is the browser process whose
85
+ * WebView socket we want.
86
+ */
87
+ function browserPid(adb, pkg) {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ const output = String(yield adb.adbExec(['shell', 'pidof', pkg])).trim();
90
+ return output ? output.split(/\s+/)[0] : null;
91
+ });
92
+ }
93
+ function getJson(port, path) {
94
+ return __awaiter(this, void 0, void 0, function* () {
95
+ const response = yield (0, node_fetch_1.default)(`http://localhost:${port}${path}`);
96
+ return response.json();
97
+ });
98
+ }
99
+ /**
100
+ * Confirm the devtools endpoint belongs to the browser we are setting up.
101
+ * Chrome for Android reports the owning package in /json/version, which
102
+ * disambiguates the shared chrome_devtools_remote name.
103
+ */
104
+ function ownedByPackage(port, pkg) {
105
+ return __awaiter(this, void 0, void 0, function* () {
106
+ try {
107
+ const version = yield getJson(port, '/json/version');
108
+ const owner = version['Android-Package'];
109
+ if (!owner) {
110
+ return true; // endpoint does not report an owner; nothing to contradict
111
+ }
112
+ if (owner !== pkg) {
113
+ logger_js_1.default.info(`ensureBrowserReady: devtools socket belongs to ${owner}, not ${pkg}`);
114
+ return false;
115
+ }
116
+ }
117
+ catch (e) {
118
+ logger_js_1.default.info(`ensureBrowserReady: /json/version check failed: ${e.message}`);
119
+ }
120
+ return true;
121
+ });
122
+ }
123
+ /**
124
+ * Ask /json/list the way the driver does. The socket can be up while the
125
+ * browser has no page — that is the "Debug list is empty or invalid" failure —
126
+ * so an attachable *page* is the only meaningful proof of readiness. Workers
127
+ * also carry a webSocketDebuggerUrl and must not be mistaken for one.
128
+ */
129
+ function verifyReady(adb_1, socketName_1, pkg_1) {
130
+ return __awaiter(this, arguments, void 0, function* (adb, socketName, pkg, timeoutMs = 5000, intervalMs = 500) {
131
+ const port = yield (0, get_port_1.default)();
132
+ try {
133
+ yield adb.adbExec(['forward', `tcp:${port}`, `localabstract:${socketName}`]);
134
+ if (!(yield ownedByPackage(port, pkg))) {
135
+ return false;
136
+ }
137
+ const deadline = Date.now() + timeoutMs;
138
+ for (;;) {
139
+ let pages = [];
140
+ let total = -1;
141
+ try {
142
+ const targets = yield getJson(port, '/json/list');
143
+ if (Array.isArray(targets)) {
144
+ total = targets.length;
145
+ pages = pickPageTargets(targets);
146
+ }
147
+ }
148
+ catch (e) {
149
+ logger_js_1.default.info(`ensureBrowserReady: /json/list check failed: ${e.message}`);
150
+ }
151
+ if (pages.length > 0) {
152
+ logger_js_1.default.info(`ensureBrowserReady: ${pkg} has ${pages.length} page target(s) of ${total}`);
153
+ return true;
154
+ }
155
+ if (Date.now() >= deadline) {
156
+ logger_js_1.default.info(`ensureBrowserReady: ${pkg} has no page target (targets=${total})`);
157
+ return false;
158
+ }
159
+ yield sleep(intervalMs);
160
+ }
161
+ }
162
+ catch (error) {
163
+ logger_js_1.default.info(`ensureBrowserReady: readiness check failed: ${error.message}`);
164
+ return false;
165
+ }
166
+ finally {
167
+ try {
168
+ yield adb.adbExec(['forward', '--remove', `tcp:${port}`]);
169
+ }
170
+ catch (e) {
171
+ // the forward may already be gone
172
+ }
173
+ }
174
+ });
175
+ }
176
+ function currentActivity(driver) {
177
+ return __awaiter(this, void 0, void 0, function* () {
178
+ try {
179
+ return String(yield driver.getCurrentActivity());
180
+ }
181
+ catch (e) {
182
+ return '';
183
+ }
184
+ });
185
+ }
186
+ function openPage(adb, pkg, component, url) {
187
+ return __awaiter(this, void 0, void 0, function* () {
188
+ // target the component: a bare trailing package is not honoured by am, and the
189
+ // intent would open in whichever browser handles VIEW by default
190
+ const target = component || pkg;
191
+ yield adb.adbExec([
192
+ 'shell', 'am', 'start', '-a', 'android.intent.action.VIEW', '-d', url, '-n', target,
193
+ ]);
194
+ });
195
+ }
196
+ /**
197
+ * @param {object} opts
198
+ * @param {object} opts.driver UiAutomator2 driver used for the walkthrough
199
+ * @param {object} opts.adb appium-adb instance
200
+ * @param {string} opts.pkg browser package name
201
+ * @param {string} opts.socket devtools socket name (see DEVTOOLS_SOCKET_MAP)
202
+ * @param {string} [opts.component] pkg/activity used to open a page in this browser
203
+ * @param {boolean} [opts.pidScoped] socket name is suffixed with the pid (WebView apps)
204
+ * @param {string[]} [opts.selectors] browser-specific selectors, tried before the common ones
205
+ * @param {string} [opts.url] page to open once the socket is up
206
+ * @param {number} [opts.attempts]
207
+ * @returns {Promise<boolean>} whether the browser became ready
208
+ */
209
+ function ensureBrowserReady(opts) {
210
+ return __awaiter(this, void 0, void 0, function* () {
211
+ const { driver, adb, pkg, socket, component, pidScoped = false, selectors = [], url = 'https://www.appium.io', attempts = 12, intervalMs = 2500, } = opts;
212
+ const candidates = [...selectors, ...COMMON_SELECTORS];
213
+ for (let attempt = 0; attempt < attempts; attempt++) {
214
+ try {
215
+ // The process (and its socket) can exist while onboarding is still on
216
+ // screen, and even afterwards the browser may hold no debuggable page.
217
+ // Require onboarding gone, the socket up, and a page the driver can attach to.
218
+ const activity = yield currentActivity(driver);
219
+ if (ONBOARDING_ACTIVITY.test(activity)) {
220
+ logger_js_1.default.info(`ensureBrowserReady: still on onboarding (${activity})`);
221
+ }
222
+ else {
223
+ const socketName = yield resolveSocket(adb, socket, pkg, pidScoped);
224
+ if (socketName) {
225
+ yield openPage(adb, pkg, component, url);
226
+ // poll rather than sleeping a fixed interval: usually the page is
227
+ // there within a few hundred ms, and setup should not pay for the
228
+ // worst case on every session
229
+ if (yield verifyReady(adb, socketName, pkg)) {
230
+ return true;
231
+ }
232
+ }
233
+ }
234
+ }
235
+ catch (e) {
236
+ // fall through to the dismissal pass
237
+ }
238
+ let clicked = null;
239
+ for (const selector of candidates) {
240
+ try {
241
+ const element = yield driver.findElement('xpath', selector);
242
+ yield driver.click(element.ELEMENT);
243
+ clicked = selector;
244
+ break;
245
+ }
246
+ catch (e) {
247
+ // selector not present — try the next one
248
+ }
249
+ }
250
+ if (clicked) {
251
+ logger_js_1.default.info(`ensureBrowserReady: dismissed ${clicked}`);
252
+ }
253
+ else if (attempt % 3 === 2) {
254
+ logger_js_1.default.info(`ensureBrowserReady: nothing to dismiss, relaunching ${pkg}`);
255
+ try {
256
+ yield openPage(adb, pkg, component, url);
257
+ }
258
+ catch (e) {
259
+ // browser may still be starting
260
+ }
261
+ }
262
+ yield sleep(intervalMs);
263
+ }
264
+ return false;
265
+ });
266
+ }
267
+ /**
268
+ * Click an element without letting a stale/handled element abort the rest of the
269
+ * walkthrough — the screen often changes under it.
270
+ */
271
+ function clickSafely(driver, element) {
272
+ return __awaiter(this, void 0, void 0, function* () {
273
+ try {
274
+ yield driver.click(element.ELEMENT);
275
+ }
276
+ catch (error) {
277
+ logger_js_1.default.info(`click failed, continuing: ${error.message}`);
278
+ }
279
+ });
280
+ }
281
+ /**
282
+ * Close out a skip-welcome script: make the browser ready, always release the
283
+ * UiAutomator2 session, and fail loudly if the browser cannot serve a session.
284
+ * Without the throw, a script that dismissed nothing still exits 0 and the
285
+ * caller starts a session that is doomed to fail.
286
+ */
287
+ function finishSession(driver, opts) {
288
+ return __awaiter(this, void 0, void 0, function* () {
289
+ const ready = yield ensureBrowserReady(Object.assign({ driver }, opts));
290
+ logger_js_1.default.info(`${opts.pkg} devtools ready: ${ready}`);
291
+ try {
292
+ yield driver.deleteSession();
293
+ }
294
+ catch (e) {
295
+ logger_js_1.default.info(`deleteSession failed: ${e.message}`);
296
+ }
297
+ if (!ready) {
298
+ throw new Error(`${opts.pkg}: devtools socket never became available; the browser cannot serve a session`);
299
+ }
300
+ });
301
+ }
302
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJvd3NlclJlYWR5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc2NyaXB0cy9icm93c2VyUmVhZHkuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7QUF5Q0EsMENBSUM7QUE2QkQsZ0NBR0M7QUEyR0QsZ0RBNkRDO0FBTUQsa0NBTUM7QUFRRCxzQ0FXQztBQXBSRCw0REFBK0I7QUFDL0Isd0RBQStCO0FBQy9CLGlFQUFtQztBQUVuQzs7Ozs7Ozs7Ozs7Ozs7R0FjRztBQUVILE1BQU0sbUJBQW1CLEdBQUcsaURBQWlELENBQUM7QUFFOUUsOEVBQThFO0FBQzlFLDhFQUE4RTtBQUM5RSxNQUFNLGdCQUFnQixHQUFHO0lBQ3ZCLHVDQUF1QztJQUN2QyxxQ0FBcUM7SUFDckMsMkNBQTJDO0lBQzNDLHVDQUF1QztJQUN2Qyx1Q0FBdUM7SUFDdkMsMENBQTBDO0lBQzFDLHdDQUF3QztDQUN6QyxDQUFDO0FBRUYsTUFBTSxLQUFLLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFFeEU7Ozs7R0FJRztBQUNILFNBQWdCLGVBQWUsQ0FBQyxPQUFPO0lBQ3JDLE9BQU8sQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FDbkQsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxLQUFLLE1BQU0sSUFBSSxDQUFDLENBQUMsb0JBQW9CLENBQ3hELENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWUsYUFBYSxDQUFDLEdBQUcsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLFNBQVM7O1FBQ3RELE1BQU0sSUFB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
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
12
+ var __importDefault = (this && this.__importDefault) || function (mod) {
13
+ return (mod && mod.__esModule) ? mod : { "default": mod };
14
+ };
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ const appium_uiautomator2_driver_1 = require("appium-uiautomator2-driver");
17
+ const appium_adb_1 = require("appium-adb");
18
+ const adb_js_1 = require("../src/adb.js");
19
+ const logger_js_1 = __importDefault(require("../src/logger.js"));
20
+ const asyncbox_1 = require("asyncbox");
21
+ const browserReady_js_1 = require("./browserReady.js");
22
+ const START_APP_WAIT_DURATION = 60000;
23
+ const duckduckgo = {
24
+ pkg: 'com.duckduckgo.mobile.android',
25
+ activity: 'com.duckduckgo.app.browser.BrowserActivity',
26
+ };
27
+ const common = {
28
+ waitDuration: START_APP_WAIT_DURATION,
29
+ optionalIntentArguments: '-d www.appium.io',
30
+ };
31
+ function skipWelcomeDuckDuckGo() {
32
+ return __awaiter(this, void 0, void 0, function* () {
33
+ const adbPort = (0, adb_js_1.resolveAdbPort)();
34
+ const adb = yield appium_adb_1.ADB.createADB({ adbPort });
35
+ yield adb.adbExec(['shell', 'pm', 'clear', 'com.duckduckgo.mobile.android']);
36
+ const driver = new appium_uiautomator2_driver_1.AndroidUiautomator2Driver();
37
+ const caps = {
38
+ platformName: "Android",
39
+ "appium:automationName": "UiAutomator2",
40
+ "appium:adbPort": adbPort,
41
+ "appium:deviceName": "Android Device",
42
+ "appium:appPackage": "com.duckduckgo.mobile.android",
43
+ "appium:appActivity": "com.duckduckgo.app.browser.BrowserActivity",
44
+ };
45
+ try {
46
+ yield driver.createSession(null, {
47
+ alwaysMatch: caps,
48
+ firstMatch: [{}],
49
+ });
50
+ const activity = yield driver.getCurrentActivity();
51
+ logger_js_1.default.info(`Activity is ${activity}`);
52
+ if (activity.includes('BrowserActivity')) {
53
+ const findElementWithWaitForCondition = (strategy_1, selector_1, ...args_1) => __awaiter(this, [strategy_1, selector_1, ...args_1], void 0, function* (strategy, selector, timeout = 6000) {
54
+ try {
55
+ return yield (0, asyncbox_1.waitForCondition)(() => __awaiter(this, void 0, void 0, function* () {
56
+ try {
57
+ logger_js_1.default.info(`Attempting to find element (${strategy}: ${selector})`);
58
+ const element = yield driver.findElement(strategy, selector);
59
+ logger_js_1.default.info(`Successfully found element (${strategy}: ${selector})`);
60
+ return element;
61
+ }
62
+ catch (error) {
63
+ // Return false to continue waiting
64
+ return false;
65
+ }
66
+ }), {
67
+ waitMs: timeout,
68
+ intervalMs: 1000,
69
+ });
70
+ }
71
+ catch (error) {
72
+ throw new Error(`Failed to find element (${strategy}: ${selector}) within ${timeout}ms timeout: ${error.message}`);
73
+ }
74
+ });
75
+ let attempt = 0;
76
+ let found = false;
77
+ const MAX_RETRIES = 3;
78
+ while (attempt < MAX_RETRIES && !found) {
79
+ try {
80
+ const dismissButton = yield findElementWithWaitForCondition('id', 'com.duckduckgo.mobile.android:id/bottomSheetPromoSecondaryButton');
81
+ logger_js_1.default.info(`Dismiss button found: ${JSON.stringify(dismissButton, null, 2)} in attempt ${attempt}`);
82
+ yield driver.click(dismissButton.ELEMENT);
83
+ found = true;
84
+ }
85
+ catch (error) {
86
+ logger_js_1.default.info(`Dismiss button not found, retrying after opening a url...`);
87
+ }
88
+ finally {
89
+ yield adb.shell(['am', 'start', '-a', 'android.intent.action.VIEW', '-d', 'https://www.appium.io', duckduckgo.pkg]);
90
+ attempt++;
91
+ }
92
+ }
93
+ }
94
+ }
95
+ catch (error) {
96
+ logger_js_1.default.info(`walkthrough did not complete (${error.message}) — checking readiness anyway`);
97
+ }
98
+ finally {
99
+ yield (0, browserReady_js_1.finishSession)(driver, {
100
+ adb,
101
+ pkg: duckduckgo.pkg,
102
+ component: `${duckduckgo.pkg}/${duckduckgo.activity}`,
103
+ // WebView app: the socket carries the pid, and the bare prefix would also
104
+ // match other apps' WebViews
105
+ socket: 'webview_devtools_remote',
106
+ pidScoped: true,
107
+ selectors: [
108
+ '//*[@resource-id="com.duckduckgo.mobile.android:id/primaryCta"]',
109
+ '//*[@resource-id="com.duckduckgo.mobile.android:id/bottomSheetPromoSecondaryButton"]',
110
+ '//*[@resource-id="com.duckduckgo.mobile.android:id/daxDialogDismissButton"]',
111
+ '//android.widget.Button[@text="Got it"]',
112
+ '//android.widget.Button[@text="Maybe later"]',
113
+ ],
114
+ });
115
+ }
116
+ });
117
+ }
118
+ (() => __awaiter(void 0, void 0, void 0, function* () {
119
+ yield skipWelcomeDuckDuckGo();
120
+ process.exit(0);
121
+ }))();
122
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHVja2R1Y2tnby5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NjcmlwdHMvZHVja2R1Y2tnby5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFFQSwyRUFBdUU7QUFDdkUsMkNBQWlDO0FBQ2pDLDBDQUErQztBQUMvQyxpRUFBbUM7QUFDbkMsdUNBQTRDO0FBQzVDLHVEQUFrRDtBQUVsRCxNQUFNLHVCQUF1QixHQUFHLEtBQUssQ0FBQztBQUV0QyxNQUFNLFVBQVUsR0FBRztJQUNqQixHQUFHLEVBQUUsK0JBQStCO0lBQ3BDLFFBQVEsRUFBRSw0Q0FBNEM7Q0FDdkQsQ0FBQztBQUVGLE1BQU0sTUFBTSxHQUFHO0lBQ2IsWUFBWSxFQUFFLHVCQUF1QjtJQUNyQyx1QkFBdUIsRUFBRSxrQkFBa0I7Q0FDNUMsQ0FBQztBQUVGLFNBQWUscUJBQXFCOztRQUNsQyxNQUFNLE9BQU8sR0FBRyxJQUFBLHVCQUFjLEdBQUUsQ0FBQztRQUNqQyxNQUFNLEdBQUcsR0FBRyxNQUFNLGdCQUFHLENBQUMsU0FBUyxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUM3QyxNQUFNLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSwrQkFBK0IsQ0FBQyxDQUFDLENBQUM7UUFDN0UsTUFBTSxNQUFNLEdBQUcsSUFBSSxzREFBeUIsRUFBRSxDQUFDO1FBQy9DLE1BQU0sSUFBSSxHQUFHO1lBQ1gsWUFBWSxFQUFFLFNBQVM7WUFDdkIsdUJBQXVCLEVBQUUsY0FBYztZQUN2QyxnQkFBZ0IsRUFBRSxPQUFPO1lBQ3pCLG1CQUFtQixFQUFFLGdCQUFnQjtZQUNyQyxtQkFBbUIsRUFBRSwrQkFBK0I7WUFDcEQsb0JBQW9CLEVBQUUsNENBQTRDO1NBQ25FLENBQUM7UUFDRixJQUFJLENBQUM7WUFDSCxNQUFNLE1BQU0sQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFO2dCQUMvQixXQUFX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