You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I've implemented a class to change the device time using UiAutomator. Likely to be useful for scheduled notification testing.
It relies only on UiAutomator. The idea is to have a simple way to test notifications e2e in the end with other POM/like helpers for notifications for instance. I like the idea of making it as low level as possible. Preferably without espresso dependency. Perhaps it would make sense to integrate it in here though. It loosely follows the page object model framework.
I am open to any idea (or ticket rejection).
Here is the class at the moment.
packageorg.pnplab.flux.notifications;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.os.RemoteException;
importandroid.util.Log;
importandroidx.test.core.app.ApplicationProvider;
importandroidx.test.uiautomator.By;
importandroidx.test.uiautomator.UiCollection;
importandroidx.test.uiautomator.UiDevice;
importandroidx.test.uiautomator.UiObject;
importandroidx.test.uiautomator.UiObject2;
importandroidx.test.uiautomator.UiObjectNotFoundException;
importandroidx.test.uiautomator.UiScrollable;
importandroidx.test.uiautomator.UiSelector;
importandroidx.test.uiautomator.Until;
importjava.time.LocalDate;
importjava.time.LocalDateTime;
importjava.time.LocalTime;
importjava.time.Period;
importjava.time.format.DateTimeFormatter;
importjava.util.Locale;
// Some helper class to set the time for notifications using UIAutomator, only works with english// android and only tested w/ android v28.//// For DateTimeFormatter doc, used at multiple time in this class, see// `https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html`.// @note Have found this lib that provides helper function to handle datepicker and timepicker in// android after writing these tests `https://github.com/AdevintaSpain/Barista`.// @todo make that class locale agnostic and inject it class into Barista framework :-)publicclassDateTimeSettingsPOM {
privatefinalUiDevicedevice;
privatefinallongtimeout;
publicDateTimeSettingsPOM(UiDevicedevice, longtimeout) {
this.device = device;
this.timeout = timeout;
}
/** * Open the android Settings app at the date & time panel. */publicvoidopenSettings() {
// Start from the home screendevice.pressHome();
// Wait for launcherfinalStringlauncherPackage = device.getLauncherPackageName();
assert(launcherPackage != null);
device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), timeout);
// Get context (of Home app ?).Contextcontext = ApplicationProvider.getApplicationContext();
// Launch Date & Time settings.finalIntentintent = newIntent(android.provider.Settings.ACTION_DATE_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
/** * Enable manual time settings. * * @pre User must be in settings (see `#openSettings`). * @post User is in settings. * * @throws UiObjectNotFoundException */publicvoidenableManualDateTime() throwsUiObjectNotFoundException {
// Toggle automatic date & time off.UiScrollabledateTimeSettingList = newUiScrollable(newUiSelector().className("android.support.v7.widget.RecyclerView"));
UiObjectautomaticDateTimeOption = dateTimeSettingList.getChildByText(newUiSelector().className("android.widget.LinearLayout"), "Automatic date & time");
UiObjectautomaticDateTimeSwitch = automaticDateTimeOption.getChild(newUiSelector().className("android.widget.Switch"));
if (automaticDateTimeSwitch.isChecked()) {
automaticDateTimeSwitch.click();
}
}
/** * Set the time automatically based on NTP server sync. Disable manual time settings. * * @pre User must be in settings (see `#openSettings`). * @post User is in settings. * * @throws UiObjectNotFoundException */publicvoiddisableManualDateTime() throwsUiObjectNotFoundException {
// Turn automatic date & time on.UiScrollabledateTimeSettingList = newUiScrollable(newUiSelector().className("android.support.v7.widget.RecyclerView"));
UiObjectautomaticDateTimeOption = dateTimeSettingList.getChildByText(newUiSelector().className("android.widget.LinearLayout"), "Automatic date & time");
UiObjectautomaticDateTimeSwitch = automaticDateTimeOption.getChild(newUiSelector().className("android.widget.Switch"));
if (!automaticDateTimeSwitch.isChecked()) {
automaticDateTimeSwitch.click();
}
}
/** * Change the phone's date and time settings. * * @param datetimeStr "yyyy-MM-dd HH:mm" format. seconds throw exception. * * @pre User must be in settings (see `#openSettings`). * @post User is in settings. */publicvoidsetIsoDateTime(StringdatetimeStr) throwsUiObjectNotFoundException {
// Split datetime into date and time str.LocalDateTimedateTime = LocalDateTime.parse(datetimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
LocalDatelocalDate = dateTime.toLocalDate();
LocalTimelocalTime = dateTime.toLocalTime();
StringlocalDateStr = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
StringlocalTimeStr = localTime.format(DateTimeFormatter.ofPattern("HH:mm"));
// Apply date and time setting changes.setIsoDate(localDateStr);
setIsoTime(localTimeStr);
}
/** * Set the current date. * * @param dateStr "yyyy-MM-dd" format * * @pre User must be in settings (see `#openSettings`). * @pre Automatic date time must be disabled (see `#enableManualDateTime`). * @post User is in settings. * * @throws UiObjectNotFoundException */publicvoidsetIsoDate(StringdateStr) throwsUiObjectNotFoundException {
// Open Set date panel.UiScrollabledateTimeSettingList = newUiScrollable(newUiSelector().className("android.support.v7.widget.RecyclerView"));
UiObjectsetDate = dateTimeSettingList.getChildByText(newUiSelector().className("android.widget.TextView"), "Set date");
setDate.click();
// Get current day, month and year.UiObjectyearItem = newUiObject(newUiSelector().resourceId("android:id/date_picker_header_year"));
Stringyear = yearItem.getText();
UiObjectdateWithoutYearItem = newUiObject(newUiSelector().resourceId("android:id/date_picker_header_date"));
StringdateWithoutYear = dateWithoutYearItem.getText(); // ie. `Wed, Oct 9`// Parse it as a date object.DateTimeFormatterdateTimeFormatter = DateTimeFormatter.ofPattern("E, MMM d yyyy");
dateTimeFormatter = dateTimeFormatter.withLocale(Locale.US);
// Line commented out because doesn't parse with dual locale for some reason...// dateTimeFormatter = dateTimeFormatter.withLocale(Locale.FRENCH);LocalDateoutputDate = LocalDate.parse(dateWithoutYear + " " + year, dateTimeFormatter);
// Set target date.LocalDatetargetDate = LocalDate.parse(dateStr);
// Get date diff.Periodperiod = Period.between(outputDate, targetDate);
intyearDiff = period.getYears();
intmonthDiff = period.getMonths() + (yearDiff * 12);
period = period.minusMonths(monthDiff);
intdayDiff = period.getDays();
// LogLog.i("TAG", dateStr + " " + targetDate.toString() + " " + monthDiff + " " + targetDate.getDayOfMonth());
// Cycle through months.if (monthDiff == 0) {
// ...nothing to do. Currently on the right month.
}
// Go backward until targeted month is selected.elseif (monthDiff < 0) {
for (inti=monthDiff; i<0; ++i) {
UiObjectpreviousMonthButtonItem = newUiObject(newUiSelector().resourceId("android:id/prev"));
previousMonthButtonItem.click();
}
}
// Go forward until targeted month is selected.elseif (monthDiff > 0) {
for (inti=0; i<monthDiff; ++i) {
UiObjectnextMonthButtonItem = newUiObject(newUiSelector().resourceId("android:id/next"));
nextMonthButtonItem.click();
}
}
// Select the target day.UiCollectiondayList = newUiCollection(newUiSelector().resourceId("android:id/month_view"));
UiObjectdayItem = dayList.getChildByText(newUiSelector().className("android.view.View"), "" + targetDate.getDayOfMonth());
dayItem.click();
// Accept.UiObjectokButton = newUiObject(newUiSelector().resourceId("android:id/button1"));
okButton.click();
}
/** * Set the current time. * * @param timeStr "hh:mm" format. seconds throw exception. * * @pre User must be in settings (see `#openSettings`). * @pre Automatic date time must be disabled (see `#enableManualDateTime`). * @post User is in settings. * * @throws UiObjectNotFoundException */publicvoidsetIsoTime(StringtimeStr) throwsUiObjectNotFoundException {
// Open `Set time` panel.UiScrollabledateTimeSettingList = newUiScrollable(newUiSelector().className("android.support.v7.widget.RecyclerView"));
UiObjectsetTime = dateTimeSettingList.getChildByText(newUiSelector().className("android.widget.TextView"), "Set time");
setTime.click();
// Switch to input mode.UiObjecttoggleButton = newUiObject(newUiSelector().resourceId("android:id/toggle_mode"));
toggleButton.click();
// Set target time.LocalTimetargetTime = LocalTime.parse(timeStr);
StringtargetTimeMode = targetTime.format(DateTimeFormatter.ofPattern("a")); // a == AM | PMStringtargetHour = targetTime.format(DateTimeFormatter.ofPattern("h")); // h == 1-12StringtargetMinute = "" + targetTime.getMinute();
// Get PM / AM.UiScrollablespinner = newUiScrollable(newUiSelector().resourceId("android:id/am_pm_spinner"));
UiObjectspinnerText = spinner.getChild(newUiSelector().resourceId("android:id/text1"));
StringtimeMode = spinnerText.getText();
// LogLog.i("TAG", timeStr + " " + targetTimeMode + " " + targetHour + " " + targetMinute);
// Toggle time mode if needed.if (!timeMode.equals(targetTimeMode)) {
// Open spinner list.spinner.click();
// Select target time mode item.UiObject2targetTimeModeObject = device.findObject(By.text(targetTimeMode));
targetTimeModeObject.click();
}
// Select HourUiObject2inputHour = device.findObject(By.res("android:id/input_hour"));
inputHour.setText(targetHour);
// Select minuteUiObject2inputMinute = device.findObject(By.res("android:id/input_minute"));
inputMinute.setText(targetMinute);
// Accept.UiObject2okButton2 = device.findObject(By.text("OK"));
okButton2.click();
}
/** * Close the android Settings app. * * @throws RemoteException * @throws UiObjectNotFoundException */publicvoidcloseSettings() throwsRemoteException, UiObjectNotFoundException {
// Close settings.device.pressRecentApps();
UiObjectapp = newUiObject(newUiSelector().description("Settings Date & time"));
app.swipeUp(100);
// Return to home screen (quit recent app panel).device.pressHome();
}
/** * Return the current phone's iso datetime read from the date & time settings panel. Relevant * method to test this class' other ones ;) * * @return iso datetime "yyyy-MM-dd HH:mm" format. * * @pre User must be in settings (see `#openSettings`). * @post User is in settings. * * @throws UiObjectNotFoundException */publicStringreadIsoDateTime() throwsUiObjectNotFoundException {
// Get date string.UiScrollabledateTimeSettingList = newUiScrollable(newUiSelector().className("android.support.v7.widget.RecyclerView"));
UiObjectsetDateItem = dateTimeSettingList.getChildByText(newUiSelector().className("android.widget.RelativeLayout"), "Set date");
UiObjectdateObject = setDateItem.getChild(newUiSelector().resourceId("android:id/summary"));
StringdateStr = dateObject.getText();
// Get time string.UiObjectsetTimeItem = dateTimeSettingList.getChildByText(newUiSelector().className("android.widget.RelativeLayout"), "Set time");
UiObjecttimeObject = setTimeItem.getChild(newUiSelector().resourceId("android:id/summary"));
StringtimeStr = timeObject.getText();
// Parse retrieved strings into local date.DateTimeFormatterformatter = DateTimeFormatter.ofPattern("MMMM d, yyyy h:mm a", Locale.US);
LocalDatedatetime = LocalDate.parse(dateStr + " " + timeStr, formatter);
// Format local date into iso string.StringisoDatetime = datetime.toString();
returnisoDatetime;
}
}
The text was updated successfully, but these errors were encountered:
Hi @nuKs! Thanks a million for this code, it is exactly what I was looking for! I'm using it as a separate utils class for testing, not part of any other framework, and it's super useful to have.
For anyone interested, I've converted the code into Kotlin and did some very minor updates to support both android v28 and v29+:
Hi,
I've implemented a class to change the device time using UiAutomator. Likely to be useful for scheduled notification testing.
It relies only on UiAutomator. The idea is to have a simple way to test notifications e2e in the end with other POM/like helpers for notifications for instance. I like the idea of making it as low level as possible. Preferably without espresso dependency. Perhaps it would make sense to integrate it in here though. It loosely follows the page object model framework.
I am open to any idea (or ticket rejection).
Here is the class at the moment.
The text was updated successfully, but these errors were encountered: