appium-xcuitest-driver 10.3.0 → 10.4.1
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/CHANGELOG.md +12 -0
- package/build/lib/commands/active-app-info.d.ts +9 -0
- package/build/lib/commands/active-app-info.d.ts.map +1 -0
- package/build/lib/commands/active-app-info.js +14 -0
- package/build/lib/commands/active-app-info.js.map +1 -0
- package/build/lib/commands/alert.d.ts +42 -45
- package/build/lib/commands/alert.d.ts.map +1 -1
- package/build/lib/commands/alert.js +66 -62
- package/build/lib/commands/alert.js.map +1 -1
- package/build/lib/commands/app-management.d.ts +150 -153
- package/build/lib/commands/app-management.d.ts.map +1 -1
- package/build/lib/commands/app-management.js +300 -286
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/app-strings.d.ts +14 -17
- package/build/lib/commands/app-strings.d.ts.map +1 -1
- package/build/lib/commands/app-strings.js +23 -24
- package/build/lib/commands/app-strings.js.map +1 -1
- package/build/lib/commands/appearance.d.ts +19 -22
- package/build/lib/commands/appearance.d.ts.map +1 -1
- package/build/lib/commands/appearance.js +56 -56
- package/build/lib/commands/appearance.js.map +1 -1
- package/build/lib/commands/audit.d.ts +22 -17
- package/build/lib/commands/audit.d.ts.map +1 -1
- package/build/lib/commands/audit.js +17 -18
- package/build/lib/commands/audit.js.map +1 -1
- package/build/lib/commands/battery.d.ts +11 -14
- package/build/lib/commands/battery.d.ts.map +1 -1
- package/build/lib/commands/battery.js +36 -37
- package/build/lib/commands/battery.js.map +1 -1
- package/build/lib/commands/biometric.d.ts +30 -33
- package/build/lib/commands/biometric.d.ts.map +1 -1
- package/build/lib/commands/biometric.js +42 -41
- package/build/lib/commands/biometric.js.map +1 -1
- package/build/lib/commands/certificate.d.ts +48 -45
- package/build/lib/commands/certificate.d.ts.map +1 -1
- package/build/lib/commands/certificate.js +218 -205
- package/build/lib/commands/certificate.js.map +1 -1
- package/build/lib/commands/clipboard.d.ts +19 -22
- package/build/lib/commands/clipboard.d.ts.map +1 -1
- package/build/lib/commands/clipboard.js +30 -30
- package/build/lib/commands/clipboard.js.map +1 -1
- package/build/lib/commands/condition.d.ts +49 -26
- package/build/lib/commands/condition.d.ts.map +1 -1
- package/build/lib/commands/condition.js +87 -86
- package/build/lib/commands/condition.js.map +1 -1
- package/build/lib/commands/content-size.d.ts +26 -29
- package/build/lib/commands/content-size.d.ts.map +1 -1
- package/build/lib/commands/content-size.js +36 -36
- package/build/lib/commands/content-size.js.map +1 -1
- package/build/lib/commands/context.d.ts +161 -108
- package/build/lib/commands/context.d.ts.map +1 -1
- package/build/lib/commands/context.js +530 -517
- package/build/lib/commands/context.js.map +1 -1
- package/build/lib/commands/deviceInfo.d.ts +9 -12
- package/build/lib/commands/deviceInfo.d.ts.map +1 -1
- package/build/lib/commands/deviceInfo.js +17 -18
- package/build/lib/commands/deviceInfo.js.map +1 -1
- package/build/lib/commands/element.d.ts +102 -105
- package/build/lib/commands/element.d.ts.map +1 -1
- package/build/lib/commands/element.js +337 -323
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/execute.d.ts +24 -19
- package/build/lib/commands/execute.d.ts.map +1 -1
- package/build/lib/commands/execute.js +63 -62
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/file-movement.d.ts +77 -80
- package/build/lib/commands/file-movement.d.ts.map +1 -1
- package/build/lib/commands/file-movement.js +130 -124
- package/build/lib/commands/file-movement.js.map +1 -1
- package/build/lib/commands/find.d.ts +18 -21
- package/build/lib/commands/find.d.ts.map +1 -1
- package/build/lib/commands/find.js +158 -156
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/general.d.ts +124 -116
- package/build/lib/commands/general.d.ts.map +1 -1
- package/build/lib/commands/general.js +248 -232
- package/build/lib/commands/general.js.map +1 -1
- package/build/lib/commands/geolocation.d.ts +43 -46
- package/build/lib/commands/geolocation.d.ts.map +1 -1
- package/build/lib/commands/geolocation.js +10 -11
- package/build/lib/commands/geolocation.js.map +1 -1
- package/build/lib/commands/gesture.d.ts +273 -276
- package/build/lib/commands/gesture.d.ts.map +1 -1
- package/build/lib/commands/gesture.js +506 -492
- package/build/lib/commands/gesture.js.map +1 -1
- package/build/lib/commands/increase-contrast.d.ts +20 -23
- package/build/lib/commands/increase-contrast.d.ts.map +1 -1
- package/build/lib/commands/increase-contrast.js +30 -30
- package/build/lib/commands/increase-contrast.js.map +1 -1
- package/build/lib/commands/iohid.d.ts +1370 -1373
- package/build/lib/commands/iohid.d.ts.map +1 -1
- package/build/lib/commands/iohid.js +30 -31
- package/build/lib/commands/iohid.js.map +1 -1
- package/build/lib/commands/keyboard.d.ts +29 -32
- package/build/lib/commands/keyboard.d.ts.map +1 -1
- package/build/lib/commands/keyboard.js +53 -51
- package/build/lib/commands/keyboard.js.map +1 -1
- package/build/lib/commands/keychains.d.ts +9 -12
- package/build/lib/commands/keychains.d.ts.map +1 -1
- package/build/lib/commands/keychains.js +13 -14
- package/build/lib/commands/keychains.js.map +1 -1
- package/build/lib/commands/localization.d.ts +16 -19
- package/build/lib/commands/localization.d.ts.map +1 -1
- package/build/lib/commands/localization.js +25 -26
- package/build/lib/commands/localization.js.map +1 -1
- package/build/lib/commands/location.d.ts +36 -39
- package/build/lib/commands/location.d.ts.map +1 -1
- package/build/lib/commands/location.js +99 -98
- package/build/lib/commands/location.js.map +1 -1
- package/build/lib/commands/lock.d.ts +21 -24
- package/build/lib/commands/lock.d.ts.map +1 -1
- package/build/lib/commands/lock.js +39 -38
- package/build/lib/commands/lock.js.map +1 -1
- package/build/lib/commands/log.d.ts +43 -37
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +174 -171
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/memory.d.ts +9 -12
- package/build/lib/commands/memory.d.ts.map +1 -1
- package/build/lib/commands/memory.js +37 -38
- package/build/lib/commands/memory.js.map +1 -1
- package/build/lib/commands/navigation.d.ts +30 -33
- package/build/lib/commands/navigation.d.ts.map +1 -1
- package/build/lib/commands/navigation.js +92 -92
- package/build/lib/commands/navigation.js.map +1 -1
- package/build/lib/commands/notifications.d.ts +26 -29
- package/build/lib/commands/notifications.d.ts.map +1 -1
- package/build/lib/commands/notifications.js +53 -53
- package/build/lib/commands/notifications.js.map +1 -1
- package/build/lib/commands/pasteboard.d.ts +21 -24
- package/build/lib/commands/pasteboard.d.ts.map +1 -1
- package/build/lib/commands/pasteboard.js +37 -37
- package/build/lib/commands/pasteboard.js.map +1 -1
- package/build/lib/commands/pcap.d.ts +39 -26
- package/build/lib/commands/pcap.d.ts.map +1 -1
- package/build/lib/commands/pcap.js +81 -81
- package/build/lib/commands/pcap.js.map +1 -1
- package/build/lib/commands/performance.d.ts +63 -44
- package/build/lib/commands/performance.d.ts.map +1 -1
- package/build/lib/commands/performance.js +105 -105
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.d.ts +33 -36
- package/build/lib/commands/permissions.d.ts.map +1 -1
- package/build/lib/commands/permissions.js +66 -65
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/proxy-helper.d.ts +12 -15
- package/build/lib/commands/proxy-helper.d.ts.map +1 -1
- package/build/lib/commands/proxy-helper.js +53 -54
- package/build/lib/commands/proxy-helper.js.map +1 -1
- package/build/lib/commands/record-audio.d.ts +49 -29
- package/build/lib/commands/record-audio.d.ts.map +1 -1
- package/build/lib/commands/record-audio.js +100 -104
- package/build/lib/commands/record-audio.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts +54 -18
- package/build/lib/commands/recordscreen.d.ts.map +1 -1
- package/build/lib/commands/recordscreen.js +127 -129
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/screenshots.d.ts +14 -17
- package/build/lib/commands/screenshots.d.ts.map +1 -1
- package/build/lib/commands/screenshots.js +108 -107
- package/build/lib/commands/screenshots.js.map +1 -1
- package/build/lib/commands/simctl.d.ts +11 -14
- package/build/lib/commands/simctl.d.ts.map +1 -1
- package/build/lib/commands/simctl.js +23 -26
- package/build/lib/commands/simctl.js.map +1 -1
- package/build/lib/commands/source.d.ts +14 -17
- package/build/lib/commands/source.d.ts.map +1 -1
- package/build/lib/commands/source.js +40 -43
- package/build/lib/commands/source.js.map +1 -1
- package/build/lib/commands/timeouts.d.ts +44 -33
- package/build/lib/commands/timeouts.d.ts.map +1 -1
- package/build/lib/commands/timeouts.js +65 -63
- package/build/lib/commands/timeouts.js.map +1 -1
- package/build/lib/commands/web.d.ts +275 -197
- package/build/lib/commands/web.d.ts.map +1 -1
- package/build/lib/commands/web.js +866 -785
- package/build/lib/commands/web.js.map +1 -1
- package/build/lib/commands/xctest-record-screen.d.ts +63 -66
- package/build/lib/commands/xctest-record-screen.d.ts.map +1 -1
- package/build/lib/commands/xctest-record-screen.js +103 -102
- package/build/lib/commands/xctest-record-screen.js.map +1 -1
- package/build/lib/commands/xctest.d.ts +55 -51
- package/build/lib/commands/xctest.d.ts.map +1 -1
- package/build/lib/commands/xctest.js +116 -117
- package/build/lib/commands/xctest.js.map +1 -1
- package/build/lib/driver.d.ts +277 -1597
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +318 -235
- package/build/lib/driver.js.map +1 -1
- package/build/lib/execute-method-map.d.ts.map +1 -1
- package/build/lib/execute-method-map.js +9 -0
- package/build/lib/execute-method-map.js.map +1 -1
- package/lib/commands/active-app-info.js +12 -0
- package/lib/commands/alert.js +68 -65
- package/lib/commands/app-management.js +308 -301
- package/lib/commands/app-strings.js +24 -26
- package/lib/commands/appearance.js +54 -56
- package/lib/commands/audit.js +18 -20
- package/lib/commands/battery.js +35 -37
- package/lib/commands/biometric.js +44 -46
- package/lib/commands/certificate.js +226 -215
- package/lib/commands/clipboard.js +30 -32
- package/lib/commands/condition.js +98 -100
- package/lib/commands/content-size.js +36 -38
- package/lib/commands/context.js +495 -490
- package/lib/commands/deviceInfo.js +19 -20
- package/lib/commands/element.js +367 -357
- package/lib/commands/execute.js +72 -72
- package/lib/commands/file-movement.js +132 -134
- package/lib/commands/find.js +160 -159
- package/lib/commands/general.js +238 -231
- package/lib/commands/geolocation.js +6 -14
- package/lib/commands/gesture.js +525 -515
- package/lib/commands/increase-contrast.js +30 -32
- package/lib/commands/iohid.js +32 -34
- package/lib/commands/keyboard.js +49 -51
- package/lib/commands/keychains.js +12 -14
- package/lib/commands/localization.js +24 -26
- package/lib/commands/location.js +102 -104
- package/lib/commands/lock.js +38 -38
- package/lib/commands/log.js +197 -198
- package/lib/commands/memory.js +40 -42
- package/lib/commands/navigation.js +96 -100
- package/lib/commands/notifications.js +57 -59
- package/lib/commands/pasteboard.js +37 -39
- package/lib/commands/pcap.js +84 -86
- package/lib/commands/performance.js +132 -133
- package/lib/commands/permissions.js +67 -69
- package/lib/commands/proxy-helper.js +60 -61
- package/lib/commands/record-audio.js +115 -120
- package/lib/commands/recordscreen.js +145 -149
- package/lib/commands/screenshots.js +116 -116
- package/lib/commands/simctl.js +25 -29
- package/lib/commands/source.js +42 -46
- package/lib/commands/timeouts.js +59 -63
- package/lib/commands/web.js +932 -859
- package/lib/commands/xctest-record-screen.js +103 -105
- package/lib/commands/xctest.js +134 -139
- package/lib/driver.js +286 -235
- package/lib/execute-method-map.ts +9 -0
- package/npm-shrinkwrap.json +8 -8
- package/package.json +1 -1
- package/build/lib/commands/activeAppInfo.d.ts +0 -12
- package/build/lib/commands/activeAppInfo.d.ts.map +0 -1
- package/build/lib/commands/activeAppInfo.js +0 -15
- package/build/lib/commands/activeAppInfo.js.map +0 -1
- package/build/lib/commands/index.d.ts +0 -96
- package/build/lib/commands/index.d.ts.map +0 -1
- package/build/lib/commands/index.js +0 -100
- package/build/lib/commands/index.js.map +0 -1
- package/build/lib/cookies.d.ts +0 -15
- package/build/lib/cookies.d.ts.map +0 -1
- package/build/lib/cookies.js +0 -84
- package/build/lib/cookies.js.map +0 -1
- package/lib/commands/activeAppInfo.js +0 -14
- package/lib/commands/index.js +0 -95
- package/lib/cookies.js +0 -92
|
@@ -3,6 +3,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getContextsAndViews = getContextsAndViews;
|
|
7
|
+
exports.useNewSafari = useNewSafari;
|
|
8
|
+
exports.activateRecentWebview = activateRecentWebview;
|
|
9
|
+
exports.listWebFrames = listWebFrames;
|
|
10
|
+
exports.connectToRemoteDebugger = connectToRemoteDebugger;
|
|
11
|
+
exports.mobileGetContexts = mobileGetContexts;
|
|
12
|
+
exports.onPageChange = onPageChange;
|
|
13
|
+
exports.stopRemote = stopRemote;
|
|
14
|
+
exports.setCurrentUrl = setCurrentUrl;
|
|
15
|
+
exports.getCurrentUrl = getCurrentUrl;
|
|
16
|
+
exports.getRecentWebviewContextId = getRecentWebviewContextId;
|
|
17
|
+
exports.isWebContext = isWebContext;
|
|
18
|
+
exports.isWebview = isWebview;
|
|
19
|
+
exports.getNewRemoteDebugger = getNewRemoteDebugger;
|
|
20
|
+
exports.getCurrentContext = getCurrentContext;
|
|
21
|
+
exports.setContext = setContext;
|
|
22
|
+
exports.getContexts = getContexts;
|
|
23
|
+
exports.setWindow = setWindow;
|
|
24
|
+
exports.getWindowHandle = getWindowHandle;
|
|
25
|
+
exports.getWindowHandles = getWindowHandles;
|
|
6
26
|
exports.notifyBiDiContextChange = notifyBiDiContextChange;
|
|
7
27
|
const appium_remote_debugger_1 = require("appium-remote-debugger");
|
|
8
28
|
const driver_1 = require("appium/driver");
|
|
@@ -18,547 +38,541 @@ const WEBVIEW_BASE = `${WEBVIEW_WIN}_`;
|
|
|
18
38
|
const DEFAULT_REMOTE_DEBUGGER_CONNECT_TIMEOUT_MS = 5000;
|
|
19
39
|
const DEFAULT_LIST_WEB_FRAMES_RETRIES = 20;
|
|
20
40
|
const DEFAULT_NATIVE_WINDOW_HANDLE = '1';
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const webviews = await this.listWebFrames(useUrl);
|
|
30
|
-
/**
|
|
31
|
-
* @type {import('./types').ViewContext[]}
|
|
32
|
-
*/
|
|
33
|
-
const ctxs = [{ id: utils_1.NATIVE_WIN, view: {} }];
|
|
34
|
-
this.contexts = [utils_1.NATIVE_WIN];
|
|
35
|
-
for (const view of webviews) {
|
|
36
|
-
ctxs.push({ id: `${WEBVIEW_BASE}${view.id}`, view });
|
|
37
|
-
this.contexts.push(view.id.toString());
|
|
38
|
-
}
|
|
39
|
-
return ctxs;
|
|
40
|
-
},
|
|
41
|
-
/**
|
|
42
|
-
* @deprecated this method is not used anywhere and will be removed in the future
|
|
43
|
-
* @this {XCUITestDriver}
|
|
44
|
-
* @returns {boolean}
|
|
45
|
-
*/
|
|
46
|
-
useNewSafari() {
|
|
47
|
-
return this.isSimulator() && this.isSafari();
|
|
48
|
-
},
|
|
49
|
-
/**
|
|
50
|
-
* @this {XCUITestDriver}
|
|
51
|
-
* @returns {Promise<void>}
|
|
52
|
-
*/
|
|
53
|
-
async activateRecentWebview() {
|
|
54
|
-
this.log.debug('Activating a recent webview');
|
|
55
|
-
const timer = new support_1.timing.Timer().start();
|
|
56
|
-
const contextId = await this.getRecentWebviewContextId(/.*/, /.*/);
|
|
57
|
-
if (contextId) {
|
|
58
|
-
this.log.info(`Picking webview '${contextId}' after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
59
|
-
await this.setContext(contextId);
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
const appDict = ( /** @type {RemoteDebugger} */(this.remote)).appDict;
|
|
63
|
-
const errSuffix = `Make sure your web application is debuggable ` +
|
|
64
|
-
`and could be inspected in Safari Web Inspector.`;
|
|
65
|
-
if (lodash_1.default.isEmpty(appDict)) {
|
|
66
|
-
throw new Error(`The remote debugger did not return any connected web applications after ` +
|
|
67
|
-
`${timer.getDuration().asMilliSeconds.toFixed(0)}ms. ` +
|
|
68
|
-
`${errSuffix} ` +
|
|
69
|
-
`You may try to change the 'webviewConnectTimeout' capability value to ` +
|
|
70
|
-
`customize the retrieval timeout.`);
|
|
71
|
-
}
|
|
72
|
-
const errSuffix2 = `${errSuffix} You may try to change the 'webviewConnectRetries' ` +
|
|
73
|
-
`capability value to customize the amount of pages retrieval retries.`;
|
|
74
|
-
const appsWithPages = lodash_1.default.values(appDict).filter(({ pageArray }) => !lodash_1.default.isEmpty(pageArray));
|
|
75
|
-
if (appsWithPages.length > 0) {
|
|
76
|
-
throw new Error(`The remote debugger returned ${support_1.util.pluralize('web application', appsWithPages.length, true)} ` +
|
|
77
|
-
`with pages after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms, ` +
|
|
78
|
-
`although none of them matched our page search criteria. ${errSuffix2}`);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
throw new Error(`The remote debugger returned ${support_1.util.pluralize('web application', lodash_1.default.size(appDict), true)}, ` +
|
|
82
|
-
`but none of them had pages after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms. ` +
|
|
83
|
-
`${errSuffix2} Also, in rare cases the device restart or device OS upgrade may fix this ` +
|
|
84
|
-
`issue if none of the above advices helps.`);
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
/**
|
|
88
|
-
* @this {XCUITestDriver}
|
|
89
|
-
* @returns {Promise<import('../types').Page[]>}
|
|
90
|
-
*/
|
|
91
|
-
async listWebFrames(useUrl = true) {
|
|
92
|
-
const shouldFilterByUrl = useUrl && !this.isRealDevice() && !!this.getCurrentUrl();
|
|
93
|
-
this.log.debug(`Selecting by url: ${shouldFilterByUrl}` +
|
|
94
|
-
(shouldFilterByUrl ? ` (expected url: '${this.getCurrentUrl()}')` : ''));
|
|
95
|
-
if (!this.remote) {
|
|
96
|
-
await this.connectToRemoteDebugger();
|
|
97
|
-
}
|
|
98
|
-
const doListPages = async (/** @type {number} */ retries) => {
|
|
99
|
-
try {
|
|
100
|
-
const pageArray = await ( /** @type {RemoteDebugger} */(this.remote)).selectApp(shouldFilterByUrl ? this.getCurrentUrl() : undefined, retries, this.opts.ignoreAboutBlankUrl);
|
|
101
|
-
if (lodash_1.default.isEmpty(pageArray)) {
|
|
102
|
-
// we have no web frames, but continue anyway
|
|
103
|
-
this.log.debug(`No web frames found after ${support_1.util.pluralize('retry', retries, true)}`);
|
|
104
|
-
}
|
|
105
|
-
return pageArray;
|
|
106
|
-
}
|
|
107
|
-
catch (err) {
|
|
108
|
-
this.log.debug(`No available web pages after ${support_1.util.pluralize('retry', retries, true)}: ${err.message}`);
|
|
109
|
-
return [];
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
/** @type {number} */
|
|
113
|
-
const maxRetriesCount = lodash_1.default.isInteger(this.opts.webviewConnectRetries)
|
|
114
|
-
? Math.max(/** @type {number} */ (this.opts.webviewConnectRetries), 1)
|
|
115
|
-
: DEFAULT_LIST_WEB_FRAMES_RETRIES;
|
|
116
|
-
this.log.debug(`About to select a web application with ${support_1.util.pluralize('retry', maxRetriesCount, true)} ` +
|
|
117
|
-
`and 500ms interval between each retry. Consider customizing the value of 'webviewConnectRetries' ` +
|
|
118
|
-
`capability to change the amount of retries.`);
|
|
119
|
-
return await doListPages(maxRetriesCount);
|
|
120
|
-
},
|
|
121
|
-
/**
|
|
122
|
-
* @this {XCUITestDriver}
|
|
123
|
-
* @returns {Promise<void>}
|
|
124
|
-
*/
|
|
125
|
-
async connectToRemoteDebugger() {
|
|
126
|
-
this.remote = await this.getNewRemoteDebugger();
|
|
127
|
-
// @ts-ignore static is fine
|
|
128
|
-
this.remote.on(appium_remote_debugger_1.RemoteDebugger.EVENT_PAGE_CHANGE, this.onPageChange.bind(this));
|
|
129
|
-
// @ts-ignore static is fine
|
|
130
|
-
this.remote.on(appium_remote_debugger_1.RemoteDebugger.EVENT_FRAMES_DETACHED, () => {
|
|
131
|
-
if (!lodash_1.default.isEmpty(this.curWebFrames)) {
|
|
132
|
-
const curWebFrames = this.curWebFrames;
|
|
133
|
-
this.log.debug(`Clearing ${support_1.util.pluralize('frame', curWebFrames.length, true)}: ${curWebFrames.join(', ')}`);
|
|
134
|
-
}
|
|
135
|
-
this.curWebFrames = [];
|
|
136
|
-
});
|
|
137
|
-
const timeoutMs = this.opts.webviewConnectTimeout ?? DEFAULT_REMOTE_DEBUGGER_CONNECT_TIMEOUT_MS;
|
|
138
|
-
const apps = await this.remote.connect(timeoutMs);
|
|
139
|
-
if (lodash_1.default.isEmpty(apps)) {
|
|
140
|
-
this.log.info(`The remote debugger did not report any active web applications within ${timeoutMs}ms timeout. ` +
|
|
141
|
-
`Consider increasing the value of 'webviewConnectTimeout' capability to wait longer ` +
|
|
142
|
-
`on slower devices.`);
|
|
143
|
-
}
|
|
144
|
-
},
|
|
41
|
+
/**
|
|
42
|
+
* @this {XCUITestDriver}
|
|
43
|
+
* @param {boolean} [useUrl=false]
|
|
44
|
+
* @returns {Promise<import('./types').ViewContext[]>}
|
|
45
|
+
*/
|
|
46
|
+
async function getContextsAndViews(useUrl = true) {
|
|
47
|
+
this.log.debug('Retrieving contexts and views');
|
|
48
|
+
const webviews = await this.listWebFrames(useUrl);
|
|
145
49
|
/**
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* The list includes extended context information, like URLs and page names.
|
|
149
|
-
* This is different from the standard `getContexts` API, because the latter
|
|
150
|
-
* only has web view names without any additional information.
|
|
151
|
-
*
|
|
152
|
-
* @remarks In situations where multiple web views are available at once, the
|
|
153
|
-
* client code would have to connect to each of them in order to detect the
|
|
154
|
-
* one which needs to be interacted with. This extra effort is not needed with
|
|
155
|
-
* the information provided by this extension.
|
|
156
|
-
* @param {number} [waitForWebviewMs=0] - The period to poll for available webview(s) (in ms)
|
|
157
|
-
* @returns {Promise<Context[]>} The list of available context objects along with their properties.
|
|
158
|
-
* @this {XCUITestDriver}
|
|
50
|
+
* @type {import('./types').ViewContext[]}
|
|
159
51
|
*/
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
52
|
+
const ctxs = [{ id: utils_1.NATIVE_WIN, view: {} }];
|
|
53
|
+
this.contexts = [utils_1.NATIVE_WIN];
|
|
54
|
+
for (const view of webviews) {
|
|
55
|
+
ctxs.push({ id: `${WEBVIEW_BASE}${view.id}`, view });
|
|
56
|
+
this.contexts.push(view.id.toString());
|
|
57
|
+
}
|
|
58
|
+
return ctxs;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* @deprecated this method is not used anywhere and will be removed in the future
|
|
62
|
+
* @this {XCUITestDriver}
|
|
63
|
+
* @returns {boolean}
|
|
64
|
+
*/
|
|
65
|
+
function useNewSafari() {
|
|
66
|
+
return this.isSimulator() && this.isSafari();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* @this {XCUITestDriver}
|
|
70
|
+
* @returns {Promise<void>}
|
|
71
|
+
*/
|
|
72
|
+
async function activateRecentWebview() {
|
|
73
|
+
this.log.debug('Activating a recent webview');
|
|
74
|
+
const timer = new support_1.timing.Timer().start();
|
|
75
|
+
const contextId = await this.getRecentWebviewContextId(/.*/, /.*/);
|
|
76
|
+
if (contextId) {
|
|
77
|
+
this.log.info(`Picking webview '${contextId}' after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
78
|
+
await this.setContext(contextId);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const appDict = ( /** @type {RemoteDebugger} */(this.remote)).appDict;
|
|
82
|
+
const errSuffix = `Make sure your web application is debuggable ` +
|
|
83
|
+
`and could be inspected in Safari Web Inspector.`;
|
|
84
|
+
if (lodash_1.default.isEmpty(appDict)) {
|
|
85
|
+
throw new Error(`The remote debugger did not return any connected web applications after ` +
|
|
86
|
+
`${timer.getDuration().asMilliSeconds.toFixed(0)}ms. ` +
|
|
87
|
+
`${errSuffix} ` +
|
|
88
|
+
`You may try to change the 'webviewConnectTimeout' capability value to ` +
|
|
89
|
+
`customize the retrieval timeout.`);
|
|
90
|
+
}
|
|
91
|
+
const errSuffix2 = `${errSuffix} You may try to change the 'webviewConnectRetries' ` +
|
|
92
|
+
`capability value to customize the amount of pages retrieval retries.`;
|
|
93
|
+
const appsWithPages = lodash_1.default.values(appDict).filter(({ pageArray }) => !lodash_1.default.isEmpty(pageArray));
|
|
94
|
+
if (appsWithPages.length > 0) {
|
|
95
|
+
throw new Error(`The remote debugger returned ${support_1.util.pluralize('web application', appsWithPages.length, true)} ` +
|
|
96
|
+
`with pages after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms, ` +
|
|
97
|
+
`although none of them matched our page search criteria. ${errSuffix2}`);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
throw new Error(`The remote debugger returned ${support_1.util.pluralize('web application', lodash_1.default.size(appDict), true)}, ` +
|
|
101
|
+
`but none of them had pages after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms. ` +
|
|
102
|
+
`${errSuffix2} Also, in rare cases the device restart or device OS upgrade may fix this ` +
|
|
103
|
+
`issue if none of the above advices helps.`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* @this {XCUITestDriver}
|
|
108
|
+
* @returns {Promise<import('../types').Page[]>}
|
|
109
|
+
*/
|
|
110
|
+
async function listWebFrames(useUrl = true) {
|
|
111
|
+
const shouldFilterByUrl = useUrl && !this.isRealDevice() && !!this.getCurrentUrl();
|
|
112
|
+
this.log.debug(`Selecting by url: ${shouldFilterByUrl}` +
|
|
113
|
+
(shouldFilterByUrl ? ` (expected url: '${this.getCurrentUrl()}')` : ''));
|
|
114
|
+
if (!this.remote) {
|
|
115
|
+
await this.connectToRemoteDebugger();
|
|
116
|
+
}
|
|
117
|
+
const doListPages = async (/** @type {number} */ retries) => {
|
|
171
118
|
try {
|
|
172
|
-
/** @type {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (contexts.length >= 2) {
|
|
177
|
-
this.log.debug(`Found webview context after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
178
|
-
return contexts;
|
|
179
|
-
}
|
|
180
|
-
this.log.debug(`No webviews found in ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
181
|
-
} while (timer.getDuration().asMilliSeconds < waitForWebviewMs);
|
|
182
|
-
return contexts;
|
|
183
|
-
}
|
|
184
|
-
finally {
|
|
185
|
-
// reset the option so there are no side effects
|
|
186
|
-
this.opts.fullContextList = curOpt;
|
|
187
|
-
}
|
|
188
|
-
},
|
|
189
|
-
/**
|
|
190
|
-
* @this {XCUITestDriver}
|
|
191
|
-
* @param {import('./types').PageChangeNotification} pageChangeNotification
|
|
192
|
-
* @returns {Promise<void>}
|
|
193
|
-
*/
|
|
194
|
-
async onPageChange(pageChangeNotification) {
|
|
195
|
-
this.log.debug(`Remote debugger notified us of a new page listing: ${JSON.stringify(pageChangeNotification)}`);
|
|
196
|
-
if (this.selectingNewPage) {
|
|
197
|
-
this.log.debug('We are in the middle of selecting a page, ignoring');
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
if (!this.remote?.isConnected) {
|
|
201
|
-
this.log.debug('We have not yet connected, ignoring');
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
const { appIdKey, pageArray } = pageChangeNotification;
|
|
205
|
-
/** @type {string[]} */
|
|
206
|
-
const newIds = [];
|
|
207
|
-
/** @type {string[]} */
|
|
208
|
-
const newPages = [];
|
|
209
|
-
/** @type {string|null} */
|
|
210
|
-
let keyId = null;
|
|
211
|
-
for (const page of pageArray) {
|
|
212
|
-
const id = page.id.toString();
|
|
213
|
-
newIds.push(id);
|
|
214
|
-
if (page.isKey) {
|
|
215
|
-
keyId = id;
|
|
119
|
+
const pageArray = await ( /** @type {RemoteDebugger} */(this.remote)).selectApp(shouldFilterByUrl ? this.getCurrentUrl() : undefined, retries, this.opts.ignoreAboutBlankUrl);
|
|
120
|
+
if (lodash_1.default.isEmpty(pageArray)) {
|
|
121
|
+
// we have no web frames, but continue anyway
|
|
122
|
+
this.log.debug(`No web frames found after ${support_1.util.pluralize('retry', retries, true)}`);
|
|
216
123
|
}
|
|
217
|
-
|
|
218
|
-
// add if this is a new page
|
|
219
|
-
if (!lodash_1.default.includes(this.contexts, contextId)) {
|
|
220
|
-
if (isUrlIgnored(page.url, this.opts.safariIgnoreWebHostnames)) {
|
|
221
|
-
this.log.info(`Not tracking '${page.url}' page because it is blacklisted. ` +
|
|
222
|
-
`'safariIgnoreWebHostnames'=${this.opts.safariIgnoreWebHostnames}`);
|
|
223
|
-
}
|
|
224
|
-
else {
|
|
225
|
-
newPages.push(id);
|
|
226
|
-
this.contexts.push(contextId);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
if (!keyId) {
|
|
231
|
-
// if there is no key id, pull the first id from the page array and use that
|
|
232
|
-
// as a stand in
|
|
233
|
-
this.log.debug('No key id found. Choosing first id from page array');
|
|
234
|
-
keyId = newIds[0] || null;
|
|
124
|
+
return pageArray;
|
|
235
125
|
}
|
|
236
|
-
|
|
237
|
-
this.log.debug(
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
}
|
|
264
|
-
else {
|
|
265
|
-
// at this point, there are no new pages, and the current page still exists
|
|
266
|
-
this.log.debug('New page listing is same as old, doing nothing');
|
|
126
|
+
catch (err) {
|
|
127
|
+
this.log.debug(`No available web pages after ${support_1.util.pluralize('retry', retries, true)}: ${err.message}`);
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
/** @type {number} */
|
|
132
|
+
const maxRetriesCount = lodash_1.default.isInteger(this.opts.webviewConnectRetries)
|
|
133
|
+
? Math.max(/** @type {number} */ (this.opts.webviewConnectRetries), 1)
|
|
134
|
+
: DEFAULT_LIST_WEB_FRAMES_RETRIES;
|
|
135
|
+
this.log.debug(`About to select a web application with ${support_1.util.pluralize('retry', maxRetriesCount, true)} ` +
|
|
136
|
+
`and 500ms interval between each retry. Consider customizing the value of 'webviewConnectRetries' ` +
|
|
137
|
+
`capability to change the amount of retries.`);
|
|
138
|
+
return await doListPages(maxRetriesCount);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* @this {XCUITestDriver}
|
|
142
|
+
* @returns {Promise<void>}
|
|
143
|
+
*/
|
|
144
|
+
async function connectToRemoteDebugger() {
|
|
145
|
+
this.remote = await this.getNewRemoteDebugger();
|
|
146
|
+
// @ts-ignore static is fine
|
|
147
|
+
this.remote.on(appium_remote_debugger_1.RemoteDebugger.EVENT_PAGE_CHANGE, this.onPageChange.bind(this));
|
|
148
|
+
// @ts-ignore static is fine
|
|
149
|
+
this.remote.on(appium_remote_debugger_1.RemoteDebugger.EVENT_FRAMES_DETACHED, () => {
|
|
150
|
+
if (!lodash_1.default.isEmpty(this.curWebFrames)) {
|
|
151
|
+
const curWebFrames = this.curWebFrames;
|
|
152
|
+
this.log.debug(`Clearing ${support_1.util.pluralize('frame', curWebFrames.length, true)}: ${curWebFrames.join(', ')}`);
|
|
267
153
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
154
|
+
this.curWebFrames = [];
|
|
155
|
+
});
|
|
156
|
+
const timeoutMs = this.opts.webviewConnectTimeout ?? DEFAULT_REMOTE_DEBUGGER_CONNECT_TIMEOUT_MS;
|
|
157
|
+
const apps = await this.remote.connect(timeoutMs);
|
|
158
|
+
if (lodash_1.default.isEmpty(apps)) {
|
|
159
|
+
this.log.info(`The remote debugger did not report any active web applications within ${timeoutMs}ms timeout. ` +
|
|
160
|
+
`Consider increasing the value of 'webviewConnectTimeout' capability to wait longer ` +
|
|
161
|
+
`on slower devices.`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Retrieves the list of available contexts.
|
|
166
|
+
*
|
|
167
|
+
* The list includes extended context information, like URLs and page names.
|
|
168
|
+
* This is different from the standard `getContexts` API, because the latter
|
|
169
|
+
* only has web view names without any additional information.
|
|
170
|
+
*
|
|
171
|
+
* @remarks In situations where multiple web views are available at once, the
|
|
172
|
+
* client code would have to connect to each of them in order to detect the
|
|
173
|
+
* one which needs to be interacted with. This extra effort is not needed with
|
|
174
|
+
* the information provided by this extension.
|
|
175
|
+
* @param {number} [waitForWebviewMs=0] - The period to poll for available webview(s) (in ms)
|
|
176
|
+
* @returns {Promise<Context[]>} The list of available context objects along with their properties.
|
|
177
|
+
* @this {XCUITestDriver}
|
|
178
|
+
*/
|
|
179
|
+
async function mobileGetContexts(waitForWebviewMs = 0) {
|
|
180
|
+
// make sure it is a number, so the duration check works properly
|
|
181
|
+
if (!lodash_1.default.isNumber(waitForWebviewMs)) {
|
|
182
|
+
waitForWebviewMs = parseInt(waitForWebviewMs, 10);
|
|
183
|
+
if (isNaN(waitForWebviewMs)) {
|
|
184
|
+
waitForWebviewMs = 0;
|
|
276
185
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
this.
|
|
186
|
+
}
|
|
187
|
+
const curOpt = this.opts.fullContextList;
|
|
188
|
+
this.opts.fullContextList = true;
|
|
189
|
+
const timer = new support_1.timing.Timer().start();
|
|
190
|
+
try {
|
|
191
|
+
/** @type {FullContext[]} */
|
|
192
|
+
let contexts;
|
|
193
|
+
do {
|
|
194
|
+
contexts = /** @type {FullContext[]} */ (await this.getContexts());
|
|
195
|
+
if (contexts.length >= 2) {
|
|
196
|
+
this.log.debug(`Found webview context after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
197
|
+
return contexts;
|
|
288
198
|
}
|
|
289
|
-
|
|
290
|
-
|
|
199
|
+
this.log.debug(`No webviews found in ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
|
|
200
|
+
} while (timer.getDuration().asMilliSeconds < waitForWebviewMs);
|
|
201
|
+
return contexts;
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
// reset the option so there are no side effects
|
|
205
|
+
this.opts.fullContextList = curOpt;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* @this {XCUITestDriver}
|
|
210
|
+
* @param {import('./types').PageChangeNotification} pageChangeNotification
|
|
211
|
+
* @returns {Promise<void>}
|
|
212
|
+
*/
|
|
213
|
+
async function onPageChange(pageChangeNotification) {
|
|
214
|
+
this.log.debug(`Remote debugger notified us of a new page listing: ${JSON.stringify(pageChangeNotification)}`);
|
|
215
|
+
if (this.selectingNewPage) {
|
|
216
|
+
this.log.debug('We are in the middle of selecting a page, ignoring');
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (!this.remote?.isConnected) {
|
|
220
|
+
this.log.debug('We have not yet connected, ignoring');
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const { appIdKey, pageArray } = pageChangeNotification;
|
|
224
|
+
/** @type {string[]} */
|
|
225
|
+
const newIds = [];
|
|
226
|
+
/** @type {string[]} */
|
|
227
|
+
const newPages = [];
|
|
228
|
+
/** @type {string|null} */
|
|
229
|
+
let keyId = null;
|
|
230
|
+
for (const page of pageArray) {
|
|
231
|
+
const id = page.id.toString();
|
|
232
|
+
newIds.push(id);
|
|
233
|
+
if (page.isKey) {
|
|
234
|
+
keyId = id;
|
|
235
|
+
}
|
|
236
|
+
const contextId = `${appIdKey}.${id}`;
|
|
237
|
+
// add if this is a new page
|
|
238
|
+
if (!lodash_1.default.includes(this.contexts, contextId)) {
|
|
239
|
+
if (isUrlIgnored(page.url, this.opts.safariIgnoreWebHostnames)) {
|
|
240
|
+
this.log.info(`Not tracking '${page.url}' page because it is blacklisted. ` +
|
|
241
|
+
`'safariIgnoreWebHostnames'=${this.opts.safariIgnoreWebHostnames}`);
|
|
291
242
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
const helpers = {
|
|
296
|
-
/**
|
|
297
|
-
* @this {XCUITestDriver}
|
|
298
|
-
* @returns {Promise<void>}
|
|
299
|
-
*/
|
|
300
|
-
async stopRemote(closeWindowBeforeDisconnecting = false) {
|
|
301
|
-
if (!this.remote) {
|
|
302
|
-
throw this.log.errorWithException('Tried to leave a web frame but were not in one');
|
|
303
|
-
}
|
|
304
|
-
if (closeWindowBeforeDisconnecting) {
|
|
305
|
-
await this.closeWindow();
|
|
306
|
-
}
|
|
307
|
-
await this.remote.disconnect();
|
|
308
|
-
this.curContext = null;
|
|
309
|
-
await notifyBiDiContextChange.bind(this)();
|
|
310
|
-
this.curWebFrames = [];
|
|
311
|
-
this.remote = null;
|
|
312
|
-
},
|
|
313
|
-
/**
|
|
314
|
-
* @this {XCUITestDriver}
|
|
315
|
-
* @param {string|undefined|null} url
|
|
316
|
-
*/
|
|
317
|
-
setCurrentUrl(url) {
|
|
318
|
-
this._currentUrl = url;
|
|
319
|
-
},
|
|
320
|
-
/**
|
|
321
|
-
* @this {XCUITestDriver}
|
|
322
|
-
* @returns {string|undefined|null}
|
|
323
|
-
*/
|
|
324
|
-
getCurrentUrl() {
|
|
325
|
-
return this._currentUrl;
|
|
326
|
-
},
|
|
327
|
-
/**
|
|
328
|
-
* @param {RegExp} titleRegExp
|
|
329
|
-
* @param {RegExp} urlRegExp
|
|
330
|
-
* @this {XCUITestDriver}
|
|
331
|
-
* @returns {Promise<string|undefined>}
|
|
332
|
-
*/
|
|
333
|
-
async getRecentWebviewContextId(titleRegExp, urlRegExp) {
|
|
334
|
-
if (!lodash_1.default.isRegExp(titleRegExp) && !lodash_1.default.isRegExp(urlRegExp)) {
|
|
335
|
-
throw new driver_1.errors.InvalidArgumentError('A regular expression for either web view title or url must be provided');
|
|
336
|
-
}
|
|
337
|
-
const currentUrl = this.getCurrentUrl();
|
|
338
|
-
const contexts = lodash_1.default.filter(await this.getContextsAndViews(false), 'view');
|
|
339
|
-
// first try to match by current url
|
|
340
|
-
if (currentUrl) {
|
|
341
|
-
const ctx = contexts.find(({ view }) => (view?.url || '') === currentUrl);
|
|
342
|
-
if (ctx) {
|
|
343
|
-
return ctx.id;
|
|
243
|
+
else {
|
|
244
|
+
newPages.push(id);
|
|
245
|
+
this.contexts.push(contextId);
|
|
344
246
|
}
|
|
345
247
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
includeSafari: this.opts.includeSafariInWebviews,
|
|
376
|
-
pageLoadMs: this.pageLoadMs,
|
|
377
|
-
platformVersion: this.opts.platformVersion,
|
|
378
|
-
socketPath,
|
|
379
|
-
remoteDebugProxy: this.opts.remoteDebugProxy,
|
|
380
|
-
garbageCollectOnExecute: support_1.util.hasValue(this.opts.safariGarbageCollect)
|
|
381
|
-
? !!this.opts.safariGarbageCollect
|
|
382
|
-
: false,
|
|
383
|
-
udid: this.opts.udid,
|
|
384
|
-
logAllCommunication: this.opts.safariLogAllCommunication,
|
|
385
|
-
logAllCommunicationHexDump: this.opts.safariLogAllCommunicationHexDump,
|
|
386
|
-
socketChunkSize: this.opts.safariSocketChunkSize,
|
|
387
|
-
webInspectorMaxFrameLength: this.opts.safariWebInspectorMaxFrameLength,
|
|
388
|
-
pageLoadStrategy: this.caps.pageLoadStrategy,
|
|
389
|
-
}, this.isRealDevice());
|
|
390
|
-
},
|
|
391
|
-
};
|
|
392
|
-
const commands = {
|
|
393
|
-
/**
|
|
394
|
-
* @this {XCUITestDriver}
|
|
395
|
-
* @returns {Promise<string>}
|
|
396
|
-
*/
|
|
397
|
-
async getCurrentContext() {
|
|
398
|
-
if (this.curContext && this.curContext !== utils_1.NATIVE_WIN) {
|
|
399
|
-
return `${WEBVIEW_BASE}${this.curContext}`;
|
|
400
|
-
}
|
|
401
|
-
return utils_1.NATIVE_WIN;
|
|
402
|
-
},
|
|
403
|
-
/**
|
|
404
|
-
* Set context
|
|
405
|
-
*
|
|
406
|
-
* @param {string|Context} name - The name of context to set. It could be 'null' as NATIVE_WIN.
|
|
407
|
-
* @param {any} [callback] The callback. (It is not called in this method)
|
|
408
|
-
* @param {boolean} [skipReadyCheck=false] - Whether it waits for the new context is ready
|
|
409
|
-
* @this {XCUITestDriver}
|
|
410
|
-
* @returns {Promise<void>}
|
|
411
|
-
*/
|
|
412
|
-
async setContext(name, callback, skipReadyCheck = false) {
|
|
413
|
-
function alreadyInContext(desired, current) {
|
|
414
|
-
return (desired === current ||
|
|
415
|
-
(desired === null && current === utils_1.NATIVE_WIN) ||
|
|
416
|
-
(desired === utils_1.NATIVE_WIN && current === null));
|
|
417
|
-
}
|
|
418
|
-
function isNativeContext(context) {
|
|
419
|
-
return context === utils_1.NATIVE_WIN || context === null;
|
|
420
|
-
}
|
|
421
|
-
// allow the full context list to be passed in
|
|
422
|
-
const strName = String(typeof name === 'object' && name.id ? name.id : name);
|
|
423
|
-
this.log.debug(`Attempting to set context to '${strName || utils_1.NATIVE_WIN}' from '${this.curContext ? this.curContext : utils_1.NATIVE_WIN}'`);
|
|
424
|
-
if (alreadyInContext(strName, this.curContext) ||
|
|
425
|
-
alreadyInContext(lodash_1.default.replace(strName, WEBVIEW_BASE, ''), this.curContext)) {
|
|
426
|
-
// already in the named context, no need to do anything
|
|
427
|
-
this.log.debug(`Already in '${strName || utils_1.NATIVE_WIN}' context. Doing nothing.`);
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
if (isNativeContext(strName)) {
|
|
431
|
-
// switching into the native context
|
|
432
|
-
this.curContext = null;
|
|
433
|
-
await notifyBiDiContextChange.bind(this)();
|
|
248
|
+
}
|
|
249
|
+
if (!keyId) {
|
|
250
|
+
// if there is no key id, pull the first id from the page array and use that
|
|
251
|
+
// as a stand in
|
|
252
|
+
this.log.debug('No key id found. Choosing first id from page array');
|
|
253
|
+
keyId = newIds[0] || null;
|
|
254
|
+
}
|
|
255
|
+
if (!support_1.util.hasValue(this.curContext)) {
|
|
256
|
+
this.log.debug('We do not appear to have window set yet, ignoring');
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const [curAppIdKey, curPageIdKey] = this.curContext.split('.');
|
|
260
|
+
if (curAppIdKey !== appIdKey) {
|
|
261
|
+
this.log.debug('Page change not referring to currently selected app, ignoring.');
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
/** @type {string|null} */
|
|
265
|
+
let newPage = null;
|
|
266
|
+
if (newPages.length) {
|
|
267
|
+
newPage = /** @type {string} */ (lodash_1.default.last(newPages));
|
|
268
|
+
this.log.debug(`We have new pages, selecting page '${newPage}'`);
|
|
269
|
+
}
|
|
270
|
+
else if (!lodash_1.default.includes(newIds, curPageIdKey)) {
|
|
271
|
+
this.log.debug('New page listing from remote debugger does not contain ' +
|
|
272
|
+
'current window; assuming it is closed');
|
|
273
|
+
if (!support_1.util.hasValue(keyId)) {
|
|
274
|
+
this.log.error('Do not have our current window anymore, and there ' +
|
|
275
|
+
'are not any more to load! Doing nothing...');
|
|
276
|
+
this.setCurrentUrl(undefined);
|
|
434
277
|
return;
|
|
435
278
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
if (
|
|
449
|
-
|
|
279
|
+
this.log.debug(`Debugger already selected page '${keyId}', ` + `confirming that choice.`);
|
|
280
|
+
this.curContext = `${appIdKey}.${keyId}`;
|
|
281
|
+
newPage = keyId;
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
// at this point, there are no new pages, and the current page still exists
|
|
285
|
+
this.log.debug('New page listing is same as old, doing nothing');
|
|
286
|
+
}
|
|
287
|
+
// make sure that the page listing isn't indicating a redirect
|
|
288
|
+
if (support_1.util.hasValue(this.curContext)) {
|
|
289
|
+
const currentPageId = parseInt(String(lodash_1.default.last(this.curContext.split('.'))), 10);
|
|
290
|
+
const page = lodash_1.default.find(pageArray, (p) => parseInt(String(p.id), 10) === currentPageId);
|
|
291
|
+
if (page && page.url !== this.getCurrentUrl()) {
|
|
292
|
+
this.log.debug(`Redirected from '${this.getCurrentUrl()}' to '${page.url}'`);
|
|
293
|
+
this.setCurrentUrl(page.url);
|
|
450
294
|
}
|
|
295
|
+
}
|
|
296
|
+
if (support_1.util.hasValue(newPage)) {
|
|
297
|
+
this.selectingNewPage = true;
|
|
451
298
|
const oldContext = this.curContext;
|
|
452
|
-
this.curContext =
|
|
453
|
-
// `contextId` will be in the form of `appId.pageId` in this case
|
|
454
|
-
const [appIdKey, pageIdKey] = lodash_1.default.map(contextId.split('.'), (id) => parseInt(id, 10));
|
|
299
|
+
this.curContext = `${appIdKey}.${newPage}`;
|
|
455
300
|
try {
|
|
456
|
-
this.
|
|
457
|
-
await ( /** @type {RemoteDebugger} */(this.remote)).selectPage(appIdKey, pageIdKey, skipReadyCheck);
|
|
301
|
+
await this.remote.selectPage(appIdKey, parseInt(newPage, 10));
|
|
458
302
|
await notifyBiDiContextChange.bind(this)();
|
|
459
303
|
}
|
|
460
|
-
catch (
|
|
461
|
-
this.
|
|
462
|
-
|
|
304
|
+
catch (e) {
|
|
305
|
+
this.log.warn(`Failed to select page: ${e.message}`);
|
|
306
|
+
this.curContext = oldContext;
|
|
463
307
|
}
|
|
464
308
|
finally {
|
|
465
309
|
this.selectingNewPage = false;
|
|
466
310
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
|
-
try {
|
|
519
|
-
await this.setContext(name, lodash_1.default.noop, skipReadyCheck);
|
|
520
|
-
}
|
|
521
|
-
catch (err) {
|
|
522
|
-
// translate the error in terms of windows
|
|
523
|
-
throw (0, driver_1.isErrorType)(err, driver_1.errors.NoSuchContextError) ? new driver_1.errors.NoSuchWindowError() : err;
|
|
524
|
-
}
|
|
525
|
-
},
|
|
526
|
-
/**
|
|
527
|
-
* @this {XCUITestDriver}
|
|
528
|
-
* @returns {Promise<string>}
|
|
529
|
-
*/
|
|
530
|
-
async getWindowHandle() {
|
|
531
|
-
if (!this.isWebContext()) {
|
|
532
|
-
// https://github.com/appium/appium/issues/20710
|
|
533
|
-
return DEFAULT_NATIVE_WINDOW_HANDLE;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* @this {XCUITestDriver}
|
|
315
|
+
* @returns {Promise<void>}
|
|
316
|
+
*/
|
|
317
|
+
async function stopRemote(closeWindowBeforeDisconnecting = false) {
|
|
318
|
+
if (!this.remote) {
|
|
319
|
+
throw this.log.errorWithException('Tried to leave a web frame but were not in one');
|
|
320
|
+
}
|
|
321
|
+
if (closeWindowBeforeDisconnecting) {
|
|
322
|
+
await this.closeWindow();
|
|
323
|
+
}
|
|
324
|
+
await this.remote.disconnect();
|
|
325
|
+
this.curContext = null;
|
|
326
|
+
await notifyBiDiContextChange.bind(this)();
|
|
327
|
+
this.curWebFrames = [];
|
|
328
|
+
this.remote = null;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* @this {XCUITestDriver}
|
|
332
|
+
* @param {string|undefined|null} url
|
|
333
|
+
*/
|
|
334
|
+
function setCurrentUrl(url) {
|
|
335
|
+
this._currentUrl = url;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* @this {XCUITestDriver}
|
|
339
|
+
* @returns {string|undefined|null}
|
|
340
|
+
*/
|
|
341
|
+
function getCurrentUrl() {
|
|
342
|
+
return this._currentUrl;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* @param {RegExp} titleRegExp
|
|
346
|
+
* @param {RegExp} urlRegExp
|
|
347
|
+
* @this {XCUITestDriver}
|
|
348
|
+
* @returns {Promise<string|undefined>}
|
|
349
|
+
*/
|
|
350
|
+
async function getRecentWebviewContextId(titleRegExp, urlRegExp) {
|
|
351
|
+
if (!lodash_1.default.isRegExp(titleRegExp) && !lodash_1.default.isRegExp(urlRegExp)) {
|
|
352
|
+
throw new driver_1.errors.InvalidArgumentError('A regular expression for either web view title or url must be provided');
|
|
353
|
+
}
|
|
354
|
+
const currentUrl = this.getCurrentUrl();
|
|
355
|
+
const contexts = lodash_1.default.filter(await this.getContextsAndViews(false), 'view');
|
|
356
|
+
// first try to match by current url
|
|
357
|
+
if (currentUrl) {
|
|
358
|
+
const ctx = contexts.find(({ view }) => (view?.url || '') === currentUrl);
|
|
359
|
+
if (ctx) {
|
|
360
|
+
return ctx.id;
|
|
534
361
|
}
|
|
535
|
-
|
|
536
|
-
|
|
362
|
+
}
|
|
363
|
+
// if not, try to match by regular expression
|
|
364
|
+
return contexts.find(({ view }) => (view?.title && titleRegExp?.test(view.title)) || (view?.url && urlRegExp?.test(view.url)))?.id;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* @this {XCUITestDriver}
|
|
368
|
+
* @returns {boolean}
|
|
369
|
+
*/
|
|
370
|
+
function isWebContext() {
|
|
371
|
+
return !!this.curContext && this.curContext !== utils_1.NATIVE_WIN;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* @this {XCUITestDriver}
|
|
375
|
+
* @returns {boolean}
|
|
376
|
+
*/
|
|
377
|
+
function isWebview() {
|
|
378
|
+
return this.isWebContext();
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* @this {XCUITestDriver}
|
|
382
|
+
* @returns {Promise<RemoteDebugger>}
|
|
383
|
+
*/
|
|
384
|
+
async function getNewRemoteDebugger() {
|
|
385
|
+
const socketPath = this.isRealDevice()
|
|
386
|
+
? undefined
|
|
387
|
+
: (await /** @type {import('../driver').Simulator} */ (this.device).getWebInspectorSocket() ?? undefined);
|
|
388
|
+
return (0, appium_remote_debugger_1.createRemoteDebugger)({
|
|
389
|
+
bundleId: this.opts.bundleId,
|
|
390
|
+
additionalBundleIds: this.opts.additionalWebviewBundleIds,
|
|
391
|
+
isSafari: this.isSafari(),
|
|
392
|
+
includeSafari: this.opts.includeSafariInWebviews,
|
|
393
|
+
pageLoadMs: this.pageLoadMs,
|
|
394
|
+
platformVersion: this.opts.platformVersion,
|
|
395
|
+
socketPath,
|
|
396
|
+
remoteDebugProxy: this.opts.remoteDebugProxy,
|
|
397
|
+
garbageCollectOnExecute: support_1.util.hasValue(this.opts.safariGarbageCollect)
|
|
398
|
+
? !!this.opts.safariGarbageCollect
|
|
399
|
+
: false,
|
|
400
|
+
udid: this.opts.udid,
|
|
401
|
+
logAllCommunication: this.opts.safariLogAllCommunication,
|
|
402
|
+
logAllCommunicationHexDump: this.opts.safariLogAllCommunicationHexDump,
|
|
403
|
+
socketChunkSize: this.opts.safariSocketChunkSize,
|
|
404
|
+
webInspectorMaxFrameLength: this.opts.safariWebInspectorMaxFrameLength,
|
|
405
|
+
pageLoadStrategy: this.caps.pageLoadStrategy,
|
|
406
|
+
}, this.isRealDevice());
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* @this {XCUITestDriver}
|
|
410
|
+
* @returns {Promise<string>}
|
|
411
|
+
*/
|
|
412
|
+
async function getCurrentContext() {
|
|
413
|
+
if (this.curContext && this.curContext !== utils_1.NATIVE_WIN) {
|
|
414
|
+
return `${WEBVIEW_BASE}${this.curContext}`;
|
|
415
|
+
}
|
|
416
|
+
return utils_1.NATIVE_WIN;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Set context
|
|
420
|
+
*
|
|
421
|
+
* @param {string|Context} name - The name of context to set. It could be 'null' as NATIVE_WIN.
|
|
422
|
+
* @param {any} [callback] The callback. (It is not called in this method)
|
|
423
|
+
* @param {boolean} [skipReadyCheck=false] - Whether it waits for the new context is ready
|
|
424
|
+
* @this {XCUITestDriver}
|
|
425
|
+
* @returns {Promise<void>}
|
|
426
|
+
*/
|
|
427
|
+
async function setContext(name, callback, skipReadyCheck = false) {
|
|
428
|
+
function alreadyInContext(desired, current) {
|
|
429
|
+
return (desired === current ||
|
|
430
|
+
(desired === null && current === utils_1.NATIVE_WIN) ||
|
|
431
|
+
(desired === utils_1.NATIVE_WIN && current === null));
|
|
432
|
+
}
|
|
433
|
+
function isNativeContext(context) {
|
|
434
|
+
return context === utils_1.NATIVE_WIN || context === null;
|
|
435
|
+
}
|
|
436
|
+
// allow the full context list to be passed in
|
|
437
|
+
const strName = String(typeof name === 'object' && name.id ? name.id : name);
|
|
438
|
+
this.log.debug(`Attempting to set context to '${strName || utils_1.NATIVE_WIN}' from '${this.curContext ? this.curContext : utils_1.NATIVE_WIN}'`);
|
|
439
|
+
if (alreadyInContext(strName, this.curContext) ||
|
|
440
|
+
alreadyInContext(lodash_1.default.replace(strName, WEBVIEW_BASE, ''), this.curContext)) {
|
|
441
|
+
// already in the named context, no need to do anything
|
|
442
|
+
this.log.debug(`Already in '${strName || utils_1.NATIVE_WIN}' context. Doing nothing.`);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (isNativeContext(strName)) {
|
|
446
|
+
// switching into the native context
|
|
447
|
+
this.curContext = null;
|
|
448
|
+
await notifyBiDiContextChange.bind(this)();
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
// switching into a webview context
|
|
452
|
+
// if contexts have not already been retrieved, get them
|
|
453
|
+
if (lodash_1.default.isUndefined(this.contexts)) {
|
|
454
|
+
await this.getContexts();
|
|
455
|
+
}
|
|
456
|
+
let contextId = lodash_1.default.replace(strName, WEBVIEW_BASE, '');
|
|
457
|
+
if (contextId === '') {
|
|
458
|
+
// allow user to pass in "WEBVIEW" without an index
|
|
459
|
+
// the second context will be the first webview as
|
|
460
|
+
// the first is always NATIVE_APP
|
|
461
|
+
contextId = /** @type {string[]} */ (this.contexts)[1];
|
|
462
|
+
}
|
|
463
|
+
if (!lodash_1.default.includes(this.contexts, contextId)) {
|
|
464
|
+
throw new driver_1.errors.NoSuchContextError();
|
|
465
|
+
}
|
|
466
|
+
const oldContext = this.curContext;
|
|
467
|
+
this.curContext = this.curWindowHandle = contextId;
|
|
468
|
+
// `contextId` will be in the form of `appId.pageId` in this case
|
|
469
|
+
const [appIdKey, pageIdKey] = lodash_1.default.map(contextId.split('.'), (id) => parseInt(id, 10));
|
|
470
|
+
try {
|
|
471
|
+
this.selectingNewPage = true;
|
|
472
|
+
await ( /** @type {RemoteDebugger} */(this.remote)).selectPage(appIdKey, pageIdKey, skipReadyCheck);
|
|
473
|
+
await notifyBiDiContextChange.bind(this)();
|
|
474
|
+
}
|
|
475
|
+
catch (err) {
|
|
476
|
+
this.curContext = this.curWindowHandle = oldContext;
|
|
477
|
+
throw err;
|
|
478
|
+
}
|
|
479
|
+
finally {
|
|
480
|
+
this.selectingNewPage = false;
|
|
481
|
+
}
|
|
482
|
+
// attempt to start performance logging, if requested
|
|
483
|
+
if (this.opts.enablePerformanceLogging && this.remote) {
|
|
484
|
+
const context = this.curContext;
|
|
485
|
+
this.log.debug(`Starting performance log on '${context}'`);
|
|
486
|
+
[this.logs.performance,] = log_1.assignBiDiLogListener.bind(this)(new ios_performance_log_1.IOSPerformanceLog({
|
|
487
|
+
remoteDebugger: this.remote,
|
|
488
|
+
log: this.log,
|
|
489
|
+
}), {
|
|
490
|
+
type: 'performance',
|
|
491
|
+
context,
|
|
492
|
+
});
|
|
493
|
+
await this.logs.performance?.startCapture();
|
|
494
|
+
}
|
|
495
|
+
// start safari logging if the logs handlers are active
|
|
496
|
+
if (name && name !== utils_1.NATIVE_WIN && this.logs) {
|
|
497
|
+
if (this.logs.safariConsole) {
|
|
498
|
+
( /** @type {RemoteDebugger} */(this.remote)).startConsole(this.logs.safariConsole.onConsoleLogEvent.bind(this.logs.safariConsole));
|
|
537
499
|
}
|
|
538
|
-
this.
|
|
539
|
-
|
|
540
|
-
},
|
|
541
|
-
/**
|
|
542
|
-
* @this {XCUITestDriver}
|
|
543
|
-
* @returns {Promise<string[]>}
|
|
544
|
-
*/
|
|
545
|
-
async getWindowHandles() {
|
|
546
|
-
if (!this.isWebContext()) {
|
|
547
|
-
// https://github.com/appium/appium/issues/20710
|
|
548
|
-
return [DEFAULT_NATIVE_WINDOW_HANDLE];
|
|
500
|
+
if (this.logs.safariNetwork) {
|
|
501
|
+
( /** @type {RemoteDebugger} */(this.remote)).startNetwork(this.logs.safariNetwork.onNetworkEvent.bind(this.logs.safariNetwork));
|
|
549
502
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* @this {XCUITestDriver}
|
|
507
|
+
* @returns {Promise<string[]|FullContext[]>}
|
|
508
|
+
*/
|
|
509
|
+
async function getContexts() {
|
|
510
|
+
this.log.debug('Getting list of available contexts');
|
|
511
|
+
const contexts = await this.getContextsAndViews(false);
|
|
512
|
+
if (this.opts.fullContextList) {
|
|
513
|
+
return /** @type {import('./types').FullContext[]} */ (contexts.map((context) => ({
|
|
514
|
+
id: context.id.toString(),
|
|
515
|
+
title: context.view?.title,
|
|
516
|
+
url: context.view?.url,
|
|
517
|
+
bundleId: context.view?.bundleId,
|
|
518
|
+
})));
|
|
519
|
+
}
|
|
520
|
+
return /** @type {string[]} */ (contexts.map((context) => context.id.toString()));
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* @this {XCUITestDriver}
|
|
524
|
+
* @param {string} name
|
|
525
|
+
* @param {boolean} [skipReadyCheck]
|
|
526
|
+
* @returns {Promise<void>}
|
|
527
|
+
*/
|
|
528
|
+
async function setWindow(name, skipReadyCheck) {
|
|
529
|
+
if (!this.isWebContext()) {
|
|
530
|
+
// https://github.com/appium/appium/issues/20710
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
try {
|
|
534
|
+
await this.setContext(name, lodash_1.default.noop, skipReadyCheck);
|
|
535
|
+
}
|
|
536
|
+
catch (err) {
|
|
537
|
+
// translate the error in terms of windows
|
|
538
|
+
throw (0, driver_1.isErrorType)(err, driver_1.errors.NoSuchContextError) ? new driver_1.errors.NoSuchWindowError() : err;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* @this {XCUITestDriver}
|
|
543
|
+
* @returns {Promise<string>}
|
|
544
|
+
*/
|
|
545
|
+
async function getWindowHandle() {
|
|
546
|
+
if (!this.isWebContext()) {
|
|
547
|
+
// https://github.com/appium/appium/issues/20710
|
|
548
|
+
return DEFAULT_NATIVE_WINDOW_HANDLE;
|
|
549
|
+
}
|
|
550
|
+
if (!this.curContext) {
|
|
551
|
+
throw new driver_1.errors.InvalidContextError();
|
|
552
|
+
}
|
|
553
|
+
this.log.debug(`Getting current window handle`);
|
|
554
|
+
return this.curContext;
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* @this {XCUITestDriver}
|
|
558
|
+
* @returns {Promise<string[]>}
|
|
559
|
+
*/
|
|
560
|
+
async function getWindowHandles() {
|
|
561
|
+
if (!this.isWebContext()) {
|
|
562
|
+
// https://github.com/appium/appium/issues/20710
|
|
563
|
+
return [DEFAULT_NATIVE_WINDOW_HANDLE];
|
|
564
|
+
}
|
|
565
|
+
this.log.debug('Getting list of available window handles');
|
|
566
|
+
const contexts = await this.getContextsAndViews(false);
|
|
567
|
+
return (contexts
|
|
568
|
+
// get rid of the native app context
|
|
569
|
+
.filter((context) => context.id !== utils_1.NATIVE_WIN)
|
|
570
|
+
// get the `app.id` format expected
|
|
571
|
+
.map((context) =>
|
|
572
|
+
// This is non-nullable because the `FullContext` having `id` `NATIVE_WIN`
|
|
573
|
+
// _looks like_ the only with an empty view.
|
|
574
|
+
context.view?.id?.toString() ?? ''));
|
|
575
|
+
}
|
|
562
576
|
/**
|
|
563
577
|
* Checks if a URL is blacklisted in the 'safariIgnoreWebHostnames' capability
|
|
564
578
|
*
|
|
@@ -603,7 +617,6 @@ async function notifyBiDiContextChange() {
|
|
|
603
617
|
this.eventEmitter.emit(constants_1.BIDI_EVENT_NAME, (0, models_1.makeContextUpdatedEvent)(name));
|
|
604
618
|
this.eventEmitter.emit(constants_1.BIDI_EVENT_NAME, (0, models_1.makeObsoleteContextUpdatedEvent)(name));
|
|
605
619
|
}
|
|
606
|
-
exports.default = { ...helpers, ...extensions, ...commands };
|
|
607
620
|
/**
|
|
608
621
|
* @typedef {import('../driver').XCUITestDriver} XCUITestDriver
|
|
609
622
|
* @typedef {import('./types').Context} Context
|