appium-webdriveragent 16.14.0 → 16.14.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 +7 -0
- package/WebDriverAgentLib/Categories/XCAXClient_iOS+FBSnapshotReqParams.m +8 -0
- package/WebDriverAgentLib/Commands/FBCustomCommands.m +35 -10
- package/WebDriverAgentLib/Info.plist +2 -2
- package/WebDriverAgentTests/IntegrationApp/Classes/ViewController.m +15 -0
- package/WebDriverAgentTests/IntegrationTests/FBConfigurationTests.m +52 -0
- package/WebDriverAgentTests/IntegrationTests/FBScreenTests.m +142 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [16.14.1](https://github.com/appium/WebDriverAgent/compare/v16.14.0...v16.14.1) (2026-10-07)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
* report geometry for the selected display ([#1291](https://github.com/appium/WebDriverAgent/issues/1291)) ([43fa6da](https://github.com/appium/WebDriverAgent/commit/43fa6da647fb8adca21fdbd106d8f73d782d6717))
|
|
6
|
+
* skip accessibility idle checks for WebKit services ([#1293](https://github.com/appium/WebDriverAgent/issues/1293)) ([9d06611](https://github.com/appium/WebDriverAgent/commit/9d06611d1f5d342fd16458f707dca3f3e3ec00fc))
|
|
7
|
+
|
|
1
8
|
## [16.14.0](https://github.com/appium/WebDriverAgent/compare/v16.13.6...v16.14.0) (2026-10-04)
|
|
2
9
|
|
|
3
10
|
### Features
|
|
@@ -109,6 +109,14 @@ static id swizzledRequestSnapshotForElement(id self, SEL _cmd, id element, id at
|
|
|
109
109
|
return original_requestSnapshotForElement(self, _cmd, element, attributes, parameters, error);
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
// Remote WKWebView elements belong to a WebKit service, not the host app.
|
|
113
|
+
// Sending the idle-check AX action to WebContent can crash it (#1290).
|
|
114
|
+
// Read process metadata only: resolving UI attributes here can reenter
|
|
115
|
+
// snapshotting. Leave these services on the original snapshot path.
|
|
116
|
+
if ([application.bundleID hasPrefix:@"com.apple.WebKit."]) {
|
|
117
|
+
return original_requestSnapshotForElement(self, _cmd, element, attributes, parameters, error);
|
|
118
|
+
}
|
|
119
|
+
|
|
112
120
|
NSNumber *pidKey = @(pid);
|
|
113
121
|
@synchronized (unresponsiveApplicationPidsLock) {
|
|
114
122
|
NSDate *markedUnresponsiveAt = unresponsiveApplicationPids[pidKey];
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
#import "XCUIElement.h"
|
|
35
35
|
#import "XCUIElement+FBIsVisible.h"
|
|
36
36
|
#import "XCUIElementQuery.h"
|
|
37
|
+
#import "XCUIScreen.h"
|
|
37
38
|
#import "FBUnattachedAppLauncher.h"
|
|
38
39
|
|
|
39
40
|
@implementation FBCustomCommands
|
|
@@ -162,17 +163,41 @@
|
|
|
162
163
|
|
|
163
164
|
+ (id<FBResponsePayload>)handleGetScreen:(FBRouteRequest *)request
|
|
164
165
|
{
|
|
166
|
+
NSError *error = nil;
|
|
167
|
+
XCUIScreen *screen = [FBScreen currentScreenWithError:&error];
|
|
168
|
+
if (nil == screen) {
|
|
169
|
+
return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:error.localizedDescription
|
|
170
|
+
traceback:nil]);
|
|
171
|
+
}
|
|
165
172
|
XCUIApplication *app = XCUIApplication.fb_systemApplication;
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
CGSize screenSize = app.frame.size;
|
|
172
|
-
#else
|
|
173
|
-
CGSize screenSize = FBAdjustDimensionsForApplication(app.wdFrame.size, app.interfaceOrientation);
|
|
173
|
+
CGSize screenSize = CGSizeMake(CGRectGetWidth(screen.bounds) / screen.scale,
|
|
174
|
+
CGRectGetHeight(screen.bounds) / screen.scale);
|
|
175
|
+
#if !TARGET_OS_TV && !TARGET_OS_WATCH
|
|
176
|
+
XCUIApplication *activeApp = request.session ? request.session.activeApplication : XCUIApplication.fb_activeApplication;
|
|
177
|
+
screenSize = FBAdjustDimensionsForApplication(screenSize, activeApp.interfaceOrientation);
|
|
174
178
|
#endif
|
|
175
179
|
|
|
180
|
+
// SpringBoard can expose hidden status bars belonging to other displays, and
|
|
181
|
+
// Duo also exposes full-screen containers for its side-mounted status UI.
|
|
182
|
+
// Only a visible horizontal bar at the top of this display can be subtracted
|
|
183
|
+
// from a rectangular viewport.
|
|
184
|
+
CGSize statusBarSize = CGSizeZero;
|
|
185
|
+
for (XCUIElement *statusBar in app.statusBars.allElementsBoundByIndex) {
|
|
186
|
+
// Resolve the element before reading its screen: displayID can be zero on
|
|
187
|
+
// an unresolved query result even when the bar belongs to the main screen.
|
|
188
|
+
CGRect frame = statusBar.frame;
|
|
189
|
+
if (statusBar.screen.displayID != screen.displayID || !statusBar.fb_isVisible) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (fabs(CGRectGetMinY(frame)) <= 1 && fabs(CGRectGetMinX(frame)) <= 1
|
|
193
|
+
&& fabs(CGRectGetWidth(frame) - screenSize.width) <= 1
|
|
194
|
+
&& CGRectGetHeight(frame) > 0 && CGRectGetHeight(frame) < screenSize.height
|
|
195
|
+
&& CGRectGetHeight(frame) < CGRectGetWidth(frame)) {
|
|
196
|
+
statusBarSize = frame.size;
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
176
201
|
return FBResponseWithObject(
|
|
177
202
|
@{
|
|
178
203
|
@"screenSize":@{@"width": @(screenSize.width),
|
|
@@ -181,8 +206,8 @@
|
|
|
181
206
|
@"statusBarSize": @{@"width": @(statusBarSize.width),
|
|
182
207
|
@"height": @(statusBarSize.height),
|
|
183
208
|
},
|
|
184
|
-
@"displayId": @(
|
|
185
|
-
@"scale": @(
|
|
209
|
+
@"displayId": @(screen.displayID),
|
|
210
|
+
@"scale": @(screen.scale),
|
|
186
211
|
});
|
|
187
212
|
}
|
|
188
213
|
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
<key>CFBundlePackageType</key>
|
|
16
16
|
<string>FMWK</string>
|
|
17
17
|
<key>CFBundleShortVersionString</key>
|
|
18
|
-
<string>16.14.
|
|
18
|
+
<string>16.14.1</string>
|
|
19
19
|
<key>CFBundleSignature</key>
|
|
20
20
|
<string>????</string>
|
|
21
21
|
<key>CFBundleVersion</key>
|
|
22
|
-
<string>16.14.
|
|
22
|
+
<string>16.14.1</string>
|
|
23
23
|
<key>NSPrincipalClass</key>
|
|
24
24
|
<string/>
|
|
25
25
|
</dict>
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
#import "ViewController.h"
|
|
10
10
|
#import "FBCoordinateProbeViewController.h"
|
|
11
11
|
|
|
12
|
+
#if !TARGET_OS_TV
|
|
13
|
+
#import <WebKit/WebKit.h>
|
|
14
|
+
#endif
|
|
15
|
+
|
|
12
16
|
@interface ViewController ()
|
|
13
17
|
@property (weak, nonatomic) IBOutlet UILabel *orentationLabel;
|
|
14
18
|
@property (weak, nonatomic) IBOutlet UIButton *button;
|
|
@@ -19,6 +23,17 @@
|
|
|
19
23
|
- (void)viewDidLoad
|
|
20
24
|
{
|
|
21
25
|
[super viewDidLoad];
|
|
26
|
+
|
|
27
|
+
#if !TARGET_OS_TV
|
|
28
|
+
if ([NSProcessInfo.processInfo.arguments containsObject:@"--webview-fixture"]) {
|
|
29
|
+
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
|
|
30
|
+
webView.autoresizingMask = UIViewAutoresizingFlexibleWidth
|
|
31
|
+
| UIViewAutoresizingFlexibleHeight;
|
|
32
|
+
[self.view addSubview:webView];
|
|
33
|
+
[webView loadHTMLString:@"<!doctype html><html><body>"
|
|
34
|
+
"<p>WebContent snapshot fixture</p></body></html>" baseURL:nil];
|
|
35
|
+
}
|
|
36
|
+
#endif
|
|
22
37
|
|
|
23
38
|
UIAccessibilityCustomAction *action1 =
|
|
24
39
|
[[UIAccessibilityCustomAction alloc] initWithName:@"Custom Action 1"
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
#import "FBConfiguration.h"
|
|
13
13
|
#import "FBRuntimeUtils.h"
|
|
14
14
|
#import "FBTestMacros.h"
|
|
15
|
+
#import "FBXCAccessibilityElement.h"
|
|
16
|
+
#import "FBXCAXClientProxy.h"
|
|
17
|
+
#import "XCUIApplication.h"
|
|
15
18
|
#import "XCUIElement.h"
|
|
16
19
|
#import "XCUIElement+FBIsVisible.h"
|
|
17
20
|
|
|
@@ -68,4 +71,53 @@
|
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
|
|
74
|
+
- (void)testAccessibilityDeadlineAllowsResponsiveNativeAppSnapshots
|
|
75
|
+
{
|
|
76
|
+
[self launchApplication];
|
|
77
|
+
NSTimeInterval previousDeadline = FBConfiguration.sharedInstance.accessibilityDeadline;
|
|
78
|
+
@try {
|
|
79
|
+
FBConfiguration.sharedInstance.accessibilityDeadline = 3;
|
|
80
|
+
NSError *error = nil;
|
|
81
|
+
XCTAssertNotNil([self.testedApplication snapshotWithError:&error]);
|
|
82
|
+
XCTAssertNil(error);
|
|
83
|
+
} @finally {
|
|
84
|
+
FBConfiguration.sharedInstance.accessibilityDeadline = previousDeadline;
|
|
85
|
+
[self.testedApplication terminate];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
- (void)testAccessibilityDeadlineAllowsWebContentSnapshots
|
|
90
|
+
{
|
|
91
|
+
NSTimeInterval previousDeadline = FBConfiguration.sharedInstance.accessibilityDeadline;
|
|
92
|
+
@try {
|
|
93
|
+
// Resolve the remote AX element before enabling the guard so the test
|
|
94
|
+
// exercises a WebContent-owned snapshot, not just the host app's tree.
|
|
95
|
+
FBConfiguration.sharedInstance.accessibilityDeadline = 0;
|
|
96
|
+
self.testedApplication.launchArguments = @[@"--webview-fixture"];
|
|
97
|
+
[self.testedApplication launch];
|
|
98
|
+
XCUIElement *text = self.testedApplication.webViews.staticTexts[
|
|
99
|
+
@"WebContent snapshot fixture"];
|
|
100
|
+
XCTAssertTrue([text waitForExistenceWithTimeout:15]);
|
|
101
|
+
NSError *error = nil;
|
|
102
|
+
id<FBXCElementSnapshot> initial = [text snapshotWithError:&error];
|
|
103
|
+
XCTAssertNotNil(initial);
|
|
104
|
+
XCTAssertNil(error);
|
|
105
|
+
id<FBXCAccessibilityElement> element = initial.accessibilityElement;
|
|
106
|
+
XCTAssertNotEqual(element.processIdentifier, self.testedApplication.processID);
|
|
107
|
+
|
|
108
|
+
FBConfiguration.sharedInstance.accessibilityDeadline = 3;
|
|
109
|
+
for (NSUInteger i = 0; i < 3; i++) {
|
|
110
|
+
error = nil;
|
|
111
|
+
id<FBXCElementSnapshot> snapshot = [FBXCAXClientProxy.sharedClient
|
|
112
|
+
snapshotForElement:element attributes:@[] inDepth:YES error:&error];
|
|
113
|
+
XCTAssertNotNil(snapshot);
|
|
114
|
+
XCTAssertNil(error);
|
|
115
|
+
}
|
|
116
|
+
XCTAssertTrue(text.exists);
|
|
117
|
+
} @finally {
|
|
118
|
+
FBConfiguration.sharedInstance.accessibilityDeadline = previousDeadline;
|
|
119
|
+
[self.testedApplication terminate];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
71
123
|
@end
|
|
@@ -11,11 +11,23 @@
|
|
|
11
11
|
#import "FBIntegrationTestCase.h"
|
|
12
12
|
#import "FBConfiguration.h"
|
|
13
13
|
#import "FBScreen.h"
|
|
14
|
+
#import "FBRunLoopSpinner.h"
|
|
15
|
+
#import "XCUIDevice+FBRotation.h"
|
|
16
|
+
#import "XCUIDevice+FBHinge.h"
|
|
17
|
+
#import "XCUIElement.h"
|
|
14
18
|
#import "FBActiveAppDetectionPoint.h"
|
|
15
19
|
#import "FBExceptions.h"
|
|
16
20
|
#import "FBScreenRecordingRequest.h"
|
|
17
21
|
#import "FBScreenshot.h"
|
|
18
22
|
#import "XCUIScreen.h"
|
|
23
|
+
#import "FBCustomCommands.h"
|
|
24
|
+
#import "FBRouteRequest.h"
|
|
25
|
+
#import "FBResponsePayload.h"
|
|
26
|
+
#import "RouteResponse.h"
|
|
27
|
+
|
|
28
|
+
@interface FBCustomCommands (FBScreenInfoTesting)
|
|
29
|
+
+ (id<FBResponsePayload>)handleGetScreen:(FBRouteRequest *)request;
|
|
30
|
+
@end
|
|
19
31
|
|
|
20
32
|
@interface FBScreen (FBLookupTesting)
|
|
21
33
|
+ (nullable XCUIScreen *)screenWithDisplayID:(long long)displayID device:(id)device error:(NSError **)error;
|
|
@@ -299,4 +311,134 @@
|
|
|
299
311
|
XCTAssertTrue([FBScreen scale] >= 2);
|
|
300
312
|
}
|
|
301
313
|
|
|
314
|
+
- (NSDictionary *)screenInfoResponse
|
|
315
|
+
{
|
|
316
|
+
FBRouteRequest *request = [FBRouteRequest routeRequestWithURL:[NSURL URLWithString:@"http://localhost:8100/wda/screen"]
|
|
317
|
+
parameters:@{}
|
|
318
|
+
arguments:@{}];
|
|
319
|
+
RouteResponse *response = [RouteResponse new];
|
|
320
|
+
[[FBCustomCommands handleGetScreen:request] dispatchWithResponse:response];
|
|
321
|
+
return [NSJSONSerialization JSONObjectWithData:response.responseData options:0 error:nil][@"value"];
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
- (void)testScreenInfoFollowsDisplaySelection
|
|
325
|
+
{
|
|
326
|
+
for (NSDictionary *screen in [FBScreen screensWithError:nil]) {
|
|
327
|
+
FBConfiguration.sharedInstance.currentDisplayId = screen[@"displayId"];
|
|
328
|
+
NSDictionary *info = [self screenInfoResponse];
|
|
329
|
+
XCTAssertNil(info[@"error"]);
|
|
330
|
+
XCTAssertEqualObjects(info[@"displayId"], screen[@"displayId"]);
|
|
331
|
+
XCTAssertEqualObjects(info[@"scale"], screen[@"scale"]);
|
|
332
|
+
double width = [info[@"screenSize"][@"width"] doubleValue];
|
|
333
|
+
double height = [info[@"screenSize"][@"height"] doubleValue];
|
|
334
|
+
double scale = [screen[@"scale"] doubleValue];
|
|
335
|
+
double expectedWidth = [screen[@"bounds"][@"width"] doubleValue] / scale;
|
|
336
|
+
double expectedHeight = [screen[@"bounds"][@"height"] doubleValue] / scale;
|
|
337
|
+
XCTAssertEqualWithAccuracy(MIN(width, height), MIN(expectedWidth, expectedHeight), 0.01);
|
|
338
|
+
XCTAssertEqualWithAccuracy(MAX(width, height), MAX(expectedWidth, expectedHeight), 0.01);
|
|
339
|
+
double barHeight = [info[@"statusBarSize"][@"height"] doubleValue];
|
|
340
|
+
XCTAssertGreaterThanOrEqual(barHeight, 0);
|
|
341
|
+
XCTAssertLessThan(barHeight, height);
|
|
342
|
+
if (barHeight > 0) {
|
|
343
|
+
XCTAssertEqualWithAccuracy([info[@"statusBarSize"][@"width"] doubleValue], width, 1);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
// tearDown restores the default display even when an assertion fails.
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
- (void)testScreenInfoFollowsDisplayReset
|
|
350
|
+
{
|
|
351
|
+
// Exercise reset independently of the display-selection assertions.
|
|
352
|
+
FBConfiguration.sharedInstance.currentDisplayId = @([self unknownDisplayID]);
|
|
353
|
+
FBConfiguration.sharedInstance.currentDisplayId = nil;
|
|
354
|
+
XCTAssertEqualObjects([self screenInfoResponse][@"displayId"], @([FBScreen displayID]));
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
- (void)testScreenInfoRejectsUnavailableDisplay
|
|
358
|
+
{
|
|
359
|
+
FBConfiguration.sharedInstance.currentDisplayId = @([self unknownDisplayID]);
|
|
360
|
+
NSDictionary *info = [self screenInfoResponse];
|
|
361
|
+
XCTAssertEqualObjects(info[@"error"], @"invalid argument");
|
|
362
|
+
XCTAssertTrue([info[@"message"] containsString:@"Available display ids"]);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
- (void)testScreenInfoInBothLandscapeOrientations
|
|
366
|
+
{
|
|
367
|
+
XCTSkipIf(XCUIDevice.sharedDevice.fb_canAttemptSimulatedHingeAngleInjection,
|
|
368
|
+
@"Foldable orientations are covered by testScreenInfoAcrossFoldStates");
|
|
369
|
+
XCUIElement *window = self.testedApplication.windows.firstMatch;
|
|
370
|
+
(void)window.frame;
|
|
371
|
+
XCTSkipIf(window.screen.displayID != XCUIScreen.mainScreen.displayID,
|
|
372
|
+
@"Requires the fixture on the main display");
|
|
373
|
+
[self addTeardownBlock:^{
|
|
374
|
+
[[XCUIDevice sharedDevice] fb_setDeviceInterfaceOrientation:UIDeviceOrientationPortrait];
|
|
375
|
+
}];
|
|
376
|
+
BOOL expectsVisibleBar = UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad;
|
|
377
|
+
for (NSNumber *orientation in @[@(UIDeviceOrientationLandscapeLeft), @(UIDeviceOrientationLandscapeRight)]) {
|
|
378
|
+
XCTAssertTrue([[XCUIDevice sharedDevice] fb_setDeviceInterfaceOrientation:orientation.integerValue]);
|
|
379
|
+
__block NSDictionary *info = nil;
|
|
380
|
+
// iPad keeps its top status bar in landscape. Wait for rotation to finish
|
|
381
|
+
// rather than accepting a transient zero crop as a successful result.
|
|
382
|
+
XCTAssertTrue([[[FBRunLoopSpinner new] timeout:5] spinUntilTrue:^BOOL {
|
|
383
|
+
info = [self screenInfoResponse];
|
|
384
|
+
double width = [info[@"screenSize"][@"width"] doubleValue];
|
|
385
|
+
double height = [info[@"screenSize"][@"height"] doubleValue];
|
|
386
|
+
double barWidth = [info[@"statusBarSize"][@"width"] doubleValue];
|
|
387
|
+
double barHeight = [info[@"statusBarSize"][@"height"] doubleValue];
|
|
388
|
+
if (nil != info[@"error"] || width <= height || height <= 0) {
|
|
389
|
+
return NO;
|
|
390
|
+
}
|
|
391
|
+
if (barHeight == 0) {
|
|
392
|
+
return !expectsVisibleBar && barWidth == 0;
|
|
393
|
+
}
|
|
394
|
+
return barHeight > 0 && barHeight < height && fabs(barWidth - width) <= 1;
|
|
395
|
+
}], @"Unexpected landscape screen metadata: %@", info);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
- (void)testScreenInfoAcrossFoldStates
|
|
400
|
+
{
|
|
401
|
+
XCUIDevice *device = XCUIDevice.sharedDevice;
|
|
402
|
+
XCTSkipIf(!device.fb_canAttemptSimulatedHingeAngleInjection, @"Requires a foldable simulator");
|
|
403
|
+
NSError *error = nil;
|
|
404
|
+
NSNumber *originalAngle = [device fb_getSimulatedHingeAngle:&error];
|
|
405
|
+
XCTAssertNotNil(originalAngle, @"%@", error);
|
|
406
|
+
[self addTeardownBlock:^{
|
|
407
|
+
if (nil != originalAngle) {
|
|
408
|
+
[device fb_setSimulatedHingeAngle:originalAngle.doubleValue error:nil];
|
|
409
|
+
}
|
|
410
|
+
}];
|
|
411
|
+
for (NSNumber *angle in @[@0, @90, @180, @0]) {
|
|
412
|
+
[self.testedApplication terminate];
|
|
413
|
+
XCTAssertTrue([device fb_setSimulatedHingeAngle:angle.doubleValue error:&error], @"%@", error);
|
|
414
|
+
[self launchApplication];
|
|
415
|
+
XCUIElement *window = self.testedApplication.windows.firstMatch;
|
|
416
|
+
CGRect frame = window.frame;
|
|
417
|
+
FBConfiguration.sharedInstance.currentDisplayId = @(window.screen.displayID);
|
|
418
|
+
__block NSDictionary *info = nil;
|
|
419
|
+
XCTAssertTrue([[[FBRunLoopSpinner new] timeout:5] spinUntilTrue:^BOOL {
|
|
420
|
+
info = [self screenInfoResponse];
|
|
421
|
+
double width = [info[@"screenSize"][@"width"] doubleValue];
|
|
422
|
+
double height = [info[@"screenSize"][@"height"] doubleValue];
|
|
423
|
+
double barHeight = [info[@"statusBarSize"][@"height"] doubleValue];
|
|
424
|
+
return nil == info[@"error"] && fabs(width - frame.size.width) <= 1
|
|
425
|
+
&& fabs(height - frame.size.height) <= 1
|
|
426
|
+
&& barHeight >= 0 && barHeight < height
|
|
427
|
+
&& (barHeight == 0 || fabs([info[@"statusBarSize"][@"width"] doubleValue] - width) <= 1)
|
|
428
|
+
&& (angle.doubleValue == 0 || barHeight == 0);
|
|
429
|
+
}], @"Unexpected screen metadata at hinge angle %@: %@", angle, info);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
- (void)testScreenInfoIncludesTopStatusBarOnSingleDisplay
|
|
434
|
+
{
|
|
435
|
+
XCTSkipIf([FBScreen screensWithError:nil].count != 1, @"Requires a single-display device");
|
|
436
|
+
// The integration fixture uses the ordinary visible portrait status bar.
|
|
437
|
+
// An unresolved XCUIElement has displayID == 0; it must not be filtered out.
|
|
438
|
+
NSDictionary *info = [self screenInfoResponse];
|
|
439
|
+
XCTAssertGreaterThan([info[@"statusBarSize"][@"height"] doubleValue], 0);
|
|
440
|
+
XCTAssertEqualWithAccuracy([info[@"statusBarSize"][@"width"] doubleValue],
|
|
441
|
+
[info[@"screenSize"][@"width"] doubleValue], 1);
|
|
442
|
+
}
|
|
443
|
+
|
|
302
444
|
@end
|