appium-mac2-driver 4.1.1 → 4.3.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/WebDriverAgentMac/IntegrationTests/AMFindElementTests.m +165 -2
  3. package/WebDriverAgentMac/IntegrationTests/AMIntegrationTestCase.h +11 -0
  4. package/WebDriverAgentMac/IntegrationTests/AMIntegrationTestCase.m +33 -0
  5. package/WebDriverAgentMac/IntegrationTests/AMW3CActionsTests.m +7 -9
  6. package/WebDriverAgentMac/WebDriverAgent/Base.lproj/Main.storyboard +16 -1
  7. package/WebDriverAgentMac/WebDriverAgent/WebViewController.h +21 -0
  8. package/WebDriverAgentMac/WebDriverAgent/WebViewController.m +49 -0
  9. package/WebDriverAgentMac/WebDriverAgentLib/Categories/NSPredicate+FBFormat.m +80 -0
  10. package/WebDriverAgentMac/WebDriverAgentLib/Categories/XCUIElement+AMAttributes.h +29 -1
  11. package/WebDriverAgentMac/WebDriverAgentLib/Categories/XCUIElement+AMAttributes.m +66 -15
  12. package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMHTTPServer.h +84 -0
  13. package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMHTTPServer.m +493 -0
  14. package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMTCPSocket.h +109 -0
  15. package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMTCPSocket.m +235 -0
  16. package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBWebServer.h +1 -1
  17. package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBWebServer.m +9 -21
  18. package/WebDriverAgentMac/WebDriverAgentLib/Routing/RouteRequest.h +36 -0
  19. package/WebDriverAgentMac/WebDriverAgentLib/Routing/RouteRequest.m +33 -0
  20. package/WebDriverAgentMac/WebDriverAgentLib/Routing/RouteResponse.h +37 -0
  21. package/WebDriverAgentMac/WebDriverAgentLib/Routing/RouteResponse.m +62 -0
  22. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMSnapshotUtils.h +22 -0
  23. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMSnapshotUtils.m +5 -11
  24. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/FBElementUtils.m +7 -1
  25. package/WebDriverAgentMac/WebDriverAgentMac.xcodeproj/project.pbxproj +46 -180
  26. package/npm-shrinkwrap.json +75 -146
  27. package/package.json +2 -1
  28. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.h +0 -1226
  29. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.m +0 -8513
  30. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncUdpSocket.h +0 -1036
  31. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncUdpSocket.m +0 -5632
  32. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDNumber.h +0 -12
  33. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDNumber.m +0 -88
  34. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDRange.h +0 -56
  35. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDRange.m +0 -106
  36. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPConnection.h +0 -107
  37. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPConnection.m +0 -2238
  38. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPLogging.h +0 -122
  39. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPMessage.h +0 -48
  40. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPMessage.m +0 -114
  41. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPResponse.h +0 -149
  42. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPServer.h +0 -200
  43. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPServer.m +0 -720
  44. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPDataResponse.h +0 -13
  45. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPDataResponse.m +0 -83
  46. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPErrorResponse.h +0 -9
  47. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPErrorResponse.m +0 -40
  48. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/HTTPResponseProxy.h +0 -13
  49. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/HTTPResponseProxy.m +0 -84
  50. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/Route.h +0 -18
  51. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/Route.m +0 -11
  52. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteRequest.h +0 -16
  53. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteRequest.m +0 -50
  54. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteResponse.h +0 -20
  55. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteResponse.m +0 -66
  56. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingConnection.h +0 -5
  57. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingConnection.m +0 -142
  58. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingHTTPServer.h +0 -55
  59. package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingHTTPServer.m +0 -288
@@ -0,0 +1,235 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * See the NOTICE file distributed with this work for additional
5
+ * information regarding copyright ownership.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #import "AMTCPSocket.h"
18
+
19
+ @interface AMTCPSocket ()
20
+ @property (readonly, nonatomic) dispatch_queue_t socketQueue;
21
+ @property (nullable, nonatomic) nw_listener_t listener;
22
+ @property (readonly, nonatomic) NSMutableArray<nw_connection_t> *connectedClients;
23
+ @end
24
+
25
+
26
+ @implementation AMTCPSocket
27
+
28
+ - (instancetype)initWithPort:(uint16_t)port
29
+ {
30
+ if ((self = [super init])) {
31
+ _socketQueue = dispatch_queue_create("socketQueue", NULL);
32
+ _connectedClients = [[NSMutableArray alloc] initWithCapacity:1];
33
+ _port = port;
34
+ _delegate = nil;
35
+ }
36
+ return self;
37
+ }
38
+
39
+ - (BOOL)startWithError:(NSError **)error
40
+ {
41
+ nw_parameters_t parameters = nw_parameters_create_secure_tcp(NW_PARAMETERS_DISABLE_PROTOCOL,
42
+ NW_PARAMETERS_DEFAULT_CONFIGURATION);
43
+ NSString *portString = [NSString stringWithFormat:@"%u", (unsigned int)self.port];
44
+ const char * _Nonnull portCString = (const char * _Nonnull)portString.UTF8String;
45
+
46
+ nw_listener_t listener;
47
+ if (nil != self.interface) {
48
+ const char * _Nonnull interfaceCString = (const char * _Nonnull)((NSString * _Nonnull)self.interface).UTF8String;
49
+ nw_endpoint_t localEndpoint = nw_endpoint_create_host(interfaceCString, portCString);
50
+ nw_parameters_set_local_endpoint(parameters, localEndpoint);
51
+ // The port is already encoded in localEndpoint above - do not also pass it to
52
+ // nw_listener_create_with_port, which would be ambiguous.
53
+ listener = nw_listener_create(parameters);
54
+ } else {
55
+ listener = nw_listener_create_with_port(portCString, parameters);
56
+ }
57
+ if (nil == listener) {
58
+ if (error) {
59
+ *error = [NSError errorWithDomain:@"AMTCPSocket"
60
+ code:1
61
+ userInfo:@{NSLocalizedDescriptionKey: @"Failed to create the TCP listener"}];
62
+ }
63
+ return NO;
64
+ }
65
+ self.listener = listener;
66
+
67
+ __weak typeof(self) weakSelf = self;
68
+ nw_listener_set_queue(listener, self.socketQueue);
69
+ nw_listener_set_new_connection_handler(listener, ^(nw_connection_t connection) {
70
+ [weakSelf acceptConnection:connection];
71
+ });
72
+
73
+ dispatch_semaphore_t startupSemaphore = dispatch_semaphore_create(0);
74
+ __block NSError *startupError = nil;
75
+ nw_listener_set_state_changed_handler(listener, ^(nw_listener_state_t state, nw_error_t nwError) {
76
+ if (nw_listener_state_ready == state) {
77
+ __strong typeof(weakSelf) strongSelf = weakSelf;
78
+ if (strongSelf) {
79
+ strongSelf->_port = nw_listener_get_port(listener);
80
+ }
81
+ dispatch_semaphore_signal(startupSemaphore);
82
+ } else if (nw_listener_state_failed == state || nw_listener_state_cancelled == state) {
83
+ // NSLocalizedDescriptionKey must be a string, not the underlying NSError itself, or
84
+ // -[NSError localizedDescription] crashes trying to treat it as one.
85
+ NSError *underlyingError = nwError ? (NSError *)CFBridgingRelease(nw_error_copy_cf_error(nwError)) : nil;
86
+ if ([underlyingError.domain isEqualToString:NSPOSIXErrorDomain]) {
87
+ // Surface POSIX errors (e.g. EADDRINUSE) directly, since callers like FBWebServer check
88
+ // for them by domain/code on the top-level error to decide whether to retry another port.
89
+ startupError = underlyingError;
90
+ } else {
91
+ NSMutableDictionary<NSString *, id> *userInfo = [NSMutableDictionary dictionary];
92
+ userInfo[NSLocalizedDescriptionKey] = underlyingError.localizedDescription ?: @"The TCP listener failed to start";
93
+ if (underlyingError) {
94
+ userInfo[NSUnderlyingErrorKey] = underlyingError;
95
+ }
96
+ startupError = [NSError errorWithDomain:@"AMTCPSocket" code:2 userInfo:userInfo];
97
+ }
98
+ dispatch_semaphore_signal(startupSemaphore);
99
+ }
100
+ });
101
+ nw_listener_start(listener);
102
+ BOOL didStartInTime = 0 == dispatch_semaphore_wait(startupSemaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)));
103
+ if (!didStartInTime) {
104
+ startupError = [NSError errorWithDomain:@"AMTCPSocket"
105
+ code:3
106
+ userInfo:@{NSLocalizedDescriptionKey: @"Timed out while starting the TCP listener"}];
107
+ }
108
+ if (nil != startupError) {
109
+ if (error) {
110
+ *error = startupError;
111
+ }
112
+ // Cancel rather than just dropping our reference - otherwise a late ready/failed callback
113
+ // can still fire and the port stays bound at the OS level even though the caller was told
114
+ // startup failed.
115
+ nw_listener_cancel(listener);
116
+ self.listener = nil;
117
+ return NO;
118
+ }
119
+ return YES;
120
+ }
121
+
122
+ - (void)acceptConnection:(nw_connection_t)connection
123
+ {
124
+ @synchronized (self.connectedClients) {
125
+ [self.connectedClients addObject:connection];
126
+ }
127
+
128
+ __weak typeof(self) weakSelf = self;
129
+ nw_connection_set_queue(connection, self.socketQueue);
130
+ nw_connection_set_state_changed_handler(connection, ^(nw_connection_state_t state, nw_error_t connectionError) {
131
+ if (nw_connection_state_ready == state) {
132
+ __strong typeof(weakSelf) strongSelf = weakSelf;
133
+ if (nil == strongSelf) {
134
+ return;
135
+ }
136
+ id<AMTCPSocketDelegate> delegate = strongSelf.delegate;
137
+ if (nil != delegate) {
138
+ [delegate didClientConnect:connection];
139
+ }
140
+ [strongSelf scheduleReceiveForConnection:connection];
141
+ } else if (nw_connection_state_failed == state || nw_connection_state_cancelled == state) {
142
+ [weakSelf handleDisconnectForConnection:connection];
143
+ }
144
+ });
145
+ nw_connection_start(connection);
146
+ }
147
+
148
+ - (void)scheduleReceiveForConnection:(nw_connection_t)connection
149
+ {
150
+ __weak typeof(self) weakSelf = self;
151
+ nw_connection_receive(connection, 1, UINT32_MAX, ^(dispatch_data_t _Nullable content,
152
+ nw_content_context_t _Nullable context,
153
+ bool isComplete,
154
+ nw_error_t _Nullable receiveError) {
155
+ __strong typeof(weakSelf) strongSelf = weakSelf;
156
+ if (nil == strongSelf) {
157
+ return;
158
+ }
159
+ if (nil != content) {
160
+ dispatch_data_t nonnullContent = (dispatch_data_t _Nonnull)content;
161
+ NSMutableData *data = [NSMutableData data];
162
+ dispatch_data_apply(nonnullContent, ^bool(dispatch_data_t _Nonnull region, size_t offset, const void * _Nonnull buffer, size_t size) {
163
+ [data appendBytes:buffer length:size];
164
+ return true;
165
+ });
166
+ if (data.length > 0) {
167
+ id<AMTCPSocketDelegate> delegate = strongSelf.delegate;
168
+ if (nil != delegate) {
169
+ [delegate client:connection didReceiveData:data];
170
+ }
171
+ }
172
+ }
173
+ if (nil != receiveError || (isComplete && nil == content)) {
174
+ [strongSelf handleDisconnectForConnection:connection];
175
+ return;
176
+ }
177
+ [strongSelf scheduleReceiveForConnection:connection];
178
+ });
179
+ }
180
+
181
+ - (void)handleDisconnectForConnection:(nw_connection_t)connection
182
+ {
183
+ BOOL wasConnected;
184
+ @synchronized (self.connectedClients) {
185
+ wasConnected = [self.connectedClients containsObject:connection];
186
+ [self.connectedClients removeObject:connection];
187
+ }
188
+ if (wasConnected) {
189
+ id<AMTCPSocketDelegate> delegate = self.delegate;
190
+ if (nil != delegate) {
191
+ [delegate didClientDisconnect:connection];
192
+ }
193
+ }
194
+ }
195
+
196
+ - (void)writeData:(NSData *)data toClient:(nw_connection_t)client
197
+ {
198
+ [self writeData:data toClient:client completion:nil];
199
+ }
200
+
201
+ - (void)writeData:(NSData *)data toClient:(nw_connection_t)client completion:(nullable void (^)(void))completion
202
+ {
203
+ dispatch_data_t dispatchData = dispatch_data_create(data.bytes, data.length, self.socketQueue, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
204
+ nw_connection_send(client, dispatchData, NW_CONNECTION_DEFAULT_STREAM_CONTEXT, false, ^(nw_error_t _Nullable sendError) {
205
+ if (completion) {
206
+ completion();
207
+ }
208
+ });
209
+ }
210
+
211
+ - (void)stop
212
+ {
213
+ NSArray<nw_connection_t> *clients;
214
+ @synchronized (self.connectedClients) {
215
+ clients = self.connectedClients.copy;
216
+ [self.connectedClients removeAllObjects];
217
+ }
218
+ // Cancel on socketQueue, the same queue every connection's send/receive is bound to (see
219
+ // -acceptConnection:), so a write already issued just before -stop (e.g. a shutdown route's
220
+ // response) is processed before the cancellation rather than racing it.
221
+ dispatch_async(self.socketQueue, ^{
222
+ for (nw_connection_t client in clients) {
223
+ nw_connection_cancel(client);
224
+ }
225
+ });
226
+
227
+ self.delegate = nil;
228
+ nw_listener_t listener = self.listener;
229
+ if (nil != listener) {
230
+ nw_listener_cancel((nw_listener_t _Nonnull)listener);
231
+ self.listener = nil;
232
+ }
233
+ }
234
+
235
+ @end
@@ -9,7 +9,7 @@
9
9
 
10
10
  #import <Foundation/Foundation.h>
11
11
 
12
- @class RouteResponse, RoutingHTTPServer, FBExceptionHandler;
12
+ @class RouteResponse, AMHTTPServer, FBExceptionHandler;
13
13
  @protocol FBWebServerDelegate;
14
14
 
15
15
  NS_ASSUME_NONNULL_BEGIN
@@ -9,8 +9,7 @@
9
9
 
10
10
  #import "FBWebServer.h"
11
11
 
12
- #import "RoutingConnection.h"
13
- #import "RoutingHTTPServer.h"
12
+ #import "AMHTTPServer.h"
14
13
 
15
14
  #import "FBCommandHandler.h"
16
15
  #import "FBErrorBuilder.h"
@@ -25,23 +24,9 @@
25
24
  static NSString *const FBServerURLBeginMarker = @"ServerURLHere->";
26
25
  static NSString *const FBServerURLEndMarker = @"<-ServerURLHere";
27
26
 
28
- @interface FBHTTPConnection : RoutingConnection
29
- @end
30
-
31
- @implementation FBHTTPConnection
32
-
33
- - (void)handleResourceNotFound
34
- {
35
- [FBLogger logFmt:@"Received request for %@ which we do not handle", self.requestURI];
36
- [super handleResourceNotFound];
37
- }
38
-
39
- @end
40
-
41
-
42
27
  @interface FBWebServer ()
43
28
  @property (nonatomic, strong) FBExceptionHandler *exceptionHandler;
44
- @property (nonatomic, strong) RoutingHTTPServer *server;
29
+ @property (nonatomic, strong) AMHTTPServer *server;
45
30
  @property (atomic, assign) BOOL keepAlive;
46
31
  @end
47
32
 
@@ -76,13 +61,12 @@ static NSString *const FBServerURLEndMarker = @"<-ServerURLHere";
76
61
 
77
62
  - (void)startHTTPServer
78
63
  {
79
- self.server = [[RoutingHTTPServer alloc] init];
64
+ self.server = [[AMHTTPServer alloc] init];
80
65
  [self.server setRouteQueue:dispatch_get_main_queue()];
81
66
  [self.server setInterface:FBConfiguration.sharedConfiguration.serverInterface];
82
67
  [self.server setDefaultHeader:@"Server" value:@"WebDriverAgent/1.0"];
83
68
  [self.server setDefaultHeader:@"Access-Control-Allow-Origin" value:@"*"];
84
69
  [self.server setDefaultHeader:@"Access-Control-Allow-Headers" value:@"Content-Type, X-Requested-With"];
85
- [self.server setConnectionClass:[FBHTTPConnection self]];
86
70
 
87
71
  [self registerRouteHandlers:[self.class collectCommandHandlerClasses]];
88
72
  [self registerServerKeyRouteHandlers];
@@ -119,7 +103,7 @@ static NSString *const FBServerURLEndMarker = @"<-ServerURLHere";
119
103
  self.keepAlive = NO;
120
104
  }
121
105
 
122
- - (BOOL)attemptToStartServer:(RoutingHTTPServer *)server onPort:(NSInteger)port withError:(NSError **)error
106
+ - (BOOL)attemptToStartServer:(AMHTTPServer *)server onPort:(NSInteger)port withError:(NSError **)error
123
107
  {
124
108
  server.port = (UInt16)port;
125
109
  NSError *innerError = nil;
@@ -195,7 +179,11 @@ static NSString *const FBServerURLEndMarker = @"<-ServerURLHere";
195
179
  [FBSession.activeSession kill];
196
180
  } @finally {
197
181
  [response respondWithString:@"Shutting down"];
198
- [self.delegate webServerDidRequestShutdown:self];
182
+ // Deferred so the "Shutting down" response is written to the client before
183
+ // webServerDidRequestShutdown: tears down the server's socket out from under it.
184
+ dispatch_async(dispatch_get_main_queue(), ^{
185
+ [self.delegate webServerDidRequestShutdown:self];
186
+ });
199
187
  }
200
188
  }];
201
189
 
@@ -0,0 +1,36 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * See the NOTICE file distributed with this work for additional
5
+ * information regarding copyright ownership.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ // A minimal request value type, exposing just the surface FBWebServer's route blocks and
18
+ // FBRoute.decorateRequest: read.
19
+
20
+ #import <Foundation/Foundation.h>
21
+
22
+ NS_ASSUME_NONNULL_BEGIN
23
+
24
+ @interface RouteRequest : NSObject
25
+
26
+ @property (nonatomic, copy, readonly) NSURL *url;
27
+ @property (nonatomic, copy, readonly) NSDictionary<NSString *, NSString *> *params;
28
+ @property (nonatomic, copy, readonly) NSData *body;
29
+
30
+ - (instancetype)initWithURL:(NSURL *)url
31
+ params:(NSDictionary<NSString *, NSString *> *)params
32
+ body:(NSData *)body;
33
+
34
+ @end
35
+
36
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,33 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * See the NOTICE file distributed with this work for additional
5
+ * information regarding copyright ownership.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #import "RouteRequest.h"
18
+
19
+ @implementation RouteRequest
20
+
21
+ - (instancetype)initWithURL:(NSURL *)url
22
+ params:(NSDictionary<NSString *, NSString *> *)params
23
+ body:(NSData *)body
24
+ {
25
+ if ((self = [super init])) {
26
+ _url = url.copy;
27
+ _params = params.copy;
28
+ _body = body.copy;
29
+ }
30
+ return self;
31
+ }
32
+
33
+ @end
@@ -0,0 +1,37 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * See the NOTICE file distributed with this work for additional
5
+ * information regarding copyright ownership.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ // A minimal response value type, exposing just the surface FBRoute.m/FBResponseJSONPayload.m
18
+ // call on it.
19
+
20
+ #import <Foundation/Foundation.h>
21
+
22
+ NS_ASSUME_NONNULL_BEGIN
23
+
24
+ @interface RouteResponse : NSObject
25
+
26
+ @property (nonatomic) NSInteger statusCode;
27
+ @property (nonatomic, copy, readonly) NSDictionary<NSString *, NSString *> *headers;
28
+ @property (nonatomic, copy, readonly, nullable) NSData *responseData;
29
+
30
+ - (void)setHeader:(NSString *)field value:(NSString *)value;
31
+ - (void)respondWithString:(NSString *)string;
32
+ - (void)respondWithString:(NSString *)string encoding:(NSStringEncoding)encoding;
33
+ - (void)respondWithData:(NSData *)data;
34
+
35
+ @end
36
+
37
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,62 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * See the NOTICE file distributed with this work for additional
5
+ * information regarding copyright ownership.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #import "RouteResponse.h"
18
+
19
+ @interface RouteResponse ()
20
+ @property (nonatomic, copy) NSMutableDictionary<NSString *, NSString *> *mutableHeaders;
21
+ @end
22
+
23
+ @implementation RouteResponse
24
+
25
+ - (instancetype)init
26
+ {
27
+ if ((self = [super init])) {
28
+ _statusCode = 200;
29
+ _mutableHeaders = [NSMutableDictionary dictionary];
30
+ }
31
+ return self;
32
+ }
33
+
34
+ - (NSDictionary<NSString *, NSString *> *)headers
35
+ {
36
+ return self.mutableHeaders.copy;
37
+ }
38
+
39
+ - (void)setHeader:(NSString *)field value:(NSString *)value
40
+ {
41
+ self.mutableHeaders[field] = value;
42
+ }
43
+
44
+ - (void)respondWithData:(NSData *)data
45
+ {
46
+ _responseData = data.copy;
47
+ if (nil == self.mutableHeaders[@"Content-Length"]) {
48
+ self.mutableHeaders[@"Content-Length"] = [NSString stringWithFormat:@"%lu", (unsigned long)data.length];
49
+ }
50
+ }
51
+
52
+ - (void)respondWithString:(NSString *)string
53
+ {
54
+ [self respondWithString:string encoding:NSUTF8StringEncoding];
55
+ }
56
+
57
+ - (void)respondWithString:(NSString *)string encoding:(NSStringEncoding)encoding
58
+ {
59
+ [self respondWithData:[string dataUsingEncoding:encoding] ?: [NSData data]];
60
+ }
61
+
62
+ @end
@@ -43,6 +43,17 @@ NS_ASSUME_NONNULL_BEGIN
43
43
  */
44
44
  + (nullable NSString *)wdIdentifierWithSnapshot:(nullable id<XCUIElementSnapshot>)snapshot;
45
45
 
46
+ /**
47
+ Whether this process is trusted for the Accessibility API. WebKit DOM identifier
48
+ resolution silently yields no results without this, since AXDOMIdentifier reads
49
+ fail with kAXErrorAPIDisabled - useful for tests and diagnostics to tell "no DOM id
50
+ fallback happened because the setting is off" apart from "no DOM id fallback
51
+ happened because this process lacks Accessibility permission".
52
+
53
+ @return YES if AXDOMIdentifier reads are expected to work, NO otherwise
54
+ */
55
+ + (BOOL)isAccessibilityTrusted;
56
+
46
57
  /**
47
58
  Resolves snapshot hashes back to live elements below the given root element.
48
59
 
@@ -57,6 +68,17 @@ NS_ASSUME_NONNULL_BEGIN
57
68
  rootSnapshot:(id<XCUIElementSnapshot>)rootSnapshot
58
69
  includeOnlyFirstMatch:(BOOL)firstMatch;
59
70
 
71
+ /**
72
+ Reads the non-standard AXDOMIdentifier attribute, where WebKit publishes a web
73
+ node's HTML `id`. Returns nil for native elements, which report
74
+ kAXErrorAttributeUnsupported for it, or when this process lacks Accessibility
75
+ permission.
76
+
77
+ @param snapshot snapshot instance to read the DOM identifier from
78
+ @return The DOM identifier or nil
79
+ */
80
+ + (nullable NSString *)domIdentifierWithSnapshot:(nullable id)snapshot;
81
+
60
82
  @end
61
83
 
62
84
  NS_ASSUME_NONNULL_END
@@ -65,17 +65,6 @@ static BOOL AMIsAccessibilityTrusted(void)
65
65
  return isTrusted;
66
66
  }
67
67
 
68
- @interface AMSnapshotUtils ()
69
-
70
- /**
71
- Reads the non-standard AXDOMIdentifier attribute, where WebKit publishes a web
72
- node's HTML `id`. Returns nil for native elements, which report
73
- kAXErrorAttributeUnsupported for it.
74
- */
75
- + (nullable NSString *)domIdentifierWithSnapshot:(nullable id)snapshot;
76
-
77
- @end
78
-
79
68
  @implementation AMSnapshotUtils
80
69
 
81
70
  + (NSString *)hashWithSnapshot:(id)snapshot
@@ -94,6 +83,11 @@ static BOOL AMIsAccessibilityTrusted(void)
94
83
  return [self domIdentifierWithSnapshot:snapshot] ?: identifier;
95
84
  }
96
85
 
86
+ + (BOOL)isAccessibilityTrusted
87
+ {
88
+ return AMIsAccessibilityTrusted();
89
+ }
90
+
97
91
  + (NSArray<XCUIElement *> *)elementsWithHashes:(NSSet<NSString *> *)hashes
98
92
  rootElement:(XCUIElement *)rootElement
99
93
  rootSnapshot:(id<XCUIElementSnapshot>)rootSnapshot
@@ -11,6 +11,7 @@
11
11
 
12
12
  #import "FBExceptions.h"
13
13
  #import "FBMacros.h"
14
+ #import "XCUIElement+AMAttributes.h"
14
15
 
15
16
  @implementation FBElementUtils
16
17
 
@@ -43,7 +44,12 @@
43
44
  FBStringify(XCUIElement, title),
44
45
  FBStringify(XCUIElement, value),
45
46
  FBStringify(XCUIElement, frame),
46
- FBStringify(XCUIElement, identifier)
47
+ FBStringify(XCUIElement, identifier),
48
+ AM_IDENTIFIER_ATTRIBUTE_NAME,
49
+ AM_RECT_ATTRIBUTE_NAME,
50
+ AM_TEXT_ATTRIBUTE_NAME,
51
+ AM_TYPE_ATTRIBUTE_NAME,
52
+ AM_HAS_KEYBOARD_INPUT_FOCUS_ATTRIBUTE_NAME
47
53
  ];
48
54
  });
49
55
  return attributeNames;