Skip to content

Commit

Permalink
feat(android): add testID support to date (not time) picker (#705)
Browse files Browse the repository at this point in the history
* add testid support

* switch tests to use testID for picker

* adjust docs to explain testID working on android

* remove accidental var

* fix accidentally broken matcher

* Rephrase testID docs to be more generic instad of focused on detox

* docs: review

---------

Co-authored-by: Maurice Döpke <mauricedoepkeoutlook.de>
Co-authored-by: Vojtech Novak <vonovak@gmail.com>
  • Loading branch information
mauricedoepke and vonovak committed Jul 6, 2023
1 parent 4bd4586 commit e571d71
Show file tree
Hide file tree
Showing 10 changed files with 30 additions and 3 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,15 @@ Alternatively, use the `themeVariant` prop.

If true, the user won't be able to interact with the view.

#### `testID` (`optional`)

Usually used by app automation frameworks.
Fully supported on iOS. On Android, only supported for `mode="date"`.

```js
<RNDateTimePicker testID="datePicker" />
```

#### `View Props` (`optional`, `iOS only`)

On iOS, you can pass any [View props](https://reactnative.dev/docs/view#props) to the component. Given that the underlying component is a native view, not all of them are guaranteed to be supported, but `testID` and `onLayout` are known to work.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ public void dismiss(Promise promise) {
* <li>
* {@code display} To set the date picker display to 'calendar/spinner/default'
* </li>
* <li>
* {@code testID} testID for testing with e.g. detox.
* </li>
* </ul>
*
* @param promise This will be invoked with parameters action, year,
Expand Down Expand Up @@ -198,6 +201,9 @@ private Bundle createFragmentArguments(ReadableMap options) {
if (options.hasKey(RNConstants.ARG_TZOFFSET_MINS) && !options.isNull(RNConstants.ARG_TZOFFSET_MINS)) {
args.putLong(RNConstants.ARG_TZOFFSET_MINS, (long) options.getDouble(RNConstants.ARG_TZOFFSET_MINS));
}
if (options.hasKey(RNConstants.ARG_TESTID) && !options.isNull(RNConstants.ARG_TESTID)) {
args.putString(RNConstants.ARG_TESTID, options.getString(RNConstants.ARG_TESTID));
}
return args;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public final class RNConstants {
public static final String ARG_DISPLAY = "display";
public static final String ARG_DIALOG_BUTTONS = "dialogButtons";
public static final String ARG_TZOFFSET_MINS = "timeZoneOffsetInMinutes";
public static final String ARG_TESTID = "testID";
public static final String ACTION_DATE_SET = "dateSetAction";
public static final String ACTION_TIME_SET = "timeSetAction";
public static final String ACTION_DISMISSED = "dismissedAction";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ private DatePickerDialog createDialog(Bundle args) {
datePicker.setOnDateChangedListener(new KeepDateInRangeListener(args));
}

if (args != null && args.containsKey(RNConstants.ARG_TESTID)) {
datePicker.setTag(args.getString(RNConstants.ARG_TESTID));
}

return dialog;
}

Expand Down
2 changes: 1 addition & 1 deletion example/e2e/detoxTest.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe('e2e tests', () => {
const calendarHorizontalScrollView = element(
by
.type('android.widget.ScrollView')
.withAncestor(by.type('android.widget.DatePicker')),
.withAncestor(by.id('dateTimePicker')),
);
await calendarHorizontalScrollView.swipe('left', 'fast', 1);
await calendarHorizontalScrollView.tap({x: 50, y: 200});
Expand Down
3 changes: 1 addition & 2 deletions example/e2e/utils/matchers.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ const getInlineTimePickerIOS = () => element(by.label('Time Picker'));

const getDateTimePickerControlIOS = () => element(by.type('UIDatePicker'));

const getDatePickerAndroid = () =>
element(by.type('android.widget.DatePicker'));
const getDatePickerAndroid = () => element(by.id('dateTimePicker'));

module.exports = {
getTimeText,
Expand Down
2 changes: 2 additions & 0 deletions src/DateTimePickerAndroid.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ function open(props: AndroidNativeProps) {
neutralButtonLabel,
positiveButtonLabel,
negativeButtonLabel,
testID,
} = props;
validateAndroidProps(props);
invariant(originalValue, 'A date or time must be specified as `value` prop.');
Expand Down Expand Up @@ -84,6 +85,7 @@ function open(props: AndroidNativeProps) {
minuteInterval,
timeZoneOffsetInMinutes,
dialogButtons,
testID,
});

switch (action) {
Expand Down
3 changes: 3 additions & 0 deletions src/androidUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type OpenParams = {
maximumDate: AndroidNativeProps['maximumDate'],
minuteInterval: AndroidNativeProps['minuteInterval'],
timeZoneOffsetInMinutes: AndroidNativeProps['timeZoneOffsetInMinutes'],
testID: AndroidNativeProps['testID'],
dialogButtons: {
positive: ProcessedButton,
negative: ProcessedButton,
Expand Down Expand Up @@ -64,6 +65,7 @@ function getOpenPicker(
maximumDate,
timeZoneOffsetInMinutes,
dialogButtons,
testID,
}: OpenParams) =>
// $FlowFixMe - `AbstractComponent` [1] is not an instance type.
pickers[ANDROID_MODE.date].open({
Expand All @@ -73,6 +75,7 @@ function getOpenPicker(
maximumDate,
timeZoneOffsetInMinutes,
dialogButtons,
testID,
});
}
}
Expand Down
1 change: 1 addition & 0 deletions src/datepicker.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default class DatePickerAndroid {
* - `value` (`Date` object) - date to show by default
* - `minimumDate` (`Date` object) - minimum date that can be selected
* - `maximumDate` (`Date` object) - maximum date that can be selected
* - `testID` (`string`) - Sets view tag for use with automation frameworks
* - `display` (`enum('calendar', 'spinner', 'default')`) - To set the date-picker display to calendar/spinner/default
* - 'calendar': Show a date picker in calendar mode.
* - 'spinner': Show a date picker in spinner mode.
Expand Down
2 changes: 2 additions & 0 deletions src/datetimepicker.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default function RNDateTimePickerAndroid(
positiveButtonLabel,
negativeButtonLabel,
neutralButtonLabel,
testID,
} = props;
const valueTimestamp = value.getTime();

Expand Down Expand Up @@ -58,6 +59,7 @@ export default function RNDateTimePickerAndroid(
positiveButtonLabel,
negativeButtonLabel,
neutralButtonLabel,
testID,
};
DateTimePickerAndroid.open(params);
},
Expand Down

0 comments on commit e571d71

Please sign in to comment.