18

If we have a TextSpan that is a child of a RichText widget, how would you test the text content.

new TextSpan(
  text: 'Hello world!',
  style: new TextStyle(color: Colors.black),
)

In your tests, with a Text widget, you can use expect(find.text('Hello world!'), findsOneWidget), but this doesn't work if you have a TextSpan.

expect(find.byType(TextSpan), findsOneWidget) also does not find any widgets of type TextSpan.

S.D.
  • 5,197
  • 9
  • 38
  • 64

6 Answers6

8

In addition to Rémi's answer, here is the way to find the text from a RichText. You set the key to the RichText and then you can do:

Finder widgetFinder = find.byKey(key);

Finder rtFinder =
   find.descendant(of: widgetFinder, matching: find.byType(RichText));
RichText richText = rtFinder.evaluate().first.widget as RichText;
String richTextText = richText.text.toPlainText();

print('Text from Text widget: $richTextText');
expect(richTextText, 'This is my text',
   reason: 'Text from found text widget do not match');
sceee
  • 1,681
  • 19
  • 34
7

That's not possible. As TextSpan doesn't actually render anything. It is data information used by another object to actually render something.

What you can do instead is to find the widget to which you pass your TextSpan. And then verify it's correct

Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
  • how would you find the widget to which you pass the TextSpan (which is the RichText, correct)? – sceee Sep 09 '19 at 18:19
  • I answered my question from the comment by myself, see my answer to this question which clarifies Rémi's second point. – sceee Sep 09 '19 at 19:19
5

It can be achieved by using byWidgetPredicate

expect(
    find.byWidgetPredicate((widget) =>
        widget is RichText &&
        widget.text.toPlainText() ==
            'Hello World!.'),
    findsOneWidget);
Sathish
  • 96
  • 1
  • 9
2

You can find the RichText widget instead. Here's the find.byWidgetPredicate call.

expect(find.byWidgetPredicate((widget) => fromRichTextToPlainText(widget) == 'Hello world!'), findsOneWidget);

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

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;
}
Bienvenido David
  • 4,118
  • 1
  • 25
  • 16
0

From above snippets - I found below bit customised version helpful to me..

String? fromRichTextToPlainText(final Widget widget) {
  if (widget is RichText) {
    return widget.text.toPlainText();
  }
  return null;
}
expect(
          find.byWidgetPredicate(
              (widget) => fromRichTextToPlainText(widget) == 'My Rich Text'),
          findsOneWidget);
jignesh.world
  • 1,396
  • 1
  • 11
  • 26
0

In case someone needs to not just find the widget, but also tap on it:

Finding a TextSpan to tap on with Flutter tests

David Schneider
  • 472
  • 5
  • 13