#flutter #flutter-test
Вопрос:
В моем коде, когда страна выбирается из раскрывающейся кнопки, под ней отображается форма. При тестировании этого виджета я не знаю, как заставить функцию onchanged запускаться на кнопке раскрывающегося списка, когда я нажимаю элемент из выпадающего меню. У меня есть инструкция print в функции onchanged, которую я не вижу на консоли отладки при запуске теста. Тест также завершается неудачно при запуске последнего ожидаемого() раскомментированного кода.
КОНСОЛЬ ОТЛАДКИ
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure object was thrown running a test:
Expected: 'Afghanistan'
Actual: 'Select Country'
Which: is different.
Expected: Afghanista ...
Actual: Select Cou ...
^
Differ at offset 0
When the exception was thrown, this was the stack:
#4 main.<anonymous closure> (file:///C:/Users/calvo/Documents/flutter/projects/freegapp/test/PersonalInfo_widget_test.dart:48:5)
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)
...
This was caught by the test expectation on the following line:
file:///C:/Users/calvo/Documents/flutter/projects/freegapp/test/PersonalInfo_widget_test.dart line 48
The test description was:
make profile
════════════════════════════════════════════════════════════════════════════════════════════════════
Test failed. See exception logs above.
The test description was: make profile
✖ make profile
Exited (1)
PersonalInfo.дарт
import 'package:flutter/material.dart';
import 'package:freegapp/Selling.dart';
import 'package:freegapp/src/MyUserInfo.dart';
import 'package:image_picker/image_picker.dart';
import 'package:freegapp/src/mocks/ImagePickerMock.dart';
import 'dart:io';
import 'package:freegapp/src/ApplicationStateFirebase.dart';
import 'package:freegapp/src/mocks/ApplicationStateFirebaseMock.dart';
import 'dart:convert';
import 'dart:typed_data';
import 'package:path_provider/path_provider.dart';
import 'package:geolocator/geolocator.dart';
import 'package:geocoding/geocoding.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:flutter/services.dart';
import 'package:flutter/src/services/asset_bundle.dart' show rootBundle;
class PersonalInfo extends StatefulWidget {
PersonalInfo({
required this.logout,
required this.myUserInfo,
Key? key,
}) : super(key: key); // Initializes key for subclasses.
final void Function() logout;
final MyUserInfo myUserInfo;
@override
_PersonalInfoState createState() => _PersonalInfoState();
}
class _PersonalInfoState extends State<PersonalInfo> {
final homeAddressController = TextEditingController();
final phoneNumberController = TextEditingController();
final latitudeController = TextEditingController();
final longitudeController = TextEditingController();
List<XFile>? _imageFileList;
var currentAddress;
var currentPosition;
final ImagePicker _picker = ImagePicker();
final ImagePickerMock _mockPicker = ImagePickerMock();
final _formKey = GlobalKey<FormState>(debugLabel: '_PersonalInfoStateForm');
var _formIsVisible = true;
String? countriesJsonString;
final defaultDropDownValue = 'Select Country';
var dropdownValue;
@override
void initState() {
super.initState();
dropdownValue = widget.myUserInfo.country ?? defaultDropDownValue;
homeAddressController.text = widget.myUserInfo.homeAddress == null
? ''
: widget.myUserInfo.homeAddress.toString();
phoneNumberController.text = widget.myUserInfo.phoneNumber == null
? ''
: widget.myUserInfo.phoneNumber.toString();
latitudeController.text = widget.myUserInfo.latitude == null
? ''
: widget.myUserInfo.latitude.toString();
longitudeController.text = widget.myUserInfo.longitude == null
? ''
: widget.myUserInfo.longitude.toString();
}
@override
void dispose() {
// Clean up the controller when the widget is removed from the
// widget tree.
homeAddressController.dispose();
phoneNumberController.dispose();
latitudeController.dispose();
longitudeController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Container(
height: 160,
width: MediaQuery.of(context).size.width,
child: imageProfile(widget.myUserInfo.profilePic)),
SizedBox(
height: 20,
),
FutureBuilder(
future: loadCountriesFromAsset(),
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
// futurer hasn't finished yet, return a place holder
return Text('Loading');
}
return DropdownButton<String>(
key: Key('DropdownButtonPersonalInfo'),
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (String? newValue) {
setState(() {
print('we inside');
dropdownValue = newValue!;
if (dropdownValue == defaultDropDownValue) {
_formIsVisible = false;
} else {
_formIsVisible = true;
}
});
},
items: List<String>.from(
jsonDecode(countriesJsonString.toString())['names'])
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
}),
Expanded(
child: Visibility(
visible: _formIsVisible, child: form(widget.myUserInfo))),
],
));
}
Future<dynamic> loadCountriesFromAsset() async {
final contents = await rootBundle.loadString('assets/countries.json');
countriesJsonString = contents;
if (dropdownValue == defaultDropDownValue) {
_formIsVisible = false;
} else {
_formIsVisible = true;
}
}
...
PersonalInfo_widget_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
import 'package:freegapp/PersonalInfo.dart';
import 'package:freegapp/src/mocks/ApplicationStateFirebaseMock.dart';
import 'package:provider/provider.dart';
import 'package:flutter/foundation.dart';
// import 'dart:io';
void main() {
testWidgets('make profile', (WidgetTester tester) async {
await tester.pumpWidget(ChangeNotifierProvider(
create: (context) => ApplicationStateFirebaseMock(),
builder: (context, _) => MaterialApp(
home: Consumer<ApplicationStateFirebaseMock>(
builder: (context, appState, _) => PersonalInfo(
key: Key('PersonalInfo'),
logout: () {
appState.signOut;
},
myUserInfo: appState.myUserInfo)))));
await tester.pumpAndSettle();
expect(find.byKey(Key('PersonalInfo')), findsOneWidget);
expect(
find.byKey(Key('profilePicCircleAvatarPersonalInfo')), findsOneWidget);
await tester.tap(find.byIcon(Icons.camera_alt_outlined));
await tester.pumpAndSettle();
await tester.tap(find.byIcon(Icons.image));
await tester.pumpAndSettle();
expect(
find.byKey(Key('profilePicCircleAvatarPersonalInfo')), findsOneWidget);
// expect(find.text('Select Country'), findsOneWidget);
expect(
(tester.widget(find.byKey(Key('DropdownButtonPersonalInfo')))
as DropdownButton)
.value,
equals('Select Country'));
expect(find.byKey(Key('ListViewFormPersonalInfo')), findsNothing);
await tester.tap(find.byIcon(Icons.arrow_downward), warnIfMissed: false);
// await tester.tap(find.byIcon(Icons.arrow_downward), warnIfMissed: false);
await tester.pump();
await tester.pump(Duration(seconds: 1));
// after opening the menu we have two widgets with text 'Afghanistan'
// one in index stack of the dropdown button and one in the menu .
// apparently the last one is from the menu.
await tester.tap(find.text('Afghanistan').last, warnIfMissed: false);
await tester.pump();
await tester.pump(Duration(seconds: 1));
expect(
(tester.widget(find.byKey(Key('DropdownButtonPersonalInfo')))
as DropdownButton)
.value,
equals('Afghanistan'));
// expect(find.byKey(Key('ListViewFormPersonalInfo')), findsOneWidget);
});
}
countries.json sample
{
"names": ["Select Country",
"Afghanistan",
"Åland Islands",
"Albania",
"Algeria",
"American Samoa",
"Andorra",
"Angola",
"Anguilla",
"Antarctica",
"Antigua and Barbuda",
"Argentina",
"Armenia",
"Aruba",
"Australia",
"Austria",
"Azerbaijan",
"Bahamas",
"Bahrain"
]
}