Flutter Driver scrolling through dropdown list - flutter

I would like to scroll through a drop-down list 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 ValueKey, and have tried digging through the Flutter Inspector in Intellij as well, but have had no luck thus far.

I have tried find.byType(Scrollable); and it doesn't seem to work even after widgetTester.tap(). Turns out I need to wait for the screen to update with widgetTester.pumpAndSettle()
testWidgets("Test DropdownButton", (WidgetTester widgetTester) async {
await widgetTester.pumpWidget(MyApp())
final dropdownButtonFinder = find.byKey(const ValueKey('DropdownButton')); final dropdownItemFinder = find.widgetWithText(InkWell, 'Item 50'); // find.textContaining() doesn't seem to work
// Tap on the DropdownButton
await widgetTester.tap(dropdownButtonFinder);
await widgetTester.pumpAndSettle(const Duration(seconds: 2));
final dropdownListFinder = find.byType(Scrollable);
expect(dropdownListFinder, findsOneWidget); // Finds Scrollable from tapping DropDownButton
// Scroll until the item to be found appears.
await widgetTester.scrollUntilVisible(dropdownItemFinder, 500.0,
scrollable: dropdownListFinder);
await widgetTester.tap(dropdownItemFinder);
await widgetTester.pumpAndSettle(const Duration(seconds: 2));
// Verify that the item contains the correct text.
expect(find.textContaining('Item 50'), findsOneWidget);
});
Main code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> mockList() => List<String>.generate(100, (i) => 'Item $i');
String? dropdownValue;
#override
Widget build(BuildContext context) {
// debugPrint('${foo!}');
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
key: Key('Widget1'),
),
body: Center(
child: DropdownButton(
key: Key('DropdownButton'),
value: dropdownValue,
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: mockList()
.map<DropdownMenuItem<String>>(
(String value) => DropdownMenuItem<String>(
value: value,
child: Text(value),
key: Key('item$value'),
),
)
.toList(),
)
);
}
}
Running the test

Related

How to Change Button text depending on textfield?

enter image description here
Here I want to change the button which depends on a text field, like when the text field is filled then show the button C, and when clicked the C button then change the button name C to AC and also need to change text field fill to empty.
check this example to demonstrate the output you need
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Location',
theme: ThemeData(
primarySwatch: Colors.amber,
),
home: const MyHomePage(title: 'Flutter Location Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, this.title}) : super(key: key);
final String? title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _controller = TextEditingController();
String? buttonText;
#override
void initState() {
_controller.addListener(_checkTextIsEmpty);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title!),
),
body: Center(
child: Column(
children: [
TextField(
controller: _controller,
onChanged: (value) {},
),
Text(buttonText ?? ''),
],
),
),
);
}
void _checkTextIsEmpty() {
final value = _controller.text.isEmpty ? "AC" : "C";
setState(() {
buttonText = value;
});
}
}

getText() method of FlutterSummerNote returns blank on first button click

I have a project that needs an integration of html editor, and I found interest about FlutterSummerNote package because of its interesting features. However, when I integrate it into my project, I am encountering an error regarding FlutterSummerNote package. When I clicked the Save button for the first time, I am getting blank value, but when I click the second time and so forth I can get the value from _keyEditor.currentState?.getText() method. I am using flutter_summernote: ^1.0.0 version. Below is the sample code. Any help please?
import 'package:flutter/material.dart';
import 'package:flutter_summernote/flutter_summernote.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Demo Flutter Summernote'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({required this.title});
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
GlobalKey<FlutterSummernoteState> _keyEditor = GlobalKey();
String result = "";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
elevation: 0,
actions: <Widget>[
IconButton(
icon: Icon(Icons.save),
onPressed: () async {
final value = await _keyEditor.currentState?.getText();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
duration: Duration(seconds: 5),
content: Text(value ?? "-"),
));
},
)
],
),
backgroundColor: Colors.white,
body: FlutterSummernote(
hint: "Your text here...",
key: _keyEditor,
hasAttachment: true,
customToolbar: """
[
['style', ['bold', 'italic', 'underline', 'clear']],
['font', ['strikethrough', 'superscript', 'subscript']],
['insert', ['link', 'table', 'hr']]
]
""",
),
);
}
I was able to solve this problem by calling the function to get the text twice and consecutively as so:
final value = await _keyEditor.currentState?.getText();
final value = await _keyEditor.currentState?.getText();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
duration: Duration(seconds: 5),
content: Text(value ?? "-"),
));

Flutter - How to select DropdownButton item in widget test

I tried selecting a DropdownButton item like this:
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:dropdown_test_sample/main.dart';
void main() {
testWidgets('Select Dropdown item test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const SampleApp());
final dropdown = find.byKey(const ValueKey('dropdown'));
await tester.tap(dropdown);
await tester.pumpAndSettle();
final dropdownItem = find.byKey(const ValueKey('First item key'));
await tester.tap(dropdownItem);
await tester.pumpAndSettle();
});
}
But unfortunately, It throws this exception:
There seems to be something that keeps creating an identical DropdownButton item with the same key, thereby making the widget test fail because, tester.tap() cannot "tap" on two widgets at the same time.
Here's the full implementation of the DropdownButton widget:
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Dropdown Test Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const Home(),
);
}
}
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: DummyDropdown(
key: ValueKey('dropdown'),
),
),
);
}
}
class DummyDropdown extends StatefulWidget {
const DummyDropdown({Key? key}) : super(key: key);
#override
State<DummyDropdown> createState() => _DummyDropdownState();
}
class _DummyDropdownState extends State<DummyDropdown> {
String? text = 'Dropdown';
String? textValue;
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: textValue,
underline: Container(),
dropdownColor: Theme.of(context).cardColor,
style: Theme.of(context).textTheme.bodyText2,
hint: Text(
text!,
),
icon: const Icon(Icons.keyboard_arrow_down),
onChanged: (newValue) {
setState(
() {
textValue = newValue;
text = newValue;
},
);
},
items: <String>['First item', 'Second item', 'Third item']
.map<DropdownMenuItem<String>>(
(value) {
return DropdownMenuItem<String>(
value: value,
key: ValueKey('$value key'),
child: Text(
value,
),
);
},
).toList(),
);
}
}
Widget testing in drop down button is different than other widgets please see here for more. In this is case select the last element from the text "First Item".This will work.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:testapp/main.dart';
void main() {
testWidgets('Select Dropdown item test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const SampleApp());
final dropdown = find.byKey(const ValueKey('dropdown'));
await tester.tap(dropdown);
await tester.pumpAndSettle();
///if you want to tap first item
final dropdownItem = find.text('First item').last;
await tester.tap(dropdownItem);
await tester.pumpAndSettle();
});
}
The issue is here. when we tap the drop down one was already selected and other one is not selected. So you can test that item using the text value.
final dropdownItem = find.text('First item').last;

capture data from DropDownButton in flutter and send it to the database

I'm new to flutter app development and would like to ask for your help
I already learned to capture the data of a TextFormField but with the DropDownButtons I have no idea how it is I try to use controller to put a name but I get an error
I have a DropDownButton and it works for me, it is loading the list successfully and I would like to know, how to capture the data I select in the DropDownButton and send it to my database
This is the code that I am using:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _mySelection;
final String url = "http://webmyls.com/php/getdata.php";
List data = List();
Future<String> getSWData() async {
var res = await http
.get(Uri.encodeFull(url), headers: {"Accept": "application/json"});
var resBody = json.decode(res.body);
setState(() {
data = resBody;
});
print(data);
return "Sucess";
}
#override
void initState() {
super.initState();
this.getSWData();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new DropdownButton(
//data != null,
isDense: true,
hint: new Text("Select"),
items: data.map((item) {
return new DropdownMenuItem(
child: new Text(item['item_name']),
value: item['id'].toString(),
);
}).toList(),
onChanged: (newVal) {
setState(() {
_mySelection = newVal;
});
},
value: _mySelection,
),
),
);
}
}
I hope you can help me.
the latest dropdown value is always stores in your _mySelection. So the only thing you should do is to save _mySelection in your database.

Cursor defaults to start of Textfield when typing, using TextEditingController + onChanged - Flutter

I'm developing an app that will have some single line Textfields that are essentially used to store notes in each, so I am using shared_preferences dependency to set/get these values, but using this with a TextEditingController and onChanged parameter I find the cursor moves to the start of the Textfield when typing.
I've researched this and can see a lot of suggestions to use a Listener (as below) for the TextSelection to set cursor permanently at the end of the Textfield, but I was hoping to allow the user to move the cursor anywhere in that box to type where they like.
text1.addListener(() {
final text = text1.text;
text1.value = text1.value.copyWith(
text: text,
selection:
TextSelection(baseOffset: text.length, extentOffset: text.length),
composing: TextRange.empty,
);
});
Here is an example below that replicates the issue I'm experiencing, if anyone has any suggestions?
I could use a Save button, but I was hoping to just allow the user to amend text and move the cursor where they need, and the onChanged parameter could then save any changes to shared_preferences;
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Textfield Test'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
TextEditingController text1 = TextEditingController();
SharedPreferences sharedPreferences;
#override
void initState() {
super.initState();
getText();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: text1,
onChanged: _setText,
),
],
),
),
);
}
_setText(String value) async {
sharedPreferences = await SharedPreferences.getInstance();
setState(() {
sharedPreferences.setString("text1", text1.text);
getText();
});
}
getText() async {
sharedPreferences = await SharedPreferences.getInstance();
setState(() {
text1.text = sharedPreferences.getString("text1");
});
}
}
you have to wait while the output of this function because this is async function.
onChanged: (value)async{
_setText(value)
}
Just to let anyone know reading this post, i found where i was going wrong.
On the _setText function id defined, i just needed to remove the line 'getText();', and now it doesn't move the cursor around when typing, and works fine.