I would like to select a date through date picker as part of a flutter driver test. however, I can't seem to figure out exactly how I would do this?
I've tried using a find.textandfind.bySemanticsLabel, and have tried but have had no luck thus far.
my code :
Future<void> executeStep() async {
await FlutterDriverUtils.waitForFlutter(world.driver);
NewOrderForm newOrderForm = NewOrderForm(world.driver);
await newOrderForm.setFieldKontrak();
//Open Date Picker
await newOrderForm.setDateKontrak();
//Select date 24
await driver.waitFor(find.bySemanticsLabel('24'));
await driver.tap(find.text('24'),timeout: Duration(seconds: 15));
await driver.waitFor(find.text('OK'));
await driver.tap(find.text('OK'));
await newOrderForm.setProyekField();
}
Screen capture :
I ran a sample test that selects a date from datepicker and it worked well. Below is what I did:
main.dart has a simple RaisedButton upon clicking on which DatePicker opens:
return Scaffold(
body: Center(
child: RaisedButton(
onPressed: () {
_showDatePicker();
},
child: Text('Click')
)
)
);
void _showDatePicker() async {
DateTime picked = await showDatePicker(
context: context,
initialDate: new DateTime.now(),
firstDate: new DateTime(2019),
lastDate: new DateTime(2021)
);
if(picked != null) setState(() => _value = picked.toString());
}
Below is the flutter driver test that first identifies the RaisedButton -> taps on it -> finds the date to be selected -> taps on it -> taps OK
test('datepicker test', () async {
final dateButton = find.text('Click');
await driver.waitFor(dateButton);
await driver.tap(dateButton);
await driver.tap(find.text('15'));
await driver.tap(find.text('OK'));
print('October 15 selected and tapped OK');
});
Test result:
In the code you provided, you may try below snippet, ie, tap on 24 and directly tap on OK instead of telling driver to wait for OK button to find.
await driver.tap(find.text('24'));
await driver.tap(find.text('OK'));
Hope this helps you to resolve the issue.
Related
I am trying to achieve schedule conflict in my uni app, itenerary, where a user wouldnt be allowed to add a trip that has a date that is already taken.
I am struggling to get the right query but this is what i have tried
List dateinput= [];
DateTime? pickeddate = await showDatePicker(context: context,
initialDate:DateTime.now(),
firstDate: DateTime.now().subtract(Duration(days: 0)),
lastDate: DateTime(2025));
setState(() {
date.text= DateFormat('yyyy-MM-dd').format(pickeddate!);
});
//my query
final collection = FirebaseFirestore.instance.collection('UserTrip')
.orderBy('tripDate')
.get()
.then((value) =>
value.docs.forEach((element) {
List data1 = element.data() as List;
dateinput.add(data1);
print(dateinput);
}));
//and I'm trying to implement that return error on pressed on the add trip button
if (dateinput.contains(date.text)) {
//return error
} else {
uploadFile();}
I am using shared_preferences to store a bool value locally but I think I am doing something wrong.
So first of all, here is my initState:
#override
initState(){
super.initState();
checkIfUserHasData();
getBoolValuesSF();
}
on checkIfUserHasData, Im calling another function at the end (addBoolToSF)
Future<void> checkIfUserHasData ()async {
var collection = FirebaseFirestore.instance.
collection('users').doc(userID).collection('personalInfo');
var querySnapshots = await collection.get();
for (var snapshot in querySnapshots.docs) {
documentID = snapshot.id;
}
await FirebaseFirestore.instance
.collection('users')
.doc(userID)
.collection('personalInfo').doc(documentID)
.get().then((value) {
if (!mounted) return;
setState(() {
gender = value.get('gender');
profileImageUrl = value.get('url');
print(profileImageUrl);
print(gender);
});
});
if (gender != null){
if (!mounted) return;
setState((){
isUserNew = false;
});
if(gender == "Male"){
setState(() => genderIsMale = true);
addBoolToSF();
}else{
setState(() => genderIsMale = false);
addBoolToSF();
}
}else {
return;
}
}
Then addBoolToSF:
addBoolToSF() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('genderType', genderIsMale);
}
Lastely getBoolValuesSF:
getBoolValuesSF() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
bool _genderType = ((prefs.getBool('genderType') ?? true)) ;
genderType = _genderType;
});
}
When the genderType value is obtained I then decide which image to be the background image on the screen:
CachedNetworkImage(
placeholder: (context, url) =>
CircularProgressIndicator(),
imageUrl: genderType ? // : //
With all of that said, here is what is happening when the gender is changed on the firebase firestore:
The first time I navigate or refresh the screen nothing is changed and I get this error:
type 'Null' is not a subtype of type 'bool'
The second time I refresh or navigate to the screen, I do get the correct image on place but I get the same error message again
type 'Null' is not a subtype of type 'bool'
I have tried several ways to solve this issue but i dont seem to get it right.
Edit: I have noticed that when I removed the last part for CachedNetworkImage, I get no error so I think the problem might be on this part
In case like that when you need to wait for a future to build some UI, the go to way is to use a FutureBuilder
You use it like this
FutureBuilder<bool>(
future: getBoolValuesSF,
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
// build your UI here based on snapshot value
},
)
checkIfUserHasData() and getBoolValuesSF() both are future method. you can create another async method and put it inside initState.
#override
initState(){
super.initState();
newMthod();
}
newMthod() async{
await checkIfUserHasData();
await getBoolValuesSF();
}
I'm using image picker plugin to pick videos from gallery in my flutter app. I want to set the maximum duration of the picked video to 30 seconds. The below code doesn't work even after setting the max duration. Is there any way to display an error or automatically trim the first 30secs if users pick a bigger video.
pickVideo(ImageSource src) async {
Navigator.pop(context);
final video = await ImagePicker().getVideo(
source: src,
maxDuration: Duration(seconds: 30),
);
I made a work around for this by throwing an error when a video longer than x seconds is selected. It looks as follows:
Future<void> pickVideo() async {
try {
final picker = ImagePicker();
var pickedFile = await picker.pickVideo(source: ImageSource.gallery, maxDuration: Duration(seconds: maxSeconds));
if (pickedFile == null) {
return;
}
VideoPlayerController testLengthController = new VideoPlayerController.file(File(pickedFile.path));//Your file here
await testLengthController.initialize();
if (testLengthController.value.duration.inSeconds > 60) {
pickedFile = null;
throw('we only allow videos that are shorter than 1 minute!');
} else {
setState(() {
videoFile = XFile(pickedFile.path);
_startVideoPlayer();
});
}
testLengthController.dispose();
} catch (e) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: Container(
child: Text(e.toString()),
),
);
});
return;
}
}
I'm using the timePicker in Flutter.
Once I have picked the time from the popup dialog it displays the picked time but it doesn't display only the time eg: 12:45, it also shows TimeOfDay eg: TimeOfDay(12:45).
How do I get rid of the TimeOfDay text?
//Declaration example
TimeOfDay _time = new TimeOfDay.now();
//Time picker example code
Future<Null> _selectTime(BuildContext context) async {
final TimeOfDay picked = await showTimePicker(context: context, initialTime: _time);`
if (picked != null && picked != _time) {
print('${_time.toString()}');
setState(() {
_time = picked;
});
}
}
//Display example
Text(
'${_time.toString()}',
),
I would like the time to look like: 12:45 and not:TimeOfDay(12:45).
This will print in the required format.
Text(
_time.format(context),
),
String interpolation of hour and minute will work:
"${_time.hour}:${_time.minute}"
I want to immediately show minute picker to user after he has picked the hour with showTimePicker widget. how can I do that? here is my current code for showTimePicker:
final TimeOfDay timePicked = await showTimePicker(
context: context,
initialTime: selectedTime,
);
if (picked != null && timePicked != selectedTime) {
setState(() {
selectedTime = timePicked;
});
}
Sorry you can't do that in Flutter as of now. However, you can do it natively using MethodChannel.
You need to use TimePickerDialog.OnTimeSetListener. More info