diff --git a/EarlGrey.xcodeproj/project.pbxproj b/EarlGrey.xcodeproj/project.pbxproj index eb56cdf6e..5c8567d16 100644 --- a/EarlGrey.xcodeproj/project.pbxproj +++ b/EarlGrey.xcodeproj/project.pbxproj @@ -115,6 +115,8 @@ C5EFB20120117AF00010D067 /* EarlGreyImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = C5EFB1FF20117AF00010D067 /* EarlGreyImpl.m */; }; D210ED8D1E6F47D100978B9E /* GREYMultiFingerSwipeAction.h in Headers */ = {isa = PBXBuildFile; fileRef = D210ED8B1E6F47D100978B9E /* GREYMultiFingerSwipeAction.h */; settings = {ATTRIBUTES = (Private, ); }; }; D210ED8E1E6F47D100978B9E /* GREYMultiFingerSwipeAction.m in Sources */ = {isa = PBXBuildFile; fileRef = D210ED8C1E6F47D100978B9E /* GREYMultiFingerSwipeAction.m */; }; + F892EDF820164F12008DB046 /* GREYPreciseSwipeAction.h in Headers */ = {isa = PBXBuildFile; fileRef = F892EDF620164F11008DB046 /* GREYPreciseSwipeAction.h */; settings = {ATTRIBUTES = (Private, ); }; }; + F892EDF920164F12008DB046 /* GREYPreciseSwipeAction.m in Sources */ = {isa = PBXBuildFile; fileRef = F892EDF720164F12008DB046 /* GREYPreciseSwipeAction.m */; }; FD1001B01C5B46C200B2DB0A /* GREYAction.h in Headers */ = {isa = PBXBuildFile; fileRef = FD1001011C5B46C100B2DB0A /* GREYAction.h */; settings = {ATTRIBUTES = (Public, ); }; }; FD1001B11C5B46C200B2DB0A /* GREYActionBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = FD1001021C5B46C100B2DB0A /* GREYActionBlock.h */; settings = {ATTRIBUTES = (Public, ); }; }; FD1001B21C5B46C200B2DB0A /* GREYActionBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = FD1001031C5B46C100B2DB0A /* GREYActionBlock.m */; }; @@ -302,6 +304,8 @@ C5EFB1FF20117AF00010D067 /* EarlGreyImpl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EarlGreyImpl.m; sourceTree = ""; }; D210ED8B1E6F47D100978B9E /* GREYMultiFingerSwipeAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GREYMultiFingerSwipeAction.h; sourceTree = ""; }; D210ED8C1E6F47D100978B9E /* GREYMultiFingerSwipeAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GREYMultiFingerSwipeAction.m; sourceTree = ""; }; + F892EDF620164F11008DB046 /* GREYPreciseSwipeAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GREYPreciseSwipeAction.h; sourceTree = ""; }; + F892EDF720164F12008DB046 /* GREYPreciseSwipeAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GREYPreciseSwipeAction.m; sourceTree = ""; }; FD06C66B1BECAD8B009032A5 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; FD06C66C1BECAD8B009032A5 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; FD06C66F1BECAD9B009032A5 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -595,6 +599,8 @@ FD1001151C5B46C100B2DB0A /* GREYSlideAction.m */, FD1001161C5B46C100B2DB0A /* GREYSwipeAction.h */, FD1001171C5B46C100B2DB0A /* GREYSwipeAction.m */, + F892EDF620164F11008DB046 /* GREYPreciseSwipeAction.h */, + F892EDF720164F12008DB046 /* GREYPreciseSwipeAction.m */, FD1001181C5B46C100B2DB0A /* GREYTapAction.h */, FD1001191C5B46C100B2DB0A /* GREYTapAction.m */, FD10011A1C5B46C100B2DB0A /* GREYTapper.h */, @@ -985,6 +991,7 @@ FDCB29941E2467F60001557E /* GREYActions+Internal.h in Headers */, 597E02E81D55AD6D0052A8D1 /* NSURL+GREYAdditions.h in Headers */, 597E02ED1D55AD6D0052A8D1 /* UITouch+GREYAdditions.h in Headers */, + F892EDF820164F12008DB046 /* GREYPreciseSwipeAction.h in Headers */, 597E02EA1D55AD6D0052A8D1 /* UIAnimation+GREYAdditions.h in Headers */, 3F5122141EE1D37E0000CC56 /* GREYTraversal.h in Headers */, 597E02EC1D55AD6D0052A8D1 /* UIScrollView+GREYAdditions.h in Headers */, @@ -1150,6 +1157,7 @@ 7CCBEBA71DCD2F0500CC01B8 /* GREYError.m in Sources */, FD1002061C5B46C200B2DB0A /* GREYConstants.m in Sources */, FD10021B1C5B46C200B2DB0A /* GREYCAAnimationDelegate.m in Sources */, + F892EDF920164F12008DB046 /* GREYPreciseSwipeAction.m in Sources */, FD1001B41C5B46C200B2DB0A /* GREYActions.m in Sources */, FD6D0B991C6D49400001EA75 /* GREYBaseAction.m in Sources */, FD10025C1C5B489A00B2DB0A /* fishhook.c in Sources */, diff --git a/EarlGrey/Action/GREYActions.h b/EarlGrey/Action/GREYActions.h index e75c8214a..84eb94bcd 100644 --- a/EarlGrey/Action/GREYActions.h +++ b/EarlGrey/Action/GREYActions.h @@ -181,6 +181,32 @@ NS_ASSUME_NONNULL_BEGIN xOriginStartPercentage:(CGFloat)xOriginStartPercentage yOriginStartPercentage:(CGFloat)yOriginStartPercentage; +/** + * Returns an action that swipes through the view from a given @c startPoint to a given + * @c endPoint. + * + * @param startPoint The point where the swipe should begin. Relative to the matched view's origin. + * @param endPoint The point where the swipe should end. Relative to the matched view's origin. + * + * @return A GREYAction that performs a fast swipe through a view from a specific start point + * to a specific end point. + */ ++ (id)actionForSwipeFastWithStartPoint:(CGPoint)startPoint + endPoint:(CGPoint)endPoint; + +/** + * Returns an action that swipes through the view from a given @c startPoint to a given + * @c endPoint. + * + * @param startPoint The point where the swipe should begin. + * @param endPoint The point where the swipe should end. + * + * @return A GREYAction that performs a slow swipe through a view from a specific start point + * to a specific end point. + */ ++ (id)actionForSwipeSlowWithStartPoint:(CGPoint)startPoint + endPoint:(CGPoint)endPoint; + /** * Returns an action that performs a multi-finger slow swipe through the view in the given * @c direction. @@ -458,6 +484,20 @@ GREY_EXPORT id grey_swipeSlowInDirectionWithStartPoint(GREYDirection CGFloat xOriginStartPercentage, CGFloat yOriginStartPercentage); +/** + * Shorthand macro for + * GREYActions::actionForSwipeFastWithStartPoint:endPoint:. + */ +GREY_EXPORT id grey_swipeFastFromStartToEndPoint(CGPoint startPoint, + CGPoint endPoint); + +/** + * Shorthand macro for + * GREYActions::actionForSwipeSlowWithStartPoint:endPoint:. + */ +GREY_EXPORT id grey_swipeSlowFromStartToEndPoint(CGPoint startPoint, + CGPoint endPoint); + /** * Shorthand macro for * GREYActions::actionForMultiFingerSwipeSlowInDirection:numberOfFingers:. diff --git a/EarlGrey/Action/GREYActions.m b/EarlGrey/Action/GREYActions.m index 8fd2618a3..a09315834 100644 --- a/EarlGrey/Action/GREYActions.m +++ b/EarlGrey/Action/GREYActions.m @@ -28,6 +28,7 @@ #import "Action/GREYScrollToContentEdgeAction.h" #import "Action/GREYSlideAction.h" #import "Action/GREYSwipeAction.h" +#import "Action/GREYPreciseSwipeAction.h" #import "Action/GREYTapAction.h" #import "Additions/NSError+GREYAdditions.h" #import "Additions/NSObject+GREYAdditions.h" @@ -88,6 +89,20 @@ + (void)initialize { yOriginStartPercentage)]; } ++ (id)actionForSwipeFastWithStartPoint:(CGPoint)startPoint + endPoint:(CGPoint)endPoint { + return [[GREYPreciseSwipeAction alloc] initWithStartPoint:startPoint + endPoint:endPoint + duration:kGREYSwipeFastDuration]; +} + ++ (id)actionForSwipeSlowWithStartPoint:(CGPoint)startPoint + endPoint:(CGPoint)endPoint { + return [[GREYPreciseSwipeAction alloc] initWithStartPoint:startPoint + endPoint:endPoint + duration:kGREYSwipeSlowDuration]; +} + + (id)actionForMultiFingerSwipeSlowInDirection:(GREYDirection)direction numberOfFingers:(NSUInteger)numberOfFingers { return [[GREYMultiFingerSwipeAction alloc] initWithDirection:direction @@ -673,6 +688,18 @@ + (BOOL)grey_disableAutoCorrectForDelegateAndTypeText:(NSString *)text yOriginStartPercentage:yOriginStartPercentage]; } +id grey_swipeFastFromStartToEndPoint(CGPoint startPoint, + CGPoint endPoint) { + return [GREYActions actionForSwipeFastWithStartPoint:startPoint + endPoint:endPoint]; +} + +id grey_swipeSlowFromStartToEndPoint(CGPoint startPoint, + CGPoint endPoint) { + return [GREYActions actionForSwipeSlowWithStartPoint:startPoint + endPoint:endPoint]; +} + id grey_multiFingerSwipeSlowInDirection(GREYDirection direction, NSUInteger numberOfFingers) { return [GREYActions actionForMultiFingerSwipeSlowInDirection:direction diff --git a/EarlGrey/Action/GREYPreciseSwipeAction.h b/EarlGrey/Action/GREYPreciseSwipeAction.h new file mode 100644 index 000000000..7a91a474f --- /dev/null +++ b/EarlGrey/Action/GREYPreciseSwipeAction.h @@ -0,0 +1,54 @@ +// +// Copyright 2018 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * A GREYAction that swipes/flicks the matched element from a concrete start point to an end point. + */ +@interface GREYPreciseSwipeAction : GREYBaseAction + +/** + * @remark init is not an available initializer. Use the other initializers. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * @remark initWithName:constraints: is overridden from its superclass. + */ +- (instancetype)initWithName:(NSString *)name + constraints:(id)constraints NS_UNAVAILABLE; + +/** + * Performs a swipe from the given @c startPoint to the given @c endPoint. + * + * @param startPoint The point where the swipe should begin. Relative to the matched view's origin. + * @param endPoint The point where the swipe should end. Relative to the matched view's origin. + * @param duration The time interval for which the swipe takes place. + * + * @return An instance of GREYPreciseSwipeAction, initialized with the provided start point, + * end point and duration. + */ +- (instancetype)initWithStartPoint:(CGPoint)startPoint + endPoint:(CGPoint)endPoint + duration:(CFTimeInterval)duration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/EarlGrey/Action/GREYPreciseSwipeAction.m b/EarlGrey/Action/GREYPreciseSwipeAction.m new file mode 100644 index 000000000..ea397a702 --- /dev/null +++ b/EarlGrey/Action/GREYPreciseSwipeAction.m @@ -0,0 +1,120 @@ +// +// Copyright 2018 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "Action/GREYPreciseSwipeAction.h" + +#import "Action/GREYPathGestureUtils.h" +#import "Additions/NSError+GREYAdditions.h" +#import "Additions/NSObject+GREYAdditions.h" +#import "Additions/NSString+GREYAdditions.h" +#import "Assertion/GREYAssertionDefines.h" +#import "Assertion/GREYAssertions+Internal.h" +#import "Common/GREYError.h" +#import "Common/GREYThrowDefines.h" +#import "Event/GREYSyntheticEvents.h" +#import "Matcher/GREYAllOf.h" +#import "Matcher/GREYMatcher.h" +#import "Matcher/GREYMatchers.h" +#import "Matcher/GREYNot.h" + +@implementation GREYPreciseSwipeAction { + /** + * The point where the swipe should begin. + */ + CGPoint _startPoint; + /** + * The point where the swipe should end. + */ + CGPoint _endPoint; + /** + * The duration within which the swipe action must be complete. + */ + CFTimeInterval _duration; +} + +- (instancetype)initWithStartPoint:(CGPoint)startPoint + endPoint:(CGPoint)endPoint + duration:(CFTimeInterval)duration { + + NSString *name = + [NSString stringWithFormat:@"Precise swipe from %@ to %@ for duration %g", + NSStringFromCGPoint(startPoint), + NSStringFromCGPoint(endPoint), + duration]; + self = [super initWithName:name + constraints:grey_allOf(grey_interactable(), + grey_not(grey_systemAlertViewShown()), + grey_kindOfClass([UIView class]), + grey_respondsToSelector(@selector(accessibilityFrame)), + nil)]; + if (self) { + _startPoint = startPoint; + _endPoint = endPoint; + _duration = duration; + } + return self; +} + +#pragma mark - GREYAction + +- (BOOL)perform:(id)element error:(__strong NSError **)errorOrNil { + if (![self satisfiesConstraintsForElement:element error:errorOrNil]) { + return NO; + } + CGRect accessibilityFrame = [element accessibilityFrame]; + CGPoint startPoint = + CGPointMake(_startPoint.x + accessibilityFrame.origin.x, + _startPoint.y + accessibilityFrame.origin.y); + CGPoint endPoint = + CGPointMake(_endPoint.x + accessibilityFrame.origin.x, + _endPoint.y + accessibilityFrame.origin.y); + + UIWindow *window = [element window]; + if (!window) { + if ([element isKindOfClass:[UIWindow class]]) { + window = (UIWindow *)element; + } else { + NSString *errorDescription = + [NSString stringWithFormat:@"Cannot swipe on view [V], as it has no window and " + @"it isn't a window itself."]; + NSDictionary *glossary = @{ @"V" : [element grey_description] }; + GREYError *error; + error = GREYErrorMake(kGREYSyntheticEventInjectionErrorDomain, + kGREYOrientationChangeFailedErrorCode, + errorDescription); + error.descriptionGlossary = glossary; + if (errorOrNil) { + *errorOrNil = error; + } else { + [GREYAssertions grey_raiseExceptionNamed:kGREYGenericFailureException + exceptionDetails:@"" + withError:error]; + } + return NO; + } + } + NSArray *touchPath = [GREYPathGestureUtils touchPathForDragGestureWithStartPoint:startPoint + endPoint:endPoint + cancelInertia:NO]; + + [GREYSyntheticEvents touchAlongPath:touchPath + relativeToWindow:window + forDuration:_duration + expendable:YES]; + return YES; +} + +@end diff --git a/Tests/FunctionalTests/Sources/FTRGestureTest.m b/Tests/FunctionalTests/Sources/FTRGestureTest.m index 824b946a3..1c010a650 100644 --- a/Tests/FunctionalTests/Sources/FTRGestureTest.m +++ b/Tests/FunctionalTests/Sources/FTRGestureTest.m @@ -192,6 +192,65 @@ - (void)testSwipeWithLocationForAllDirections { assertWithMatcher:grey_sufficientlyVisible()]; } +- (void)testPreciseSwipe { + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Grey Box")] + performAction:grey_swipeFastFromStartToEndPoint(CGPointMake(55.f, 5.f), CGPointMake(55.f, 100.f))]; + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"swipe down")] + assertWithMatcher:grey_sufficientlyVisible()]; + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"x:55.0 - y:5.0")] + assertWithMatcher:grey_sufficientlyVisible()]; + + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Grey Box")] + performAction:grey_swipeFastFromStartToEndPoint(CGPointMake(2.f, 30.f), CGPointMake(80.f, 38.f))]; + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"swipe right")] + assertWithMatcher:grey_sufficientlyVisible()]; + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"x:2.0 - y:30.0")] + assertWithMatcher:grey_sufficientlyVisible()]; + + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Grey Box")] + performAction:grey_swipeSlowFromStartToEndPoint(CGPointMake(150.f, 80.f), CGPointMake(50.f, 80.f))]; + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"swipe left")] + assertWithMatcher:grey_sufficientlyVisible()]; + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"x:150.0 - y:80.0")] + assertWithMatcher:grey_sufficientlyVisible()]; + + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Grey Box")] + performAction:grey_swipeSlowFromStartToEndPoint(CGPointMake(40.f, 100.f), CGPointMake(40.f, 30.f))]; + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"swipe up")] + assertWithMatcher:grey_sufficientlyVisible()]; + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"x:40.0 - y:100.0")] + assertWithMatcher:grey_sufficientlyVisible()]; + + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Grey Box")] + performAction:grey_swipeFastFromStartToEndPoint(CGPointMake(40.f, 100.f), CGPointMake(40.f, -50.f))]; + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"swipe up")] + assertWithMatcher:grey_sufficientlyVisible()]; + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"x:40.0 - y:100.0")] + assertWithMatcher:grey_sufficientlyVisible()]; +} + +- (void)testPreciseSwipeOnWindow { + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Window swipes start here")] + performAction:grey_swipeFastFromStartToEndPoint(CGPointMake(55.f, 5.f), CGPointMake(55.f, 100.f))]; + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"swipe down on window")] + assertWithMatcher:grey_sufficientlyVisible()]; + + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Window swipes start here")] + performAction:grey_swipeFastFromStartToEndPoint(CGPointMake(2.f, 30.f), CGPointMake(80.f, 38.f))]; + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"swipe right on window")] + assertWithMatcher:grey_sufficientlyVisible()]; + + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Window swipes start here")] + performAction:grey_swipeSlowFromStartToEndPoint(CGPointMake(150.f, 80.f), CGPointMake(50.f, 80.f))]; + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"swipe left on window")] + assertWithMatcher:grey_sufficientlyVisible()]; + + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Window swipes start here")] + performAction:grey_swipeSlowFromStartToEndPoint(CGPointMake(40.f, 100.f), CGPointMake(40.f, 30.f))]; + [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"swipe up on window")] + assertWithMatcher:grey_sufficientlyVisible()]; +} + - (void)testPinchWorksInAllDirectionsInPortraitMode { [self ftr_assertPinchWorksInAllDirections]; } diff --git a/Tests/UnitTests/Sources/GREYActionsTest.m b/Tests/UnitTests/Sources/GREYActionsTest.m index 0686254da..42a6effb9 100644 --- a/Tests/UnitTests/Sources/GREYActionsTest.m +++ b/Tests/UnitTests/Sources/GREYActionsTest.m @@ -240,5 +240,55 @@ - (void)testReplaceTextFailsOnUIView { @"Wrong error element description."); } +- (void)testPreciseSwipeActionConstraintsFailed { + UIView *view = [[UIView alloc] init]; + id swipe = [GREYActions actionForSwipeFastWithStartPoint:CGPointZero endPoint:CGPointMake(10.f, 10.f)]; + @try { + [swipe perform:view error:nil]; + XCTFail(@"Should have thrown an exception"); + } @catch (NSException *exception) { + NSString *reason = @"Cannot perform action due to constraint(s) failure."; + NSString *actionName = @"Precise swipe from {0, 0} to {10, 10} for duration 0.1"; + XCTAssertEqualObjects([exception name], kGREYActionFailedException, + @"Should throw GREYActionFailException"); + NSRange reasonRange = [exception.reason rangeOfString:reason]; + XCTAssertNotEqual(reasonRange.location, NSNotFound, + @"Did we change the exception reason?"); + NSRange actionNameRange = [exception.reason rangeOfString:actionName]; + XCTAssertNotEqual(actionNameRange.location, NSNotFound, + @"Did we change the action name?"); + NSRange viewDescriptionRange = [exception.reason rangeOfString:[view grey_description]]; + XCTAssertNotEqual(viewDescriptionRange.location, NSNotFound, + @"Did we change the element description?"); + } +} + +- (void)testPreciseSwipeOnViewWithoutWindow { + // First, disable other constraint checks so the action won't fail because of them + [[GREYConfiguration sharedInstance] setValue:@NO + forConfigKey:kGREYConfigKeyActionConstraintsEnabled]; + + UIView *view = [[UIView alloc] init]; + [[[self.mockSharedApplication stub] + andReturnValue:@(UIDeviceOrientationPortrait)] statusBarOrientation]; + id swipe = [GREYActions actionForSwipeFastWithStartPoint:CGPointMake(5.f, 5.f) endPoint:CGPointMake(5.f, 20.f)]; + + @try { + [swipe perform:view error:nil]; + XCTFail(@"Should have thrown an exception"); + } @catch (NSException *exception) { + NSString *reason = @"Cannot swipe on view [V], as it has no window and " + @"it isn't a window itself."; + XCTAssertEqualObjects([exception name], kGREYGenericFailureException, + @"Should throw GREYActionFailException"); + NSRange reasonRange = [exception.reason rangeOfString:reason]; + XCTAssertNotEqual(reasonRange.location, NSNotFound, + @"Did we change the exception reason?"); + NSRange viewDescriptionRange = [exception.reason rangeOfString:[view grey_description]]; + XCTAssertNotEqual(viewDescriptionRange.location, NSNotFound, + @"Did we change the element description?"); + } +} + @end diff --git a/Tests/UnitTests/Sources/GREYPreciseSwipeActionTest.m b/Tests/UnitTests/Sources/GREYPreciseSwipeActionTest.m new file mode 100644 index 000000000..3b9c41fae --- /dev/null +++ b/Tests/UnitTests/Sources/GREYPreciseSwipeActionTest.m @@ -0,0 +1,41 @@ +// +// Copyright 2018 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import + +#import "GREYBaseTest.h" + +@interface GREYPreciseSwipeActionTest : GREYBaseTest +@end + +@implementation GREYPreciseSwipeActionTest + +- (void)verifyGREYPreciseSwipeActionValidaWithStartPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint { + GREYPreciseSwipeAction *swipeAction = [[GREYPreciseSwipeAction alloc] initWithStartPoint:startPoint endPoint:endPoint duration:1.0]; + XCTAssertNotNil(swipeAction); +} + +- (void)testValidPreciseSwipeAction { + [self verifyGREYPreciseSwipeActionValidaWithStartPoint:CGPointZero endPoint:CGPointZero]; + [self verifyGREYPreciseSwipeActionValidaWithStartPoint:CGPointZero endPoint:CGPointMake(10.f, 10.f)]; + [self verifyGREYPreciseSwipeActionValidaWithStartPoint:CGPointMake(-5.f, -10.f) endPoint:CGPointZero]; + [self verifyGREYPreciseSwipeActionValidaWithStartPoint:CGPointMake(100.f, 100.f) endPoint:CGPointMake(50.f, 100.f)]; + [self verifyGREYPreciseSwipeActionValidaWithStartPoint:CGPointMake(100.f, 100.f) endPoint:CGPointMake(50.f, 100.f)]; +} + +@end + diff --git a/Tests/UnitTests/UnitTests.xcodeproj/project.pbxproj b/Tests/UnitTests/UnitTests.xcodeproj/project.pbxproj index 08198510c..c252d961b 100644 --- a/Tests/UnitTests/UnitTests.xcodeproj/project.pbxproj +++ b/Tests/UnitTests/UnitTests.xcodeproj/project.pbxproj @@ -74,6 +74,7 @@ 7C38A9671E1C800B00E37A8F /* GREYErrorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7C38A9661E1C800B00E37A8F /* GREYErrorTest.m */; }; 7CA881CC1E1D888E00EE18D4 /* GREYObjectFormatterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CA881CB1E1D888E00EE18D4 /* GREYObjectFormatterTest.m */; }; 7CA881D61E1DBFBE00EE18D4 /* GREYFailureFormatterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CA881D51E1DBFBE00EE18D4 /* GREYFailureFormatterTest.m */; }; + F8C4A4B920BBDC66008941DC /* GREYPreciseSwipeActionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F8C4A4B820BBDC66008941DC /* GREYPreciseSwipeActionTest.m */; }; F9C5093F1D11E9CF00D4FDED /* GREYTestHelperTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F9C5093E1D11E9CF00D4FDED /* GREYTestHelperTest.m */; }; FD1948341DA232E000B9BA2D /* GREYStopwatchTest.m in Sources */ = {isa = PBXBuildFile; fileRef = FD19482C1DA2324200B9BA2D /* GREYStopwatchTest.m */; }; FD4AB2B61D23181400D0C44D /* GREYAnalyticsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = FD1BCE911D1B3F0B0069D0C6 /* GREYAnalyticsTest.m */; }; @@ -244,6 +245,7 @@ 7C38A9661E1C800B00E37A8F /* GREYErrorTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GREYErrorTest.m; sourceTree = ""; }; 7CA881CB1E1D888E00EE18D4 /* GREYObjectFormatterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GREYObjectFormatterTest.m; sourceTree = ""; }; 7CA881D51E1DBFBE00EE18D4 /* GREYFailureFormatterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GREYFailureFormatterTest.m; sourceTree = ""; }; + F8C4A4B820BBDC66008941DC /* GREYPreciseSwipeActionTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GREYPreciseSwipeActionTest.m; sourceTree = ""; }; F9C5093E1D11E9CF00D4FDED /* GREYTestHelperTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GREYTestHelperTest.m; sourceTree = ""; }; FD19482C1DA2324200B9BA2D /* GREYStopwatchTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GREYStopwatchTest.m; sourceTree = ""; }; FD1BCE911D1B3F0B0069D0C6 /* GREYAnalyticsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GREYAnalyticsTest.m; sourceTree = ""; }; @@ -333,6 +335,7 @@ 59467EC31C9379DE0089498B /* GREYScrollActionTest.m */, 6113A2F01D7F74F400443D9B /* GREYStringDescriptionTest.m */, 59467EC51C9379DE0089498B /* GREYSwipeActionTest.m */, + F8C4A4B820BBDC66008941DC /* GREYPreciseSwipeActionTest.m */, 59467EC61C9379DE0089498B /* GREYSwizzlerTest.m */, 59467EC71C9379DE0089498B /* GREYSyncAPITest.m */, 59467EC81C9379DE0089498B /* GREYTimedIdlingResourceTest.m */, @@ -633,6 +636,7 @@ 598B73E61DDC2465007DB8AF /* EarlGreyTest.m in Sources */, 594A1A2C1D8BB8F500625FB3 /* NSURL+GREYAdditionsTest.m in Sources */, 59467F111C9379FC0089498B /* CAAnimation+GREYAdditionsTest.m in Sources */, + F8C4A4B920BBDC66008941DC /* GREYPreciseSwipeActionTest.m in Sources */, 59467F121C9379FC0089498B /* CALayer+GREYAdditionsTest.m in Sources */, 59467F131C9379FC0089498B /* CGGeometry+GREYAdditionsTest.m in Sources */, 59467F141C9379FC0089498B /* GREYActionsTest.m in Sources */,