mirror of
https://github.com/flutter/flutter.git
synced 2026-01-14 17:35:51 +08:00
WIP Commits separated as follows: - Update lints in analysis_options files - Run `dart fix --apply` - Clean up leftover analysis issues - Run `dart format .` in the right places. Local analysis and testing passes. Checking CI now. Part of https://github.com/flutter/flutter/issues/178827 - Adoption of flutter_lints in examples/api coming in a separate change (cc @loic-sharma) ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
1131 lines
38 KiB
Dart
1131 lines
38 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 'package:flutter/rendering.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
|
|
|
|
import '../rendering/rendering_tester.dart' show TestCallbackPainter;
|
|
|
|
class TestPaintingContext implements PaintingContext {
|
|
final List<Invocation> invocations = <Invocation>[];
|
|
|
|
@override
|
|
void noSuchMethod(Invocation invocation) {
|
|
invocations.add(invocation);
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
testWidgets('Can construct an empty Stack', (WidgetTester tester) async {
|
|
await tester.pumpWidget(const Directionality(textDirection: TextDirection.ltr, child: Stack()));
|
|
});
|
|
|
|
testWidgets('Can construct an empty Centered Stack', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(child: Stack()),
|
|
),
|
|
);
|
|
});
|
|
|
|
testWidgets('Can change position data', (WidgetTester tester) async {
|
|
const key = Key('container');
|
|
|
|
await tester.pumpWidget(
|
|
const Stack(
|
|
alignment: Alignment.topLeft,
|
|
children: <Widget>[
|
|
Positioned(left: 10.0, child: SizedBox(key: key, width: 10.0, height: 10.0)),
|
|
],
|
|
),
|
|
);
|
|
|
|
Element container;
|
|
StackParentData parentData;
|
|
|
|
container = tester.element(find.byKey(key));
|
|
parentData = container.renderObject!.parentData! as StackParentData;
|
|
expect(parentData.top, isNull);
|
|
expect(parentData.right, isNull);
|
|
expect(parentData.bottom, isNull);
|
|
expect(parentData.left, equals(10.0));
|
|
expect(parentData.width, isNull);
|
|
expect(parentData.height, isNull);
|
|
|
|
await tester.pumpWidget(
|
|
const Stack(
|
|
alignment: Alignment.topLeft,
|
|
children: <Widget>[
|
|
Positioned(right: 10.0, child: SizedBox(key: key, width: 10.0, height: 10.0)),
|
|
],
|
|
),
|
|
);
|
|
|
|
container = tester.element(find.byKey(key));
|
|
parentData = container.renderObject!.parentData! as StackParentData;
|
|
expect(parentData.top, isNull);
|
|
expect(parentData.right, equals(10.0));
|
|
expect(parentData.bottom, isNull);
|
|
expect(parentData.left, isNull);
|
|
expect(parentData.width, isNull);
|
|
expect(parentData.height, isNull);
|
|
});
|
|
|
|
testWidgets('Can remove parent data', (WidgetTester tester) async {
|
|
const key = Key('container');
|
|
const sizedBox = SizedBox(key: key, width: 10.0, height: 10.0);
|
|
|
|
await tester.pumpWidget(
|
|
const Stack(
|
|
textDirection: TextDirection.ltr,
|
|
children: <Widget>[Positioned(left: 10.0, child: sizedBox)],
|
|
),
|
|
);
|
|
Element containerElement = tester.element(find.byKey(key));
|
|
|
|
StackParentData parentData;
|
|
parentData = containerElement.renderObject!.parentData! as StackParentData;
|
|
expect(parentData.top, isNull);
|
|
expect(parentData.right, isNull);
|
|
expect(parentData.bottom, isNull);
|
|
expect(parentData.left, equals(10.0));
|
|
expect(parentData.width, isNull);
|
|
expect(parentData.height, isNull);
|
|
|
|
await tester.pumpWidget(
|
|
const Stack(textDirection: TextDirection.ltr, children: <Widget>[sizedBox]),
|
|
);
|
|
containerElement = tester.element(find.byKey(key));
|
|
|
|
parentData = containerElement.renderObject!.parentData! as StackParentData;
|
|
expect(parentData.top, isNull);
|
|
expect(parentData.right, isNull);
|
|
expect(parentData.bottom, isNull);
|
|
expect(parentData.left, isNull);
|
|
expect(parentData.width, isNull);
|
|
expect(parentData.height, isNull);
|
|
});
|
|
|
|
testWidgets('Can align non-positioned children (LTR)', (WidgetTester tester) async {
|
|
const child0Key = Key('child0');
|
|
const child1Key = Key('child1');
|
|
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(
|
|
child: Stack(
|
|
alignment: Alignment.center,
|
|
children: <Widget>[
|
|
SizedBox(key: child0Key, width: 20.0, height: 20.0),
|
|
SizedBox(key: child1Key, width: 10.0, height: 10.0),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final Element child0 = tester.element(find.byKey(child0Key));
|
|
final child0RenderObjectParentData = child0.renderObject!.parentData! as StackParentData;
|
|
expect(child0RenderObjectParentData.offset, equals(Offset.zero));
|
|
|
|
final Element child1 = tester.element(find.byKey(child1Key));
|
|
final child1RenderObjectParentData = child1.renderObject!.parentData! as StackParentData;
|
|
expect(child1RenderObjectParentData.offset, equals(const Offset(5.0, 5.0)));
|
|
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(
|
|
child: Stack(
|
|
alignment: AlignmentDirectional.bottomEnd,
|
|
children: <Widget>[
|
|
SizedBox(key: child0Key, width: 20.0, height: 20.0),
|
|
SizedBox(key: child1Key, width: 10.0, height: 10.0),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(child0RenderObjectParentData.offset, equals(Offset.zero));
|
|
expect(child1RenderObjectParentData.offset, equals(const Offset(10.0, 10.0)));
|
|
});
|
|
|
|
testWidgets('Can align non-positioned children (RTL)', (WidgetTester tester) async {
|
|
const child0Key = Key('child0');
|
|
const child1Key = Key('child1');
|
|
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.rtl,
|
|
child: Center(
|
|
child: Stack(
|
|
alignment: Alignment.center,
|
|
children: <Widget>[
|
|
SizedBox(key: child0Key, width: 20.0, height: 20.0),
|
|
SizedBox(key: child1Key, width: 10.0, height: 10.0),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final Element child0 = tester.element(find.byKey(child0Key));
|
|
final child0RenderObjectParentData = child0.renderObject!.parentData! as StackParentData;
|
|
expect(child0RenderObjectParentData.offset, equals(Offset.zero));
|
|
|
|
final Element child1 = tester.element(find.byKey(child1Key));
|
|
final child1RenderObjectParentData = child1.renderObject!.parentData! as StackParentData;
|
|
expect(child1RenderObjectParentData.offset, equals(const Offset(5.0, 5.0)));
|
|
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.rtl,
|
|
child: Center(
|
|
child: Stack(
|
|
alignment: AlignmentDirectional.bottomEnd,
|
|
children: <Widget>[
|
|
SizedBox(key: child0Key, width: 20.0, height: 20.0),
|
|
SizedBox(key: child1Key, width: 10.0, height: 10.0),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(child0RenderObjectParentData.offset, equals(Offset.zero));
|
|
expect(child1RenderObjectParentData.offset, equals(const Offset(0.0, 10.0)));
|
|
});
|
|
|
|
testWidgets('Can construct an empty IndexedStack', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
const Directionality(textDirection: TextDirection.ltr, child: IndexedStack()),
|
|
);
|
|
});
|
|
|
|
testWidgets('Can construct an empty Centered IndexedStack', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(child: IndexedStack()),
|
|
),
|
|
);
|
|
});
|
|
|
|
testWidgets('Can construct an IndexedStack', (WidgetTester tester) async {
|
|
const itemCount = 3;
|
|
late List<int> itemsPainted;
|
|
|
|
Widget buildFrame(int index) {
|
|
itemsPainted = <int>[];
|
|
final items = List<Widget>.generate(itemCount, (int i) {
|
|
return CustomPaint(
|
|
painter: TestCallbackPainter(
|
|
onPaint: () {
|
|
itemsPainted.add(i);
|
|
},
|
|
),
|
|
child: Text('$i', textDirection: TextDirection.ltr),
|
|
);
|
|
});
|
|
return Center(
|
|
child: IndexedStack(alignment: Alignment.topLeft, index: index, children: items),
|
|
);
|
|
}
|
|
|
|
void expectFindsChild(int n) {
|
|
for (var i = 0; i < 3; i++) {
|
|
expect(find.text('$i', skipOffstage: false), findsOneWidget);
|
|
|
|
if (i == n) {
|
|
expect(find.text('$i'), findsOneWidget);
|
|
} else {
|
|
expect(find.text('$i'), findsNothing);
|
|
}
|
|
}
|
|
}
|
|
|
|
await tester.pumpWidget(buildFrame(0));
|
|
expectFindsChild(0);
|
|
expect(itemsPainted, equals(<int>[0]));
|
|
|
|
await tester.pumpWidget(buildFrame(1));
|
|
expectFindsChild(1);
|
|
expect(itemsPainted, equals(<int>[1]));
|
|
|
|
await tester.pumpWidget(buildFrame(2));
|
|
expectFindsChild(2);
|
|
expect(itemsPainted, equals(<int>[2]));
|
|
});
|
|
|
|
testWidgets('Can hit test an IndexedStack', (WidgetTester tester) async {
|
|
const key = Key('indexedStack');
|
|
const itemCount = 3;
|
|
late List<int> itemsTapped;
|
|
|
|
Widget buildFrame(int index) {
|
|
itemsTapped = <int>[];
|
|
final items = List<Widget>.generate(itemCount, (int i) {
|
|
return GestureDetector(
|
|
child: Text('$i', textDirection: TextDirection.ltr),
|
|
onTap: () {
|
|
itemsTapped.add(i);
|
|
},
|
|
);
|
|
});
|
|
return Center(
|
|
child: IndexedStack(alignment: Alignment.topLeft, key: key, index: index, children: items),
|
|
);
|
|
}
|
|
|
|
await tester.pumpWidget(buildFrame(0));
|
|
expect(itemsTapped, isEmpty);
|
|
await tester.tap(find.byKey(key));
|
|
expect(itemsTapped, <int>[0]);
|
|
|
|
await tester.pumpWidget(buildFrame(2));
|
|
expect(itemsTapped, isEmpty);
|
|
await tester.tap(find.byKey(key));
|
|
expect(itemsTapped, <int>[2]);
|
|
});
|
|
|
|
testWidgets('IndexedStack sets non-selected indexes to visible=false', (
|
|
WidgetTester tester,
|
|
) async {
|
|
Widget buildStack({required int itemCount, required int? selectedIndex}) {
|
|
final children = List<Widget>.generate(itemCount, (int i) {
|
|
return _ShowVisibility(index: i);
|
|
});
|
|
return Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: IndexedStack(index: selectedIndex, children: children),
|
|
);
|
|
}
|
|
|
|
await tester.pumpWidget(buildStack(itemCount: 3, selectedIndex: null));
|
|
expect(find.text('index 0 is visible ? false', skipOffstage: false), findsOneWidget);
|
|
expect(find.text('index 1 is visible ? false', skipOffstage: false), findsOneWidget);
|
|
expect(find.text('index 2 is visible ? false', skipOffstage: false), findsOneWidget);
|
|
|
|
await tester.pumpWidget(buildStack(itemCount: 3, selectedIndex: 0));
|
|
expect(find.text('index 0 is visible ? true', skipOffstage: false), findsOneWidget);
|
|
expect(find.text('index 1 is visible ? false', skipOffstage: false), findsOneWidget);
|
|
expect(find.text('index 2 is visible ? false', skipOffstage: false), findsOneWidget);
|
|
|
|
await tester.pumpWidget(buildStack(itemCount: 3, selectedIndex: 1));
|
|
expect(find.text('index 0 is visible ? false', skipOffstage: false), findsOneWidget);
|
|
expect(find.text('index 1 is visible ? true', skipOffstage: false), findsOneWidget);
|
|
expect(find.text('index 2 is visible ? false', skipOffstage: false), findsOneWidget);
|
|
|
|
await tester.pumpWidget(buildStack(itemCount: 3, selectedIndex: 2));
|
|
expect(find.text('index 0 is visible ? false', skipOffstage: false), findsOneWidget);
|
|
expect(find.text('index 1 is visible ? false', skipOffstage: false), findsOneWidget);
|
|
expect(find.text('index 2 is visible ? true', skipOffstage: false), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('Can set width and height', (WidgetTester tester) async {
|
|
const key = Key('container');
|
|
|
|
const kBoxDecoration = BoxDecoration(color: Color(0xFF00FF00));
|
|
|
|
await tester.pumpWidget(
|
|
const Stack(
|
|
textDirection: TextDirection.ltr,
|
|
children: <Widget>[
|
|
Positioned(
|
|
left: 10.0,
|
|
width: 11.0,
|
|
height: 12.0,
|
|
child: DecoratedBox(key: key, decoration: kBoxDecoration),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
|
|
Element box;
|
|
RenderBox renderBox;
|
|
StackParentData parentData;
|
|
|
|
box = tester.element(find.byKey(key));
|
|
renderBox = box.renderObject! as RenderBox;
|
|
parentData = renderBox.parentData! as StackParentData;
|
|
expect(parentData.top, isNull);
|
|
expect(parentData.right, isNull);
|
|
expect(parentData.bottom, isNull);
|
|
expect(parentData.left, equals(10.0));
|
|
expect(parentData.width, equals(11.0));
|
|
expect(parentData.height, equals(12.0));
|
|
expect(parentData.offset.dx, equals(10.0));
|
|
expect(parentData.offset.dy, equals(0.0));
|
|
expect(renderBox.size.width, equals(11.0));
|
|
expect(renderBox.size.height, equals(12.0));
|
|
|
|
await tester.pumpWidget(
|
|
const Stack(
|
|
textDirection: TextDirection.ltr,
|
|
children: <Widget>[
|
|
Positioned(
|
|
right: 10.0,
|
|
width: 11.0,
|
|
height: 12.0,
|
|
child: DecoratedBox(key: key, decoration: kBoxDecoration),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
|
|
box = tester.element(find.byKey(key));
|
|
renderBox = box.renderObject! as RenderBox;
|
|
parentData = renderBox.parentData! as StackParentData;
|
|
expect(parentData.top, isNull);
|
|
expect(parentData.right, equals(10.0));
|
|
expect(parentData.bottom, isNull);
|
|
expect(parentData.left, isNull);
|
|
expect(parentData.width, equals(11.0));
|
|
expect(parentData.height, equals(12.0));
|
|
expect(parentData.offset.dx, equals(779.0));
|
|
expect(parentData.offset.dy, equals(0.0));
|
|
expect(renderBox.size.width, equals(11.0));
|
|
expect(renderBox.size.height, equals(12.0));
|
|
});
|
|
|
|
testWidgets('Can set and update clipBehavior', (WidgetTester tester) async {
|
|
await tester.pumpWidget(const Stack(textDirection: TextDirection.ltr));
|
|
final RenderStack renderObject = tester.allRenderObjects.whereType<RenderStack>().first;
|
|
expect(renderObject.clipBehavior, equals(Clip.hardEdge));
|
|
|
|
await tester.pumpWidget(const Stack(textDirection: TextDirection.ltr));
|
|
expect(renderObject.clipBehavior, equals(Clip.hardEdge));
|
|
});
|
|
|
|
testWidgets('Clip.none is respected by describeApproximateClip', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
const Stack(
|
|
textDirection: TextDirection.ltr,
|
|
children: <Widget>[
|
|
Positioned(left: 1000, right: 2000, child: SizedBox(width: 2000, height: 2000)),
|
|
],
|
|
),
|
|
);
|
|
final RenderStack renderObject = tester.allRenderObjects.whereType<RenderStack>().first;
|
|
expect(renderObject.clipBehavior, equals(Clip.hardEdge));
|
|
|
|
var visited = false;
|
|
renderObject.visitChildren((RenderObject child) {
|
|
visited = true;
|
|
expect(
|
|
renderObject.describeApproximatePaintClip(child),
|
|
const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0),
|
|
);
|
|
});
|
|
expect(visited, true);
|
|
visited = false;
|
|
renderObject.clipBehavior = Clip.none;
|
|
renderObject.visitChildren((RenderObject child) {
|
|
visited = true;
|
|
expect(renderObject.describeApproximatePaintClip(child), null);
|
|
});
|
|
expect(visited, true);
|
|
});
|
|
|
|
testWidgets('IndexedStack with null index', (WidgetTester tester) async {
|
|
bool? tapped;
|
|
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(
|
|
child: IndexedStack(
|
|
index: null,
|
|
children: <Widget>[
|
|
GestureDetector(
|
|
behavior: HitTestBehavior.opaque,
|
|
onTap: () {
|
|
tapped = true;
|
|
},
|
|
child: const SizedBox(width: 200.0, height: 200.0),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.tap(find.byType(IndexedStack), warnIfMissed: false);
|
|
final RenderBox box = tester.renderObject(find.byType(IndexedStack));
|
|
expect(box.size, equals(const Size(200.0, 200.0)));
|
|
expect(tapped, isNull);
|
|
});
|
|
|
|
testWidgets('IndexedStack reports hidden children as offstage', (WidgetTester tester) async {
|
|
final children = <Widget>[for (int i = 0; i < 5; i++) Text('child $i')];
|
|
|
|
Future<void> pumpIndexedStack(int? activeIndex) async {
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: IndexedStack(index: activeIndex, children: children),
|
|
),
|
|
);
|
|
}
|
|
|
|
final Finder finder = find.byType(Text);
|
|
final Finder finderIncludingOffstage = find.byType(Text, skipOffstage: false);
|
|
|
|
await pumpIndexedStack(null);
|
|
expect(finder, findsNothing); // IndexedStack with null index shows nothing
|
|
expect(finderIncludingOffstage, findsNWidgets(5));
|
|
|
|
for (var i = 0; i < 5; i++) {
|
|
await pumpIndexedStack(i);
|
|
|
|
expect(finder, findsOneWidget);
|
|
expect(finderIncludingOffstage, findsNWidgets(5));
|
|
|
|
expect(find.text('child $i'), findsOneWidget);
|
|
}
|
|
});
|
|
|
|
testWidgets('IndexedStack excludes focus for hidden children', (WidgetTester tester) async {
|
|
const children = <Widget>[Focus(child: Text('child 0')), Focus(child: Text('child 1'))];
|
|
|
|
Future<void> pumpIndexedStack(int? activeIndex) async {
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: IndexedStack(index: activeIndex, children: children),
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> requestFocusAndPump(FocusNode node) async {
|
|
node.requestFocus();
|
|
await tester.pump();
|
|
}
|
|
|
|
await pumpIndexedStack(0);
|
|
|
|
final Element child0 = tester.element(find.text('child 0', skipOffstage: false));
|
|
final Element child1 = tester.element(find.text('child 1', skipOffstage: false));
|
|
final FocusNode child0FocusNode = Focus.of(child0);
|
|
final FocusNode child1FocusNode = Focus.of(child1);
|
|
|
|
await requestFocusAndPump(child0FocusNode);
|
|
|
|
expect(child0FocusNode.hasFocus, true);
|
|
expect(child1FocusNode.hasFocus, false);
|
|
|
|
await requestFocusAndPump(child1FocusNode);
|
|
|
|
expect(child0FocusNode.hasFocus, true);
|
|
expect(child1FocusNode.hasFocus, false);
|
|
|
|
await pumpIndexedStack(1);
|
|
await requestFocusAndPump(child1FocusNode);
|
|
|
|
expect(child0FocusNode.hasFocus, false);
|
|
expect(child1FocusNode.hasFocus, true);
|
|
|
|
await requestFocusAndPump(child0FocusNode);
|
|
|
|
expect(child0FocusNode.hasFocus, false);
|
|
expect(child1FocusNode.hasFocus, true);
|
|
});
|
|
|
|
testWidgets('IndexedStack: hidden children can not receive tap events', (
|
|
WidgetTester tester,
|
|
) async {
|
|
var tapped = false;
|
|
final children = <Widget>[
|
|
const Text('child'),
|
|
GestureDetector(onTap: () => tapped = true, child: const Text('hiddenChild')),
|
|
];
|
|
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: IndexedStack(children: children),
|
|
),
|
|
);
|
|
|
|
await tester.tap(find.text('hiddenChild', skipOffstage: false), warnIfMissed: false);
|
|
await tester.pump();
|
|
|
|
expect(tapped, false);
|
|
});
|
|
|
|
testWidgets('Stack clip test', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(
|
|
child: Stack(
|
|
children: <Widget>[
|
|
SizedBox(width: 100.0, height: 100.0),
|
|
Positioned(top: 0.0, left: 0.0, child: SizedBox(width: 200.0, height: 200.0)),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
RenderBox box = tester.renderObject(find.byType(Stack));
|
|
var context = TestPaintingContext();
|
|
box.paint(context, Offset.zero);
|
|
expect(context.invocations.first.memberName, equals(#pushClipRect));
|
|
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(
|
|
child: Stack(
|
|
clipBehavior: Clip.none,
|
|
children: <Widget>[
|
|
SizedBox(width: 100.0, height: 100.0),
|
|
Positioned(top: 0.0, left: 0.0, child: SizedBox(width: 200.0, height: 200.0)),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
box = tester.renderObject(find.byType(Stack));
|
|
context = TestPaintingContext();
|
|
box.paint(context, Offset.zero);
|
|
expect(context.invocations.first.memberName, equals(#paintChild));
|
|
});
|
|
|
|
testWidgets('Stack sizing: default', (WidgetTester tester) async {
|
|
final logs = <String>[];
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(
|
|
child: ConstrainedBox(
|
|
constraints: const BoxConstraints(
|
|
minWidth: 2.0,
|
|
maxWidth: 3.0,
|
|
minHeight: 5.0,
|
|
maxHeight: 7.0,
|
|
),
|
|
child: Stack(
|
|
children: <Widget>[
|
|
LayoutBuilder(
|
|
builder: (BuildContext context, BoxConstraints constraints) {
|
|
logs.add(constraints.toString());
|
|
return const Placeholder();
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
expect(logs, <String>['BoxConstraints(0.0<=w<=3.0, 0.0<=h<=7.0)']);
|
|
});
|
|
|
|
testWidgets('Stack sizing: explicit', (WidgetTester tester) async {
|
|
final logs = <String>[];
|
|
Widget buildStack(StackFit sizing) {
|
|
return Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(
|
|
child: ConstrainedBox(
|
|
constraints: const BoxConstraints(
|
|
minWidth: 2.0,
|
|
maxWidth: 3.0,
|
|
minHeight: 5.0,
|
|
maxHeight: 7.0,
|
|
),
|
|
child: Stack(
|
|
fit: sizing,
|
|
children: <Widget>[
|
|
LayoutBuilder(
|
|
builder: (BuildContext context, BoxConstraints constraints) {
|
|
logs.add(constraints.toString());
|
|
return const Placeholder();
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
await tester.pumpWidget(buildStack(StackFit.loose));
|
|
logs.add('=1=');
|
|
await tester.pumpWidget(buildStack(StackFit.expand));
|
|
logs.add('=2=');
|
|
await tester.pumpWidget(buildStack(StackFit.passthrough));
|
|
expect(logs, <String>[
|
|
'BoxConstraints(0.0<=w<=3.0, 0.0<=h<=7.0)',
|
|
'=1=',
|
|
'BoxConstraints(w=3.0, h=7.0)',
|
|
'=2=',
|
|
'BoxConstraints(2.0<=w<=3.0, 5.0<=h<=7.0)',
|
|
]);
|
|
});
|
|
|
|
testWidgets('Positioned.directional control test', (WidgetTester tester) async {
|
|
final Key key = UniqueKey();
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Stack(
|
|
children: <Widget>[
|
|
Positioned.directional(
|
|
textDirection: TextDirection.rtl,
|
|
start: 50.0,
|
|
child: SizedBox(key: key, width: 75.0, height: 175.0),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(tester.getTopLeft(find.byKey(key)), const Offset(675.0, 0.0));
|
|
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Stack(
|
|
children: <Widget>[
|
|
Positioned.directional(
|
|
textDirection: TextDirection.ltr,
|
|
start: 50.0,
|
|
child: SizedBox(key: key, width: 75.0, height: 175.0),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(tester.getTopLeft(find.byKey(key)), const Offset(50.0, 0.0));
|
|
});
|
|
|
|
testWidgets('PositionedDirectional control test', (WidgetTester tester) async {
|
|
final Key key = UniqueKey();
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.rtl,
|
|
child: Stack(
|
|
children: <Widget>[
|
|
PositionedDirectional(
|
|
start: 50.0,
|
|
child: SizedBox(key: key, width: 75.0, height: 175.0),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(tester.getTopLeft(find.byKey(key)), const Offset(675.0, 0.0));
|
|
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Stack(
|
|
children: <Widget>[
|
|
PositionedDirectional(
|
|
start: 50.0,
|
|
child: SizedBox(key: key, width: 75.0, height: 175.0),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(tester.getTopLeft(find.byKey(key)), const Offset(50.0, 0.0));
|
|
});
|
|
|
|
testWidgets('Can change the text direction of a Stack', (WidgetTester tester) async {
|
|
await tester.pumpWidget(const Stack(alignment: Alignment.center));
|
|
await tester.pumpWidget(const Stack(textDirection: TextDirection.rtl));
|
|
await tester.pumpWidget(const Stack(alignment: Alignment.center));
|
|
});
|
|
|
|
testWidgets('Alignment with partially-positioned children', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.rtl,
|
|
child: Stack(
|
|
alignment: Alignment.center,
|
|
children: <Widget>[
|
|
SizedBox(width: 100.0, height: 100.0),
|
|
Positioned(left: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
Positioned(right: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
Positioned(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
Positioned(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(start: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(end: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(0)),
|
|
const Rect.fromLTWH(350.0, 250.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(1)),
|
|
const Rect.fromLTWH(0.0, 250.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(2)),
|
|
const Rect.fromLTWH(700.0, 250.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(3)),
|
|
const Rect.fromLTWH(350.0, 0.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(4)),
|
|
const Rect.fromLTWH(350.0, 500.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(5)),
|
|
const Rect.fromLTWH(700.0, 250.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(6)),
|
|
const Rect.fromLTWH(0.0, 250.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(7)),
|
|
const Rect.fromLTWH(350.0, 0.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(8)),
|
|
const Rect.fromLTWH(350.0, 500.0, 100.0, 100.0),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Stack(
|
|
alignment: Alignment.center,
|
|
children: <Widget>[
|
|
SizedBox(width: 100.0, height: 100.0),
|
|
Positioned(left: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
Positioned(right: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
Positioned(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
Positioned(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(start: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(end: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(0)),
|
|
const Rect.fromLTWH(350.0, 250.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(1)),
|
|
const Rect.fromLTWH(0.0, 250.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(2)),
|
|
const Rect.fromLTWH(700.0, 250.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(3)),
|
|
const Rect.fromLTWH(350.0, 0.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(4)),
|
|
const Rect.fromLTWH(350.0, 500.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(5)),
|
|
const Rect.fromLTWH(0.0, 250.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(6)),
|
|
const Rect.fromLTWH(700.0, 250.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(7)),
|
|
const Rect.fromLTWH(350.0, 0.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(8)),
|
|
const Rect.fromLTWH(350.0, 500.0, 100.0, 100.0),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Stack(
|
|
alignment: Alignment.bottomRight,
|
|
children: <Widget>[
|
|
SizedBox(width: 100.0, height: 100.0),
|
|
Positioned(left: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
Positioned(right: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
Positioned(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
Positioned(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(start: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(end: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(0)),
|
|
const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(1)),
|
|
const Rect.fromLTWH(0.0, 500.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(2)),
|
|
const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(3)),
|
|
const Rect.fromLTWH(700.0, 0.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(4)),
|
|
const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(5)),
|
|
const Rect.fromLTWH(0.0, 500.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(6)),
|
|
const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(7)),
|
|
const Rect.fromLTWH(700.0, 0.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(8)),
|
|
const Rect.fromLTWH(700.0, 500.0, 100.0, 100.0),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Stack(
|
|
alignment: Alignment.topLeft,
|
|
children: <Widget>[
|
|
SizedBox(width: 100.0, height: 100.0),
|
|
Positioned(left: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
Positioned(right: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
Positioned(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
Positioned(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(start: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(end: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(top: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
PositionedDirectional(bottom: 0.0, child: SizedBox(width: 100.0, height: 100.0)),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(0)),
|
|
const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(1)),
|
|
const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(2)),
|
|
const Rect.fromLTWH(700.0, 0.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(3)),
|
|
const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(4)),
|
|
const Rect.fromLTWH(0.0, 500.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(5)),
|
|
const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(6)),
|
|
const Rect.fromLTWH(700.0, 0.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(7)),
|
|
const Rect.fromLTWH(0.0, 0.0, 100.0, 100.0),
|
|
);
|
|
expect(
|
|
tester.getRect(find.byType(SizedBox).at(8)),
|
|
const Rect.fromLTWH(0.0, 500.0, 100.0, 100.0),
|
|
);
|
|
});
|
|
|
|
testWidgets(
|
|
'Stack error messages',
|
|
experimentalLeakTesting: LeakTesting.settings
|
|
.withIgnoredAll(), // leaking by design because of exception
|
|
(WidgetTester tester) async {
|
|
await tester.pumpWidget(const Stack());
|
|
final exception = tester.takeException().toString();
|
|
|
|
expect(
|
|
exception,
|
|
startsWith(
|
|
'No Directionality widget found.\n'
|
|
"Stack widgets require a Directionality widget ancestor to resolve the 'alignment' argument.\n"
|
|
"The default value for 'alignment' is AlignmentDirectional.topStart, which requires a text direction.\n"
|
|
'The specific widget that could not find a Directionality ancestor was:\n'
|
|
' Stack\n'
|
|
'The ownership chain for the affected widget is: "Stack ← ', // Omitted full ownership chain because it is not relevant for the test.
|
|
),
|
|
);
|
|
expect(
|
|
exception,
|
|
endsWith(
|
|
'_ViewScope ← ⋯"\n' // End of ownership chain.
|
|
'Typically, the Directionality widget is introduced by the MaterialApp or WidgetsApp widget at the '
|
|
'top of your application widget tree. It determines the ambient reading direction and is used, for '
|
|
'example, to determine how to lay out text, how to interpret "start" and "end" values, and to resolve '
|
|
'EdgeInsetsDirectional, AlignmentDirectional, and other *Directional objects.\n'
|
|
'Instead of providing a Directionality widget, another solution would be passing a non-directional '
|
|
"'alignment', or an explicit 'textDirection', to the Stack.",
|
|
),
|
|
);
|
|
},
|
|
);
|
|
|
|
testWidgets('Can update clipBehavior of IndexedStack', (WidgetTester tester) async {
|
|
await tester.pumpWidget(const IndexedStack(textDirection: TextDirection.ltr));
|
|
final RenderIndexedStack renderObject = tester.renderObject<RenderIndexedStack>(
|
|
find.byType(IndexedStack),
|
|
);
|
|
expect(renderObject.clipBehavior, equals(Clip.hardEdge));
|
|
|
|
// Update clipBehavior to Clip.antiAlias
|
|
|
|
await tester.pumpWidget(
|
|
const IndexedStack(textDirection: TextDirection.ltr, clipBehavior: Clip.antiAlias),
|
|
);
|
|
final RenderIndexedStack renderIndexedObject = tester.renderObject<RenderIndexedStack>(
|
|
find.byType(IndexedStack),
|
|
);
|
|
expect(renderIndexedObject.clipBehavior, equals(Clip.antiAlias));
|
|
});
|
|
|
|
testWidgets('IndexedStack sizing: explicit', (WidgetTester tester) async {
|
|
final logs = <String>[];
|
|
Widget buildIndexedStack(StackFit sizing) {
|
|
return Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(
|
|
child: ConstrainedBox(
|
|
constraints: const BoxConstraints(
|
|
minWidth: 2.0,
|
|
maxWidth: 3.0,
|
|
minHeight: 5.0,
|
|
maxHeight: 7.0,
|
|
),
|
|
child: IndexedStack(
|
|
sizing: sizing,
|
|
children: <Widget>[
|
|
LayoutBuilder(
|
|
builder: (BuildContext context, BoxConstraints constraints) {
|
|
logs.add(constraints.toString());
|
|
return const Placeholder();
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
await tester.pumpWidget(buildIndexedStack(StackFit.loose));
|
|
logs.add('=1=');
|
|
await tester.pumpWidget(buildIndexedStack(StackFit.expand));
|
|
logs.add('=2=');
|
|
await tester.pumpWidget(buildIndexedStack(StackFit.passthrough));
|
|
expect(logs, <String>[
|
|
'BoxConstraints(0.0<=w<=3.0, 0.0<=h<=7.0)',
|
|
'=1=',
|
|
'BoxConstraints(w=3.0, h=7.0)',
|
|
'=2=',
|
|
'BoxConstraints(2.0<=w<=3.0, 5.0<=h<=7.0)',
|
|
]);
|
|
});
|
|
|
|
testWidgets('IndexedStack does not assert with the default parameters', (
|
|
WidgetTester tester,
|
|
) async {
|
|
await tester.pumpWidget(
|
|
const Directionality(textDirection: TextDirection.ltr, child: IndexedStack()),
|
|
);
|
|
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('IndexedStack does not assert when index is null', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: IndexedStack(index: null, children: <Widget>[SizedBox.shrink(), SizedBox.shrink()]),
|
|
),
|
|
);
|
|
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('IndexedStack asserts when index is negative', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: IndexedStack(index: -1, children: <Widget>[SizedBox.shrink(), SizedBox.shrink()]),
|
|
),
|
|
);
|
|
|
|
expect(tester.takeException(), isA<AssertionError>());
|
|
});
|
|
|
|
testWidgets('IndexedStack asserts when index is not in children range', (
|
|
WidgetTester tester,
|
|
) async {
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: IndexedStack(index: 2, children: <Widget>[SizedBox.shrink(), SizedBox.shrink()]),
|
|
),
|
|
);
|
|
|
|
expect(tester.takeException(), isA<AssertionError>());
|
|
});
|
|
}
|
|
|
|
class _ShowVisibility extends StatelessWidget {
|
|
const _ShowVisibility({required this.index});
|
|
|
|
final int index;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Text('index $index is visible ? ${Visibility.of(context)}');
|
|
}
|
|
}
|