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.
- package/CHANGELOG.md +12 -0
- package/WebDriverAgentMac/IntegrationTests/AMFindElementTests.m +165 -2
- package/WebDriverAgentMac/IntegrationTests/AMIntegrationTestCase.h +11 -0
- package/WebDriverAgentMac/IntegrationTests/AMIntegrationTestCase.m +33 -0
- package/WebDriverAgentMac/IntegrationTests/AMW3CActionsTests.m +7 -9
- package/WebDriverAgentMac/WebDriverAgent/Base.lproj/Main.storyboard +16 -1
- package/WebDriverAgentMac/WebDriverAgent/WebViewController.h +21 -0
- package/WebDriverAgentMac/WebDriverAgent/WebViewController.m +49 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Categories/NSPredicate+FBFormat.m +80 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Categories/XCUIElement+AMAttributes.h +29 -1
- package/WebDriverAgentMac/WebDriverAgentLib/Categories/XCUIElement+AMAttributes.m +66 -15
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMHTTPServer.h +84 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMHTTPServer.m +493 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMTCPSocket.h +109 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMTCPSocket.m +235 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBWebServer.h +1 -1
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBWebServer.m +9 -21
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/RouteRequest.h +36 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/RouteRequest.m +33 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/RouteResponse.h +37 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/RouteResponse.m +62 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMSnapshotUtils.h +22 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMSnapshotUtils.m +5 -11
- package/WebDriverAgentMac/WebDriverAgentLib/Utilities/FBElementUtils.m +7 -1
- package/WebDriverAgentMac/WebDriverAgentMac.xcodeproj/project.pbxproj +46 -180
- package/npm-shrinkwrap.json +75 -146
- package/package.json +2 -1
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.h +0 -1226
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.m +0 -8513
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncUdpSocket.h +0 -1036
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncUdpSocket.m +0 -5632
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDNumber.h +0 -12
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDNumber.m +0 -88
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDRange.h +0 -56
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDRange.m +0 -106
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPConnection.h +0 -107
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPConnection.m +0 -2238
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPLogging.h +0 -122
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPMessage.h +0 -48
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPMessage.m +0 -114
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPResponse.h +0 -149
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPServer.h +0 -200
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPServer.m +0 -720
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPDataResponse.h +0 -13
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPDataResponse.m +0 -83
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPErrorResponse.h +0 -9
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPErrorResponse.m +0 -40
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/HTTPResponseProxy.h +0 -13
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/HTTPResponseProxy.m +0 -84
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/Route.h +0 -18
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/Route.m +0 -11
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteRequest.h +0 -16
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteRequest.m +0 -50
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteResponse.h +0 -20
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteResponse.m +0 -66
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingConnection.h +0 -5
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingConnection.m +0 -142
- package/WebDriverAgentMac/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingHTTPServer.h +0 -55
- 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,8 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
#import "FBWebServer.h"
|
|
11
11
|
|
|
12
|
-
#import "
|
|
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)
|
|
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 = [[
|
|
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:(
|
|
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
|
-
|
|
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;
|