[Flutter] Tests : d'où sort le widget HeroControllerScope ?
Bonjour.
J'ai un test unitaire qui échoue
Code:
1 2 3 4 5 6
| ══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure was thrown running a test:
Expected: exactly one matching node in the widget tree
Actual: _WidgetPredicateFinder:<zero widgets with widget matching predicate (Closure: (Widget) =>
bool) (ignoring offstage widgets)>
Which: means none were found but one was expected |
En utilisant debugDumpApp();, je me rends compte que l'application ressort le widget HeroControllerScope :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| AutomatedTestWidgetsFlutterBinding - DEBUG MODE
[root](renderObject: RenderView#ae39a)
└View-[GlobalObjectKey TestFlutterView#81a0a]
└_ViewScope
└_MediaQueryFromView(state: _MediaQueryFromViewState#6ab7a)
└MediaQuery(...)
└StreamBuilder<XFile>(state: _StreamBuilderBaseState<XFile, AsyncSnapshot<XFile>>#d6910)
└BlocProvider<BlocXXX>(state: ProviderState#31496)
└MaterialApp(state: _MaterialAppState#41775)
└ScrollConfiguration(behavior: MaterialScrollBehavior)
└HeroControllerScope
...
└AnimatedTheme(duration: 200ms, state: _AnimatedThemeState#ba34b(ticker inactive, ThemeDataTween(ThemeData#662fa → ThemeData#662fa)))
└Theme(ThemeData#662fa, dependencies: [DefaultSelectionStyle])
└_InheritedTheme
└CupertinoTheme(...)
└_InheritedCupertinoTheme
.... |
Je ne sais vraiment pas d'où ça sort, à aucun moment je n'ai utilisé HeroControllerScope, et il n'apparait lors d'un Ctrl+F que dans flutter\SDK\packages\flutter\lib\src\.
Le test en question :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group("Bottom bar", () {
late BlocXXX blocXXX;
late StreamBuilder<XFile> testedStream;
Widget snapshotBottomBar(BuildContext context, AsyncSnapshot<XFile> snapshot) {
return BlocProvider<BlocXXX>(
bloc: blocXXX,
child: const MaterialApp(
locale: Locale('fr', 'FR'),
localizationsDelegates: [
DefaultWidgetsLocalizations.delegate,
DefaultMaterialLocalizations.delegate
],
home: BottomBar("_title"))
);
}
setUp(() {
blocXXX = BlocXXX();
testedStream = StreamBuilder(
initialData: XFile("lalilulelo"),
stream: blocXXX.stream,
builder: snapshotBottomBar
);
});
testWidgets('nominal', (WidgetTester tester) async {
FlutterError.onError = ignoreOverflowErrors;
await tester.pumpWidget(testedStream);
debugDumpApp();
expect(
find.byWidgetPredicate((widget) => widget is FloatingActionButton &&
widget.child == const Icon(Icons.camera)
),
findsOneWidget);
});
});
} |
Note : j'utilise l'architecture BLoC, qui complique sensiblement les tests... à mon grand désarroi. Mais ça fonctionne.
Note 2 : la partie ignoreOverflowErrors et TestWidgetsFlutterBinding.ensureInitialized(); proviennent de cette page (pour ignorer les erreurs de RenderFlex Overflow).
Le BottomBar utilise cette hiérarchie
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class BottomBar extends StatelessWidget {
Directionality(
SizedBox(
Column(
Container(
Text(),
),
Container(
StreamBuilder<XFile>(
Row(
FloatingActionButton(),
FloatingActionButton(),
FloatingActionButton()
)
),
),
)
),
)
} |
Quant au bloc il est simplissime :
Code:
1 2 3 4 5 6 7 8
| class BlocXXX extends Bloc {
XFile? selected;
final StreamController<XFile> _imgCtrl = StreamController<XFile>();
Stream<XFile> get stream => _imgCtrl.stream;
Sink<XFile> get sink => _imgCtrl.sink;
// D'autres fonctions
} |
Je jette une bouteille à la mer. Est-ce que quelqu'un a déjà eu ce HeroController qui sort de nulle part ? Pourquoi je ne retrouve pas ma BottomBar lors du test ?
J'avoue que je sèche.