829 lines
26 KiB
Dart
829 lines
26 KiB
Dart
// 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 'dart:ui' as ui;
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/gestures.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
|
|
import '../rendering/mock_canvas.dart';
|
|
import 'semantics_tester.dart';
|
|
|
|
void main() {
|
|
testWidgets('Text respects media query', (WidgetTester tester) async {
|
|
await tester.pumpWidget(const MediaQuery(
|
|
data: MediaQueryData(textScaleFactor: 1.3),
|
|
child: Center(
|
|
child: Text('Hello', textDirection: TextDirection.ltr),
|
|
),
|
|
));
|
|
|
|
RichText text = tester.firstWidget(find.byType(RichText));
|
|
expect(text, isNotNull);
|
|
expect(text.textScaleFactor, 1.3);
|
|
|
|
await tester.pumpWidget(const Center(
|
|
child: Text('Hello', textDirection: TextDirection.ltr),
|
|
));
|
|
|
|
text = tester.firstWidget(find.byType(RichText));
|
|
expect(text, isNotNull);
|
|
expect(text.textScaleFactor, 1.0);
|
|
});
|
|
|
|
testWidgets('Text respects textScaleFactor with default font size', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
const Center(child: Text('Hello', textDirection: TextDirection.ltr))
|
|
);
|
|
|
|
RichText text = tester.firstWidget(find.byType(RichText));
|
|
expect(text, isNotNull);
|
|
expect(text.textScaleFactor, 1.0);
|
|
final Size baseSize = tester.getSize(find.byType(RichText));
|
|
expect(baseSize.width, equals(70.0));
|
|
expect(baseSize.height, equals(14.0));
|
|
|
|
await tester.pumpWidget(const Center(
|
|
child: Text(
|
|
'Hello',
|
|
textScaleFactor: 1.5,
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
));
|
|
|
|
text = tester.firstWidget(find.byType(RichText));
|
|
expect(text, isNotNull);
|
|
expect(text.textScaleFactor, 1.5);
|
|
final Size largeSize = tester.getSize(find.byType(RichText));
|
|
expect(largeSize.width, 105.0);
|
|
expect(largeSize.height, equals(21.0));
|
|
});
|
|
|
|
testWidgets('Text respects textScaleFactor with explicit font size', (WidgetTester tester) async {
|
|
await tester.pumpWidget(const Center(
|
|
child: Text('Hello',
|
|
style: TextStyle(fontSize: 20.0), textDirection: TextDirection.ltr),
|
|
));
|
|
|
|
RichText text = tester.firstWidget(find.byType(RichText));
|
|
expect(text, isNotNull);
|
|
expect(text.textScaleFactor, 1.0);
|
|
final Size baseSize = tester.getSize(find.byType(RichText));
|
|
expect(baseSize.width, equals(100.0));
|
|
expect(baseSize.height, equals(20.0));
|
|
|
|
await tester.pumpWidget(const Center(
|
|
child: Text('Hello',
|
|
style: TextStyle(fontSize: 20.0),
|
|
textScaleFactor: 1.3,
|
|
textDirection: TextDirection.ltr),
|
|
));
|
|
|
|
text = tester.firstWidget(find.byType(RichText));
|
|
expect(text, isNotNull);
|
|
expect(text.textScaleFactor, 1.3);
|
|
final Size largeSize = tester.getSize(find.byType(RichText));
|
|
expect(largeSize.width, anyOf(131.0, 130.0));
|
|
expect(largeSize.height, equals(26.0));
|
|
});
|
|
|
|
testWidgets('Text throws a nice error message if there\'s no Directionality', (WidgetTester tester) async {
|
|
await tester.pumpWidget(const Text('Hello'));
|
|
final String message = tester.takeException().toString();
|
|
expect(message, contains('Directionality'));
|
|
expect(message, contains(' Text '));
|
|
});
|
|
|
|
testWidgets('Text can be created from TextSpans and uses defaultTextStyle', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
const DefaultTextStyle(
|
|
style: TextStyle(
|
|
fontSize: 20.0,
|
|
),
|
|
child: Text.rich(
|
|
TextSpan(
|
|
text: 'Hello',
|
|
children: <TextSpan>[
|
|
TextSpan(
|
|
text: ' beautiful ',
|
|
style: TextStyle(fontStyle: FontStyle.italic),
|
|
),
|
|
TextSpan(
|
|
text: 'world',
|
|
style: TextStyle(fontWeight: FontWeight.bold),
|
|
),
|
|
],
|
|
),
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
),
|
|
);
|
|
|
|
final RichText text = tester.firstWidget(find.byType(RichText));
|
|
expect(text, isNotNull);
|
|
expect(text.text.style.fontSize, 20.0);
|
|
});
|
|
|
|
testWidgets('inline widgets works with ellipsis', (WidgetTester tester) async {
|
|
// Regression test for https://github.com/flutter/flutter/issues/35869
|
|
const TextStyle textStyle = TextStyle(fontFamily: 'Ahem');
|
|
await tester.pumpWidget(
|
|
Text.rich(
|
|
TextSpan(
|
|
children: <InlineSpan>[
|
|
const TextSpan(
|
|
text: 'a very very very very very very very very very very long line',
|
|
),
|
|
WidgetSpan(
|
|
child: SizedBox(
|
|
width: 20,
|
|
height: 40,
|
|
child: Card(
|
|
child: RichText(
|
|
text: const TextSpan(text: 'widget should be truncated'),
|
|
textDirection: TextDirection.rtl,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
style: textStyle,
|
|
),
|
|
textDirection: TextDirection.ltr,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
);
|
|
expect(tester.takeException(), null);
|
|
}, skip: isBrowser); // TODO(yjbanov): https://github.com/flutter/flutter/issues/42086
|
|
|
|
testWidgets('semanticsLabel can override text label', (WidgetTester tester) async {
|
|
final SemanticsTester semantics = SemanticsTester(tester);
|
|
await tester.pumpWidget(
|
|
const Text(
|
|
'\$\$',
|
|
semanticsLabel: 'Double dollars',
|
|
textDirection: TextDirection.ltr,
|
|
)
|
|
);
|
|
final TestSemantics expectedSemantics = TestSemantics.root(
|
|
children: <TestSemantics>[
|
|
TestSemantics.rootChild(
|
|
label: 'Double dollars',
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
],
|
|
);
|
|
expect(
|
|
semantics,
|
|
hasSemantics(
|
|
expectedSemantics,
|
|
ignoreTransform: true,
|
|
ignoreId: true,
|
|
ignoreRect: true,
|
|
),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Text('\$\$', semanticsLabel: 'Double dollars')),
|
|
);
|
|
|
|
expect(
|
|
semantics,
|
|
hasSemantics(
|
|
expectedSemantics,
|
|
ignoreTransform: true,
|
|
ignoreId: true,
|
|
ignoreRect: true,
|
|
),
|
|
);
|
|
semantics.dispose();
|
|
});
|
|
|
|
testWidgets('semanticsLabel can be shorter than text', (WidgetTester tester) async {
|
|
final SemanticsTester semantics = SemanticsTester(tester);
|
|
await tester.pumpWidget(Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: RichText(
|
|
text: TextSpan(
|
|
children: <InlineSpan>[
|
|
const TextSpan(
|
|
text: 'Some Text',
|
|
semanticsLabel: '',
|
|
),
|
|
TextSpan(
|
|
text: 'Clickable',
|
|
recognizer: TapGestureRecognizer()..onTap = () { },
|
|
),
|
|
]),
|
|
),
|
|
));
|
|
final TestSemantics expectedSemantics = TestSemantics.root(
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
TestSemantics(
|
|
label: 'Clickable',
|
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
|
flags: <SemanticsFlag>[SemanticsFlag.isLink],
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
expect(
|
|
semantics,
|
|
hasSemantics(
|
|
expectedSemantics,
|
|
ignoreTransform: true,
|
|
ignoreId: true,
|
|
ignoreRect: true,
|
|
),
|
|
);
|
|
semantics.dispose();
|
|
});
|
|
|
|
testWidgets('recognizers split semantic node', (WidgetTester tester) async {
|
|
final SemanticsTester semantics = SemanticsTester(tester);
|
|
const TextStyle textStyle = TextStyle(fontFamily: 'Ahem');
|
|
await tester.pumpWidget(
|
|
Text.rich(
|
|
TextSpan(
|
|
children: <TextSpan>[
|
|
const TextSpan(text: 'hello '),
|
|
TextSpan(
|
|
text: 'world',
|
|
recognizer: TapGestureRecognizer()..onTap = () { },
|
|
),
|
|
const TextSpan(text: ' this is a '),
|
|
const TextSpan(text: 'cat-astrophe'),
|
|
],
|
|
style: textStyle,
|
|
),
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
);
|
|
final TestSemantics expectedSemantics = TestSemantics.root(
|
|
children: <TestSemantics>[
|
|
TestSemantics.rootChild(
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
label: 'hello ',
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
TestSemantics(
|
|
label: 'world',
|
|
textDirection: TextDirection.ltr,
|
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
|
flags: <SemanticsFlag>[SemanticsFlag.isLink],
|
|
),
|
|
TestSemantics(
|
|
label: ' this is a cat-astrophe',
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
expect(
|
|
semantics,
|
|
hasSemantics(
|
|
expectedSemantics,
|
|
ignoreTransform: true,
|
|
ignoreId: true,
|
|
ignoreRect: true,
|
|
),
|
|
);
|
|
semantics.dispose();
|
|
});
|
|
|
|
testWidgets('recognizers split semantic node when TextSpan overflows', (WidgetTester tester) async {
|
|
final SemanticsTester semantics = SemanticsTester(tester);
|
|
const TextStyle textStyle = TextStyle(fontFamily: 'Ahem');
|
|
await tester.pumpWidget(
|
|
SizedBox(
|
|
height: 10,
|
|
child: Text.rich(
|
|
TextSpan(
|
|
children: <TextSpan>[
|
|
const TextSpan(text: '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'),
|
|
TextSpan(
|
|
text: 'world',
|
|
recognizer: TapGestureRecognizer()..onTap = () { },
|
|
),
|
|
],
|
|
style: textStyle,
|
|
),
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
),
|
|
);
|
|
final TestSemantics expectedSemantics = TestSemantics.root(
|
|
children: <TestSemantics>[
|
|
TestSemantics.rootChild(
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
label: '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n',
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
TestSemantics(
|
|
label: 'world',
|
|
textDirection: TextDirection.ltr,
|
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
|
flags: <SemanticsFlag>[SemanticsFlag.isLink],
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
expect(
|
|
semantics,
|
|
hasSemantics(
|
|
expectedSemantics,
|
|
ignoreTransform: true,
|
|
ignoreId: true,
|
|
ignoreRect: true,
|
|
),
|
|
);
|
|
semantics.dispose();
|
|
});
|
|
|
|
testWidgets('recognizers split semantic nodes with text span labels', (WidgetTester tester) async {
|
|
final SemanticsTester semantics = SemanticsTester(tester);
|
|
const TextStyle textStyle = TextStyle(fontFamily: 'Ahem');
|
|
await tester.pumpWidget(
|
|
Text.rich(
|
|
TextSpan(
|
|
children: <TextSpan>[
|
|
const TextSpan(text: 'hello '),
|
|
TextSpan(
|
|
text: 'world',
|
|
recognizer: TapGestureRecognizer()..onTap = () { },
|
|
),
|
|
const TextSpan(text: ' this is a '),
|
|
const TextSpan(
|
|
text: 'cat-astrophe',
|
|
semanticsLabel: 'regrettable event',
|
|
),
|
|
],
|
|
style: textStyle,
|
|
),
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
);
|
|
final TestSemantics expectedSemantics = TestSemantics.root(
|
|
children: <TestSemantics>[
|
|
TestSemantics.rootChild(
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
label: 'hello ',
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
TestSemantics(
|
|
label: 'world',
|
|
textDirection: TextDirection.ltr,
|
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
|
flags: <SemanticsFlag>[SemanticsFlag.isLink],
|
|
),
|
|
TestSemantics(
|
|
label: ' this is a regrettable event',
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
expect(
|
|
semantics,
|
|
hasSemantics(
|
|
expectedSemantics,
|
|
ignoreTransform: true,
|
|
ignoreId: true,
|
|
ignoreRect: true,
|
|
),
|
|
);
|
|
semantics.dispose();
|
|
});
|
|
|
|
|
|
testWidgets('recognizers split semantic node - bidi', (WidgetTester tester) async {
|
|
final SemanticsTester semantics = SemanticsTester(tester);
|
|
const TextStyle textStyle = TextStyle(fontFamily: 'Ahem');
|
|
await tester.pumpWidget(
|
|
RichText(
|
|
text: TextSpan(
|
|
style: textStyle,
|
|
children: <TextSpan>[
|
|
const TextSpan(text: 'hello world${Unicode.RLE}${Unicode.RLO} '),
|
|
TextSpan(
|
|
text: 'BOY',
|
|
recognizer: LongPressGestureRecognizer()..onLongPress = () { },
|
|
),
|
|
const TextSpan(text: ' HOW DO${Unicode.PDF} you ${Unicode.RLO} DO '),
|
|
TextSpan(
|
|
text: 'SIR',
|
|
recognizer: TapGestureRecognizer()..onTap = () { },
|
|
),
|
|
const TextSpan(text: '${Unicode.PDF}${Unicode.PDF} good bye'),
|
|
],
|
|
),
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
);
|
|
// The expected visual order of the text is:
|
|
// hello world RIS OD you OD WOH YOB good bye
|
|
final TestSemantics expectedSemantics = TestSemantics.root(
|
|
children: <TestSemantics>[
|
|
TestSemantics.rootChild(
|
|
rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0),
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
rect: const Rect.fromLTRB(-4.0, -4.0, 480.0, 18.0),
|
|
label: 'hello world ',
|
|
textDirection: TextDirection.ltr, // text direction is declared as LTR.
|
|
),
|
|
TestSemantics(
|
|
rect: const Rect.fromLTRB(150.0, -4.0, 200.0, 18.0),
|
|
label: 'RIS',
|
|
textDirection: TextDirection.rtl, // in the last string we switched to RTL using RLE.
|
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
|
flags: <SemanticsFlag>[SemanticsFlag.isLink],
|
|
),
|
|
TestSemantics(
|
|
rect: const Rect.fromLTRB(192.0, -4.0, 424.0, 18.0),
|
|
label: ' OD you OD WOH ', // Still RTL.
|
|
textDirection: TextDirection.rtl,
|
|
),
|
|
TestSemantics(
|
|
rect: const Rect.fromLTRB(416.0, -4.0, 466.0, 18.0),
|
|
label: 'YOB',
|
|
textDirection: TextDirection.rtl, // Still RTL.
|
|
actions: <SemanticsAction>[
|
|
SemanticsAction.longPress,
|
|
],
|
|
),
|
|
TestSemantics(
|
|
rect: const Rect.fromLTRB(472.0, -4.0, 606.0, 18.0),
|
|
label: ' good bye',
|
|
textDirection: TextDirection.rtl, // Begin as RTL but pop to LTR.
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
expect(
|
|
semantics,
|
|
hasSemantics(
|
|
expectedSemantics,
|
|
ignoreTransform: true,
|
|
ignoreId: true,
|
|
),
|
|
);
|
|
semantics.dispose();
|
|
}, skip: true); // TODO(jonahwilliams): correct once https://github.com/flutter/flutter/issues/20891 is resolved.
|
|
|
|
testWidgets('TapGesture recognizers contribute link semantics', (WidgetTester tester) async {
|
|
final SemanticsTester semantics = SemanticsTester(tester);
|
|
const TextStyle textStyle = TextStyle(fontFamily: 'Ahem');
|
|
await tester.pumpWidget(
|
|
Text.rich(
|
|
TextSpan(
|
|
children: <TextSpan>[
|
|
TextSpan(
|
|
text: 'click me',
|
|
recognizer: TapGestureRecognizer()..onTap = () { },
|
|
),
|
|
],
|
|
style: textStyle,
|
|
),
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
);
|
|
final TestSemantics expectedSemantics = TestSemantics.root(
|
|
children: <TestSemantics>[
|
|
TestSemantics.rootChild(
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
label: 'click me',
|
|
textDirection: TextDirection.ltr,
|
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
|
flags: <SemanticsFlag>[SemanticsFlag.isLink]
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
expect(semantics, hasSemantics(
|
|
expectedSemantics,
|
|
ignoreTransform: true,
|
|
ignoreId: true,
|
|
ignoreRect: true,
|
|
));
|
|
semantics.dispose();
|
|
});
|
|
|
|
testWidgets('inline widgets generate semantic nodes', (WidgetTester tester) async {
|
|
final SemanticsTester semantics = SemanticsTester(tester);
|
|
const TextStyle textStyle = TextStyle(fontFamily: 'Ahem');
|
|
await tester.pumpWidget(
|
|
Text.rich(
|
|
TextSpan(
|
|
children: <InlineSpan>[
|
|
const TextSpan(text: 'a '),
|
|
TextSpan(
|
|
text: 'pebble',
|
|
recognizer: TapGestureRecognizer()..onTap = () { },
|
|
),
|
|
const TextSpan(text: ' in the '),
|
|
WidgetSpan(
|
|
child: SizedBox(
|
|
width: 20,
|
|
height: 40,
|
|
child: Card(
|
|
child: RichText(
|
|
text: const TextSpan(text: 'INTERRUPTION'),
|
|
textDirection: TextDirection.rtl,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
const TextSpan(text: 'sky'),
|
|
],
|
|
style: textStyle,
|
|
),
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
);
|
|
final TestSemantics expectedSemantics = TestSemantics.root(
|
|
children: <TestSemantics>[
|
|
TestSemantics.rootChild(
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
label: 'a ',
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
TestSemantics(
|
|
label: 'pebble',
|
|
textDirection: TextDirection.ltr,
|
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
|
flags: <SemanticsFlag>[SemanticsFlag.isLink],
|
|
),
|
|
TestSemantics(
|
|
label: ' in the ',
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
TestSemantics(
|
|
label: 'INTERRUPTION',
|
|
textDirection: TextDirection.rtl,
|
|
),
|
|
TestSemantics(
|
|
label: 'sky',
|
|
textDirection: TextDirection.ltr,
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
expect(
|
|
semantics,
|
|
hasSemantics(
|
|
expectedSemantics,
|
|
ignoreTransform: true,
|
|
ignoreId: true,
|
|
ignoreRect: true,
|
|
),
|
|
);
|
|
semantics.dispose();
|
|
}, skip: isBrowser); // TODO(yjbanov): https://github.com/flutter/flutter/issues/42086
|
|
|
|
testWidgets('inline widgets semantic nodes scale', (WidgetTester tester) async {
|
|
final SemanticsTester semantics = SemanticsTester(tester);
|
|
const TextStyle textStyle = TextStyle(fontFamily: 'Ahem');
|
|
await tester.pumpWidget(
|
|
Text.rich(
|
|
TextSpan(
|
|
children: <InlineSpan>[
|
|
const TextSpan(text: 'a '),
|
|
TextSpan(
|
|
text: 'pebble',
|
|
recognizer: TapGestureRecognizer()..onTap = () { },
|
|
),
|
|
const TextSpan(text: ' in the '),
|
|
WidgetSpan(
|
|
child: SizedBox(
|
|
width: 20,
|
|
height: 40,
|
|
child: Card(
|
|
child: RichText(
|
|
text: const TextSpan(text: 'INTERRUPTION'),
|
|
textDirection: TextDirection.rtl,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
const TextSpan(text: 'sky'),
|
|
],
|
|
style: textStyle,
|
|
),
|
|
textDirection: TextDirection.ltr,
|
|
textScaleFactor: 2,
|
|
),
|
|
);
|
|
final TestSemantics expectedSemantics = TestSemantics.root(
|
|
children: <TestSemantics>[
|
|
TestSemantics.rootChild(
|
|
rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0),
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
label: 'a ',
|
|
textDirection: TextDirection.ltr,
|
|
rect: const Rect.fromLTRB(-4.0, 48.0, 60.0, 84.0),
|
|
),
|
|
TestSemantics(
|
|
label: 'pebble',
|
|
textDirection: TextDirection.ltr,
|
|
actions: <SemanticsAction>[SemanticsAction.tap],
|
|
flags: <SemanticsFlag>[SemanticsFlag.isLink],
|
|
rect: const Rect.fromLTRB(52.0, 48.0, 228.0, 84.0),
|
|
),
|
|
TestSemantics(
|
|
label: ' in the ',
|
|
textDirection: TextDirection.ltr,
|
|
rect: const Rect.fromLTRB(220.0, 48.0, 452.0, 84.0),
|
|
),
|
|
TestSemantics(
|
|
label: 'INTERRUPTION',
|
|
textDirection: TextDirection.rtl,
|
|
rect: const Rect.fromLTRB(0.0, 0.0, 40.0, 80.0),
|
|
),
|
|
TestSemantics(
|
|
label: 'sky',
|
|
textDirection: TextDirection.ltr,
|
|
rect: const Rect.fromLTRB(484.0, 48.0, 576.0, 84.0),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
expect(
|
|
semantics,
|
|
hasSemantics(
|
|
expectedSemantics,
|
|
ignoreTransform: true,
|
|
ignoreId: true,
|
|
),
|
|
);
|
|
semantics.dispose();
|
|
}, skip: isBrowser); // TODO(yjbanov): https://github.com/flutter/flutter/issues/42086
|
|
|
|
testWidgets('Overflow is clipping correctly - short text with overflow: clip', (WidgetTester tester) async {
|
|
await _pumpTextWidget(
|
|
tester: tester,
|
|
overflow: TextOverflow.clip,
|
|
text: 'Hi',
|
|
);
|
|
|
|
expect(find.byType(Text), isNot(paints..clipRect()));
|
|
});
|
|
|
|
testWidgets('Overflow is clipping correctly - long text with overflow: ellipsis', (WidgetTester tester) async {
|
|
await _pumpTextWidget(
|
|
tester: tester,
|
|
overflow: TextOverflow.ellipsis,
|
|
text: 'a long long long long text, should be clip',
|
|
);
|
|
|
|
expect(
|
|
find.byType(Text),
|
|
paints..clipRect(rect: const Rect.fromLTWH(0, 0, 50, 50)),
|
|
);
|
|
}, skip: isBrowser);
|
|
|
|
testWidgets('Overflow is clipping correctly - short text with overflow: ellipsis', (WidgetTester tester) async {
|
|
await _pumpTextWidget(
|
|
tester: tester,
|
|
overflow: TextOverflow.ellipsis,
|
|
text: 'Hi',
|
|
);
|
|
|
|
expect(find.byType(Text), isNot(paints..clipRect()));
|
|
});
|
|
|
|
testWidgets('Overflow is clipping correctly - long text with overflow: fade', (WidgetTester tester) async {
|
|
await _pumpTextWidget(
|
|
tester: tester,
|
|
overflow: TextOverflow.fade,
|
|
text: 'a long long long long text, should be clip',
|
|
);
|
|
|
|
expect(
|
|
find.byType(Text),
|
|
paints..clipRect(rect: const Rect.fromLTWH(0, 0, 50, 50)),
|
|
);
|
|
});
|
|
|
|
testWidgets('Overflow is clipping correctly - short text with overflow: fade', (WidgetTester tester) async {
|
|
await _pumpTextWidget(
|
|
tester: tester,
|
|
overflow: TextOverflow.fade,
|
|
text: 'Hi',
|
|
);
|
|
|
|
expect(find.byType(Text), isNot(paints..clipRect()));
|
|
});
|
|
|
|
testWidgets('Overflow is clipping correctly - long text with overflow: visible', (WidgetTester tester) async {
|
|
await _pumpTextWidget(
|
|
tester: tester,
|
|
overflow: TextOverflow.visible,
|
|
text: 'a long long long long text, should be clip',
|
|
);
|
|
|
|
expect(find.byType(Text), isNot(paints..clipRect()));
|
|
});
|
|
|
|
testWidgets('Overflow is clipping correctly - short text with overflow: visible', (WidgetTester tester) async {
|
|
await _pumpTextWidget(
|
|
tester: tester,
|
|
overflow: TextOverflow.visible,
|
|
text: 'Hi',
|
|
);
|
|
|
|
expect(find.byType(Text), isNot(paints..clipRect()));
|
|
});
|
|
|
|
testWidgets('textWidthBasis affects the width of a Text widget', (WidgetTester tester) async {
|
|
Future<void> createText(TextWidthBasis textWidthBasis) {
|
|
return tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: Center(
|
|
child: Container(
|
|
// Each word takes up more than a half of a line. Together they
|
|
// wrap onto two lines, but leave a lot of extra space.
|
|
child: Text(
|
|
'twowordsthateachtakeupmorethanhalfof alineoftextsothattheywrapwithlotsofextraspace',
|
|
textDirection: TextDirection.ltr,
|
|
textWidthBasis: textWidthBasis,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
const double fontHeight = 14.0;
|
|
const double screenWidth = 800.0;
|
|
|
|
// When textWidthBasis is parent, takes up full screen width.
|
|
await createText(TextWidthBasis.parent);
|
|
final Size textSizeParent = tester.getSize(find.byType(Text));
|
|
expect(textSizeParent.width, equals(screenWidth));
|
|
expect(textSizeParent.height, equals(fontHeight * 2));
|
|
|
|
// When textWidthBasis is longestLine, sets the width to as small as
|
|
// possible for the two lines.
|
|
await createText(TextWidthBasis.longestLine);
|
|
final Size textSizeLongestLine = tester.getSize(find.byType(Text));
|
|
expect(textSizeLongestLine.width, equals(630.0));
|
|
expect(textSizeLongestLine.height, equals(fontHeight * 2));
|
|
}, skip: isBrowser); // TODO(yjbanov): https://github.com/flutter/flutter/issues/44020
|
|
|
|
testWidgets('Paragraph.getBoxesForRange returns nothing when selection range is zero length', (WidgetTester tester) async {
|
|
final ui.ParagraphBuilder builder = ui.ParagraphBuilder(ui.ParagraphStyle());
|
|
builder.addText('hello');
|
|
final ui.Paragraph paragraph = builder.build();
|
|
paragraph.layout(const ui.ParagraphConstraints(width: 1000));
|
|
expect(paragraph.getBoxesForRange(2, 2), isEmpty);
|
|
});
|
|
}
|
|
|
|
Future<void> _pumpTextWidget({ WidgetTester tester, String text, TextOverflow overflow }) {
|
|
return tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(
|
|
child: Container(
|
|
width: 50.0,
|
|
height: 50.0,
|
|
child: Text(
|
|
text,
|
|
overflow: overflow,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|