| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter/gestures.dart'; |
| import 'package:flutter/material.dart'; |
| import 'package:flutter/rendering.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| void main() { |
| testWidgets('RichText with recognizers without handlers does not throw', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: RichText( |
| text: TextSpan(text: 'root', children: <InlineSpan>[ |
| TextSpan(text: 'one', recognizer: TapGestureRecognizer()), |
| TextSpan(text: 'two', recognizer: LongPressGestureRecognizer()), |
| TextSpan(text: 'three', recognizer: DoubleTapGestureRecognizer()), |
| ]), |
| ), |
| ), |
| ); |
| |
| expect(tester.getSemantics(find.byType(RichText)), matchesSemantics( |
| children: <Matcher>[ |
| matchesSemantics( |
| label: 'root', |
| ), |
| matchesSemantics( |
| label: 'one', |
| ), |
| matchesSemantics( |
| label: 'two', |
| ), |
| matchesSemantics( |
| label: 'three', |
| ), |
| ], |
| )); |
| }); |
| |
| testWidgets('TextSpan Locale works', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: RichText( |
| text: TextSpan( |
| text: 'root', |
| locale: const Locale('es', 'MX'), |
| children: <InlineSpan>[ |
| TextSpan(text: 'one', recognizer: TapGestureRecognizer()), |
| const WidgetSpan( |
| child: SizedBox(), |
| ), |
| TextSpan(text: 'three', recognizer: DoubleTapGestureRecognizer()), |
| ] |
| ), |
| ), |
| ), |
| ); |
| expect(tester.getSemantics(find.byType(RichText)), matchesSemantics( |
| children: <Matcher>[ |
| matchesSemantics( |
| attributedLabel: AttributedString( |
| 'root', |
| attributes: <StringAttribute>[ |
| LocaleStringAttribute(range: const TextRange(start: 0, end: 4), locale: const Locale('es', 'MX')), |
| ] |
| ), |
| ), |
| matchesSemantics( |
| attributedLabel: AttributedString( |
| 'one', |
| attributes: <StringAttribute>[ |
| LocaleStringAttribute(range: const TextRange(start: 0, end: 3), locale: const Locale('es', 'MX')), |
| ] |
| ), |
| ), |
| matchesSemantics( |
| attributedLabel: AttributedString( |
| 'three', |
| attributes: <StringAttribute>[ |
| LocaleStringAttribute(range: const TextRange(start: 0, end: 5), locale: const Locale('es', 'MX')), |
| ] |
| ), |
| ), |
| ], |
| )); |
| }); |
| |
| testWidgets('TextSpan spellOut works', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: RichText( |
| text: TextSpan( |
| text: 'root', |
| spellOut: true, |
| children: <InlineSpan>[ |
| TextSpan(text: 'one', recognizer: TapGestureRecognizer()), |
| const WidgetSpan( |
| child: SizedBox(), |
| ), |
| TextSpan(text: 'three', recognizer: DoubleTapGestureRecognizer()), |
| ] |
| ), |
| ), |
| ), |
| ); |
| expect(tester.getSemantics(find.byType(RichText)), matchesSemantics( |
| children: <Matcher>[ |
| matchesSemantics( |
| attributedLabel: AttributedString( |
| 'root', |
| attributes: <StringAttribute>[ |
| SpellOutStringAttribute(range: const TextRange(start: 0, end: 4)), |
| ] |
| ), |
| ), |
| matchesSemantics( |
| attributedLabel: AttributedString( |
| 'one', |
| attributes: <StringAttribute>[ |
| SpellOutStringAttribute(range: const TextRange(start: 0, end: 3)), |
| ] |
| ), |
| ), |
| matchesSemantics( |
| attributedLabel: AttributedString( |
| 'three', |
| attributes: <StringAttribute>[ |
| SpellOutStringAttribute(range: const TextRange(start: 0, end: 5)), |
| ] |
| ), |
| ), |
| ], |
| )); |
| }); |
| |
| testWidgets('WidgetSpan calculate correct intrinsic heights', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Center( |
| child: Container( |
| color: Colors.green, |
| child: IntrinsicHeight( |
| child: RichText( |
| text: TextSpan( |
| children: <InlineSpan>[ |
| const TextSpan(text: 'Start\n', style: TextStyle(height: 1.0, fontSize: 16)), |
| WidgetSpan( |
| child: Row( |
| children: const <Widget>[ |
| SizedBox(height: 16, width: 16), |
| ], |
| ), |
| ), |
| const TextSpan(text: 'End', style: TextStyle(height: 1.0, fontSize: 16)), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| expect(tester.getSize(find.byType(IntrinsicHeight)).height, 3 * 16); |
| }); |
| |
| testWidgets('RichText implements debugFillProperties', (WidgetTester tester) async { |
| final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); |
| RichText( |
| text: const TextSpan(text: 'rich text'), |
| textAlign: TextAlign.center, |
| textDirection: TextDirection.rtl, |
| softWrap: false, |
| overflow: TextOverflow.ellipsis, |
| textScaleFactor: 1.3, |
| maxLines: 1, |
| locale: const Locale('zh', 'HK'), |
| strutStyle: const StrutStyle( |
| fontSize: 16, |
| ), |
| textWidthBasis: TextWidthBasis.longestLine, |
| textHeightBehavior: const TextHeightBehavior(applyHeightToFirstAscent: false), |
| ).debugFillProperties(builder); |
| |
| final List<String> description = builder.properties |
| .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) |
| .map((DiagnosticsNode node) => node.toString()) |
| .toList(); |
| |
| expect(description, unorderedMatches(<dynamic>[ |
| contains('textAlign: center'), |
| contains('textDirection: rtl'), |
| contains('softWrap: no wrapping except at line break characters'), |
| contains('overflow: ellipsis'), |
| contains('textScaleFactor: 1.3'), |
| contains('maxLines: 1'), |
| contains('textWidthBasis: longestLine'), |
| contains('text: "rich text"'), |
| contains('locale: zh_HK'), |
| allOf(startsWith('strutStyle: StrutStyle('), contains('size: 16.0')), |
| allOf( |
| startsWith('textHeightBehavior: TextHeightBehavior('), |
| contains('applyHeightToFirstAscent: false'), |
| contains('applyHeightToLastDescent: true'), |
| ), |
| ])); |
| }); |
| } |