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

Select date on IOS UIDatePicker with actionForSetDate #1148

Merged
merged 4 commits into from
Feb 9, 2019
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
Empty file modified detox-cli/cli.js
100644 → 100755
Empty file.
6 changes: 6 additions & 0 deletions detox/ios/Detox.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
394D589C1E50B59400556DB9 /* NSBundle+TestsFix.m in Sources */ = {isa = PBXBuildFile; fileRef = 394D589B1E50B59400556DB9 /* NSBundle+TestsFix.m */; };
397EC9B51E7EDE0B00D5F2BB /* EarlGreyStatistics.h in Headers */ = {isa = PBXBuildFile; fileRef = 397EC9B31E7EDE0B00D5F2BB /* EarlGreyStatistics.h */; };
397EC9B61E7EDE0B00D5F2BB /* EarlGreyStatistics.m in Sources */ = {isa = PBXBuildFile; fileRef = 397EC9B41E7EDE0B00D5F2BB /* EarlGreyStatistics.m */; };
398260E8220CC9530061E83E /* GREYActions+Detox.m in Sources */ = {isa = PBXBuildFile; fileRef = 398260D4220CA56D0061E83E /* GREYActions+Detox.m */; };
399BF36821933F0C00F96D50 /* ExternalLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 399BF36621933F0C00F96D50 /* ExternalLogging.h */; };
399BF36921933F0C00F96D50 /* ExternalLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 399BF36721933F0C00F96D50 /* ExternalLogging.m */; };
39A34C711E30F10D00BEBB59 /* DetoxAppDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 39A34C6F1E30F10D00BEBB59 /* DetoxAppDelegateProxy.h */; settings = {ATTRIBUTES = (Private, ); }; };
Expand Down Expand Up @@ -230,6 +231,8 @@
3975C78220272ED500C59ED8 /* src */ = {isa = PBXFileReference; lastKnownFileType = folder; name = src; path = ../src; sourceTree = "<group>"; };
397EC9B31E7EDE0B00D5F2BB /* EarlGreyStatistics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EarlGreyStatistics.h; sourceTree = "<group>"; };
397EC9B41E7EDE0B00D5F2BB /* EarlGreyStatistics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EarlGreyStatistics.m; sourceTree = "<group>"; };
398260CE220CA5380061E83E /* GREYActions+Detox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GREYActions+Detox.h"; sourceTree = "<group>"; };
398260D4220CA56D0061E83E /* GREYActions+Detox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "GREYActions+Detox.m"; sourceTree = "<group>"; };
399BF36621933F0C00F96D50 /* ExternalLogging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExternalLogging.h; sourceTree = "<group>"; };
399BF36721933F0C00F96D50 /* ExternalLogging.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExternalLogging.m; sourceTree = "<group>"; };
39A34C6F1E30F10D00BEBB59 /* DetoxAppDelegateProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetoxAppDelegateProxy.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -395,6 +398,8 @@
391FA5E81E7FD96D0056F82F /* GREYIdlingResourcePrettyPrint.m */,
46A6A6341EF696B600E3AA79 /* GREYConfiguration+Detox.h */,
46A6A63B1EF697BB00E3AA79 /* GREYConfiguration+Detox.m */,
398260CE220CA5380061E83E /* GREYActions+Detox.h */,
398260D4220CA56D0061E83E /* GREYActions+Detox.m */,
);
name = EarlGreyExtensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -700,6 +705,7 @@
39CEFCDB1E34E91B00A09124 /* DetoxUserNotificationDispatcher.swift in Sources */,
394767C21DBF98A700D72256 /* GREYMatchers+Detox.m in Sources */,
394767AF1DBF987E00D72256 /* DetoxManager.m in Sources */,
398260E8220CC9530061E83E /* GREYActions+Detox.m in Sources */,
39FFD9471FD730A600C97030 /* DetoxCrashHandler.mm in Sources */,
46A6A63D1EF697BB00E3AA79 /* GREYConfiguration+Detox.m in Sources */,
);
Expand Down
2 changes: 2 additions & 0 deletions detox/ios/Detox/DTXMethodInvocation.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#import "DTXMethodInvocation.h"
@import EarlGrey;
#import <EarlGrey/GreyActions.h>
#import "GREYActions+Detox.h"

@implementation DTXMethodInvocation

Expand Down
16 changes: 16 additions & 0 deletions detox/ios/Detox/GREYActions+Detox.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// GREYActions+Detox.h
// Detox
//
// Created by Matt Findley on 2/7/19.
// Copyright © 2019 Wix. All rights reserved.
//

@import Foundation;
#import <EarlGrey/EarlGrey.h>

@interface GREYActions (Detox)

+ (id<GREYAction>)detoxSetDatePickerDate:(NSString *)dateString withFormat:(NSString *)dateFormat;

@end
23 changes: 23 additions & 0 deletions detox/ios/Detox/GREYActions+Detox.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// GREYActions+Detox.m
// Detox
//
// Created by Matt Findley on 2/7/19.
// Copyright © 2019 Wix. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "GREYActions+Detox.h"
#import <EarlGrey/GREYActions.h>

@implementation GREYActions (Detox)

+ (id<GREYAction>)detoxSetDatePickerDate:(NSString *)dateString withFormat:(NSString *)dateFormat
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = dateFormat;

NSDate *date = [formatter dateFromString:dateString];
return [GREYActions actionForSetDate:date];
}
@end
31 changes: 31 additions & 0 deletions detox/src/ios/earlgreyapi/GREYActions+Detox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**

This code is generated.
For more information see generation/README.md.
*/



class GREYActions {
static detoxSetDatePickerDateWithFormat(dateString, dateFormat) {
if (typeof dateString !== "string") throw new Error("dateString should be a string, but got " + (dateString + (" (" + (typeof dateString + ")"))));
if (typeof dateFormat !== "string") throw new Error("dateFormat should be a string, but got " + (dateFormat + (" (" + (typeof dateFormat + ")"))));
return {
target: {
type: "Class",
value: "GREYActions"
},
method: "detoxSetDatePickerDate:withFormat:",
args: [{
type: "NSString",
value: dateString
}, {
type: "NSString",
value: dateFormat
}]
};
}

}

module.exports = GREYActions;
13 changes: 12 additions & 1 deletion detox/src/ios/expect.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const GreyActions = require('./earlgreyapi/GREYActions');
const GreyInteraction = require('./earlgreyapi/GREYInteraction');
const GreyCondition = require('./earlgreyapi/GREYCondition');
const GreyConditionDetox = require('./earlgreyapi/GREYConditionDetox');
const GreyActionsDetox = require('./earlgreyapi/GREYActions+Detox');

let invocationManager;

Expand Down Expand Up @@ -184,7 +185,14 @@ class SwipeAction extends Action {
class ScrollColumnToValue extends Action {
constructor(column,value) {
super();
this._call = invoke.callDirectly(GreyActions.actionForSetPickerColumnToValue(column,value))
this._call = invoke.callDirectly(GreyActions.actionForSetPickerColumnToValue(column, value));
}
}

class SetDatePickerDate extends Action {
constructor(dateString, dateFormat) {
super();
this._call = invoke.callDirectly(GreyActionsDetox.detoxSetDatePickerDateWithFormat(dateString, dateFormat));
}
}

Expand Down Expand Up @@ -330,6 +338,9 @@ class Element {
async setColumnToValue(column,value) {
return await new ActionInteraction(this, new ScrollColumnToValue(column, value)).execute();
}
async setDatePickerDate(dateString, dateFormat) {
return await new ActionInteraction(this, new SetDatePickerDate(dateString, dateFormat)).execute();
}
}

class Expect { }
Expand Down
3 changes: 3 additions & 0 deletions detox/src/ios/expect.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ describe('expect', async () => {
it(`element by type`, async () => {
await e.expect(e.element(e.by.type('test'))).toBeVisible();
await e.element(e.by.type('UIPickerView')).setColumnToValue(1,"6");
await e.element(e.by.type('UIPickerView')).setDatePickerDate('2019-2-8T05:10:00-08:00', "yyyy-MM-dd'T'HH:mm:ssZZZZZ");
});

it(`element by traits`, async () => {
Expand Down Expand Up @@ -152,6 +153,8 @@ describe('expect', async () => {
await expectToThrow(() => e.element(e.by.id('ScrollView799')).swipe('down', 'NotFastNorSlow'));
await expectToThrow(() => e.element(e.by.id('ScrollView799')).swipe('down', 'NotFastNorSlow', 0.9));
await expectToThrow(() => e.element(e.by.id('ScrollView799')).atIndex('NaN'));
await expectToThrow(() => e.element(e.by.type('UIPickerView')).setDatePickerDate(0, 'mm'));
await expectToThrow(() => e.element(e.by.type('UIPickerView')).setDatePickerDate('something', 0));
});

it(`exportGlobals() should export api functions`, async () => {
Expand Down
11 changes: 8 additions & 3 deletions detox/test/e2e/17.datePicker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@ describe(':ios: DatePicker', () => {
await device.reloadReactNative();
await element(by.text('DatePicker')).tap();
});

it('datePicker should trigger change handler correctly', async () => {
await element(by.type('UIPickerView')).setColumnToValue(1,"6");
await element(by.type('UIPickerView')).setColumnToValue(2,"34");
await expect(element(by.id("timeLabel"))).toHaveText('choosenTime is 6:34');
});

});

it('can select dates on a UIDatePicker', async () => {
await element(by.type('UIDatePicker')).setDatePickerDate('2019-02-06T05:10:00-08:00', "yyyy-MM-dd'T'HH:mm:ssZZZZZ");

await expect(element(by.id('dateTimeLabel'))).toHaveText('choosenDateTime is 2-6-2019 5:10');
});

});
48 changes: 25 additions & 23 deletions detox/test/src/Screens/DatePickerScreen.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,49 @@
import React, { Component } from 'react';
import {
Text,
View,
StyleSheet,
DatePickerIOS
} from 'react-native';
import { Text, View, StyleSheet, DatePickerIOS } from 'react-native';
Copy link
Member

@rotemmiz rotemmiz Feb 9, 2019

Choose a reason for hiding this comment

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

You can't add DatePickerIOS on a shared component, it needs to run on both iOS and Android.
You might need to split this screen to .ios.js and .android.js.
This is probably the reason why the e2e hangs, the app crashes.

Copy link
Contributor

Choose a reason for hiding this comment

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

But that’s not a new change. How did it work until now?

Copy link
Member

Choose a reason for hiding this comment

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

ho, you're right, I haven't noticed that


export default class DatePickerScreen extends Component {

constructor(props) {
super(props);
this.state = {
chosenDate: new Date()
}
};
this._setDate = this._setDate.bind(this);
}

_setDate(newDate) {
this.setState({
chosenDate :newDate
})
chosenDate: newDate
});
}

getTime() {
minutes = this.state.chosenDate.getMinutes()
hour = this.state.chosenDate.getHours()
if( hour > 12 ) {
minutes = this.state.chosenDate.getMinutes();
hour = this.state.chosenDate.getHours();

if (hour > 12) {
hour = hour - 12;
}
return `${hour}:${minutes}`
return `${hour}:${minutes}`;
}

getDateTime() {
year = this.state.chosenDate.getFullYear();
month = this.state.chosenDate.getMonth() + 1;
day = this.state.chosenDate.getDate();

return `${month}-${day}-${year} ${this.getTime()}`;
}

render() {
return (
<View style={{flex: 1, paddingTop: 20, justifyContent: 'center', alignItems: 'center'}}>
<Text style = {styles.dateText} testID='timeLabel'>
<Text style={styles.dateText} testID='timeLabel'>
{"choosenTime is " + this.getTime()}
</Text>
<DatePickerIOS
style = {styles.datePicker}
date = {this.state.chosenDate}
onDateChange={this._setDate}
/>
<Text style={styles.dateText} testID="dateTimeLabel">
{"choosenDateTime is " + this.getDateTime()}
</Text>
<DatePickerIOS style={styles.datePicker} date={this.state.chosenDate} onDateChange={this._setDate} />
</View>
);
}
Expand All @@ -51,9 +53,9 @@ const styles = StyleSheet.create({
datePicker: {
width:'100%',
height:200,
backgroundColor:'green',
backgroundColor:'green'
},
dateText: {
textAlign: 'center',
}
textAlign:'center'
}
});
13 changes: 12 additions & 1 deletion docs/APIRef.ActionsOnElement.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Actions are functions that emulate user behavior. They are being performed on ma
- [`.swipe()`](#swipedirection-speed-percentage)
- [`.setColumnToValue()`](#setcolumntovaluecolumnvalue--ios-only) **iOS only**
- [`.pinchWithAngle()`](#pinchWithAngle--ios-only) **iOS only**
- [`.setDatePickerDate()`](#setdatepickerdate--ios-only) **iOS only**


### `tap()`
Expand Down Expand Up @@ -146,4 +147,14 @@ angle - value in radiant - default is 0<br>
```js
await expect(element(by.id('PinchableScrollView'))).toBeVisible();
await element(by.id('PinchableScrollView')).pinchWithAngle('outward', 'slow', 0);
```
```

### `setDatePickerDate(dateString, dateFormat)` iOS only

dateString - string representing a date in the supplied dateFormat<br>
dateFormat - format for the dateString supplied<br>

```js
await expect(element(by.type('UIDatePicker'))).toBeVisible();
await element(by.type('UIDatePicker)).setDatePickerDate('2019-02-06T05:10:00-08:00', "yyyy-MM-dd'T'HH:mm:ssZZZZZ");
```
3 changes: 2 additions & 1 deletion generation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const iosFiles = {
'../detox/ios/EarlGrey/EarlGrey/Synchronization/GREYCondition.h': '../detox/src/ios/earlgreyapi/GREYCondition.js',
'../detox/ios/Detox/GREYConfiguration+Detox.h': '../detox/src/ios/earlgreyapi/GREYConfigurationDetox.js',
'../detox/ios/EarlGrey/EarlGrey/Common/GREYConfiguration.h': '../detox/src/ios/earlgreyapi/GREYConfiguration.js',
'../detox/ios/EarlGrey/EarlGrey/Core/EarlGreyImpl.h': '../detox/src/ios/earlgreyapi/EarlGreyImpl.js'
'../detox/ios/EarlGrey/EarlGrey/Core/EarlGreyImpl.h': '../detox/src/ios/earlgreyapi/EarlGreyImpl.js',
'../detox/ios/Detox/GREYActions+Detox.h': '../detox/src/ios/earlgreyapi/GREYActions+Detox.js'
};

generateIOSAdapters(iosFiles);
Expand Down