Categories
dart flutter software_dev testing

Wrap widgets in MaterialApp and Scaffold for Widget Testing

When testing single widgets, wrap the widgets in a MaterialApp and Scaffold in the test to avoid the following nastiness…

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═════════════════════════
The following assertion was thrown building Text("qinc was here"):
No Directionality widget found.
RichText widgets require a Directionality widget ancestor.
The specific widget that could not find a Directionality ancestor was:
  RichText
The ownership chain for the affected widget is: "RichText ← Text ← DisplayMeSomeText ← [root]"
Typically, the Directionality widget is introduced by the MaterialApp or WidgetsApp widget at the
top of your application widget tree. It determines the ambient reading direction and is used, for
example, to determine how to lay out text, how to interpret "start" and "end" values, and to resolve
EdgeInsetsDirectional, AlignmentDirectional, and other *Directional objects.

Widget under test

class DisplayMeSomeText extends StatelessWidget {
  final String _theText;
  const DisplayMeSomeText(this._theText, {Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) =>Text(_theText);
}

BAD BAD BAD

void main() {
  testWidgets('Ensure expected text is displayed', (WidgetTester tester) async {
    const sometext = "qinc was here";
    await tester.pumpWidget(const DisplayMeSomeText(sometext));
    await tester.pumpAndSettle();
    expect(find.text(sometext), findsOneWidget);
  });
}

BETTER BETTER BETTER

void main() {
  testWidgets('Ensure expected text is displayed', (WidgetTester tester) async {
    const sometext = "qinc was here";

    await tester.pumpWidget(
      const MaterialApp(
        home: Scaffold(
          body: DisplayMeSomeText(sometext),
        ),
      ),
    );
    await tester.pumpAndSettle();
    expect(find.text(sometext), findsOneWidget);
  });
}

To make this easier in all widget tests, the following utility method is helpful.

EVEN BETTER..imho

Widget constructTestMaterialApp(Widget widget) => MaterialApp(
      home: Scaffold(
        body: widget,
      ),
    );

void main() {
  testWidgets('Ensure expected text is displayed', (WidgetTester tester) async {
    const sometext = "qinc was here";
    await tester.pumpWidget(constructTestMaterialApp(
      const DisplayMeSomeText(sometext),
    ));
    await tester.pumpAndSettle();
    expect(find.text(sometext), findsOneWidget);
  });
}