-
Notifications
You must be signed in to change notification settings - Fork 29.1k
Open
Labels
P2Important issues not at the top of the work listImportant issues not at the top of the work lista: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)Accessibility, e.g. VoiceOver or TalkBack. (aka a11y)a: tests"flutter test", flutter_test, or one of our tests"flutter test", flutter_test, or one of our testsframeworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.team-frameworkOwned by Framework teamOwned by Framework teamtriaged-frameworkTriaged by Framework teamTriaged by Framework team
Description
I've run into this issue at #114999 (comment).
Description
Complete test code sample
test
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Theme(
data: ThemeData.light(),
child: const Directionality(
textDirection: TextDirection.rtl,
child: Box(),
),
),
),
);
await tester.pumpAndSettle();
// From `tester.getSemantics(find.byType(Box)).toStringDeep()`
//
// SemanticsNode#6
// │ Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
// │
// ├─SemanticsNode#1
// │ Rect.fromLTRB(45.6, 50.1, 601.0, 500.8)
// │
// └─SemanticsNode#2
// Rect.fromLTRB(10.6, 100.1, 701.0, 400.8)`
final SemanticsNode semanticsNode = tester.getSemantics(find.byType(Box));
// This fails.
// expect(
// semanticsNode,
// matchesSemantics(
// children: <Matcher>[
// matchesSemantics(
// rect: const Rect.fromLTRB(45.6, 50.1, 601.0, 500.8),
// ),
// matchesSemantics(
// rect: const Rect.fromLTRB(10.6, 100.1, 701.0, 400.8),
// ),
// ],
// ),
// );
// This woorks.
// Get semantics node rects.
final List<Rect> rects = <Rect>[];
semanticsNode.visitChildren((SemanticsNode node) {
rects.add(
Rect.fromLTRB(
node.rect.left.roundToDouble(),
node.rect.top.roundToDouble(),
node.rect.right.roundToDouble(),
node.rect.bottom.roundToDouble(),
),
);
return true;
});
// Test that the semantics node rect sizes are correct.
expect(rects, <Rect>[
const Rect.fromLTRB(46.0, 50.0, 601.0, 501.0),
const Rect.fromLTRB(11.0, 100.0, 701.0, 401.0)
]);
});
}
class Box extends LeafRenderObjectWidget {
const Box({super.key});
@override
RenderObject createRenderObject(BuildContext context) {
return _RenderBox(
textDirection: Directionality.of(context),
);
}
}
class _RenderBox extends RenderBox {
_RenderBox({required TextDirection textDirection})
: _textDirection = textDirection;
TextDirection get textDirection => _textDirection;
TextDirection _textDirection;
set textDirection(TextDirection value) {
assert(value != null);
if (value == _textDirection) {
return;
}
_textDirection = value;
}
@override
void paint(PaintingContext context, Offset offset) {}
@override
void performLayout() {}
@override
Size computeDryLayout(BoxConstraints constraints) {
return constraints.biggest;
}
@override
bool get sizedByParent => true;
SemanticsNode? _startSemanticsNode = SemanticsNode();
SemanticsNode? _endSemanticsNode = SemanticsNode();
@override
void assembleSemanticsNode(SemanticsNode node, SemanticsConfiguration config,
Iterable<SemanticsNode> children) {
assert(children.isEmpty);
const Rect leftRect =
Rect.fromLTRB(10.568696, 100.12334, 700.98776, 400.7890);
const Rect rightRect =
Rect.fromLTRB(45.568696, 50.12334, 600.98776, 500.7890);
switch (textDirection) {
case TextDirection.ltr:
_startSemanticsNode!.rect = leftRect;
_endSemanticsNode!.rect = rightRect;
break;
case TextDirection.rtl:
_startSemanticsNode!.rect = rightRect;
_endSemanticsNode!.rect = leftRect;
break;
}
final List<SemanticsNode> finalChildren = <SemanticsNode>[
_startSemanticsNode!,
_endSemanticsNode!,
];
node.updateWith(config: config, childrenInInversePaintOrder: finalChildren);
}
@override
void clearSemantics() {
super.clearSemantics();
_startSemanticsNode = null;
_endSemanticsNode = null;
}
@override
void describeSemanticsConfiguration(SemanticsConfiguration config) {
super.describeSemanticsConfiguration(config);
config.isSemanticBoundary = true;
}
}
When providing rect
from getSemantics
to matchesSemantics.rect
, the test fails.
// From `tester.getSemantics(find.byType(Box)).toStringDeep()`
//
// SemanticsNode#6
// │ Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
// │
// ├─SemanticsNode#1
// │ Rect.fromLTRB(45.6, 50.1, 601.0, 500.8)
// │
// └─SemanticsNode#2
// Rect.fromLTRB(10.6, 100.1, 701.0, 400.8)
Test:
expect(
tester.getSemantics(find.byType(Box)),
matchesSemantics(
children: <Matcher>[
matchesSemantics(
rect: const Rect.fromLTRB(45.6, 50.1, 601.0, 500.8),
),
matchesSemantics(
rect: const Rect.fromLTRB(10.6, 100.1, 701.0, 400.8),
),
],
),
);
Result:
Actual: SemanticsNode:<SemanticsNode#6(Rect.fromLTRB(0.0, 0.0, 800.0, 600.0))>
Which: rect was: Rect.fromLTRB(45.6, 50.1, 601.0, 500.8)
Investigation:
The match fails when you provide rect
size fromgetSemantics
to matchesSemantics.rect
.
Since the data.rect
is not rounded when matching matchesSemantics.rect
, this fails.
flutter/packages/flutter_test/lib/src/matchers.dart
Lines 2421 to 2423 in c7d1154
if (rect != null && rect != data.rect) { | |
return failWithDescription(matchState, 'rect was: ${data.rect}'); | |
} |
Workaround
// This woorks.
// Get semantics node rects.
final List<Rect> rects = <Rect>[];
semanticsNode.visitChildren((SemanticsNode node) {
rects.add(
Rect.fromLTRB(
node.rect.left.roundToDouble(),
node.rect.top.roundToDouble(),
node.rect.right.roundToDouble(),
node.rect.bottom.roundToDouble(),
),
);
return true;
});
// Test that the semantics node rect sizes are correct.
expect(rects, <Rect>[
const Rect.fromLTRB(46.0, 50.0, 601.0, 501.0),
const Rect.fromLTRB(11.0, 100.0, 701.0, 401.0)
]);
});
Metadata
Metadata
Assignees
Labels
P2Important issues not at the top of the work listImportant issues not at the top of the work lista: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)Accessibility, e.g. VoiceOver or TalkBack. (aka a11y)a: tests"flutter test", flutter_test, or one of our tests"flutter test", flutter_test, or one of our testsframeworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.team-frameworkOwned by Framework teamOwned by Framework teamtriaged-frameworkTriaged by Framework teamTriaged by Framework team