How to test DatePickerIOS - detox

I need to enter a day using the native IOS DatePicker. How do I spin the control wheel to a certain value that might not be in the view, since this starts out with the current date?

Detox 7.3.x supports interaction with iOS UIPickerView. Match UIPickerView by type, and interact with it.
await expect(element(by.type('UIPickerView'))).toBeVisible();
await element(by.type('UIPickerView')).setColumnToValue(1,"6");
await element(by.type('UIPickerView')).setColumnToValue(2,"34");
Docs are here:
https://github.com/wix/detox/blob/master/docs/APIRef.ActionsOnElement.md#setcolumntovaluecolumnvalue--ios-only

datetimepicker have Detox test you can check code here:
https://github.com/react-native-community/datetimepicker/blob/master/example/e2e/detoxTest.spec.js#L54
if (global.device.getPlatform() === 'ios') {
const testElement = await element(
by.type('UIPickerView').withAncestor(by.id('dateTimePicker')),
);
await testElement.setColumnToValue(0, 'November');
await testElement.setColumnToValue(1, '3');
await testElement.setColumnToValue(2, '1800');
await expect(dateTimeText).toHaveText('11/03/1800');
} else {
// for Android
}

Related

How to get the Default Calendar in Android using the Expo SDK Calendar API?

SOLVED: Used await and a variable to store the promise.
I am trying to insert an event into the default calendar on an android device using react-native and expo sdk. Previously, one could create an event using the createEventAsync() method with the 1st argument as Calendar.DEFAULT but that is no longer supported. I can use the getCalendarsAsync() method to get all calenders but the object I am getting back is making no sense. Some code:
async addReservationToCalendar(date) {
await this.obtainCalendarPermission();
console.log(Calendar.getCalendarsAsync());
}
Someone had suggested that I could iterate through the responses to find a calendar with the isPrimary attribute set to true but I don't see how I achieve this. I have already gotten the permission and I am receiving the following promise as a response.
Promise {
"_40": 0,
"_55": null,
"_65": 0,
"_72": null,
}.
What do I need to do to set a calendar event on an android device using the expo Calendar API ?
Because that's a promise, you need to do like this
Calendar.getCalendarsAsync().then(calendars => console.log(calendars))
Thats a promise so either you can use then statement or async await .
So
Or you can do
async addReservationToCalendar(date) {
await this.obtainCalendarPermission();
let result = await Calendar.getCalendarsAsync();
console.log(result,'result')
console.log(Calendar.getCalendarsAsync());
}
or
Calendar.getCalendarsAsync().then(calendars => console.log(calendars,'calenders'))
Hope it helps.
Version 39 has an example at https://docs.expo.io/versions/v39.0.0/sdk/calendar/#usage:
async function getDefaultCalendarSource() {
const calendars = await Calendar.getCalendarsAsync();
const defaultCalendars = calendars.filter(each => each.source.name === 'Default');
return defaultCalendars[0].source;
}

How goBack screen in test with detox

I make automatization react native test with detox, It has the next screen sequence A -> B -> C and i wish to go back to the screen B <- C.
Is there a solution for this?
There's a testId on the back button, so you can do this:
await element(by.id("header-back")).tap();
sometimes
await element(by.id("header-back")).tap();
does not work and
await element(by.traits(['button']))
.atIndex(0)
.tap();
selects another button. In that case, you can try to use swipe right on ios assuming that it is a stack navigator. Use the outer container view
await element(by.id('containerView')).swipe('right', 'fast', 0.1);
the solution was to use traits button as follows:
await element(by.traits(['button'])).atIndex(0).tap();
You could go ahead and create a utility
export const pressBack = async () => {
if (device.getPlatform() === 'android') {
await device.pressBack(); // Android only
} else {
await element(by.traits(['button']))
.atIndex(0)
.tap();
}
};
Android: device.pressBack()
iOS: go back last screen #828
If you are using react-native-navigation you can use:
const backButton = () => {
if (device.getPlatform() === 'ios') {
return element(by.type('_UIBackButtonContainerView'));
} else {
return element(by.label('Navigate Up'));
}
};
...
await backButton().tap();
For iOS in detox#17.3.6 & react-native-navigation#6.10.1 you can use:
return element(by.id('pop'));
Another way that works is
await element(by.id('header-back')).atIndex(0).tap()
This uses the built in testID that the default back button that comes with react-navigation v5. You may need to mess with the atIndex() number since for me it seems to match 2 back buttons but the first one was the one I was looking for.

How to check if a user device is using fingerprint/face as unlock method. [ReactNative] [Expo]

I'm using ReactNative based on Expo Toolkit to develop a App and I want know how I can check if the user is using the fingerprint (TouchID on iPhone) or face detection (FaceID on iPhone X>) to unlock the device.
I already know how to check if device has the required hardware using Expo SDK, as follow:
let hasFPSupport = await Expo.Fingerprint.hasHardwareAsync();
But I need check if the user choose the fingerprint/face as unlock method on your device, instead pattern or pin.
Thanks
Here's an update to Donald's answer that takes into account Expo's empty string for the model name of the new iPhone XS. It also takes into account the Simulator.
const hasHardwareSupport =
(await Expo.LocalAuthentication.hasHardwareAsync()) &&
(await Expo.LocalAuthentication.isEnrolledAsync());
let hasTouchIDSupport
let hasFaceIDSupport
if (hasHardwareSupport) {
if (Constants.platform.ios) {
if (
Constants.platform.ios.model === '' ||
Constants.platform.ios.model.includes('X')
) {
hasFaceIDSupport = true;
} else {
if (
Constants.platform.ios.model === 'Simulator' &&
Constants.deviceName.includes('X')
) {
hasFaceIDSupport = true;
}
}
}
hasTouchIDSupport = !hasFaceIDSupport;
}
EDIT: Expo released an update that fixes the blank model string. However you might want to keep a check for that just in case the next iPhone release cycle causes the same issue.
Currently, you could determine that a user has Face ID by checking Expo.Fingerprint.hasHardwareAsync() and Expo.Fingerprint.isEnrolledAsync(), and then also checking that they have an iPhone X using Expo.Constants.platform (docs here).
So:
const hasHardwareSupport = await Expo.Fingerprint.hasHardwareAsync() && await Expo.Fingerprint.isEnrolledAsync();`
if (hasHardwareSupport) {
const hasFaceIDSupport = Expo.Constants.platform.ios && Expo.Constants.platform.ios.model === 'iPhone X';
const hasTouchIDSupport = !hasFaceIDSupport;
}
Incase you tried the above answer and it's not working please note as at the time of my post expo's documentation has changed
- import * as LocalAuthentication from 'expo-local-authentication';
- let compatible = await LocalAuthentication.hasHardwareAsync()
We can check if device has scanned fingerprints:
await Expo.Fingerprint.isEnrolledAsync()
So, this can be used to reach the objective as follow:
let hasFPSupport = await Expo.Fingerprint.hasHardwareAsync() && await Expo.Fingerprint.isEnrolledAsync();

Ionic 3 infinite-scroll simulate in e2e test jasmine/protractor

If you go here: http://ionicframework.com/docs/api/components/infinite-scroll/InfiniteScroll/
Inspect the demo and click the last item on the list:
Then in the console type: $0.scrollIntoView()
Infinite Scroll is never triggered.
Is there a way to programmatically trigger infinite-scroll in protractor context?
The implementation of the scroll in your example rely on the speed/velocity of the scroll which I guess falls far from the expected range when scrollIntoView is called.
One workaround is to simulates a smooth scroll by emitting multiple scroll events over a reasonable time. The idea is to reproduce as close as possible the behavior of a real user.
Some browsers already provides the option via scrollIntoView (supported by Chrome 62) :
$0.scrollIntoView({behavior: "smooth", block: "end"});
Using the accepted answer, in my case, I used ion-infinite-scroll as the argument.
Complete test to check if more content is loaded in Ionic:
describe('Scroll', () => {
it('should load more when reached end', async () => {
let list = getList();
let currentCount = await list.count();
const refresher = element(by.tagName('ion-infinite-scroll')).getWebElement();
let count = 0;
while(true){
browser.executeScript(`arguments[0].scrollIntoView({behavior: "smooth", block: "end"});`, refresher);
browser.sleep(1000); // wait for data to be loaded from api
list = getList();
let newCount = await list.count();
expect(newCount).toBeGreaterThanOrEqual(currentCount)
expect(newCount).toBeLessThanOrEqual(currentCount * 2)
if(newCount === currentCount){
break;
}
currentCount = newCount;
count++;
}
expect(count).toBeGreaterThan(0);
})
});
function getList() {
return element(by.className(pageId + ' list')).all(by.tagName('ion-item'));
}

React Native Show custom message after Capturing image

I am trying to show a message to the user after he captures an image and the image is saved in gallery. I have surfed through the net but can not find any solution. So far what I have tried the following code from here for capturing image-
takePicture = async function() {
if (this.camera) {
this.camera.takePicture().then(data => {
FileSystem.moveAsync({
from: data,
to: `${FileSystem.documentDirectory}photos/Photo_${this.state
.photoId}.jpg`,
}).then(() => {
this.setState({
photoId: this.state.photoId + 1,
});
Vibration.vibrate();
});
});
}
};
Now I want to know what should I do to get the completion event. Any help is highly appreciated.
I am not the best with what all to put in that code, but you can make a message show this way:
Toast.makeText(getApplicationContext(),"Picture taken!",Toast.LENGTH_SHORT).show();
Instead of Toast you can use a cross platform library : react-native-dropdown-alert