Is there an easy way to find particular text built from RichText in a Flutter test?
Asked Answered
E

5

25

For example, I may have one RichText in current widget tree, that looks like

RichText(
 text: TextSpan(
   text: 'Hello ',
   style: DefaultTextStyle.of(context).style,
   children: <TextSpan>[
     TextSpan(text: 'bold', style: TextStyle(fontWeight: FontWeight.bold)),
     TextSpan(text: ' world!'),
   ],
 ),
)

I try to use find.text('Hello bold world!') but it doesn't work because it's not a Text.

Erine answered 14/12, 2016 at 21:15 Comment(0)
U
23

Simplest solution is to put a key on the RichText and read it that way.

If that's not a good fit for whatever reason, you can use find.byWidgetPredicate and pass a function that matches RichText widgets whose text.toPlainText() returns the string you want.

Unaware answered 14/12, 2016 at 22:47 Comment(2)
Thanks, the second solution will be like:expect(find.byWidgetPredicate((Widget widget) => widget is RichText && widget.text.toPlainText() == 'Hello bold world'), findsOneWidget);Avaricious
In my case, widget.text.toPlainText() actually contained 0-width space characters at the end (probably because of empty spans). The only way I got it to work was to use .startsWith : (widget) => widget is RichText && widget.text.toPlainText().startsWith('hello')Gadmon
Y
39

Framework solution

I have recently contributed this feature to the Flutter framework, i.e. to the built-in finders.

find.text()

You can now enable a findRichText parameter, which will then also find standalone RichText widgets:

find.text(
  'Hello bold world!',
  findRichText: true,
)
Yachtsman answered 27/8, 2021 at 0:8 Comment(4)
This is awesome! Thanks a lot for your contribution, this'll be great in stable!Hessney
This a great contribution. Can confirm this is on the stable channel in Flutter v2.10.1.Scofield
Nice! Can you also do find.textContaining()? :)Orthographize
Cool, saved myself from scratching my headCausation
U
23

Simplest solution is to put a key on the RichText and read it that way.

If that's not a good fit for whatever reason, you can use find.byWidgetPredicate and pass a function that matches RichText widgets whose text.toPlainText() returns the string you want.

Unaware answered 14/12, 2016 at 22:47 Comment(2)
Thanks, the second solution will be like:expect(find.byWidgetPredicate((Widget widget) => widget is RichText && widget.text.toPlainText() == 'Hello bold world'), findsOneWidget);Avaricious
In my case, widget.text.toPlainText() actually contained 0-width space characters at the end (probably because of empty spans). The only way I got it to work was to use .startsWith : (widget) => widget is RichText && widget.text.toPlainText().startsWith('hello')Gadmon
M
15

Here's the find.byWidgetPredicate call.

find.byWidgetPredicate((widget) => fromRichTextToPlainText(widget) == 'Hello bold world!')

Here's the fromRichTextToPlainText helper function. Pass it the RichText widget, it will return the plain text.

String fromRichTextToPlainText(final Widget widget) {
  if (widget is RichText) {
    if (widget.text is TextSpan) {
      final buffer = StringBuffer();
      (widget.text as TextSpan).computeToPlainText(buffer);
      return buffer.toString();
    }
  }
  return null;
}
Marden answered 21/3, 2020 at 17:31 Comment(0)
M
1

I solved for this by digging into the widget a bit more manually

    final richTextWidget = tester.element(richTextFinder).widget as RichText;
    print(richTextWidget.text.children);

With the children, I can assert they are generated as expected

Melmon answered 25/2, 2020 at 17:15 Comment(0)
A
0

You can simply achieve this by enabling findRichText: true like this,

expect(find.text("${input.newItem.price.toPrice}/${weight!.unit}", findRichText: true), findsOneWidget);
Ahrens answered 28/9, 2023 at 9:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.