Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(scrollTo): raise if scroll view element is not hittable. #3115

Merged
merged 20 commits into from
Dec 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
1b3e71c
fix(34.visibility.test.js): await for element matching.
asafkorem Nov 28, 2021
6302a4b
fix(DetoxPolicy): remove `percentDescriptionForValue` method.
asafkorem Nov 29, 2021
9b0c874
iOS(Test App): add native method for presenting overlay window.
asafkorem Nov 29, 2021
b78b551
iOS(Test App): write failed detox tests (to reproduce #2834).
asafkorem Nov 29, 2021
abdc4fe
fix(iOS): rewrite `isHittable` check logic.
asafkorem Dec 2, 2021
0c65205
fix(DetoxActions): use is-hittable assertion before UI gestures.
asafkorem Dec 2, 2021
5e055c4
fix(isHittable): check if view is hittable from first responder.
asafkorem Dec 2, 2021
1ad2a7a
UIView+DetoxUtils: remove redundant EL.
asafkorem Dec 4, 2021
2063212
fix(actions): use the correct coordinates systems.
asafkorem Dec 4, 2021
41beed4
fix(DetoxUtils): fix `error` handling.
asafkorem Dec 5, 2021
ae83497
fix(DetoxUtils): add nullable flag to error's value.
asafkorem Dec 5, 2021
44bfaa5
UIResponder+First: add reference to the source SO thread.
asafkorem Dec 6, 2021
24b9992
UIScrollView+DetoxActions: make informative assertion.
asafkorem Dec 6, 2021
adfe875
03.actions.test.js: add expectations.
asafkorem Dec 6, 2021
ad36fe3
03.actions-scroll.test.js: add tests for covered scroll view.
asafkorem Dec 6, 2021
2813ef1
03.actions-scroll.test.js: fix android test fail (due to timeout).
asafkorem Dec 6, 2021
7d12668
03.actions.test.js: expect only on iOS.
asafkorem Dec 6, 2021
1d67fe5
Publish 19.3.0-smoke.0 [ci skip]
mobile1-internal Dec 6, 2021
281cd54
03.actions.test.js: replace TODOs with reference to issue.
asafkorem Dec 6, 2021
43e7ee6
fix(33.attributes.test.js): expect both subviews to be hittable.
asafkorem Dec 6, 2021
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
8 changes: 8 additions & 0 deletions detox/ios/Detox.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@
6062B5E62720323700CBDBF0 /* DTXAddressInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6062B5E02720323700CBDBF0 /* DTXAddressInfo.mm */; };
60C1961A271F11C4000172DD /* fishhook.h in Headers */ = {isa = PBXBuildFile; fileRef = 60C19618271F11C4000172DD /* fishhook.h */; };
60C1961B271F11C4000172DD /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 60C19619271F11C4000172DD /* fishhook.c */; };
60E149C72759038F00519EE4 /* UIResponder+First.h in Headers */ = {isa = PBXBuildFile; fileRef = 60E149C52759038F00519EE4 /* UIResponder+First.h */; };
60E149C82759038F00519EE4 /* UIResponder+First.m in Sources */ = {isa = PBXBuildFile; fileRef = 60E149C62759038F00519EE4 /* UIResponder+First.m */; };
AD4781082636F7CF006774CD /* NSURL+DetoxUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = AD4781062636F7CE006774CD /* NSURL+DetoxUtils.h */; settings = {ATTRIBUTES = (Private, ); }; };
AD4781092636F7CF006774CD /* NSURL+DetoxUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = AD4781072636F7CF006774CD /* NSURL+DetoxUtils.m */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -299,6 +301,8 @@
6062B5E02720323700CBDBF0 /* DTXAddressInfo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = DTXAddressInfo.mm; path = DetoxSync/DetoxSync/DTXObjectiveCHelpers/DTXAddressInfo.mm; sourceTree = SOURCE_ROOT; };
60C19618271F11C4000172DD /* fishhook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fishhook.h; path = DetoxSync/DetoxSync/fishhook/fishhook.h; sourceTree = SOURCE_ROOT; };
60C19619271F11C4000172DD /* fishhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fishhook.c; path = DetoxSync/DetoxSync/fishhook/fishhook.c; sourceTree = SOURCE_ROOT; };
60E149C52759038F00519EE4 /* UIResponder+First.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIResponder+First.h"; sourceTree = "<group>"; };
60E149C62759038F00519EE4 /* UIResponder+First.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIResponder+First.m"; sourceTree = "<group>"; };
AD4781062636F7CE006774CD /* NSURL+DetoxUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSURL+DetoxUtils.h"; sourceTree = "<group>"; };
AD4781072636F7CF006774CD /* NSURL+DetoxUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSURL+DetoxUtils.m"; sourceTree = "<group>"; };
/* End PBXFileReference section */
Expand Down Expand Up @@ -525,6 +529,8 @@
395B06E3256D5A5600941716 /* UIView+DetoxSpeedup.m */,
AD4781062636F7CE006774CD /* NSURL+DetoxUtils.h */,
AD4781072636F7CF006774CD /* NSURL+DetoxUtils.m */,
60E149C52759038F00519EE4 /* UIResponder+First.h */,
60E149C62759038F00519EE4 /* UIResponder+First.m */,
);
path = Utilities;
sourceTree = "<group>";
Expand Down Expand Up @@ -601,6 +607,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
60E149C72759038F00519EE4 /* UIResponder+First.h in Headers */,
3947679C1DBF985400D72256 /* Detox.h in Headers */,
39CA978C245B13CB00A7FC43 /* UIDevice+DetoxActions.h in Headers */,
3980D11C2448B52C004812DD /* DTXSyntheticEvents.h in Headers */,
Expand Down Expand Up @@ -828,6 +835,7 @@
396D455725238BCE0096E7FA /* UIImage+DetoxUtils.m in Sources */,
39A34C721E30F10D00BEBB59 /* DetoxAppDelegateProxy.m in Sources */,
39EECB7D24C0A5AF009C3364 /* NSThread+DetoxUtils.m in Sources */,
60E149C82759038F00519EE4 /* UIResponder+First.m in Sources */,
390DED84248906FC00E27BE8 /* UIWindow+DetoxUtils.m in Sources */,
3980D158244C45EA004812DD /* Modifier.swift in Sources */,
39EECB4324BF4FDA009C3364 /* ReactNativeSupport.m in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion detox/ios/Detox/Actions/UIDatePicker+DetoxActions.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ @implementation UIDatePicker (DetoxActions)

- (void)dtx_adjustToDate:(NSDate*)date
{
[self dtx_assertVisible];
[self dtx_assertHittable];

NSDate* previousDate = self.date;

Expand Down
2 changes: 1 addition & 1 deletion detox/ios/Detox/Actions/UIPickerView+DetoxActions.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ @implementation UIPickerView (DetoxActions)

- (void)dtx_setComponent:(NSInteger)component toValue:(id)value
{
[self dtx_assertVisible];
[self dtx_assertHittable];

DTXViewAssert(self.dataSource != nil && self.delegate != nil, self.dtx_elementDebugAttributes, @"The picker view's data source and/or delegate are nil");

Expand Down
16 changes: 14 additions & 2 deletions detox/ios/Detox/Actions/UIScrollView+DetoxActions.m
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,10 @@ - (void)_dtx_scrollWithOffset:(CGPoint)offset normalizedStartingPoint:(CGPoint)n
}

CGPoint startPoint = CGPointMake(safeAreaToScroll.origin.x + safeAreaToScroll.size.width * normalizedStartingPoint.x, safeAreaToScroll.origin.y + safeAreaToScroll.size.height * normalizedStartingPoint.y);


CGPoint viewPoint = [self convertPoint:startPoint fromView:self.window];
[self dtx_assertScrollableAtPoint:viewPoint];

NSUInteger successfullyAppliedScrolls = 0;
while (offset.x != 0.0 || offset.y != 0.0)
{
Expand All @@ -305,7 +308,16 @@ - (void)_dtx_scrollWithOffset:(CGPoint)offset normalizedStartingPoint:(CGPoint)n
DTXViewAssert(strict == NO || successfullyAppliedScrolls > 0, self.dtx_elementDebugAttributes, @"Unable to scroll %@ in “%@”", _DTXScrollDirectionDescriptionWithOffset(offset), self.dtx_shortDescription);

self.dtx_disableDecelerationForScroll = NO;
// self.bounces = oldBounces;
}

- (void)dtx_assertScrollableAtPoint:(CGPoint)startPoint {
NSError *error;
DTXAssert([self dtx_isHittableAtPoint:startPoint error:&error],
@"View is not scrollable at the given start point. Start point (view coordinates): %@" \
"\n- Full error: %@\n----\nMore about scroll action API here: " \
"https://wix.github.io/Detox/docs/api/actions-on-element/" \
"#scrolloffset-direction-startpositionx-startpositiony",
NSStringFromCGPoint(startPoint), error.localizedDescription);
}

@end
8 changes: 1 addition & 7 deletions detox/ios/Detox/Invocation/Element.swift
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,7 @@ class Element : NSObject {
}

func isHittable() throws -> Bool {
var error: NSError? = nil
let rv = view.dtx_isHittable(at: view.dtx_accessibilityActivationPointInViewCoordinateSpace, error: &error)
if let error = error {
throw error
}

return rv
return view.dtx_isHittable
}

func takeScreenshot(fileName: String?) -> [String : Any] {
Expand Down
2 changes: 0 additions & 2 deletions detox/ios/Detox/Policy/DetoxPolicy.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ NS_ASSUME_NONNULL_BEGIN
@property (class, nonatomic, readonly) NSUInteger defaultPercentThresholdForVisibility;
@property (class, nonatomic, readonly) NSUInteger consecutiveTouchPointsWithSameContentOffsetThreshold;

+ (NSString*)percentDescriptionForValue:(CGFloat)value;

@end

NS_ASSUME_NONNULL_END
12 changes: 0 additions & 12 deletions detox/ios/Detox/Policy/DetoxPolicy.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,4 @@ + (NSUInteger)consecutiveTouchPointsWithSameContentOffsetThreshold {
return 12;
}

+ (NSString*)percentDescriptionForValue:(CGFloat)value {
static NSNumberFormatter* formatter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [NSNumberFormatter new];
formatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
formatter.numberStyle = NSNumberFormatterPercentStyle;
});

return [formatter stringFromNumber:@(value)];
}

@end
7 changes: 4 additions & 3 deletions detox/ios/Detox/Utilities/NSObject+DetoxUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,17 @@ static double LNLinearInterpolate(CGFloat from, CGFloat to, CGFloat p)
@property (nonatomic, readonly) CGRect dtx_visibleBounds;

- (BOOL)dtx_isVisible;
- (void)dtx_assertVisibleWithPercent:(nullable NSNumber *)percent;
- (BOOL)dtx_isVisibleAtRect:(CGRect)rect percent:(nullable NSNumber *)percent
error:(NSError* __strong * __nullable)error;
error:(NSError* __strong __nullable * __nullable)error;
- (void)dtx_assertVisible;
- (void)dtx_assertVisibleAtRect:(CGRect)rect percent:(nullable NSNumber *)percent;

- (BOOL)dtx_isFocused;

@property (nonatomic, readonly) BOOL dtx_isHittable;
- (BOOL)dtx_isHittableAtPoint:(CGPoint)point;
- (BOOL)dtx_isHittableAtPoint:(CGPoint)point error:(NSError* __strong * __nullable)error;
- (BOOL)dtx_isHittableAtPoint:(CGPoint)viewPoint
error:(NSError* __strong __nullable * __nullable)error;
- (void)dtx_assertHittable;
- (void)dtx_assertHittableAtPoint:(CGPoint)point;

Expand Down
41 changes: 17 additions & 24 deletions detox/ios/Detox/Utilities/NSObject+DetoxUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ static id DTXJSONSafeNSNumberOrString(double d)
DTX_ALWAYS_INLINE
static NSString* DTXPointToString(CGPoint point)
{
return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:DTXPointToDictionary(point) options:0 error:NULL] encoding:NSUTF8StringEncoding];
return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:DTXPointToDictionary(point) options:0 error:nil] encoding:NSUTF8StringEncoding];
}

@interface NSObject ()
Expand Down Expand Up @@ -137,19 +137,23 @@ - (CGRect)dtx_visibleBounds
}

- (BOOL)dtx_isVisible {
return [self dtx_isVisibleAtRect:self.dtx_bounds percent:nil error:NULL];
return [self dtx_isVisibleAtRect:self.dtx_bounds percent:nil error:nil];
}

- (BOOL)dtx_isVisibleAtRect:(CGRect)rect percent:(nullable NSNumber *)percent
error:(NSError *__strong _Nullable *)error {
error:(NSError* __strong __nullable * __nullable)error {
return [self.dtx_view dtx_isVisibleAtRect:rect percent:percent error:error];
}

- (void)dtx_assertVisible {
[self dtx_assertVisibleAtRect:self.dtx_bounds percent:nil];
[self dtx_assertVisibleWithPercent:nil];
}

- (void)dtx_assertVisibleAtRect:(CGRect)rect percent:(NSNumber *)percent {
- (void)dtx_assertVisibleWithPercent:(nullable NSNumber *)percent {
[self dtx_assertVisibleAtRect:self.dtx_bounds percent:percent];
}

- (void)dtx_assertVisibleAtRect:(CGRect)rect percent:(nullable NSNumber *)percent {
[self.dtx_view dtx_assertVisibleAtRect:rect percent:percent];
}

Expand All @@ -165,25 +169,14 @@ - (BOOL)dtx_isHittable
return YES;
}

- (BOOL)dtx_isHittableAtPoint:(CGPoint)point
{
return YES;
- (BOOL)dtx_isHittableAtPoint:(CGPoint)viewPoint
error:(NSError* __strong __nullable * __nullable)error {
return YES;
}

- (BOOL)dtx_isHittableAtPoint:(CGPoint)point error:(NSError* __strong * __nullable)error
{
return YES;
}
- (void)dtx_assertHittable {}

- (void)dtx_assertHittable
{

}

- (void)dtx_assertHittableAtPoint:(CGPoint)point
{

}
- (void)dtx_assertHittableAtPoint:(CGPoint)point {}

- (NSString *)dtx_text
{
Expand Down Expand Up @@ -267,7 +260,7 @@ - (CGPoint)dtx_accessibilityActivationPointInViewCoordinateSpace
{
return;
}

if([key isEqualToString:@"dtx_text"])
{
rv[@"text"] = obj;
Expand Down Expand Up @@ -379,9 +372,9 @@ - (CGPoint)dtx_accessibilityActivationPointInViewCoordinateSpace
return rv;
}

- (NSDictionary<NSString *,id> *)dtx_elementDebugAttributes
- (NSDictionary<NSString *, id> *)dtx_elementDebugAttributes
{
NSMutableDictionary* rv = [NSMutableDictionary new];
NSMutableDictionary<NSString *, id> *rv = [NSMutableDictionary new];
[rv addEntriesFromDictionary:NSObject.dtx_genericElementDebugAttributes];

rv[@"elementAttributes"] = [self dtx_attributes];
Expand Down
21 changes: 21 additions & 0 deletions detox/ios/Detox/Utilities/UIResponder+First.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// UIResponder+First.h
// Detox
//
// Created by Asaf Korem on 02/12/2021.
// Copyright © 2021 Wix. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIResponder (First)

/// Finds the first reponder.
/// @see https://stackoverflow.com/a/21330810/11686340
+ (instancetype)dtx_first;

@end

NS_ASSUME_NONNULL_END
26 changes: 26 additions & 0 deletions detox/ios/Detox/Utilities/UIResponder+First.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// UIResponder+First.m
// Detox
//
// Created by Asaf Korem on 02/12/2021.
// Copyright © 2021 Wix. All rights reserved.
//

#import "UIResponder+First.h"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ref stackoverflow

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

v


static __weak UIResponder *_dtx_first;

@implementation UIResponder (First)

+ (instancetype)dtx_first {
_dtx_first = nil;
[[UIApplication sharedApplication] sendAction:@selector(responderAction:) to:nil from:nil
forEvent:nil];
return _dtx_first;
}

- (void)responderAction:(id)sender {
_dtx_first = self;
}

@end
Loading