How to test custom SearchDelegate? - flutter

I'm trying to test my custom SearchDelegate. Example test would be checking after how many characters it starts giving suggestions.
I wrote two example tests which somehow affect each other. They're both the same, but the test that appears later in the code always fail when I run them together.
While debugging I found out FutureBuilder in buildSuggestions method doesn't wait for searchEngine.search(query) future to finish but it happens only for the second test.
I've already tried adding a test.runAsync with Future.delayed inside after tapping search icon. Also, I simplified the case to make it more readable.
You can find the full code here: https://github.com/pmiara/search-delegate-test-fail
or look at it below.
Application code:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class Entity {
final String value;
Entity.fromJson(Map<String, dynamic> json) : value = json['value'];
}
class MySearchDelegate extends SearchDelegate {
final MySearchEngine searchEngine;
MySearchDelegate({#required this.searchEngine});
#override
List<Widget> buildActions(BuildContext context) {
return [];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
close(context, null);
},
);
}
#override
Widget buildResults(BuildContext context) {
return FutureBuilder<List<Entity>>(
future: searchEngine.search(query),
builder: (BuildContext context, AsyncSnapshot<List<Entity>> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
final entities = snapshot.data;
return ListView.builder(
itemCount: entities.length,
itemBuilder: (context, index) => ListTile(
title: Text(entities[index].value),
onTap: () => close(context, entities[index]),
),
);
} else {
return Column();
}
},
);
}
#override
Widget buildSuggestions(BuildContext context) {
return FutureBuilder<List<Entity>>(
future: searchEngine.search(query),
builder: (BuildContext context, AsyncSnapshot<List<Entity>> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
final entities = snapshot.data;
return ListView.builder(
itemCount: entities.length,
itemBuilder: (context, index) => ListTile(
title: Text(entities[index].value),
onTap: () {
query = entities[index].value;
showResults(context);
},
),
);
} else {
return Column();
}
},
);
}
}
class MySearchEngine {
Future<List<Entity>> search(String query) async {
final jsonEntities =
await rootBundle.loadString('test_resources/entities.json');
final entities = jsonDecode(jsonEntities)
.map<Entity>((json) => Entity.fromJson(json))
.toList();
return entities;
}
}
class TestHomePage extends StatelessWidget {
final MySearchDelegate delegate;
const TestHomePage({#required this.delegate});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (BuildContext context) {
return Scaffold(
body: Center(
child: IconButton(
icon: Icon(Icons.search),
onPressed: () async {
showSearch(
context: context,
delegate: delegate,
);
},
),
),
);
},
),
);
}
}
/// Run to see what tests should "see"
void main() => runApp(
TestHomePage(
delegate: MySearchDelegate(
searchEngine: MySearchEngine(),
),
),
);
Test file:
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:search_delegate_test/search_delegate_problem.dart';
void main() {
testWidgets('First test', (WidgetTester tester) async {
final delegate = MySearchDelegate(
searchEngine: MySearchEngine(),
);
await tester.pumpWidget(
TestHomePage(
delegate: delegate,
),
);
await tester.tap(find.byIcon(Icons.search));
await tester.pumpAndSettle();
await tester.enterText(find.byType(TextField), 'query');
await tester.pumpAndSettle();
expect(find.byType(ListTile), findsNWidgets(3));
});
testWidgets('Second test', (WidgetTester tester) async {
final delegate = MySearchDelegate(
searchEngine: MySearchEngine(),
);
await tester.pumpWidget(
TestHomePage(
delegate: delegate,
),
);
await tester.tap(find.byIcon(Icons.search));
await tester.pumpAndSettle();
await tester.enterText(find.byType(TextField), 'query');
await tester.pumpAndSettle();
expect(find.byType(ListTile), findsNWidgets(3));
});
}
pubsec.yaml:
name: search_delegate_test
description: A new Flutter application.
version: 1.0.0+1
environment:
sdk: ">=2.2.2 <3.0.0"
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
test: any
flutter:
assets:
- test_resources/
uses-material-design: true
test_resources/entities.json:
[
{
"value": "abc"
},
{
"value": "abc123"
},
{
"value": "123def"
}
]
And the result of flutter doctor (I'm using Android Studio):
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.7.8+hotfix.4, on Linux, locale pl_PL.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[✓] Android Studio (version 3.4)
[!] IntelliJ IDEA Ultimate Edition (version 2019.1)
✗ Flutter plugin not installed; this adds Flutter specific functionality.
✗ Dart plugin not installed; this adds Dart specific functionality.
[!] IntelliJ IDEA Community Edition (version 2019.1)
✗ Flutter plugin not installed; this adds Flutter specific functionality.
✗ Dart plugin not installed; this adds Dart specific functionality.
[✓] Connected device (1 available)
! Doctor found issues in 2 categories.
Error that I get:
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure object was thrown running a test:
Expected: exactly 3 matching nodes in the widget tree
Actual: ?:<zero widgets with type "ListTile" (ignoring offstage widgets)>
Which: means none were found but some were expected
When the exception was thrown, this was the stack:
#4 main.<anonymous closure> (file:///path/to/project/search_delegate_test/test/serach_delegate_problem_test.dart:37:5)
<asynchronous suspension>
#5 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:118:25)
<asynchronous suspension>
#6 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:630:19)
<asynchronous suspension>
#9 TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:613:14)
#10 AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1010:24)
#16 AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.dart:1007:15)
#17 testWidgets.<anonymous closure> (package:flutter_test/src/widget_tester.dart:116:22)
#18 Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:168:27)
<asynchronous suspension>
#19 Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:250:15)
<asynchronous suspension>
#24 Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:247:5)
#25 Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:166:33)
#30 Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:165:13)
<asynchronous suspension>
#31 Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:400:25)
<asynchronous suspension>
#45 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:382:19)
#46 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:416:5)
#47 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:172:12)
(elided 28 frames from class _FakeAsync, package dart:async, package dart:async-patch, and package stack_trace)
This was caught by the test expectation on the following line:
file:///path/to/project/search_delegate_test/test/serach_delegate_problem_test.dart line 37
The test description was:
Second test
════════════════════════════════════════════════════════════════════════════════════════════════════
Test failed. See exception logs above.
The test description was: Second test

Related

LateInitializationError: Field '_deviceLocale#66168148' has not been initialized when use easy_localization to international the flutter app

I am using easy_localization to localization the flutter app(flutter stable 2.5.3), but when I run the app, shows error like this:
======== Exception caught by widgets library =======================================================
The following LateError was thrown attaching to the render tree:
LateInitializationError: Field '_deviceLocale#66168148' has not been initialized.
When the exception was thrown, this was the stack:
#0 EasyLocalizationController._deviceLocale (package:easy_localization/src/easy_localization_controller.dart)
#1 new EasyLocalizationController.<anonymous closure> (package:easy_localization/src/easy_localization_controller.dart:52:48)
#2 ListMixin.firstWhere (dart:collection/list.dart:161:15)
#3 new EasyLocalizationController (package:easy_localization/src/easy_localization_controller.dart:51:34)
#4 _EasyLocalizationState.initState (package:easy_localization/src/easy_localization_app.dart:120:30)
#5 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4805:57)
#6 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4638:5)
#7 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3673:14)
#8 Element.updateChild (package:flutter/src/widgets/framework.dart:3425:18)
#9 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1198:16)
#10 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1167:5)
#11 RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:1112:18)
#12 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2573:19)
#13 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1111:13)
#14 WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:944:7)
#15 WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:924:7)
(elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
====================================================================================================
To reproduce the problem, I made a minimal example. this is the main.dart:
import 'package:easy_localization/easy_localization.dart';
import 'package:easy_localization_loader/easy_localization_loader.dart';
import 'package:flutter/material.dart';
import 'package:flutter_learn/utilities/language_util.dart';
void main() {
runApp(EasyLocalization(
supportedLocales: [
Locale(kLanguageEN),
Locale(kLanguageZH),
],
path: 'assets/translations',
assetLoader: YamlAssetLoader(),
fallbackLocale: Locale(kLanguageEN),
child: Container(),
));
}
and this is the language_util.dart file:
import 'package:easy_localization/src/public_ext.dart';
import 'package:flutter/material.dart';
import 'package:flutter_learn/utilities/r.dart';
const kLanguageDE = 'de';
const kLanguageEN = 'en';
const kLanguageES = 'es';
const kLanguageFR = 'fr';
const kLanguageIT = 'it';
const kLanguageJA = 'ja';
const kLanguageKO = 'ko';
const kLanguagePT = 'pt';
const kLanguageRU = 'ru';
const kLanguageZH = 'zh';
final List<String> kAppLanguages = [
kLanguageEN,
kLanguageZH,
];
final List<String> kSupportedLanguages = [
kLanguageDE,
kLanguageEN,
kLanguageES,
kLanguageFR,
kLanguageIT,
kLanguageJA,
kLanguageKO,
kLanguagePT,
kLanguageRU,
kLanguageZH,
];
final Map<String, String> _knownFlagIcons = {
kLanguageDE: 'de',
kLanguageEN: 'gb',
kLanguageES: 'es',
kLanguageFR: 'fr',
kLanguageIT: 'in',
kLanguageJA: 'jp',
kLanguageKO: 'kr',
kLanguagePT: 'pt',
kLanguageRU: 'ru',
kLanguageZH: 'cn',
};
String getLanguageName(String language) {
return 'language.$language'.tr();
}
String getLanguageFlag(String language) {
return R.image('flag_icons/${_knownFlagIcons[language]}.svg');
}
Locale languageToLocale(String language) {
if (language.contains('-')) {
return Locale(
language.substring(0, 1).toUpperCase(), language.substring(1));
}
return Locale(language);
}
this is the r.dart file:
import 'package:flutter/material.dart';
class R {
static GlobalKey<NavigatorState> _navigatorKey;
static setNavigatorKey(GlobalKey navigatorKey) {
_navigatorKey = navigatorKey;
}
static GlobalKey<NavigatorState> getNavigatorKey() {
return _navigatorKey;
}
static String image(String name) {
return 'assets/images/$name';
}
}
and this is the yaml define:
name: flutter_learn
description: A new Flutter application.
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
easy_localization: ^3.0.0
easy_localization_loader: ^1.0.0
cupertino_icons: ^1.0.0
flutter:
uses-material-design: true
assets:
- assets/translations/
am I missing something? what should I do to fix this problem?
You forgot initialize easy_localization (official example). You need to call
WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized();
before creating your EasyLocalization widget.
The WidgetsFlutterBinding is, according to the docs
A concrete binding for applications based on the Widgets framework.
This is the glue that binds the framework to the Flutter engine.
That is needed to, for example, get the device locale, which is done by the EasyLocalization initialization.

Flutter/Dart - Unhandled Exception: MissingPluginException

I'm trying to access the device microphone on press with the aim of recording a voice-note. I have tried to access the current permission value but get the following error:
[VERBOSE-2:ui_dart_state.cc(166)] Unhandled Exception: MissingPluginException(No implementation found for method checkPermissionStatus on channel flutter.baseflow.com/permissions/methods)
#0 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:159:7)
<asynchronous suspension>
#1 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:334:12)
#2 MethodChannelPermissionHandler.checkPermissionStatus (package:permission_handler_platform_interface/src/method_channel/method_channel_permission_handler.dart:15:41)
#3 PermissionActions.status (package:permission_handler/permission_handler.dart:30:51)
#4 _InsideLeftState.build.<anonymous closure> (package:easy_tiger/screens/order_card_flow/insideleft.dart:19:62)
#5 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:184:24)
#6 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:524:11)
#7 BaseTapGestureRecognizer._checkUp (pa<…>
[VERBOSE-2:profiler_metrics_ios.mm(184)] Error retrieving thread information: (ipc/send) invalid destination port
Here is the code for my screen:
import 'package:flutter/material.dart';
import 'package:audio_recorder/audio_recorder.dart';
import 'package:permission_handler/permission_handler.dart';
class InsideLeft extends StatefulWidget {
#override
_InsideLeftState createState() => _InsideLeftState();
}
class _InsideLeftState extends State<InsideLeft> {
#override
Widget build(BuildContext context) {
return Container(
child: GestureDetector(
child: Icon(Icons.mic),
onTap: () async {
PermissionStatus mic = await Permission.microphone.status;
print('microphone permission? ${mic.toString()}');
// try {
//// if (mic != PermissionStatus.granted) {
//// await Permission.microphone.request();
//// }
//// } catch (e) {
//// print(e);
//// }
},
),
);
}
}
Any thoughts how to get around this?
can you please try these things :
Migrate to androidX using android Studio
delete gradle caches
Good post about this topic: Flutter MissingPluginException with several plugins

Flutter plugin just_audio example error then dispose

I've just copied the example of just_audio library and put in into my project, and then I'm doing a hot reload or pressing back, I'm getting an error
[VERBOSE-2:shell.cc(209)] Dart Error: Unhandled exception:
Bad state: You cannot close the subject while items are being added from addStream
#0 Subject.close (package:rxdart/src/subjects/subject.dart:152:7)
#1 AudioPlayer.dispose (package:just_audio/just_audio.dart:611:30)
<asynchronous suspension>
#2 _LessonPractiseScreenState.dispose (package:wbh/ui/pages/lesson/lesson_practise_screen.dart:90:13)
#3 StatefulElement.unmount (package:flutter/src/widgets/framework.dart:4773:12)
#4 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1935:13)
#5 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1933:7)
#6 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:4600:14)
#7 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1931:13)
#8 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1933:7)
#9 SingleChildRenderObjec<…>
The causing widget as I tested is:
Widget get _seekBar => StreamBuilder<Duration>(
stream: _player.durationStream,
builder: (context, snapshot) {
final duration = snapshot.data ?? Duration.zero;
return StreamBuilder<Duration>(
stream: _player.positionStream,
builder: (context, snapshot) {
if (snapshot.hasData) {
var position = snapshot.data ?? Duration.zero;
if (position > duration) {
position = duration;
}
return SeekBar(
duration: duration,
position: position,
onChanged: (newPosition) {
_player.seek(newPosition);
},
);
} else
return Container();
},
);
},
);
But I can't fix it by myself and have got no info on the net, so will appreciate any help.
This was reported as a bug via GitHub and a fix was rolled out soon after (see this issue for the discussion). Newer releases (>= 0.4.4) should resolve this issue.

Operations on File object never finishing during unit tests with Flutter

I'm writing unit tests for my Flutter app and I'm having some trouble when reading a json file. I have some json files that are used by my api mock class. Whenever I call a method on the File object, it never ends, but the test continues to execute, ending in an error because it didn't receive the data from the file object. It's very weird because it only happens when the mock api method is called from a provider that is called from a widget. If I call the mock api method directly my test, it works fine.
The structure of my app is as follows: WidgetScreen calls -> provider calls -> mockApi.
The Widget LegislacaoScreen calls the method carregarLegislacao from my provider, that in turn calls the method getLegislacoes from my mockApi, that method reads from a json file and returns the results to the provider that then notifies my widget. Any help is appreciated.
Oh and I'm running my tests with the command: flutter test test/my_test.dart
Here some code:
LegislacaoScreen:
class LegislacaoScreen extends StatefulWidget {
#override
_LegislacaoScreenState createState() => _LegislacaoScreenState();
}
class _LegislacaoScreenState extends State<LegislacaoScreen>
with AutomaticKeepAliveClientMixin {
#override
void initState() {
super.initState();
Future.microtask(carregarDados);
}
#override
bool get wantKeepAlive => true;
Future<void> carregarDados({bool reset = false}) async {
try {
final legislacaoProvider =
Provider.of<LegislacaoProvider>(context, listen: false);
await legislacaoProvider.carregarLegislacao(
page: legislacaoProvider.currentPage + 1,
reset: reset,
);
} catch (err) {}
}
Widget renderBody(legislacaoProvider) {
if (legislacaoProvider.carregandoLegislacao &&
legislacaoProvider.legislacoes.isEmpty &&
!legislacaoProvider.reseting) {
return Center(
child: CircularProgressIndicator(),
);
}
if (legislacaoProvider.erroCarregandoLegislacao) {
return MensagemAcao(
mensagem:
'Houve um erro ao carregar os dados.\nPor favor tente novamente.',
acao: () => carregarDados(reset: true),
);
}
return LegislacaoLista(
carregandoLegislacao: legislacaoProvider.carregandoLegislacao,
legislacoes: legislacaoProvider.legislacoes,
reseting: legislacaoProvider.reseting,
carregarDados: carregarDados,
isFiltroEmpty: legislacaoProvider.isFiltroEmpty,
);
}
#override
Widget build(BuildContext context) {
super.build(context);
final legislacaoProvider = Provider.of<LegislacaoProvider>(context);
return Scaffold(
appBar: CustomAppBar(
title: 'Legislação',
actions: <Widget>[
IconButton(
icon: Icon(
Icons.search,
color: legislacaoProvider.isFiltroEmpty
? Colors.white
: CustomColors.verde2,
),
onPressed: () {
Navigator.of(context)
.pushNamed(PesquisarLegislacaoScreen.routeName);
},
),
],
),
backgroundColor: Colors.white,
body: renderBody(legislacaoProvider),
);
}
Provider:
class LegislacaoProvider with ChangeNotifier {
bool _carregandoLegislacao = true;
bool _erroCarregandoLegislacao = false;
List<Legislacao> legislacoes = [];
int currentPage = 0;
bool _reseting = false;
LegislacaoApi _legislacaoApi;
LegislacaoProvider({LegislacaoApi legislacaoApi})
: _legislacaoApi = legislacaoApi ?? LegislacaoApiService();
bool get carregandoLegislacao {
return _carregandoLegislacao;
}
bool get erroCarregandoLegislacao {
return _erroCarregandoLegislacao;
}
bool get reseting {
return _reseting;
}
Future<void> carregarLegislacao({
int page = 1,
bool reset = false,
}) async {
try {
_carregandoLegislacao = true;
_erroCarregandoLegislacao = false;
_reseting = reset;
if (reset) {
page = 1;
}
notifyListeners();
legislacoes = await _legislacaoApi.getLegislacoes(
page: page,
ementa: filtro['ementa'],
conteudo: filtro['conteudo'],
ano: filtro['ano'],
periodoInicialLegislacao: filtro['periodoInicialLegislacao'],
periodoFinalLegislacao: filtro['periodoFinalLegislacao'],
tipoLegislacao: filtro['tipoLegislacao']?.id,
numero: filtro['numero'],
autor: filtro['autor'],
);
_carregandoLegislacao = false;
_reseting = false;
notifyListeners();
} catch (err) {
print(err);
_erroCarregandoLegislacao = true;
_carregandoLegislacao = false;
_reseting = false;
notifyListeners();
throw TaNaLeiException(err.toString());
}
}
}
MockApi:
class LegislacaoApiServiceMock extends LegislacaoApi {
bool _fail = false;
LegislacaoApiServiceMock();
LegislacaoApiServiceMock.fail() : _fail = true;
#override
Future<List<Legislacao>> getLegislacoes({
int page = 1,
String conteudo,
String ementa,
String ano,
DateTime periodoInicialLegislacao,
DateTime periodoFinalLegislacao,
int tipoLegislacao,
String numero,
String autor,
}) async {
if (_fail) {
throw Error();
}
final file = File('test/data/get_legislacoes.json');
print('step 1');
final json = await file.readAsString();
print('step 2 '); // <-- NEVER GETS PRINTED
return jsonDecode(json)
.map<Legislacao>(
(elemento) => Legislacao.fromJson(elemento),
)
.toList();
}
}
And finally, my tests:
final locator = GetIt.instance;
void setupLocatorLegislacaoProvider({LegislacaoApi legislacaoApi}) {
locator.registerLazySingleton<LegislacaoProvider>(() => LegislacaoProvider(
legislacaoApi: legislacaoApi,
));
}
void main() async {
TestWidgetsFlutterBinding.ensureInitialized();
setupLocatorLegislacaoProvider(legislacaoApi: LegislacaoApiServiceMock());
group('LegislacaoScreen', () {
Widget buildWidget() {
return ChangeNotifierProvider.value(
value: locator<LegislacaoProvider>();,
child: MaterialApp(
home: LegislacaoScreen(),
routes: routes,
),
);
}
testWidgets('builds screen', (WidgetTester tester) async {
final child = buildWidget();
await tester.pumpWidget(child);
expect(find.byWidget(child), findsOneWidget);
});
testWidgets('finds list when data is loaded',
(WidgetTester tester) async {
await tester.pumpWidget(buildWidget());
await tester.pump();
await tester.pump();
expect(find.byType(LegislacaoLista), findsOneWidget);
});
});
}
EDIT:
Here is the error message from running the tests:
➜ ta_na_lei git:(testes) ✗ flutter test test/ui/screens/legislacao/legislacao_screen_test.dart
00:03 +0: LegislacaoScreen builds screen
dentro de mock 1
00:04 +1: LegislacaoScreen exibe circular progress indicator quando carregando legislacao e reset true
dentro de mock 1
00:04 +2: LegislacaoScreen exibe lista de legislacao quando legislacoes carregadas
dentro de mock 1
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure object was thrown running a test:
Expected: exactly one matching node in the widget tree
Actual: _WidgetTypeFinder:<zero widgets with type "LegislacaoLista" (ignoring offstage widgets)>
Which: means none were found but one was expected
When the exception was thrown, this was the stack:
#4 main.<anonymous closure>.<anonymous closure> (file:///Users/home/Projetos/casacivil/ta_na_lei/test/ui/screens/legislacao/legislacao_screen_test.dart:49:7)
<asynchronous suspension>
#5 main.<anonymous closure>.<anonymous closure> (file:///Users/home/Projetos/casacivil/ta_na_lei/test/ui/screens/legislacao/legislacao_screen_test.dart)
#6 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:140:29)
<asynchronous suspension>
#7 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart)
#8 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:703:19)
<asynchronous suspension>
#11 TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:683:14)
#12 AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1083:24)
#18 AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.dart:1080:15)
#19 testWidgets.<anonymous closure> (package:flutter_test/src/widget_tester.dart:133:24)
#20 Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:172:27)
<asynchronous suspension>
#21 Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart)
#22 Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:246:15)
#27 Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:243:5)
#28 Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:170:33)
#33 Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:169:13)
#34 Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:400:30)
(elided 31 frames from class _FakeAsync, class _RawReceivePortImpl, class _Timer, dart:async, dart:async-patch, and package:stack_trace)
This was caught by the test expectation on the following line:
file:///Users/home/Projetos/casacivil/ta_na_lei/test/ui/screens/legislacao/legislacao_screen_test.dart line 49
The test description was:
exibe lista de legislacao quando legislacoes carregadas
════════════════════════════════════════════════════════════════════════════════════════════════════
00:04 +2 -1: LegislacaoScreen exibe lista de legislacao quando legislacoes carregadas [E]
Test failed. See exception logs above.
The test description was: exibe lista de legislacao quando legislacoes carregadas
00:04 +3 -1: Some tests failed.
EDIT 2:
It seems the issue is with the async environment, after I read this article https://medium.com/flutter/event-loop-in-widget-tester-50b3ca5e9fc5 . I tried to call my test inside a runAsync method, it did not work, then I added await Future.delayed(Duration(seconds: 5)) and It worked. For some reason its taking a long time to read the file (In other tests it reads really fast). One interesting thing is that pump with a duration does not delay the tests...
Well, it works now with this workaround, but I'd like to know the correct way to fix the issue.
await tester.runAsync(() async {
await tester.pumpWidget(buildWidget());
await Future.delayed(Duration(seconds: 5));
await tester.pump(Duration(seconds: 2));
expect(find.byType(LegislacaoLista), findsOneWidget);
});

Flutter tester..tap not working. How to solve "Bad state: No element" error?

I'm writing a widget test in my Flutter app. I'able to find the button using key or text or widget type but when I tap it, it gives Bad State No element error. Below is my test source code. I can also see the element in tester object while debugging under allWidgets item.
class MockSpeechRecognizer extends Mock implements SpeechRecognizer {}
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
setUpAll(() {
const MethodChannel('plugins.flutter.io/shared_preferences')
.setMockMethodCallHandler((MethodCall methodCall) async {
if (methodCall.method == 'getAll') {
return <String, dynamic>{}; // set initial values here if desired
}
return null;
});
setupLocator();
});
group('DashboardView Test | ', () {
testWidgets('Build Dashboard view and change keyword', (WidgetTester tester) async {
final Preferences preferences=Preferences();
preferences.keyword='hello';
final MockSpeechRecognizer speechService = MockSpeechRecognizer();
when(speechService.isServiceRunning).thenReturn(true);
locator.unregister<SpeechRecognizer>();
locator.registerLazySingleton<SpeechRecognizer>(() => speechService);
locator<LocalStorageService>().setUserPreferences(preferences);
// Build our app and trigger a frame.
binding.window.physicalSizeTestValue = Size(600, 300);
await tester.pumpWidget(MaterialApp(home:Dashboard()));
await tester.pumpAndSettle();
expect(find.byType(Dashboard),findsOneWidget);
await tester.tap(find.byKey(const Key('ChangeKeyword')));
});
});
}
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following StateError was thrown running a test:
Bad state: No element
When the exception was thrown, this was the stack:
#0 Iterable.single (dart:core/iterable.dart:554:25)
#1 WidgetController._getElementPoint (package:flutter_test/src/controller.dart:646:47)
#2 WidgetController.getCenter (package:flutter_test/src/controller.dart:618:12)
#3 WidgetController.tap (package:flutter_test/src/controller.dart:256:18)
#4 main.<anonymous closure>.<anonymous closure> (file:///E:/Siak/Meow/meow-phone-finder/test/Widgets/dashboardView_test.dart:52:20)
<asynchronous suspension>
#5 main.<anonymous closure>.<anonymous closure> (file:///E:/Siak/Meow/meow-phone-finder/test/Widgets/dashboardView_test.dart)
#6 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:140:29)
<asynchronous suspension>
#7 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart
Where do you define the Button, have you set the Key parameter?
await tester.pumpWidget(MaterialApp(home:
Container(child:
Button(
key: Key("ChangeKeyword"),
onTap: () => {},
child: Text("Press me"),
),
),
));