appium-webdriveragent 4.10.24 → 4.11.0

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 CHANGED
@@ -1,3 +1,10 @@
1
+ ## [4.11.0](https://github.com/appium/WebDriverAgent/compare/v4.10.24...v4.11.0) (2023-02-19)
2
+
3
+
4
+ ### Features
5
+
6
+ * Add openUrl handler available since Xcode 14.3 ([#661](https://github.com/appium/WebDriverAgent/issues/661)) ([bee564e](https://github.com/appium/WebDriverAgent/commit/bee564e8c6b975aff07fd1244583f0727a0f5470))
7
+
1
8
  ## [4.10.24](https://github.com/appium/WebDriverAgent/compare/v4.10.23...v4.10.24) (2023-02-17)
2
9
 
3
10
 
@@ -67,4 +67,8 @@
67
67
  - (void)_reportInvalidation;
68
68
  - (id)initWithConnection:(id)arg1;
69
69
 
70
+ // Since Xcode 14.3
71
+ - (void)openURL:(NSURL *)arg1 usingApplication:(NSString *)arg2 completion:(void (^)(_Bool, NSError *))arg3;
72
+ - (void)openDefaultApplicationForURL:(NSURL *)arg1 completion:(void (^)(_Bool, NSError *))arg2;
73
+
70
74
  @end
@@ -3666,6 +3666,7 @@
3666
3666
  "-Wno-objc-messaging-id",
3667
3667
  "-Wno-direct-ivar-access",
3668
3668
  "-Wno-cast-qual",
3669
+ "-Wno-declaration-after-statement",
3669
3670
  );
3670
3671
  };
3671
3672
  name = Debug;
@@ -3728,6 +3729,7 @@
3728
3729
  "-Wno-objc-messaging-id",
3729
3730
  "-Wno-direct-ivar-access",
3730
3731
  "-Wno-cast-qual",
3732
+ "-Wno-declaration-after-statement",
3731
3733
  );
3732
3734
  };
3733
3735
  name = Release;
@@ -3974,6 +3976,7 @@
3974
3976
  "-Wno-objc-messaging-id",
3975
3977
  "-Wno-direct-ivar-access",
3976
3978
  "-Wno-cast-qual",
3979
+ "-Wno-declaration-after-statement",
3977
3980
  );
3978
3981
  };
3979
3982
  name = Debug;
@@ -4033,6 +4036,7 @@
4033
4036
  "-Wno-objc-messaging-id",
4034
4037
  "-Wno-direct-ivar-access",
4035
4038
  "-Wno-cast-qual",
4039
+ "-Wno-declaration-after-statement",
4036
4040
  );
4037
4041
  };
4038
4042
  name = Release;
@@ -71,8 +71,9 @@ typedef NS_ENUM(NSUInteger, FBUIInterfaceAppearance) {
71
71
  - (nullable NSString *)fb_wifiIPAddress;
72
72
 
73
73
  /**
74
- Opens the particular url scheme using Siri voice recognition helpers.
75
- This will only work since XCode 8.3/iOS 10.3
74
+ Opens the particular url scheme using the default application assigned to it.
75
+ This API only works since XCode 14.3/iOS 16.4
76
+ Older Xcode/iOS version try to use Siri fallback.
76
77
 
77
78
  @param url The url scheme represented as a string, for example https://apple.com
78
79
  @param error If there is an error, upon return contains an NSError object that describes the problem.
@@ -80,6 +81,17 @@ typedef NS_ENUM(NSUInteger, FBUIInterfaceAppearance) {
80
81
  */
81
82
  - (BOOL)fb_openUrl:(NSString *)url error:(NSError **)error;
82
83
 
84
+ /**
85
+ Opens the particular url scheme using the given application
86
+ This API only works since XCode 14.3/iOS 16.4
87
+
88
+ @param url The url scheme represented as a string, for example https://apple.com
89
+ @param bundleId The bundle identifier of an application to use in order to open the given URL
90
+ @param error If there is an error, upon return contains an NSError object that describes the problem.
91
+ @return YES if the operation was successful
92
+ */
93
+ - (BOOL)fb_openUrl:(NSString *)url withApplication:(NSString *)bundleId error:(NSError **)error;
94
+
83
95
  /**
84
96
  Presses the corresponding hardware button on the device with duration.
85
97
 
@@ -21,6 +21,7 @@
21
21
  #import "FBScreenshot.h"
22
22
  #import "FBXCDeviceEvent.h"
23
23
  #import "FBXCodeCompatibility.h"
24
+ #import "FBXCTestDaemonsProxy.h"
24
25
  #import "XCUIDevice.h"
25
26
 
26
27
  static const NSTimeInterval FBHomeButtonCoolOffTime = 1.;
@@ -157,20 +158,38 @@ static bool fb_isLocked;
157
158
  buildError:error];
158
159
  }
159
160
 
161
+ NSError *err;
162
+ if ([FBXCTestDaemonsProxy openDefaultApplicationForURL:parsedUrl error:&err]) {
163
+ return YES;
164
+ }
165
+ if (![err.description containsString:@"does not support"]) {
166
+ if (error) {
167
+ *error = err;
168
+ }
169
+ return NO;
170
+ }
171
+
160
172
  id siriService = [self valueForKey:@"siriService"];
161
173
  if (nil != siriService) {
162
174
  return [self fb_activateSiriVoiceRecognitionWithText:[NSString stringWithFormat:@"Open {%@}", url] error:error];
163
175
  }
164
- #pragma clang diagnostic push
165
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
166
- // The link never gets opened by this method: https://forums.developer.apple.com/thread/25355
167
- if (![[UIApplication sharedApplication] openURL:parsedUrl]) {
168
- #pragma clang diagnostic pop
176
+
177
+ NSString *description = [NSString stringWithFormat:@"Cannot open '%@' with the default application assigned for it. Consider upgrading to Xcode 14.3+/iOS 16.4+", url];
178
+ return [[[FBErrorBuilder builder]
179
+ withDescriptionFormat:@"%@", description]
180
+ buildError:error];;
181
+ }
182
+
183
+ - (BOOL)fb_openUrl:(NSString *)url withApplication:(NSString *)bundleId error:(NSError **)error
184
+ {
185
+ NSURL *parsedUrl = [NSURL URLWithString:url];
186
+ if (nil == parsedUrl) {
169
187
  return [[[FBErrorBuilder builder]
170
- withDescriptionFormat:@"The URL %@ cannot be opened", url]
188
+ withDescriptionFormat:@"'%@' is not a valid URL", url]
171
189
  buildError:error];
172
190
  }
173
- return YES;
191
+
192
+ return [FBXCTestDaemonsProxy openURL:parsedUrl usingApplication:bundleId error:error];
174
193
  }
175
194
 
176
195
  - (BOOL)fb_activateSiriVoiceRecognitionWithText:(NSString *)text error:(NSError **)error
@@ -66,9 +66,16 @@
66
66
  if (!urlString) {
67
67
  return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:@"URL is required" traceback:nil]);
68
68
  }
69
+ NSString* bundleId = request.arguments[@"bundleId"];
69
70
  NSError *error;
70
- if (![XCUIDevice.sharedDevice fb_openUrl:urlString error:&error]) {
71
- return FBResponseWithUnknownError(error);
71
+ if (nil == bundleId) {
72
+ if (![XCUIDevice.sharedDevice fb_openUrl:urlString error:&error]) {
73
+ return FBResponseWithUnknownError(error);
74
+ }
75
+ } else {
76
+ if (![XCUIDevice.sharedDevice fb_openUrl:urlString withApplication:bundleId error:&error]) {
77
+ return FBResponseWithUnknownError(error);
78
+ }
72
79
  }
73
80
  return FBResponseWithOK();
74
81
  }
@@ -24,7 +24,7 @@
24
24
 
25
25
  NSString *arbitraryAttrPrefix = @"attribute/";
26
26
 
27
- id<FBResponsePayload> FBResponseWithOK()
27
+ id<FBResponsePayload> FBResponseWithOK(void)
28
28
  {
29
29
  return FBResponseWithStatus(FBCommandStatus.ok);
30
30
  }
@@ -502,7 +502,9 @@ static NSNumberFormatter *numberFormatter = nil;
502
502
  return [[FBErrorBuilder.builder withDescription:fullDescription] build];
503
503
  }
504
504
 
505
- + (nullable FBClassChain*)compiledQueryWithTokenizedQuery:(NSArray<FBBaseClassChainToken *> *)tokenizedQuery originalQuery:(NSString *)originalQuery error:(NSError **)error
505
+ + (nullable FBClassChain*)compiledQueryWithTokenizedQuery:(NSArray<FBBaseClassChainToken *> *)tokenizedQuery
506
+ originalQuery:(NSString *)originalQuery
507
+ error:(NSError **)error
506
508
  {
507
509
  NSMutableArray *result = [NSMutableArray array];
508
510
  XCUIElementType chainElementType = XCUIElementTypeAny;
@@ -514,8 +516,10 @@ static NSNumberFormatter *numberFormatter = nil;
514
516
  for (FBBaseClassChainToken *token in tokenizedQuery) {
515
517
  if ([token isKindOfClass:FBClassNameToken.class]) {
516
518
  if (isTypeSet) {
517
- NSString *description = [NSString stringWithFormat:@"Unexpected token '%@'. The type name can be set only once.", token.asString];
518
- *error = [self.class compilationErrorWithQuery:originalQuery description:description];
519
+ if (error) {
520
+ NSString *description = [NSString stringWithFormat:@"Unexpected token '%@'. The type name can be set only once.", token.asString];
521
+ *error = [self.class compilationErrorWithQuery:originalQuery description:description];
522
+ }
519
523
  return nil;
520
524
  }
521
525
  @try {
@@ -523,16 +527,20 @@ static NSNumberFormatter *numberFormatter = nil;
523
527
  isTypeSet = YES;
524
528
  } @catch (NSException *e) {
525
529
  if ([e.name isEqualToString:FBInvalidArgumentException]) {
526
- NSString *description = [NSString stringWithFormat:@"'%@' class name is unknown to WDA", token.asString];
527
- *error = [self.class compilationErrorWithQuery:originalQuery description:description];
530
+ if (error) {
531
+ NSString *description = [NSString stringWithFormat:@"'%@' class name is unknown to WDA", token.asString];
532
+ *error = [self.class compilationErrorWithQuery:originalQuery description:description];
533
+ }
528
534
  return nil;
529
535
  }
530
536
  @throw e;
531
537
  }
532
538
  } else if ([token isKindOfClass:FBStarToken.class]) {
533
539
  if (isTypeSet) {
534
- NSString *description = [NSString stringWithFormat:@"Unexpected token '%@'. The type name can be set only once.", token.asString];
535
- *error = [self.class compilationErrorWithQuery:originalQuery description:description];
540
+ if (error) {
541
+ NSString *description = [NSString stringWithFormat:@"Unexpected token '%@'. The type name can be set only once.", token.asString];
542
+ *error = [self.class compilationErrorWithQuery:originalQuery description:description];
543
+ }
536
544
  return nil;
537
545
  }
538
546
  chainElementType = XCUIElementTypeAny;
@@ -540,7 +548,9 @@ static NSNumberFormatter *numberFormatter = nil;
540
548
  } else if ([token isKindOfClass:FBDescendantMarkerToken.class]) {
541
549
  if (isDescendantSet) {
542
550
  NSString *description = [NSString stringWithFormat:@"Unexpected token '%@'. Descendant markers cannot be duplicated.", token.asString];
543
- *error = [self.class compilationErrorWithQuery:originalQuery description:description];
551
+ if (error) {
552
+ *error = [self.class compilationErrorWithQuery:originalQuery description:description];
553
+ }
544
554
  return nil;
545
555
  }
546
556
  isTypeSet = NO;
@@ -550,12 +560,16 @@ static NSNumberFormatter *numberFormatter = nil;
550
560
  } else if ([token isKindOfClass:FBAbstractPredicateToken.class]) {
551
561
  if (isPositionSet) {
552
562
  NSString *description = [NSString stringWithFormat:@"Predicate value '%@' must be set before position value.", token.asString];
553
- *error = [self.class compilationErrorWithQuery:originalQuery description:description];
563
+ if (error) {
564
+ *error = [self.class compilationErrorWithQuery:originalQuery description:description];
565
+ }
554
566
  return nil;
555
567
  }
556
568
  if (!((FBAbstractPredicateToken *)token).isParsingCompleted) {
557
569
  NSString *description = [NSString stringWithFormat:@"Cannot find the end of '%@' predicate value.", token.asString];
558
- *error = [self.class compilationErrorWithQuery:originalQuery description:description];
570
+ if (error) {
571
+ *error = [self.class compilationErrorWithQuery:originalQuery description:description];
572
+ }
559
573
  return nil;
560
574
  }
561
575
  NSPredicate *value = [NSPredicate fb_snapshotBlockPredicateWithPredicate:[NSPredicate predicateWithFormat:token.asString]];
@@ -567,13 +581,17 @@ static NSNumberFormatter *numberFormatter = nil;
567
581
  } else if ([token isKindOfClass:FBNumberToken.class]) {
568
582
  if (isPositionSet) {
569
583
  NSString *description = [NSString stringWithFormat:@"Position value '%@' is expected to be set only once.", token.asString];
570
- *error = [self.class compilationErrorWithQuery:originalQuery description:description];
584
+ if (error) {
585
+ *error = [self.class compilationErrorWithQuery:originalQuery description:description];
586
+ }
571
587
  return nil;
572
588
  }
573
589
  NSNumber *position = [numberFormatter numberFromString:token.asString];
574
590
  if (nil == position || 0 == position.intValue) {
575
591
  NSString *description = [NSString stringWithFormat:@"Position value '%@' is expected to be a valid integer number not equal to zero.", token.asString];
576
- *error = [self.class compilationErrorWithQuery:originalQuery description:description];
592
+ if (error) {
593
+ *error = [self.class compilationErrorWithQuery:originalQuery description:description];
594
+ }
577
595
  return nil;
578
596
  }
579
597
  chainElementPosition = position;
@@ -602,8 +620,10 @@ static NSNumberFormatter *numberFormatter = nil;
602
620
  if (isTypeSet) {
603
621
  [result addObject:[[FBClassChainItem alloc] initWithType:chainElementType position:chainElementPosition predicates:predicates.copy isDescendant:YES]];
604
622
  } else {
605
- NSString *description = @"Descendants lookup modifier '**/' should be followed with the actual element type";
606
- *error = [self.class compilationErrorWithQuery:originalQuery description:description];
623
+ if (error) {
624
+ NSString *description = @"Descendants lookup modifier '**/' should be followed with the actual element type";
625
+ *error = [self.class compilationErrorWithQuery:originalQuery description:description];
626
+ }
607
627
  return nil;
608
628
  }
609
629
  } else {
@@ -47,7 +47,7 @@ void *FBRetrieveSymbolFromBinary(const char *binary, const char *name)
47
47
 
48
48
  static NSString *sdkVersion = nil;
49
49
  static dispatch_once_t onceSdkVersionToken;
50
- NSString * _Nullable FBSDKVersion()
50
+ NSString * _Nullable FBSDKVersion(void)
51
51
  {
52
52
  dispatch_once(&onceSdkVersionToken, ^{
53
53
  NSString *sdkName = [[NSBundle mainBundle] infoDictionary][@"DTSDKName"];
@@ -14,9 +14,6 @@ NS_ASSUME_NONNULL_BEGIN
14
14
 
15
15
  @protocol XCTestManager_ManagerInterface;
16
16
 
17
- /**
18
- Temporary class used to abstract interactions with TestManager daemon between Xcode 8.2.1 and Xcode 8.3-beta
19
- */
20
17
  @interface FBXCTestDaemonsProxy : NSObject
21
18
 
22
19
  + (id<XCTestManager_ManagerInterface>)testRunnerProxy;
@@ -28,6 +25,9 @@ NS_ASSUME_NONNULL_BEGIN
28
25
  + (BOOL)synthesizeEventWithRecord:(XCSynthesizedEventRecord *)record
29
26
  error:(NSError *__autoreleasing*)error;
30
27
 
28
+ + (BOOL)openURL:(NSURL *)url usingApplication:(NSString *)bundleId error:(NSError **)error;
29
+ + (BOOL)openDefaultApplicationForURL:(NSURL *)url error:(NSError **)error;
30
+
31
31
  @end
32
32
 
33
33
  NS_ASSUME_NONNULL_END
@@ -12,6 +12,7 @@
12
12
  #import <objc/runtime.h>
13
13
 
14
14
  #import "FBConfiguration.h"
15
+ #import "FBErrorBuilder.h"
15
16
  #import "FBLogger.h"
16
17
  #import "FBRunLoopSpinner.h"
17
18
  #import "XCTestDriver.h"
@@ -96,4 +97,54 @@ static dispatch_once_t onceTestRunnerDaemonClass;
96
97
  return didSucceed;
97
98
  }
98
99
 
100
+ + (BOOL)openURL:(NSURL *)url usingApplication:(NSString *)bundleId error:(NSError *__autoreleasing*)error
101
+ {
102
+ XCTRunnerDaemonSession *session = [FBXCTRunnerDaemonSessionClass sharedSession];
103
+ if (![session respondsToSelector:@selector(openURL:usingApplication:completion:)]) {
104
+ if (error) {
105
+ [[[FBErrorBuilder builder]
106
+ withDescriptionFormat:@"The current Xcode SDK does not support opening of URLs with given application"]
107
+ buildError:error];
108
+ }
109
+ return NO;
110
+ }
111
+
112
+ __block BOOL didSucceed = NO;
113
+ [FBRunLoopSpinner spinUntilCompletion:^(void(^completion)(void)){
114
+ [session openURL:url usingApplication:bundleId completion:^(bool result, NSError *invokeError) {
115
+ if (error) {
116
+ *error = invokeError;
117
+ }
118
+ didSucceed = invokeError == nil && result;
119
+ completion();
120
+ }];
121
+ }];
122
+ return didSucceed;
123
+ }
124
+
125
+ + (BOOL)openDefaultApplicationForURL:(NSURL *)url error:(NSError *__autoreleasing*)error
126
+ {
127
+ XCTRunnerDaemonSession *session = [FBXCTRunnerDaemonSessionClass sharedSession];
128
+ if (![session respondsToSelector:@selector(openDefaultApplicationForURL:completion:)]) {
129
+ if (error) {
130
+ [[[FBErrorBuilder builder]
131
+ withDescriptionFormat:@"The current Xcode SDK does not support opening of URLs. Consider upgrading to Xcode 14.3+/iOS 16.4+"]
132
+ buildError:error];
133
+ }
134
+ return NO;
135
+ }
136
+
137
+ __block BOOL didSucceed = NO;
138
+ [FBRunLoopSpinner spinUntilCompletion:^(void(^completion)(void)){
139
+ [session openDefaultApplicationForURL:url completion:^(bool result, NSError *invokeError) {
140
+ if (error) {
141
+ *error = invokeError;
142
+ }
143
+ didSucceed = invokeError == nil && result;
144
+ completion();
145
+ }];
146
+ }];
147
+ return didSucceed;
148
+ }
149
+
99
150
  @end
@@ -118,15 +118,32 @@
118
118
  XCTAssertNil(error);
119
119
  }
120
120
 
121
- - (void)disabled_testUrlSchemeActivation
121
+ - (void)testUrlSchemeActivation
122
122
  {
123
- // This test is not stable on CI because of system slowness
123
+ if (SYSTEM_VERSION_LESS_THAN(@"16.4")) {
124
+ return;
125
+ }
126
+
124
127
  NSError *error;
125
128
  XCTAssertTrue([XCUIDevice.sharedDevice fb_openUrl:@"https://apple.com" error:&error]);
126
129
  FBAssertWaitTillBecomesTrue([FBApplication.fb_activeApplication.bundleID isEqualToString:@"com.apple.mobilesafari"]);
127
130
  XCTAssertNil(error);
128
131
  }
129
132
 
133
+ - (void)testUrlSchemeActivationWithApp
134
+ {
135
+ if (SYSTEM_VERSION_LESS_THAN(@"16.4")) {
136
+ return;
137
+ }
138
+
139
+ NSError *error;
140
+ XCTAssertTrue([XCUIDevice.sharedDevice fb_openUrl:@"https://apple.com"
141
+ withApplication:@"com.apple.mobilesafari"
142
+ error:&error]);
143
+ FBAssertWaitTillBecomesTrue([FBApplication.fb_activeApplication.bundleID isEqualToString:@"com.apple.mobilesafari"]);
144
+ XCTAssertNil(error);
145
+ }
146
+
130
147
  - (void)testPressingUnsupportedButton
131
148
  {
132
149
  NSError *error;
@@ -29,7 +29,7 @@
29
29
  xmlTextWriterPtr writer = xmlNewTextWriterDoc(&doc, 0);
30
30
  NSMutableDictionary *elementStore = [NSMutableDictionary dictionary];
31
31
  int buffersize;
32
- xmlChar *xmlbuff;
32
+ xmlChar *xmlbuff = NULL;
33
33
  int rc = xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);
34
34
  if (rc >= 0) {
35
35
  rc = [FBXPath xmlRepresentationWithRootElement:element
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-webdriveragent",
3
- "version": "4.10.24",
3
+ "version": "4.11.0",
4
4
  "description": "Package bundling WebDriverAgent",
5
5
  "main": "./build/index.js",
6
6
  "scripts": {