Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions WebDriverAgent.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,10 @@
FEC3A97A4929115A192F947A /* XCUIDeviceEventAndStateInterface-Protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 003AAAB9CB5FB38E45E05F6F /* XCUIDeviceEventAndStateInterface-Protocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
FFA7672B731B57AB9283DD40 /* FBXCElementSnapshotWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 13DE7A53287CA1EC003243C6 /* FBXCElementSnapshotWrapper.h */; };
FFD70914E6D8CE5D4FED4B69 /* XCUIAXNotificationHandling-Protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EA96C2FEDE73CB5148BA4949 /* XCUIAXNotificationHandling-Protocol.h */; };
6C07E44E139D41D6BA092F39 /* FBTouchableViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D04760558C64B8EB69380E0 /* FBTouchableViewTests.m */; };
C15E49E6B6924191BAAD9FDF /* FBIntegrationAppTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 27B518E261C14E29B943AB9B /* FBIntegrationAppTests.m */; };
81E462B8A75F497CBFC6FD8B /* TouchableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 315A15002518CB8700A3A064 /* TouchableView.m */; };
B6DE70BFF27148BDAC72F80C /* TouchSpotView.m in Sources */ = {isa = PBXBuildFile; fileRef = 315A15062518CC2800A3A064 /* TouchSpotView.m */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -1962,6 +1966,8 @@
FCD1815F2BF21CA0936B04E1 /* XCTMessagingRole_SiriAutomation-Protocol.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "XCTMessagingRole_SiriAutomation-Protocol.h"; sourceTree = "<group>"; };
FDB15E393EA0850C004D26B2 /* XCTScreenCapturePolicy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = XCTScreenCapturePolicy.h; sourceTree = "<group>"; };
FF8E3B470FC9639D5F18E2EA /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
1D04760558C64B8EB69380E0 /* FBTouchableViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBTouchableViewTests.m; sourceTree = "<group>"; };
27B518E261C14E29B943AB9B /* FBIntegrationAppTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBIntegrationAppTests.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -2632,6 +2638,7 @@
EE9B76541CF7987300275851 /* IntegrationTests */ = {
isa = PBXGroup;
children = (
27B518E261C14E29B943AB9B /* FBIntegrationAppTests.m */,
EE9B76991CF799F400275851 /* FBAlertTests.m */,
719CD8FE2126C90200C7D0C2 /* FBAutoAlertsHandlerTests.m */,
EE26409C1D0EBA25009BE6B0 /* FBElementAttributeTests.m */,
Expand Down Expand Up @@ -2675,6 +2682,7 @@
EE9B76561CF7987300275851 /* UnitTests */ = {
isa = PBXGroup;
children = (
1D04760558C64B8EB69380E0 /* FBTouchableViewTests.m */,
ADBC39951D07840300327304 /* Doubles */,
71A7EAFB1E229302001DA4F2 /* FBClassChainTests.m */,
EEE16E961D33A25500172525 /* FBConfigurationTests.m */,
Expand Down Expand Up @@ -4814,6 +4822,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B6DE70BFF27148BDAC72F80C /* TouchSpotView.m in Sources */,
81E462B8A75F497CBFC6FD8B /* TouchableView.m in Sources */,
6C07E44E139D41D6BA092F39 /* FBTouchableViewTests.m in Sources */,
713352FD26CEF31D00523CBC /* FBLRUCacheTests.m in Sources */,
EE3F8CFE1D08AA17006F02CE /* FBRunLoopSpinnerTests.m in Sources */,
A09D847635CA4C155583B967 /* FBXCAXClientProxyTests.m in Sources */,
Expand Down Expand Up @@ -4869,6 +4880,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C15E49E6B6924191BAAD9FDF /* FBIntegrationAppTests.m in Sources */,
EE26409D1D0EBA25009BE6B0 /* FBElementAttributeTests.m in Sources */,
7119E1EC1E891F8600D0B125 /* FBPickerWheelSelectTests.m in Sources */,
71ACF5B8242F2FDC00F0AAD4 /* FBSafariAlertTests.m in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,38 @@
@interface FBScrollViewController ()
@property (nonatomic, weak) IBOutlet UIScrollView *scrollView;
@property (nonatomic, strong) IBOutlet FBTableDataSource *dataSource;
@property (nonatomic, copy) NSArray<UILabel *> *rowLabels;
@end

@implementation FBScrollViewController

- (void)viewDidLoad {
[super viewDidLoad];
[self setupLabelViews];
self.scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.view.frame), self.dataSource.count * FBSubviewHeight);
}

- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
CGFloat width = CGRectGetWidth(self.scrollView.bounds);
[self.rowLabels enumerateObjectsUsingBlock:^(UILabel *label, NSUInteger index, BOOL *stop) {
label.frame = CGRectMake(0, index * FBSubviewHeight, width, FBSubviewHeight);
}];
self.scrollView.contentSize = CGSizeMake(width, self.rowLabels.count * FBSubviewHeight);
}

- (void)setupLabelViews
{
NSUInteger count = self.dataSource.count;
NSMutableArray<UILabel *> *labels = [NSMutableArray arrayWithCapacity:count];
for (NSInteger i = 0 ; i < count ; i++) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, i * FBSubviewHeight, CGRectGetWidth(self.view.frame), FBSubviewHeight)];
UILabel *label = [UILabel new];
label.text = [self.dataSource textForElementAtIndex:i];
label.textAlignment = NSTextAlignmentCenter;
[self.scrollView addSubview:label];
[labels addObject:label];
}
self.rowLabels = labels;
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

NS_ASSUME_NONNULL_BEGIN

@interface TouchViewController : UIViewController
@interface TouchViewController : UIViewController <TouchableViewDelegate>

@property (weak, nonatomic) IBOutlet TouchableView *touchable;
@property (weak, nonatomic) IBOutlet UILabel *numberOfTapsLabel;
Expand Down
3 changes: 2 additions & 1 deletion WebDriverAgentTests/IntegrationApp/Classes/TouchableView.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ NS_ASSUME_NONNULL_BEGIN
@interface TouchableView : UIView

@property (nonatomic) NSMutableDictionary<NSNumber*, TouchSpotView*> *touchViews;
// Cumulative completed contacts; cancelled contacts are excluded.
@property (nonatomic) int numberOFTaps;
@property (nonatomic) id delegate;
@property (nonatomic, weak, nullable) id<TouchableViewDelegate> delegate;

@end

Expand Down
9 changes: 7 additions & 2 deletions WebDriverAgentTests/IntegrationApp/Classes/TouchableView.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,11 @@ - (instancetype)initWithCoder:(NSCoder *)coder

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.numberOFTaps += 1;
[self.delegate shouldHandleTouchesNumber:(int)touches.count];
for (UITouch *touch in touches)
{
[self createViewForTouch:touch];
}
[self.delegate shouldHandleTouchesNumber:(int)self.touchViews.count];
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
Expand All @@ -56,8 +55,13 @@ - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
{
// Count completed contacts, independently of how UIKit batches callbacks.
if ([self viewForTouch:touch] != nil) {
self.numberOFTaps += 1;
}
[self removeViewForTouch:touch];
}
[self.delegate shouldHandleTouchesNumber:(int)self.touchViews.count];
[self.delegate shouldHandleTapsNumber:self.numberOFTaps];
}

Expand All @@ -67,6 +71,7 @@ - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self removeViewForTouch:touch];
}
[self.delegate shouldHandleTouchesNumber:(int)self.touchViews.count];
}

- (void)createViewForTouch:(UITouch *)touch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
Expand Down Expand Up @@ -142,7 +143,7 @@
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<accessibility key="accessibilityConfiguration" identifier="touchableView"/>
<constraints>
<constraint firstAttribute="width" secondItem="C6B-Wo-jWm" secondAttribute="height" multiplier="288:269" id="LeW-u7-tWl"/>
<constraint firstAttribute="width" secondItem="C6B-Wo-jWm" secondAttribute="height" multiplier="288:269" priority="749" id="LeW-u7-tWl"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Taps" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IV8-Ak-Z8e">
Expand All @@ -160,17 +161,19 @@
<nil key="highlightedColor"/>
</label>
</subviews>
<viewLayoutGuide key="safeArea" id="tch-sa-Area"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="C6B-Wo-jWm" firstAttribute="top" secondItem="gEY-Ha-hqz" secondAttribute="bottom" constant="8" id="1PW-tn-oTF"/>
<constraint firstAttribute="trailing" secondItem="IV8-Ak-Z8e" secondAttribute="trailing" constant="144" id="5Tn-XG-5OD"/>
<constraint firstAttribute="trailing" secondItem="Q4X-EY-aSL" secondAttribute="trailing" constant="130" id="6Rr-L0-eoR"/>
<constraint firstItem="IV8-Ak-Z8e" firstAttribute="firstBaseline" secondItem="C6B-Wo-jWm" secondAttribute="baseline" constant="24.5" symbolType="layoutAnchor" id="77y-Kf-c0Y"/>
<constraint firstAttribute="trailing" secondItem="C6B-Wo-jWm" secondAttribute="trailing" constant="16" id="CaC-dk-dbo"/>
<constraint firstItem="Q4X-EY-aSL" firstAttribute="leading" secondItem="aEY-AK-0k9" secondAttribute="leading" constant="125" id="Ych-oZ-hmA"/>
<constraint firstItem="Q4X-EY-aSL" firstAttribute="top" secondItem="IV8-Ak-Z8e" secondAttribute="bottom" constant="7.5" id="ktv-kW-VWI"/>
<constraint firstItem="C6B-Wo-jWm" firstAttribute="leading" secondItem="aEY-AK-0k9" secondAttribute="leading" constant="16" id="pI7-Ds-hXG"/>
<constraint firstItem="IV8-Ak-Z8e" firstAttribute="leading" secondItem="aEY-AK-0k9" secondAttribute="leading" constant="139" id="vbu-wn-Qvc"/>
<constraint firstItem="C6B-Wo-jWm" firstAttribute="top" secondItem="tch-sa-Area" secondAttribute="top" constant="8" id="1PW-tn-oTF"/>
<constraint firstItem="C6B-Wo-jWm" firstAttribute="leading" secondItem="tch-sa-Area" secondAttribute="leading" constant="16" id="pI7-Ds-hXG"/>
<constraint firstItem="tch-sa-Area" firstAttribute="trailing" secondItem="C6B-Wo-jWm" secondAttribute="trailing" constant="16" id="CaC-dk-dbo"/>
<constraint firstItem="IV8-Ak-Z8e" firstAttribute="top" secondItem="C6B-Wo-jWm" secondAttribute="bottom" constant="8" id="77y-Kf-c0Y"/>
<constraint firstItem="IV8-Ak-Z8e" firstAttribute="leading" secondItem="C6B-Wo-jWm" secondAttribute="leading" id="vbu-wn-Qvc"/>
<constraint firstItem="IV8-Ak-Z8e" firstAttribute="trailing" secondItem="C6B-Wo-jWm" secondAttribute="trailing" id="5Tn-XG-5OD"/>
<constraint firstItem="Q4X-EY-aSL" firstAttribute="top" secondItem="IV8-Ak-Z8e" secondAttribute="bottom" constant="8" id="ktv-kW-VWI"/>
<constraint firstItem="Q4X-EY-aSL" firstAttribute="leading" secondItem="C6B-Wo-jWm" secondAttribute="leading" id="Ych-oZ-hmA"/>
<constraint firstItem="Q4X-EY-aSL" firstAttribute="trailing" secondItem="C6B-Wo-jWm" secondAttribute="trailing" id="6Rr-L0-eoR"/>
<constraint firstItem="tch-sa-Area" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="Q4X-EY-aSL" secondAttribute="bottom" constant="8" id="tch-btm-Fit"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="fDl-EC-1lc"/>
Expand Down
78 changes: 78 additions & 0 deletions WebDriverAgentTests/IntegrationTests/FBIntegrationAppTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

#import "FBIntegrationTestCase.h"
#import "FBTestMacros.h"
#import "XCUIDevice+FBRotation.h"
#import "XCUIElement+FBUtilities.h"

@interface FBIntegrationAppTests : FBIntegrationTestCase
@end

@implementation FBIntegrationAppTests

- (void)setUp
{
[super setUp];
[self resetOrientation];
[self launchApplication];
}

- (void)tearDown
{
[self resetOrientation];
[super tearDown];
}

- (void)rotateTo:(UIDeviceOrientation)orientation
{
XCTAssertTrue([[XCUIDevice sharedDevice] fb_setDeviceInterfaceOrientation:orientation]);
[self.testedApplication fb_waitUntilStable];
}

- (void)testTouchControlsRemainOnScreenAfterRotation
{
[self goToTouchPage];
XCUIElement *canvas = [self.testedApplication descendantsMatchingType:XCUIElementTypeAny][@"touchableView"];
XCUIElement *taps = self.testedApplication.staticTexts[FBTapsCountLabelIdentifier];
XCUIElement *touches = self.testedApplication.staticTexts[FBTouchesCountLabelIdentifier];
NSArray<NSNumber *> *orientations = @[@(UIDeviceOrientationLandscapeLeft),
@(UIDeviceOrientationLandscapeRight),
@(UIDeviceOrientationPortrait)];
NSUInteger count = 0;
for (NSNumber *orientation in orientations) {
[self rotateTo:orientation.integerValue];
CGRect screen = self.testedApplication.frame;
XCTAssertTrue(CGRectContainsRect(screen, canvas.frame));
XCTAssertTrue(CGRectContainsRect(screen, taps.frame));
XCTAssertTrue(CGRectContainsRect(screen, touches.frame));
XCTAssertGreaterThan(CGRectGetHeight(canvas.frame), 0);
[canvas tap];
NSString *expectedTaps = [NSString stringWithFormat:@"%lu", (unsigned long)++count];
FBAssertWaitTillBecomesTrue([taps.label isEqualToString:expectedTaps]);
XCTAssertEqualObjects(touches.label, @"0");
}
}

- (void)testScrollRowsResizeWhenRotatingInBothDirections
{
[self rotateTo:UIDeviceOrientationLandscapeLeft];
[self goToScrollPageWithCells:NO];
XCUIElement *scroll = self.testedApplication.scrollViews[@"scrollView"];
XCUIElement *row = scroll.staticTexts[@"3"];
NSArray<NSNumber *> *orientations = @[@(UIDeviceOrientationPortrait),
@(UIDeviceOrientationLandscapeRight)];
for (NSNumber *orientation in orientations) {
[self rotateTo:orientation.integerValue];
XCTAssertEqualWithAccuracy(CGRectGetWidth(row.frame), CGRectGetWidth(scroll.frame), 1);
XCTAssertEqualWithAccuracy(CGRectGetMidX(row.frame), CGRectGetMidX(scroll.frame), 1);
XCTAssertTrue(row.hittable);
}
}

@end
121 changes: 121 additions & 0 deletions WebDriverAgentTests/UnitTests/FBTouchableViewTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

#import <XCTest/XCTest.h>

#import "../IntegrationApp/Classes/TouchableView.h"

// Only the location and identity are needed to replay UIKit's touch callbacks.
@interface FBFixtureTouchDouble : NSObject
@end

@implementation FBFixtureTouchDouble
- (CGPoint)locationInView:(UIView *)view
{
return CGPointMake(50, 50);
}
@end

@interface FBTouchableViewTests : XCTestCase <TouchableViewDelegate>
@property (nonatomic, strong) TouchableView *touchable;
@property (nonatomic) int reportedTouches;
@property (nonatomic) int reportedTaps;
@end

@implementation FBTouchableViewTests

- (void)setUp
{
[super setUp];
self.reportedTouches = 0;
self.reportedTaps = 0;
self.touchable = [[TouchableView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
self.touchable.delegate = self;
}

- (void)tearDown
{
self.touchable.delegate = nil;
self.touchable = nil;
[super tearDown];
}

- (void)shouldHandleTouchesNumber:(int)touchesCount
{
self.reportedTouches = touchesCount;
}

- (void)shouldHandleTapsNumber:(int)numberOfTaps
{
self.reportedTaps = numberOfTaps;
}

- (UITouch *)newTouch
{
return (UITouch *)[FBFixtureTouchDouble new];
}

- (void)testStaggeredTouchesTrackActiveFingers
{
NSSet *first = [NSSet setWithObject:[self newTouch]];
NSSet *second = [NSSet setWithObject:[self newTouch]];
[self.touchable touchesBegan:first withEvent:nil];
XCTAssertEqual(self.reportedTouches, 1);
[self.touchable touchesBegan:second withEvent:nil];
XCTAssertEqual(self.reportedTouches, 2);
XCTAssertEqual(self.reportedTaps, 0);

[self.touchable touchesEnded:first withEvent:nil];
XCTAssertEqual(self.reportedTouches, 1);
XCTAssertEqual(self.reportedTaps, 1);
[self.touchable touchesEnded:second withEvent:nil];
XCTAssertEqual(self.reportedTouches, 0);
XCTAssertEqual(self.reportedTaps, 2);
}

- (void)testSimultaneousContactsCountIndependentlyOfCallbackBatching
{
NSSet *touches = [NSSet setWithObjects:[self newTouch], [self newTouch], nil];
[self.touchable touchesBegan:touches withEvent:nil];
XCTAssertEqual(self.reportedTouches, 2);
[self.touchable touchesEnded:touches withEvent:nil];
XCTAssertEqual(self.reportedTouches, 0);
XCTAssertEqual(self.reportedTaps, 2);
}

- (void)testCancelledContactsDoNotCarryOverIntoNextTap
{
NSSet *first = [NSSet setWithObject:[self newTouch]];
NSSet *second = [NSSet setWithObject:[self newTouch]];
[self.touchable touchesBegan:first withEvent:nil];
[self.touchable touchesBegan:second withEvent:nil];
[self.touchable touchesCancelled:[first setByAddingObjectsFromSet:second] withEvent:nil];
XCTAssertEqual(self.reportedTouches, 0);
XCTAssertEqual(self.reportedTaps, 0);

NSSet *next = [NSSet setWithObject:[self newTouch]];
[self.touchable touchesBegan:next withEvent:nil];
[self.touchable touchesEnded:next withEvent:nil];
XCTAssertEqual(self.reportedTouches, 0);
XCTAssertEqual(self.reportedTaps, 1);
}

- (void)testCancellingOneFingerPreservesTheOtherContact
{
NSSet *first = [NSSet setWithObject:[self newTouch]];
NSSet *second = [NSSet setWithObject:[self newTouch]];
[self.touchable touchesBegan:[first setByAddingObjectsFromSet:second] withEvent:nil];
[self.touchable touchesCancelled:first withEvent:nil];
XCTAssertEqual(self.reportedTouches, 1);
XCTAssertEqual(self.reportedTaps, 0);
[self.touchable touchesEnded:second withEvent:nil];
XCTAssertEqual(self.reportedTouches, 0);
XCTAssertEqual(self.reportedTaps, 1);
}

@end
Loading