Skip to content

CommonFinders.text does not find Text widget created with Text.rich #19267

@mtter

Description

@mtter

The documentation of CommonFinders.text states that it "Finds [Text] and [EditableText] widgets containing string equal to the text argument."

See: https://github.com/flutter/flutter/blob/master/packages/flutter_test/lib/src/finders.dart.

Given this documentation, I was expecting that CommonFinders.text will find a Text widget containing the string, even if the widget is created using Text.rich.

However, in this case the finder does not seem to find the Widget:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  // This works
  testWidgets('finds Text widget', (WidgetTester tester) async {
    final Text text = new Text('a');

    await tester.pumpWidget(new MaterialApp(home: text));
    expect(find.text('a'), findsOneWidget);
  });

  // This fails
  testWidgets('finds Text widget created with Text.rich', (WidgetTester tester) async {
    final Text text = new Text.rich(new TextSpan(text: 'a'));

    await tester.pumpWidget(new MaterialApp(home: text));
    expect(find.text('a'), findsOneWidget);
  });
}

My understanding is that CommonFinders.text should also find the widget in the second case, as it is a Text widget, containing (exactly) the string passed to the finder. The only difference is the internal structure (string stored in Text.data property vs. stored in Text.textSpan property), which should not matter to the finder I think (even in the first case, TextFinder.build wraps the string in a RichText widget).

This is the implementation of MatchFinder.matches in _TextFinder:

 @override
  bool matches(Element candidate) {
    if (candidate.widget is Text) {
      final Text textWidget = candidate.widget;
      return textWidget.data == text;
    } else if (candidate.widget is EditableText) {
      final EditableText editable = candidate.widget;
      return editable.controller.text == text;
    }
    return false;
  }

It only checks for the data property in the widget, which is null in case the Text was created using Text.rich. I think the matcher should also take textSpan into consideration, something like this:

return textWidget.data == text || textWidget.textSpan.toPlainText() == text;

Alternatively, I could also imaging Text having something similar to TextSpan.toPlainText, returning whatever the (unstructured) text content is, and then using this in the matcher.

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: tests"flutter test", flutter_test, or one of our tests

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions