Skip to content

Commit 8552fcd

Browse files
committed
Merge branch 'master' of github.com:appium/WebDriverAgent
2 parents 8d70ef1 + 8cb480b commit 8552fcd

File tree

8 files changed

+139
-4
lines changed

8 files changed

+139
-4
lines changed

WebDriverAgent.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
71A7EAF91E224648001DA4F2 /* FBClassChainQueryParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 71A7EAF71E224648001DA4F2 /* FBClassChainQueryParser.h */; };
4848
71A7EAFA1E224648001DA4F2 /* FBClassChainQueryParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 71A7EAF81E224648001DA4F2 /* FBClassChainQueryParser.m */; };
4949
71A7EAFC1E229302001DA4F2 /* FBClassChainTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 71A7EAFB1E229302001DA4F2 /* FBClassChainTests.m */; };
50+
71AB82B21FDAE8C000D1D7C3 /* FBElementScreenshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 71AB82B11FDAE8C000D1D7C3 /* FBElementScreenshotTests.m */; };
5051
71B49EC71ED1A58100D51AD6 /* XCUIElement+FBUID.h in Headers */ = {isa = PBXBuildFile; fileRef = 71B49EC51ED1A58100D51AD6 /* XCUIElement+FBUID.h */; };
5152
71B49EC81ED1A58100D51AD6 /* XCUIElement+FBUID.m in Sources */ = {isa = PBXBuildFile; fileRef = 71B49EC61ED1A58100D51AD6 /* XCUIElement+FBUID.m */; };
5253
71BD20731F86116100B36EC2 /* XCUIApplication+FBTouchAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 71BD20711F86116100B36EC2 /* XCUIApplication+FBTouchAction.h */; };
@@ -453,6 +454,7 @@
453454
71A7EAF71E224648001DA4F2 /* FBClassChainQueryParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBClassChainQueryParser.h; sourceTree = "<group>"; };
454455
71A7EAF81E224648001DA4F2 /* FBClassChainQueryParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBClassChainQueryParser.m; sourceTree = "<group>"; };
455456
71A7EAFB1E229302001DA4F2 /* FBClassChainTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBClassChainTests.m; sourceTree = "<group>"; };
457+
71AB82B11FDAE8C000D1D7C3 /* FBElementScreenshotTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBElementScreenshotTests.m; sourceTree = "<group>"; };
456458
71B49EC51ED1A58100D51AD6 /* XCUIElement+FBUID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "XCUIElement+FBUID.h"; sourceTree = "<group>"; };
457459
71B49EC61ED1A58100D51AD6 /* XCUIElement+FBUID.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "XCUIElement+FBUID.m"; sourceTree = "<group>"; };
458460
71BD20711F86116100B36EC2 /* XCUIApplication+FBTouchAction.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "XCUIApplication+FBTouchAction.h"; sourceTree = "<group>"; };
@@ -1097,6 +1099,7 @@
10971099
children = (
10981100
EE9B76991CF799F400275851 /* FBAlertTests.m */,
10991101
EE26409C1D0EBA25009BE6B0 /* FBElementAttributeTests.m */,
1102+
71AB82B11FDAE8C000D1D7C3 /* FBElementScreenshotTests.m */,
11001103
EE006EAC1EB99B15006900A4 /* FBElementVisibilityTests.m */,
11011104
EE6A89361D0B35920083E92B /* FBFailureProofTestCaseTests.m */,
11021105
EE1E06DB1D18090F007CF043 /* FBIntegrationTestCase.h */,
@@ -1858,6 +1861,7 @@
18581861
71BD20781F869E0F00B36EC2 /* FBAppiumTouchActionsIntegrationTests.m in Sources */,
18591862
719A97AC1F88E7370063B4BD /* FBAppiumMultiTouchActionsIntegrationTests.m in Sources */,
18601863
EE22021E1ECC618900A29571 /* FBTapTest.m in Sources */,
1864+
71AB82B21FDAE8C000D1D7C3 /* FBElementScreenshotTests.m in Sources */,
18611865
);
18621866
runOnlyForDeploymentPostprocessing = 0;
18631867
};

WebDriverAgentLib/Categories/XCUIElement+FBUtilities.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ NS_ASSUME_NONNULL_BEGIN
5959
*/
6060
- (BOOL)fb_waitUntilSnapshotIsStable;
6161

62+
/**
63+
Returns screenshot of the particular element
64+
@param error If there is an error, upon return contains an NSError object that describes the problem.
65+
@return Element screenshot as PNG-encoded data or nil in case of failure
66+
*/
67+
- (nullable NSData *)fb_screenshotWithError:(NSError*__autoreleasing*)error;
68+
6269
@end
6370

6471
NS_ASSUME_NONNULL_END

WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,60 @@ - (BOOL)fb_waitUntilSnapshotIsStable
124124
return result;
125125
}
126126

127+
- (NSData *)fb_screenshotWithError:(NSError**)error
128+
{
129+
if (CGRectIsEmpty(self.frame)) {
130+
if (error) {
131+
*error = [[FBErrorBuilder.builder withDescription:@"Cannot get a screenshot of zero-sized element"] build];
132+
}
133+
return nil;
134+
}
135+
136+
Class xcScreenClass = NSClassFromString(@"XCUIScreen");
137+
if (nil == xcScreenClass) {
138+
if (error) {
139+
*error = [[FBErrorBuilder.builder withDescription:@"Element screenshots are only available since Xcode9 SDK"] build];
140+
}
141+
return nil;
142+
}
143+
144+
id mainScreen = [xcScreenClass valueForKey:@"mainScreen"];
145+
SEL mSelector = NSSelectorFromString(@"screenshotDataForQuality:rect:error:");
146+
NSMethodSignature *mSignature = [mainScreen methodSignatureForSelector:mSelector];
147+
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:mSignature];
148+
[invocation setTarget:mainScreen];
149+
[invocation setSelector:mSelector];
150+
NSUInteger quality = 1;
151+
[invocation setArgument:&quality atIndex:2];
152+
CGRect elementRect = self.frame;
153+
[invocation setArgument:&elementRect atIndex:3];
154+
[invocation setArgument:&error atIndex:4];
155+
[invocation invoke];
156+
NSData __unsafe_unretained *imageData;
157+
[invocation getReturnValue:&imageData];
158+
if (nil == imageData) {
159+
return nil;
160+
}
161+
162+
UIImage *image = [UIImage imageWithData:imageData];
163+
UIInterfaceOrientation orientation = self.application.interfaceOrientation;
164+
UIImageOrientation imageOrientation = UIImageOrientationUp;
165+
// The received element screenshot will be rotated, if the current interface orientation differs from portrait, so we need to fix that first
166+
if (orientation == UIInterfaceOrientationLandscapeRight) {
167+
imageOrientation = UIImageOrientationLeft;
168+
} else if (orientation == UIInterfaceOrientationLandscapeLeft) {
169+
imageOrientation = UIImageOrientationRight;
170+
} else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
171+
imageOrientation = UIImageOrientationDown;
172+
}
173+
CGSize size = image.size;
174+
UIGraphicsBeginImageContext(CGSizeMake(size.width, size.height));
175+
[[UIImage imageWithCGImage:(CGImageRef)[image CGImage] scale:1.0 orientation:imageOrientation] drawInRect:CGRectMake(0, 0, size.width, size.height)];
176+
UIImage* fixedImage = UIGraphicsGetImageFromCurrentImageContext();
177+
UIGraphicsEndImageContext();
178+
179+
// The resulting data is a JPEG image, so we need to convert it to PNG representation
180+
return (NSData *)UIImagePNGRepresentation(fixedImage);
181+
}
182+
127183
@end

WebDriverAgentLib/Commands/FBElementCommands.m

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ + (NSArray *)routes
5757
[[FBRoute POST:@"/element/:uuid/value"] respondWithTarget:self action:@selector(handleSetValue:)],
5858
[[FBRoute POST:@"/element/:uuid/click"] respondWithTarget:self action:@selector(handleClick:)],
5959
[[FBRoute POST:@"/element/:uuid/clear"] respondWithTarget:self action:@selector(handleClear:)],
60+
[[FBRoute GET:@"/element/:uuid/screenshot"] respondWithTarget:self action:@selector(handleElementScreenshot:)],
6061
[[FBRoute GET:@"/wda/element/:uuid/accessible"] respondWithTarget:self action:@selector(handleGetAccessible:)],
6162
[[FBRoute GET:@"/wda/element/:uuid/accessibilityContainer"] respondWithTarget:self action:@selector(handleGetIsAccessibilityContainer:)],
6263
[[FBRoute POST:@"/wda/element/:uuid/swipe"] respondWithTarget:self action:@selector(handleSwipe:)],
@@ -382,6 +383,19 @@ + (NSArray *)routes
382383
});
383384
}
384385

386+
+ (id<FBResponsePayload>)handleElementScreenshot:(FBRouteRequest *)request
387+
{
388+
FBElementCache *elementCache = request.session.elementCache;
389+
XCUIElement *element = [elementCache elementForUUID:request.parameters[@"uuid"]];
390+
NSError *error;
391+
NSData *screenshotData = [element fb_screenshotWithError:&error];
392+
if (nil == screenshotData) {
393+
return FBResponseWithError(error);
394+
}
395+
NSString *screenshot = [screenshotData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
396+
return FBResponseWithObject(screenshot);
397+
}
398+
385399
static const CGFloat DEFAULT_OFFSET = (CGFloat)0.2;
386400

387401
+ (id<FBResponsePayload>)handleWheelSelect:(FBRouteRequest *)request
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
#import <XCTest/XCTest.h>
11+
12+
#import "FBIntegrationTestCase.h"
13+
#import "XCUIDevice+FBRotation.h"
14+
#import "XCUIElement+FBUtilities.h"
15+
16+
@interface FBElementScreenshotTests : FBIntegrationTestCase
17+
@end
18+
19+
@implementation FBElementScreenshotTests
20+
21+
- (void)setUp
22+
{
23+
[super setUp];
24+
static dispatch_once_t onceToken;
25+
dispatch_once(&onceToken, ^{
26+
[self launchApplication];
27+
[self goToAlertsPage];
28+
});
29+
}
30+
31+
- (void)testElementScreenshot
32+
{
33+
[[XCUIDevice sharedDevice] fb_setDeviceInterfaceOrientation:UIDeviceOrientationLandscapeLeft];
34+
XCUIElement *button = self.testedApplication.buttons[FBShowAlertButtonName];
35+
NSError *error = nil;
36+
NSData *screenshotData = [button fb_screenshotWithError:&error];
37+
if (nil == screenshotData && [error.description containsString:@"available since Xcode9"]) {
38+
return;
39+
}
40+
XCTAssertNotNil(screenshotData);
41+
XCTAssertNil(error);
42+
UIImage *image = [UIImage imageWithData:screenshotData];
43+
XCTAssertNotNil(image);
44+
XCTAssertTrue(image.size.width > image.size.height);
45+
}
46+
47+
@end

WebDriverAgentTests/IntegrationTests/FBElementVisibilityTests.m

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@ - (void)testExtrasIconContent
5858
}
5959
}
6060

61-
- (void)testIconsFromSearchDashboard
61+
- (void)disabled_testIconsFromSearchDashboard
6262
{
63+
// This test causes:
64+
// Failure fetching attributes for element <XCAccessibilityElement: 0x60800044dd10> Device element: Error Domain=XCTDaemonErrorDomain Code=13 "Value for attribute 5017 is an error." UserInfo={NSLocalizedDescription=Value for attribute 5017 is an error.}
6365
[self launchApplication];
6466
[self goToSpringBoardDashboard];
6567
XCTAssertFalse(self.springboard.icons[@"Reminders"].fb_isVisible);

WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ - (void)testTappingAppOnSpringboard
4343
XCTAssertTrue([FBApplication fb_activeApplication].buttons[@"URL"].exists);
4444
}
4545

46-
- (void)testWaitingForSpringboard
46+
- (void)disabled_testWaitingForSpringboard
4747
{
48+
// This test is flaky on Travis
4849
NSError *error;
4950
[[XCUIDevice sharedDevice] pressButton:XCUIDeviceButtonHome];
5051
XCTAssertTrue([[FBSpringboardApplication fb_springboard] fb_waitUntilApplicationBoardIsVisible:&error]);
@@ -60,8 +61,10 @@ - (void)testApplicationTree
6061
XCTAssertNotNil(self.testedApplication.fb_accessibilityTree);
6162
}
6263

63-
- (void)testDeactivateApplication
64+
- (void)disabled_testDeactivateApplication
6465
{
66+
// This test randomly causes:
67+
// Failure fetching attributes for element <XCAccessibilityElement: 0x6080008407b0> Device element: Error Domain=XCTDaemonErrorDomain Code=13 "Value for attribute 5017 is an error." UserInfo={NSLocalizedDescription=Value for attribute 5017 is an error.}
6568
[self.testedApplication query];
6669
[self.testedApplication resolve];
6770
NSError *error;

WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,10 @@ - (void)setUp
319319
});
320320
}
321321

322-
- (void)testInvisibleDescendantWithXPathQuery
322+
- (void)disabled_testInvisibleDescendantWithXPathQuery
323323
{
324+
// this test randomly causes:
325+
// Failure fetching attributes for element <XCAccessibilityElement: 0x608000643900> Device element: Error Domain=XCTDaemonErrorDomain Code=13 "Value for attribute 5017 is an error." UserInfo={NSLocalizedDescription=Value for attribute 5017 is an error.}
324326
NSArray<XCUIElement *> *matchingSnapshots = [self.testedApplication fb_descendantsMatchingXPathQuery:@"//XCUIElementTypePageIndicator[@visible='false']" shouldReturnAfterFirstMatch:NO];
325327
XCTAssertEqual(matchingSnapshots.count, 1);
326328
XCTAssertEqual(matchingSnapshots.lastObject.elementType, XCUIElementTypePageIndicator);

0 commit comments

Comments
 (0)