Skip to content

Commit

Permalink
wait for view to appear, closes #30
Browse files Browse the repository at this point in the history
  • Loading branch information
talkol committed Oct 9, 2016
1 parent 9d01548 commit a801900
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 4 deletions.
8 changes: 8 additions & 0 deletions detox/ios/Detox.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
CCA99FFF1D227DBE00C762B8 /* ReactNativeSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = CCA99FFD1D227DBE00C762B8 /* ReactNativeSupport.h */; };
CCA9A0001D227DBE00C762B8 /* ReactNativeSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = CCA99FFE1D227DBE00C762B8 /* ReactNativeSupport.m */; };
CCE6D43B1D11A76500F81E39 /* Detox.h in Headers */ = {isa = PBXBuildFile; fileRef = CCE6D43A1D11A76500F81E39 /* Detox.h */; settings = {ATTRIBUTES = (Public, ); }; };
CCF391F71DAA8B9200BBFB1E /* GREYCondition+Detox.h in Headers */ = {isa = PBXBuildFile; fileRef = CCF391F51DAA8B9200BBFB1E /* GREYCondition+Detox.h */; };
CCF391F81DAA8B9200BBFB1E /* GREYCondition+Detox.m in Sources */ = {isa = PBXBuildFile; fileRef = CCF391F61DAA8B9200BBFB1E /* GREYCondition+Detox.m */; };
CCFA7D8F1D11C54100E15EDF /* EarlGrey.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CCFA7D8E1D11C4E400E15EDF /* EarlGrey.framework */; };
CCFA7DB31D11C63100E15EDF /* SRDelegateController.h in Headers */ = {isa = PBXBuildFile; fileRef = CCFA7D951D11C63000E15EDF /* SRDelegateController.h */; };
CCFA7DB41D11C63100E15EDF /* SRDelegateController.m in Sources */ = {isa = PBXBuildFile; fileRef = CCFA7D961D11C63000E15EDF /* SRDelegateController.m */; };
Expand Down Expand Up @@ -103,6 +105,8 @@
CCE6D4371D11A76500F81E39 /* Detox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Detox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CCE6D43A1D11A76500F81E39 /* Detox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Detox.h; sourceTree = "<group>"; };
CCE6D43C1D11A76500F81E39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
CCF391F51DAA8B9200BBFB1E /* GREYCondition+Detox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GREYCondition+Detox.h"; sourceTree = "<group>"; };
CCF391F61DAA8B9200BBFB1E /* GREYCondition+Detox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GREYCondition+Detox.m"; sourceTree = "<group>"; };
CCFA7D891D11C4E400E15EDF /* EarlGrey.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = EarlGrey.xcodeproj; path = EarlGrey/EarlGrey.xcodeproj; sourceTree = SOURCE_ROOT; };
CCFA7D951D11C63000E15EDF /* SRDelegateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRDelegateController.h; sourceTree = "<group>"; };
CCFA7D961D11C63000E15EDF /* SRDelegateController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SRDelegateController.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -180,6 +184,8 @@
children = (
CC654C741DA7B3720057ECE9 /* GREYMatchers+Detox.h */,
CC654C751DA7B3720057ECE9 /* GREYMatchers+Detox.m */,
CCF391F51DAA8B9200BBFB1E /* GREYCondition+Detox.h */,
CCF391F61DAA8B9200BBFB1E /* GREYCondition+Detox.m */,
);
name = EarlGreyExtentions;
sourceTree = "<group>";
Expand Down Expand Up @@ -340,6 +346,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
CCF391F71DAA8B9200BBFB1E /* GREYCondition+Detox.h in Headers */,
CCFA7DB51D11C63100E15EDF /* SRIOConsumer.h in Headers */,
CCFA7DB91D11C63100E15EDF /* SRProxyConnect.h in Headers */,
CC38FC4F1D622AFB00589F1C /* ReactNativeUIManagerIdlingResource.h in Headers */,
Expand Down Expand Up @@ -472,6 +479,7 @@
CC38FC461D61DEB800589F1C /* ReactNativeBridgeIdlingResource.m in Sources */,
CCFA7DB41D11C63100E15EDF /* SRDelegateController.m in Sources */,
CCFA7DC81D11C63100E15EDF /* NSURLRequest+SRWebSocket.m in Sources */,
CCF391F81DAA8B9200BBFB1E /* GREYCondition+Detox.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
15 changes: 15 additions & 0 deletions detox/ios/Detox/GREYCondition+Detox.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// GREYCondition+Detox.h
// Detox
//
// Created by Tal Kol on 10/9/16.
// Copyright © 2016 Wix. All rights reserved.
//

@import EarlGrey;

@interface GREYCondition (Detox)

+ (instancetype)detoxConditionForElementMatched:(GREYElementInteraction*)interaction;

@end
22 changes: 22 additions & 0 deletions detox/ios/Detox/GREYCondition+Detox.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// GREYCondition+Detox.m
// Detox
//
// Created by Tal Kol on 10/9/16.
// Copyright © 2016 Wix. All rights reserved.
//

#import "GREYCondition+Detox.h"

@implementation GREYCondition (Detox)

+ (instancetype)detoxConditionForElementMatched:(GREYElementInteraction*)interaction
{
return [self conditionWithName:@"Wait for element Detox Condition" block:^BOOL{
NSError *error;
[interaction assertWithMatcher:grey_notNil() error:&error];
return (error == nil);
}];
}

@end
9 changes: 6 additions & 3 deletions detox/src/ios/expect.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,14 @@ class WaitForInteraction extends Interaction {
if (!matcher instanceof Matcher) throw new Error(`WaitForInteraction ctor 2nd argument must be a valid Matcher, got ${typeof matcher}`);
this._element = element;
this._originalMatcher = matcher;
// we need to override the original matcher for the element and add matcher to it as well
this._element._selectElementWithMatcher(new CombineBothMatcher(this._element._originalMatcher, matcher));
}
withTimeout(timeout) {
throw new Error('not implemented');
if (typeof timeout !== 'number') throw new Error(`WaitForInteraction withTimeout argument must be a number, got ${typeof timeout}`);
const _conditionCall = invoke.call(invoke.IOS.Class('GREYCondition'), 'detoxConditionForElementMatched:', this._element._call);
this._call = invoke.call(_conditionCall, 'waitWithTimeout:', invoke.IOS.CGFloat(timeout));
this.execute();
}
whileElement(searchMatcher) {
return new WaitForActionInteraction(this._element, this._originalMatcher, searchMatcher);
Expand All @@ -217,8 +222,6 @@ class WaitForActionInteraction extends Interaction {
this._element = element;
this._originalMatcher = matcher;
this._searchMatcher = searchMatcher;
// we need to override the original matcher for the element and add matcher to it as well
this._element._selectElementWithMatcher(new CombineBothMatcher(this._element._originalMatcher, matcher));
}
_execute(searchAction) {
if (!searchAction instanceof Action) throw new Error(`WaitForActionInteraction _execute argument must be a valid Action, got ${typeof searchAction}`);
Expand Down
6 changes: 6 additions & 0 deletions detox/test/e2e/e-waitfor.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ describe('WaitFor', function () {
element(by.label('WaitFor')).tap();
});

it('should wait until an element is visible', function () {
expect(element(by.id('UniqueId336'))).toNotExist();
waitFor(element(by.id('UniqueId336'))).toBeVisible().withTimeout(2000);
expect(element(by.id('UniqueId336'))).toBeVisible();
});

it('should find element by scrolling until it is visible', function () {
expect(element(by.label('Text5'))).toBeNotVisible();
waitFor(element(by.label('Text5'))).toBeVisible().whileElement(by.id('ScrollView630')).scroll(50, 'down');
Expand Down
10 changes: 9 additions & 1 deletion detox/test/src/Screens/WaitForScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,23 @@ export default class WaitForScreen extends Component {
constructor(props) {
super(props);
this.state = {
greeting: undefined
greeting: undefined,
showsUp: false
};
setTimeout(() => {
this.setState({showsUp: true});
}, 1000);
}

render() {
if (this.state.greeting) return this.renderAfterButton();
return (
<View style={{flex: 1, paddingTop: 40, justifyContent: 'flex-start'}}>

{!this.state.showsUp ? false :
<Text testID='UniqueId336' style={{marginBottom: 20, textAlign: 'center'}}>I appear after 1 sec</Text>
}

<View style={{height: 100, borderColor: '#c0c0c0', borderWidth: 1, backgroundColor: '#f8f8ff', marginBottom: 20}}>
<ScrollView testID='ScrollView630'>
<Text style={{height: 30, backgroundColor: '#e8e8f8', padding: 5, margin: 10}}>Text1</Text>
Expand Down

0 comments on commit a801900

Please sign in to comment.