appium-webdriveragent 13.1.3 → 13.2.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/WebDriverAgent.xcodeproj/project.pbxproj +23 -3
- package/WebDriverAgentLib/Commands/FBSessionCommands.m +11 -176
- package/WebDriverAgentLib/Info.plist +2 -2
- package/WebDriverAgentLib/Utilities/FBSettingsHandler.h +35 -0
- package/WebDriverAgentLib/Utilities/FBSettingsHandler.m +356 -0
- package/WebDriverAgentLib/Utilities/FBXPath-Private.h +5 -0
- package/WebDriverAgentLib/Utilities/FBXPath.m +36 -4
- package/WebDriverAgentLib/Utilities/FBXPathExtensions.h +40 -0
- package/WebDriverAgentLib/Utilities/FBXPathExtensions.m +418 -0
- package/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.m +5 -0
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPErrorResponse.m +1 -3
- package/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m +103 -0
- package/WebDriverAgentTests/UnitTests/FBXPathTests.m +125 -0
- package/package.json +1 -1
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the BSD-style license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#import "FBSettingsHandler.h"
|
|
10
|
+
|
|
11
|
+
#import "FBActiveAppDetectionPoint.h"
|
|
12
|
+
#import "FBClassChainQueryParser.h"
|
|
13
|
+
#import "FBCommandStatus.h"
|
|
14
|
+
#import "FBConfiguration.h"
|
|
15
|
+
#import "FBSession.h"
|
|
16
|
+
#import "FBSettings.h"
|
|
17
|
+
|
|
18
|
+
typedef FBCommandStatus * _Nullable (^FBSettingApplyBlock)(FBSession *session, id value);
|
|
19
|
+
typedef id _Nonnull (^FBSettingGetBlock)(FBSession *session);
|
|
20
|
+
|
|
21
|
+
static id FBNormalizedSettingValue(id value)
|
|
22
|
+
{
|
|
23
|
+
return value == NSNull.null ? nil : value;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static NSSet<NSString *> *FBNilClearableSettingKeys(void)
|
|
27
|
+
{
|
|
28
|
+
static NSSet<NSString *> *keys;
|
|
29
|
+
static dispatch_once_t onceToken;
|
|
30
|
+
dispatch_once(&onceToken, ^{
|
|
31
|
+
keys = [NSSet setWithObjects:
|
|
32
|
+
FB_SETTING_DEFAULT_ALERT_ACTION,
|
|
33
|
+
FB_SETTING_ACCEPT_ALERT_BUTTON_SELECTOR,
|
|
34
|
+
FB_SETTING_DISMISS_ALERT_BUTTON_SELECTOR,
|
|
35
|
+
FB_SETTING_AUTO_CLICK_ALERT_SELECTOR,
|
|
36
|
+
nil];
|
|
37
|
+
});
|
|
38
|
+
return keys;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@implementation FBSettingsHandler
|
|
42
|
+
|
|
43
|
+
+ (NSDictionary<NSString *, FBSettingApplyBlock> *)settersMap
|
|
44
|
+
{
|
|
45
|
+
static NSDictionary<NSString *, FBSettingApplyBlock> *settersMap;
|
|
46
|
+
static dispatch_once_t onceToken;
|
|
47
|
+
dispatch_once(&onceToken, ^{
|
|
48
|
+
NSMutableDictionary<NSString *, FBSettingApplyBlock> *map = [NSMutableDictionary dictionary];
|
|
49
|
+
map[FB_SETTING_USE_COMPACT_RESPONSES] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
50
|
+
[FBConfiguration setShouldUseCompactResponses:[value boolValue]];
|
|
51
|
+
return nil;
|
|
52
|
+
};
|
|
53
|
+
map[FB_SETTING_ELEMENT_RESPONSE_ATTRIBUTES] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
54
|
+
[FBConfiguration setElementResponseAttributes:(NSString *)value];
|
|
55
|
+
return nil;
|
|
56
|
+
};
|
|
57
|
+
map[FB_SETTING_MJPEG_SERVER_SCREENSHOT_QUALITY] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
58
|
+
[FBConfiguration setMjpegServerScreenshotQuality:[value unsignedIntegerValue]];
|
|
59
|
+
return nil;
|
|
60
|
+
};
|
|
61
|
+
map[FB_SETTING_MJPEG_SERVER_FRAMERATE] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
62
|
+
[FBConfiguration setMjpegServerFramerate:[value unsignedIntegerValue]];
|
|
63
|
+
return nil;
|
|
64
|
+
};
|
|
65
|
+
map[FB_SETTING_SCREENSHOT_QUALITY] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
66
|
+
[FBConfiguration setScreenshotQuality:[value unsignedIntegerValue]];
|
|
67
|
+
return nil;
|
|
68
|
+
};
|
|
69
|
+
map[FB_SETTING_MJPEG_SCALING_FACTOR] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
70
|
+
[FBConfiguration setMjpegScalingFactor:[value floatValue]];
|
|
71
|
+
return nil;
|
|
72
|
+
};
|
|
73
|
+
map[FB_SETTING_MJPEG_FIX_ORIENTATION] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
74
|
+
[FBConfiguration setMjpegShouldFixOrientation:[value boolValue]];
|
|
75
|
+
return nil;
|
|
76
|
+
};
|
|
77
|
+
map[FB_SETTING_KEYBOARD_AUTOCORRECTION] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
78
|
+
[FBConfiguration setKeyboardAutocorrection:[value boolValue]];
|
|
79
|
+
return nil;
|
|
80
|
+
};
|
|
81
|
+
map[FB_SETTING_KEYBOARD_PREDICTION] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
82
|
+
[FBConfiguration setKeyboardPrediction:[value boolValue]];
|
|
83
|
+
return nil;
|
|
84
|
+
};
|
|
85
|
+
map[FB_SETTING_RESPECT_SYSTEM_ALERTS] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
86
|
+
[FBConfiguration setShouldRespectSystemAlerts:[value boolValue]];
|
|
87
|
+
return nil;
|
|
88
|
+
};
|
|
89
|
+
map[FB_SETTING_SNAPSHOT_MAX_DEPTH] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
90
|
+
[FBConfiguration setSnapshotMaxDepth:[value intValue]];
|
|
91
|
+
return nil;
|
|
92
|
+
};
|
|
93
|
+
map[FB_SETTING_SNAPSHOT_MAX_CHILDREN] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
94
|
+
[FBConfiguration setSnapshotMaxChildren:[value intValue]];
|
|
95
|
+
return nil;
|
|
96
|
+
};
|
|
97
|
+
map[FB_SETTING_USE_FIRST_MATCH] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
98
|
+
[FBConfiguration setUseFirstMatch:[value boolValue]];
|
|
99
|
+
return nil;
|
|
100
|
+
};
|
|
101
|
+
map[FB_SETTING_BOUND_ELEMENTS_BY_INDEX] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
102
|
+
[FBConfiguration setBoundElementsByIndex:[value boolValue]];
|
|
103
|
+
return nil;
|
|
104
|
+
};
|
|
105
|
+
map[FB_SETTING_REDUCE_MOTION] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
106
|
+
[FBConfiguration setReduceMotionEnabled:[value boolValue]];
|
|
107
|
+
return nil;
|
|
108
|
+
};
|
|
109
|
+
map[FB_SETTING_DEFAULT_ACTIVE_APPLICATION] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
110
|
+
session.defaultActiveApplication = (NSString *)value;
|
|
111
|
+
return nil;
|
|
112
|
+
};
|
|
113
|
+
map[FB_SETTING_ACTIVE_APP_DETECTION_POINT] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
114
|
+
NSError *error;
|
|
115
|
+
if (![FBActiveAppDetectionPoint.sharedInstance setCoordinatesWithString:(NSString *)value
|
|
116
|
+
error:&error]) {
|
|
117
|
+
return [FBCommandStatus invalidArgumentErrorWithMessage:error.localizedDescription
|
|
118
|
+
traceback:nil];
|
|
119
|
+
}
|
|
120
|
+
return nil;
|
|
121
|
+
};
|
|
122
|
+
map[FB_SETTING_ACCEPT_ALERT_BUTTON_SELECTOR] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
123
|
+
[FBConfiguration setAcceptAlertButtonSelector:(NSString *)value];
|
|
124
|
+
return nil;
|
|
125
|
+
};
|
|
126
|
+
map[FB_SETTING_DISMISS_ALERT_BUTTON_SELECTOR] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
127
|
+
[FBConfiguration setDismissAlertButtonSelector:(NSString *)value];
|
|
128
|
+
return nil;
|
|
129
|
+
};
|
|
130
|
+
map[FB_SETTING_AUTO_CLICK_ALERT_SELECTOR] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
131
|
+
return [self configureAutoClickAlertWithSelector:(NSString *)value forSession:session];
|
|
132
|
+
};
|
|
133
|
+
map[FB_SETTING_WAIT_FOR_IDLE_TIMEOUT] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
134
|
+
[FBConfiguration setWaitForIdleTimeout:[value doubleValue]];
|
|
135
|
+
return nil;
|
|
136
|
+
};
|
|
137
|
+
map[FB_SETTING_ANIMATION_COOL_OFF_TIMEOUT] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
138
|
+
[FBConfiguration setAnimationCoolOffTimeout:[value doubleValue]];
|
|
139
|
+
return nil;
|
|
140
|
+
};
|
|
141
|
+
map[FB_SETTING_DEFAULT_ALERT_ACTION] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
142
|
+
if (nil == value) {
|
|
143
|
+
session.defaultAlertAction = nil;
|
|
144
|
+
} else if ([value isKindOfClass:NSString.class]) {
|
|
145
|
+
session.defaultAlertAction = [(NSString *)value lowercaseString];
|
|
146
|
+
}
|
|
147
|
+
return nil;
|
|
148
|
+
};
|
|
149
|
+
map[FB_SETTING_MAX_TYPING_FREQUENCY] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
150
|
+
[FBConfiguration setMaxTypingFrequency:[value unsignedIntegerValue]];
|
|
151
|
+
return nil;
|
|
152
|
+
};
|
|
153
|
+
map[FB_SETTING_USE_CLEAR_TEXT_SHORTCUT] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
154
|
+
[FBConfiguration setUseClearTextShortcut:[value boolValue]];
|
|
155
|
+
return nil;
|
|
156
|
+
};
|
|
157
|
+
map[FB_SETTING_INCLUDE_HITTABLE_IN_PAGE_SOURCE] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
158
|
+
[FBConfiguration setIncludeHittableInPageSource:[value boolValue]];
|
|
159
|
+
return nil;
|
|
160
|
+
};
|
|
161
|
+
map[FB_SETTING_INCLUDE_NATIVE_FRAME_IN_PAGE_SOURCE] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
162
|
+
[FBConfiguration setIncludeNativeFrameInPageSource:[value boolValue]];
|
|
163
|
+
return nil;
|
|
164
|
+
};
|
|
165
|
+
map[FB_SETTING_INCLUDE_MIN_MAX_VALUE_IN_PAGE_SOURCE] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
166
|
+
[FBConfiguration setIncludeMinMaxValueInPageSource:[value boolValue]];
|
|
167
|
+
return nil;
|
|
168
|
+
};
|
|
169
|
+
map[FB_SETTING_INCLUDE_CUSTOM_ACTIONS_IN_PAGE_SOURCE] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
170
|
+
[FBConfiguration setIncludeCustomActionsInPageSource:[value boolValue]];
|
|
171
|
+
return nil;
|
|
172
|
+
};
|
|
173
|
+
map[FB_SETTING_ENFORCE_CUSTOM_SNAPSHOTS] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
174
|
+
[FBConfiguration setEnforceCustomSnapshots:[value boolValue]];
|
|
175
|
+
return nil;
|
|
176
|
+
};
|
|
177
|
+
map[FB_SETTING_LIMIT_XPATH_CONTEXT_SCOPE] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
178
|
+
[FBConfiguration setLimitXpathContextScope:[value boolValue]];
|
|
179
|
+
return nil;
|
|
180
|
+
};
|
|
181
|
+
#if !TARGET_OS_TV
|
|
182
|
+
map[FB_SETTING_SCREENSHOT_ORIENTATION] = ^FBCommandStatus *(FBSession *session, id value) {
|
|
183
|
+
NSError *error;
|
|
184
|
+
if (![FBConfiguration setScreenshotOrientation:(NSString *)value error:&error]) {
|
|
185
|
+
return [FBCommandStatus invalidArgumentErrorWithMessage:error.localizedDescription
|
|
186
|
+
traceback:nil];
|
|
187
|
+
}
|
|
188
|
+
return nil;
|
|
189
|
+
};
|
|
190
|
+
#endif
|
|
191
|
+
settersMap = map.copy;
|
|
192
|
+
});
|
|
193
|
+
return settersMap;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
+ (NSDictionary<NSString *, FBSettingGetBlock> *)gettersMap
|
|
197
|
+
{
|
|
198
|
+
static NSDictionary<NSString *, FBSettingGetBlock> *gettersMap;
|
|
199
|
+
static dispatch_once_t onceToken;
|
|
200
|
+
dispatch_once(&onceToken, ^{
|
|
201
|
+
NSMutableDictionary<NSString *, FBSettingGetBlock> *map = [NSMutableDictionary dictionary];
|
|
202
|
+
map[FB_SETTING_USE_COMPACT_RESPONSES] = ^id(FBSession *session) {
|
|
203
|
+
return @([FBConfiguration shouldUseCompactResponses]);
|
|
204
|
+
};
|
|
205
|
+
map[FB_SETTING_ELEMENT_RESPONSE_ATTRIBUTES] = ^id(FBSession *session) {
|
|
206
|
+
return [FBConfiguration elementResponseAttributes];
|
|
207
|
+
};
|
|
208
|
+
map[FB_SETTING_MJPEG_SERVER_SCREENSHOT_QUALITY] = ^id(FBSession *session) {
|
|
209
|
+
return @([FBConfiguration mjpegServerScreenshotQuality]);
|
|
210
|
+
};
|
|
211
|
+
map[FB_SETTING_MJPEG_SERVER_FRAMERATE] = ^id(FBSession *session) {
|
|
212
|
+
return @([FBConfiguration mjpegServerFramerate]);
|
|
213
|
+
};
|
|
214
|
+
map[FB_SETTING_MJPEG_SCALING_FACTOR] = ^id(FBSession *session) {
|
|
215
|
+
return @([FBConfiguration mjpegScalingFactor]);
|
|
216
|
+
};
|
|
217
|
+
map[FB_SETTING_MJPEG_FIX_ORIENTATION] = ^id(FBSession *session) {
|
|
218
|
+
return @([FBConfiguration mjpegShouldFixOrientation]);
|
|
219
|
+
};
|
|
220
|
+
map[FB_SETTING_SCREENSHOT_QUALITY] = ^id(FBSession *session) {
|
|
221
|
+
return @([FBConfiguration screenshotQuality]);
|
|
222
|
+
};
|
|
223
|
+
map[FB_SETTING_KEYBOARD_AUTOCORRECTION] = ^id(FBSession *session) {
|
|
224
|
+
return @([FBConfiguration keyboardAutocorrection]);
|
|
225
|
+
};
|
|
226
|
+
map[FB_SETTING_KEYBOARD_PREDICTION] = ^id(FBSession *session) {
|
|
227
|
+
return @([FBConfiguration keyboardPrediction]);
|
|
228
|
+
};
|
|
229
|
+
map[FB_SETTING_SNAPSHOT_MAX_DEPTH] = ^id(FBSession *session) {
|
|
230
|
+
return @([FBConfiguration snapshotMaxDepth]);
|
|
231
|
+
};
|
|
232
|
+
map[FB_SETTING_SNAPSHOT_MAX_CHILDREN] = ^id(FBSession *session) {
|
|
233
|
+
return @([FBConfiguration snapshotMaxChildren]);
|
|
234
|
+
};
|
|
235
|
+
map[FB_SETTING_USE_FIRST_MATCH] = ^id(FBSession *session) {
|
|
236
|
+
return @([FBConfiguration useFirstMatch]);
|
|
237
|
+
};
|
|
238
|
+
map[FB_SETTING_WAIT_FOR_IDLE_TIMEOUT] = ^id(FBSession *session) {
|
|
239
|
+
return @([FBConfiguration waitForIdleTimeout]);
|
|
240
|
+
};
|
|
241
|
+
map[FB_SETTING_ANIMATION_COOL_OFF_TIMEOUT] = ^id(FBSession *session) {
|
|
242
|
+
return @([FBConfiguration animationCoolOffTimeout]);
|
|
243
|
+
};
|
|
244
|
+
map[FB_SETTING_BOUND_ELEMENTS_BY_INDEX] = ^id(FBSession *session) {
|
|
245
|
+
return @([FBConfiguration boundElementsByIndex]);
|
|
246
|
+
};
|
|
247
|
+
map[FB_SETTING_REDUCE_MOTION] = ^id(FBSession *session) {
|
|
248
|
+
return @([FBConfiguration reduceMotionEnabled]);
|
|
249
|
+
};
|
|
250
|
+
map[FB_SETTING_DEFAULT_ACTIVE_APPLICATION] = ^id(FBSession *session) {
|
|
251
|
+
return session.defaultActiveApplication;
|
|
252
|
+
};
|
|
253
|
+
map[FB_SETTING_ACTIVE_APP_DETECTION_POINT] = ^id(FBSession *session) {
|
|
254
|
+
return FBActiveAppDetectionPoint.sharedInstance.stringCoordinates;
|
|
255
|
+
};
|
|
256
|
+
map[FB_SETTING_ACCEPT_ALERT_BUTTON_SELECTOR] = ^id(FBSession *session) {
|
|
257
|
+
return FBConfiguration.acceptAlertButtonSelector;
|
|
258
|
+
};
|
|
259
|
+
map[FB_SETTING_DISMISS_ALERT_BUTTON_SELECTOR] = ^id(FBSession *session) {
|
|
260
|
+
return FBConfiguration.dismissAlertButtonSelector;
|
|
261
|
+
};
|
|
262
|
+
map[FB_SETTING_AUTO_CLICK_ALERT_SELECTOR] = ^id(FBSession *session) {
|
|
263
|
+
return FBConfiguration.autoClickAlertSelector;
|
|
264
|
+
};
|
|
265
|
+
map[FB_SETTING_DEFAULT_ALERT_ACTION] = ^id(FBSession *session) {
|
|
266
|
+
return session.defaultAlertAction ?: @"";
|
|
267
|
+
};
|
|
268
|
+
map[FB_SETTING_MAX_TYPING_FREQUENCY] = ^id(FBSession *session) {
|
|
269
|
+
return @([FBConfiguration maxTypingFrequency]);
|
|
270
|
+
};
|
|
271
|
+
map[FB_SETTING_RESPECT_SYSTEM_ALERTS] = ^id(FBSession *session) {
|
|
272
|
+
return @([FBConfiguration shouldRespectSystemAlerts]);
|
|
273
|
+
};
|
|
274
|
+
map[FB_SETTING_USE_CLEAR_TEXT_SHORTCUT] = ^id(FBSession *session) {
|
|
275
|
+
return @([FBConfiguration useClearTextShortcut]);
|
|
276
|
+
};
|
|
277
|
+
map[FB_SETTING_INCLUDE_HITTABLE_IN_PAGE_SOURCE] = ^id(FBSession *session) {
|
|
278
|
+
return @([FBConfiguration includeHittableInPageSource]);
|
|
279
|
+
};
|
|
280
|
+
map[FB_SETTING_INCLUDE_NATIVE_FRAME_IN_PAGE_SOURCE] = ^id(FBSession *session) {
|
|
281
|
+
return @([FBConfiguration includeNativeFrameInPageSource]);
|
|
282
|
+
};
|
|
283
|
+
map[FB_SETTING_INCLUDE_MIN_MAX_VALUE_IN_PAGE_SOURCE] = ^id(FBSession *session) {
|
|
284
|
+
return @([FBConfiguration includeMinMaxValueInPageSource]);
|
|
285
|
+
};
|
|
286
|
+
map[FB_SETTING_INCLUDE_CUSTOM_ACTIONS_IN_PAGE_SOURCE] = ^id(FBSession *session) {
|
|
287
|
+
return @([FBConfiguration includeCustomActionsInPageSource]);
|
|
288
|
+
};
|
|
289
|
+
map[FB_SETTING_ENFORCE_CUSTOM_SNAPSHOTS] = ^id(FBSession *session) {
|
|
290
|
+
return @([FBConfiguration enforceCustomSnapshots]);
|
|
291
|
+
};
|
|
292
|
+
map[FB_SETTING_LIMIT_XPATH_CONTEXT_SCOPE] = ^id(FBSession *session) {
|
|
293
|
+
return @([FBConfiguration limitXpathContextScope]);
|
|
294
|
+
};
|
|
295
|
+
#if !TARGET_OS_TV
|
|
296
|
+
map[FB_SETTING_SCREENSHOT_ORIENTATION] = ^id(FBSession *session) {
|
|
297
|
+
return [FBConfiguration humanReadableScreenshotOrientation];
|
|
298
|
+
};
|
|
299
|
+
#endif
|
|
300
|
+
gettersMap = map.copy;
|
|
301
|
+
});
|
|
302
|
+
return gettersMap;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
+ (NSDictionary *)currentSettingsForSession:(FBSession *)session
|
|
306
|
+
{
|
|
307
|
+
NSDictionary<NSString *, FBSettingGetBlock> *gettersMap = [self gettersMap];
|
|
308
|
+
NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithCapacity:gettersMap.count];
|
|
309
|
+
for (NSString *key in gettersMap) {
|
|
310
|
+
settings[key] = gettersMap[key](session);
|
|
311
|
+
}
|
|
312
|
+
return settings.copy;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
+ (nullable FBCommandStatus *)applySettings:(NSDictionary *)settings toSession:(FBSession *)session
|
|
316
|
+
{
|
|
317
|
+
NSDictionary<NSString *, FBSettingApplyBlock> *settersMap = [self settersMap];
|
|
318
|
+
NSSet<NSString *> *nilClearableKeys = FBNilClearableSettingKeys();
|
|
319
|
+
for (NSString *key in settings) {
|
|
320
|
+
FBSettingApplyBlock handler = settersMap[key];
|
|
321
|
+
if (nil == handler) {
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
id value = FBNormalizedSettingValue(settings[key]);
|
|
325
|
+
if (nil == value && ![nilClearableKeys containsObject:key]) {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
FBCommandStatus *status = handler(session, value);
|
|
329
|
+
if (status.hasError) {
|
|
330
|
+
return status;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return nil;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
+ (FBCommandStatus *)configureAutoClickAlertWithSelector:(NSString *)selector
|
|
337
|
+
forSession:(FBSession *)session
|
|
338
|
+
{
|
|
339
|
+
if (0 == [selector length]) {
|
|
340
|
+
[FBConfiguration setAutoClickAlertSelector:selector];
|
|
341
|
+
[session disableAlertsMonitor];
|
|
342
|
+
return [FBCommandStatus ok];
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
NSError *error;
|
|
346
|
+
FBClassChain *parsedChain = [FBClassChainQueryParser parseQuery:selector error:&error];
|
|
347
|
+
if (nil == parsedChain) {
|
|
348
|
+
return [FBCommandStatus invalidSelectorErrorWithMessage:error.localizedDescription
|
|
349
|
+
traceback:nil];
|
|
350
|
+
}
|
|
351
|
+
[FBConfiguration setAutoClickAlertSelector:selector];
|
|
352
|
+
[session enableAlertsMonitor];
|
|
353
|
+
return [FBCommandStatus ok];
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
@end
|
|
@@ -51,6 +51,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
51
51
|
document:(xmlDocPtr)doc
|
|
52
52
|
contextNode:(nullable xmlNodePtr)contextNode;
|
|
53
53
|
|
|
54
|
+
+ (xmlXPathObjectPtr)evaluate:(NSString *)xpathQuery
|
|
55
|
+
document:(xmlDocPtr)doc
|
|
56
|
+
contextNode:(nullable xmlNodePtr)contextNode
|
|
57
|
+
errorMessage:(NSString * _Nullable * _Nullable)errorMessage;
|
|
58
|
+
|
|
54
59
|
@end
|
|
55
60
|
|
|
56
61
|
NS_ASSUME_NONNULL_END
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
#import "FBLogger.h"
|
|
15
15
|
#import "FBMacros.h"
|
|
16
16
|
#import "FBXMLGenerationOptions.h"
|
|
17
|
+
#import "FBXPathExtensions.h"
|
|
17
18
|
#import "FBXCElementSnapshotWrapper+Helpers.h"
|
|
18
19
|
#import "NSString+FBXMLSafeString.h"
|
|
19
20
|
#import "XCUIApplication.h"
|
|
@@ -152,7 +153,17 @@ static NSString *const topNodeIndexPath = @"top";
|
|
|
152
153
|
|
|
153
154
|
+ (id)throwException:(NSString *)name forQuery:(NSString *)xpathQuery
|
|
154
155
|
{
|
|
155
|
-
|
|
156
|
+
return [self throwException:name forQuery:xpathQuery detail:nil];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
+ (id)throwException:(NSString *)name forQuery:(NSString *)xpathQuery detail:(nullable NSString *)detail
|
|
160
|
+
{
|
|
161
|
+
NSString *reason;
|
|
162
|
+
if (nil != detail) {
|
|
163
|
+
reason = [NSString stringWithFormat:@"Cannot evaluate results for XPath expression \"%@\": %@", xpathQuery, detail];
|
|
164
|
+
} else {
|
|
165
|
+
reason = [NSString stringWithFormat:@"Cannot evaluate results for XPath expression \"%@\"", xpathQuery];
|
|
166
|
+
}
|
|
156
167
|
@throw [NSException exceptionWithName:name reason:reason userInfo:@{}];
|
|
157
168
|
return nil;
|
|
158
169
|
}
|
|
@@ -284,16 +295,18 @@ static NSString *const topNodeIndexPath = @"top";
|
|
|
284
295
|
contextNode = nodeSet->nodeTab[0];
|
|
285
296
|
}
|
|
286
297
|
}
|
|
298
|
+
NSString *evaluationError = nil;
|
|
287
299
|
xmlXPathObjectPtr queryResult = [self evaluate:xpathQuery
|
|
288
300
|
document:doc
|
|
289
|
-
contextNode:contextNode
|
|
301
|
+
contextNode:contextNode
|
|
302
|
+
errorMessage:&evaluationError];
|
|
290
303
|
if (NULL != contextNodeQueryResult) {
|
|
291
304
|
xmlXPathFreeObject(contextNodeQueryResult);
|
|
292
305
|
}
|
|
293
306
|
if (NULL == queryResult) {
|
|
294
307
|
xmlFreeTextWriter(writer);
|
|
295
308
|
xmlFreeDoc(doc);
|
|
296
|
-
return [self throwException:FBInvalidXPathException forQuery:xpathQuery];
|
|
309
|
+
return [self throwException:FBInvalidXPathException forQuery:xpathQuery detail:evaluationError];
|
|
297
310
|
}
|
|
298
311
|
|
|
299
312
|
NSArray *matchingSnapshots = [self collectMatchingSnapshots:queryResult->nodesetval
|
|
@@ -435,6 +448,14 @@ static NSString *const topNodeIndexPath = @"top";
|
|
|
435
448
|
+ (xmlXPathObjectPtr)evaluate:(NSString *)xpathQuery
|
|
436
449
|
document:(xmlDocPtr)doc
|
|
437
450
|
contextNode:(nullable xmlNodePtr)contextNode
|
|
451
|
+
{
|
|
452
|
+
return [self evaluate:xpathQuery document:doc contextNode:contextNode errorMessage:nil];
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
+ (xmlXPathObjectPtr)evaluate:(NSString *)xpathQuery
|
|
456
|
+
document:(xmlDocPtr)doc
|
|
457
|
+
contextNode:(nullable xmlNodePtr)contextNode
|
|
458
|
+
errorMessage:(NSString * _Nullable * _Nullable)errorMessage
|
|
438
459
|
{
|
|
439
460
|
xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
|
|
440
461
|
if (NULL == xpathCtx) {
|
|
@@ -443,10 +464,21 @@ static NSString *const topNodeIndexPath = @"top";
|
|
|
443
464
|
}
|
|
444
465
|
xpathCtx->node = NULL == contextNode ? doc->children : contextNode;
|
|
445
466
|
|
|
467
|
+
FBXPathExtensions *extensions = [FBXPathExtensions new];
|
|
468
|
+
[extensions registerFunctionsWithContext:xpathCtx];
|
|
469
|
+
|
|
446
470
|
xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((const xmlChar *)[xpathQuery UTF8String], xpathCtx);
|
|
447
471
|
if (NULL == xpathObj) {
|
|
472
|
+
NSString *detail = extensions.lastEvaluationError;
|
|
473
|
+
if (NULL != errorMessage) {
|
|
474
|
+
*errorMessage = detail;
|
|
475
|
+
}
|
|
476
|
+
if (nil != detail) {
|
|
477
|
+
[FBLogger logFmt:@"Failed to evaluate XPath query \"%@\": %@", xpathQuery, detail];
|
|
478
|
+
} else {
|
|
479
|
+
[FBLogger logFmt:@"Failed to invoke libxml2>xmlXPathEvalExpression for XPath query \"%@\"", xpathQuery];
|
|
480
|
+
}
|
|
448
481
|
xmlXPathFreeContext(xpathCtx);
|
|
449
|
-
[FBLogger logFmt:@"Failed to invoke libxml2>xmlXPathEvalExpression for XPath query \"%@\"", xpathQuery];
|
|
450
482
|
return NULL;
|
|
451
483
|
}
|
|
452
484
|
xmlXPathFreeContext(xpathCtx);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the BSD-style license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#import <Foundation/Foundation.h>
|
|
10
|
+
|
|
11
|
+
#ifdef __clang__
|
|
12
|
+
#pragma clang diagnostic push
|
|
13
|
+
#pragma clang diagnostic ignored "-Wpadded"
|
|
14
|
+
#endif
|
|
15
|
+
|
|
16
|
+
#import <libxml/xpath.h>
|
|
17
|
+
|
|
18
|
+
#ifdef __clang__
|
|
19
|
+
#pragma clang diagnostic pop
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
23
|
+
|
|
24
|
+
@interface FBXPathExtensions : NSObject
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
Registers XPath 2-compatible extension functions on the given libxml2 context.
|
|
28
|
+
*/
|
|
29
|
+
- (void)registerFunctionsWithContext:(xmlXPathContextPtr)xpathCtx;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
Human-readable message for the most recent XPath extension evaluation failure on this instance,
|
|
33
|
+
for example an invalid regular expression pattern or flags. Nil when no extension error has occurred.
|
|
34
|
+
Scoped to the libxml2 context this instance is registered with; each evaluation should use its own instance.
|
|
35
|
+
*/
|
|
36
|
+
@property (nonatomic, nullable, readonly, copy) NSString *lastEvaluationError;
|
|
37
|
+
|
|
38
|
+
@end
|
|
39
|
+
|
|
40
|
+
NS_ASSUME_NONNULL_END
|