| // 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/material.dart'; |
| import 'package:flutter/rendering.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| import '../rendering/mock_canvas.dart'; |
| import 'semantics_tester.dart'; |
| |
| class TestState extends StatefulWidget { |
| const TestState({ Key? key, required this.child, required this.log }) : super(key: key); |
| final Widget child; |
| final List<String> log; |
| @override |
| State<TestState> createState() => _TestStateState(); |
| } |
| |
| class _TestStateState extends State<TestState> { |
| @override |
| void initState() { |
| super.initState(); |
| widget.log.add('created new state'); |
| } |
| @override |
| Widget build(BuildContext context) { |
| return widget.child; |
| } |
| } |
| |
| void main() { |
| testWidgets('SliverVisibility', (WidgetTester tester) async { |
| final SemanticsTester semantics = SemanticsTester(tester); |
| final List<String> log = <String>[]; |
| const Key anchor = Key('drag'); |
| |
| Widget _boilerPlate(Widget sliver) { |
| return Localizations( |
| locale: const Locale('en', 'us'), |
| delegates: const <LocalizationsDelegate<dynamic>>[ |
| DefaultWidgetsLocalizations.delegate, |
| DefaultMaterialLocalizations.delegate, |
| ], |
| child: Directionality( |
| textDirection: TextDirection.ltr, |
| child: MediaQuery( |
| data: const MediaQueryData(), |
| child: CustomScrollView(slivers: <Widget>[sliver]), |
| ), |
| ), |
| ); |
| } |
| |
| final Widget testChild = SliverToBoxAdapter( |
| child: GestureDetector( |
| onTap: () { |
| log.add('tap'); |
| }, |
| child: Builder( |
| builder: (BuildContext context) { |
| final bool animating = TickerMode.of(context); |
| return TestState( |
| key: anchor, |
| log: log, |
| child: Text('a $animating', textDirection: TextDirection.rtl), |
| ); |
| }, |
| ), |
| ), |
| ); |
| |
| // We now run a sequence of pumpWidget calls one after the other. In |
| // addition to verifying that the right behavior is seen in each case, this |
| // also verifies that the widget can dynamically change from state to state. |
| |
| // Default |
| await tester.pumpWidget(_boilerPlate(SliverVisibility(sliver: testChild))); |
| expect(find.byType(Text, skipOffstage: false), findsOneWidget); |
| expect(find.text('a true', skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility), findsOneWidget); |
| expect(find.byType(SliverVisibility), paints..paragraph()); |
| RenderViewport renderViewport = tester.renderObject(find.byType(Viewport)); |
| RenderSliver renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 14.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(1)); |
| expect(log, <String>['created new state']); |
| await tester.tap(find.byKey(anchor)); |
| expect(log, <String>['created new state', 'tap']); |
| log.clear(); |
| |
| // visible: false |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| visible: false, |
| ))); |
| expect(find.byType(Text), findsNothing); |
| expect(find.byType(Text, skipOffstage: false), findsNothing); |
| expect(find.byType(SliverVisibility, skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility, skipOffstage: false), paintsNothing); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 0.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(0)); |
| expect(log, <String>[]); |
| expect(find.byKey(anchor), findsNothing); |
| log.clear(); |
| |
| // visible: false, with replacementSliver |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| replacementSliver: const SliverToBoxAdapter(child: Placeholder()), |
| visible: false, |
| ))); |
| expect(find.byType(Text, skipOffstage: false), findsNothing); |
| expect(find.byType(Placeholder), findsOneWidget); |
| expect(find.byType(SliverVisibility), findsOneWidget); |
| expect(find.byType(SliverVisibility), paints..path()); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 400.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(0)); |
| expect(log, <String>[]); |
| expect(find.byKey(anchor), findsNothing); |
| log.clear(); |
| |
| // visible: true, with replacementSliver |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| replacementSliver: const SliverToBoxAdapter(child: Placeholder()), |
| ))); |
| expect(find.byType(Text, skipOffstage: false), findsOneWidget); |
| expect(find.text('a true', skipOffstage: false), findsOneWidget); |
| expect(find.byType(Placeholder), findsNothing); |
| expect(find.byType(SliverVisibility), findsOneWidget); |
| expect(find.byType(SliverVisibility), paints..paragraph()); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 14.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(1)); |
| expect(log, <String>['created new state']); |
| await tester.tap(find.byKey(anchor)); |
| expect(log, <String>['created new state', 'tap']); |
| log.clear(); |
| |
| // visible: true, maintain all |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| maintainState: true, |
| maintainAnimation: true, |
| maintainSize: true, |
| maintainInteractivity: true, |
| maintainSemantics: true, |
| ))); |
| expect(find.byType(Text, skipOffstage: false), findsOneWidget); |
| expect(find.text('a true', skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility), findsOneWidget); |
| expect(find.byType(SliverVisibility), paints..paragraph()); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 14.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(1)); |
| expect(log, <String>['created new state']); |
| await tester.tap(find.byKey(anchor)); |
| expect(log, <String>['created new state', 'tap']); |
| log.clear(); |
| |
| // visible: false, maintain all |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| visible: false, |
| maintainState: true, |
| maintainAnimation: true, |
| maintainSize: true, |
| maintainInteractivity: true, |
| maintainSemantics: true, |
| ))); |
| expect(find.byType(Text, skipOffstage: false), findsOneWidget); |
| expect(find.text('a true', skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility), findsOneWidget); |
| expect(find.byType(SliverVisibility), paintsNothing); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 14.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(1)); |
| expect(log, <String>[]); |
| await tester.tap(find.byKey(anchor)); |
| expect(log, <String>['tap']); |
| log.clear(); |
| |
| // visible: false, maintain all, replacementSliver |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| replacementSliver: const SliverToBoxAdapter(child: Placeholder()), |
| visible: false, |
| maintainState: true, |
| maintainAnimation: true, |
| maintainSize: true, |
| maintainInteractivity: true, |
| maintainSemantics: true, |
| ))); |
| expect(find.byType(Text, skipOffstage: false), findsOneWidget); |
| expect(find.text('a true', skipOffstage: false), findsOneWidget); |
| expect(find.byType(Placeholder), findsNothing); |
| expect(find.byType(SliverVisibility), findsOneWidget); |
| expect(find.byType(SliverVisibility), paintsNothing); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 14.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(1)); |
| expect(log, <String>[]); |
| await tester.tap(find.byKey(anchor)); |
| expect(log, <String>['tap']); |
| log.clear(); |
| |
| // visible: false, maintain all but semantics |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| visible: false, |
| maintainState: true, |
| maintainAnimation: true, |
| maintainSize: true, |
| maintainInteractivity: true, |
| ))); |
| expect(find.byType(Text, skipOffstage: false), findsOneWidget); |
| expect(find.text('a true', skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility), findsOneWidget); |
| expect(find.byType(SliverVisibility), paintsNothing); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 14.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(0)); |
| expect(log, <String>[]); |
| await tester.tap(find.byKey(anchor)); |
| expect(log, <String>['tap']); |
| log.clear(); |
| |
| // visible: false, maintain all but interactivity |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| visible: false, |
| maintainState: true, |
| maintainAnimation: true, |
| maintainSize: true, |
| maintainSemantics: true, |
| ))); |
| expect(find.byType(Text, skipOffstage: false), findsOneWidget); |
| expect(find.text('a true', skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility), findsOneWidget); |
| expect(find.byType(SliverVisibility), paintsNothing); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 14.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(1)); |
| expect(log, <String>['created new state']); |
| await tester.tap(find.byKey(anchor), warnIfMissed: false); |
| expect(log, <String>['created new state']); |
| log.clear(); |
| |
| // visible: false, maintain state, animation, size. |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| visible: false, |
| maintainState: true, |
| maintainAnimation: true, |
| maintainSize: true, |
| ))); |
| expect(find.byType(Text, skipOffstage: false), findsOneWidget); |
| expect(find.text('a true', skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility), findsOneWidget); |
| expect(find.byType(SliverVisibility), paintsNothing); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 14.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(0)); |
| expect(log, <String>[]); |
| await tester.tap(find.byKey(anchor), warnIfMissed: false); |
| expect(log, <String>[]); |
| log.clear(); |
| |
| // visible: false, maintain state and animation. |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| visible: false, |
| maintainState: true, |
| maintainAnimation: true, |
| ))); |
| expect(find.byType(Text, skipOffstage: false), findsOneWidget); |
| expect(find.byType(Text), findsNothing); |
| expect(find.text('a true', skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility, skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility, skipOffstage: false), paintsNothing); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 0.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(0)); |
| expect(log, <String>['created new state']); |
| expect(find.byKey(anchor), findsNothing); |
| log.clear(); |
| |
| // visible: false, maintain state. |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| visible: false, |
| maintainState: true, |
| ))); |
| expect(find.byType(Text, skipOffstage: false), findsOneWidget); |
| expect(find.byType(Text), findsNothing); |
| expect(find.text('a false', skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility, skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility, skipOffstage: false), paintsNothing); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 0.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(0)); |
| expect(log, <String>['created new state']); |
| expect(find.byKey(anchor), findsNothing); |
| log.clear(); |
| |
| // Now we toggle the visibility off and on a few times to make sure that |
| // works. |
| |
| // visible: true, maintain state |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| maintainState: true, |
| ))); |
| expect(find.byType(Text), findsOneWidget); |
| expect(find.text('a true'), findsOneWidget); |
| expect(find.byType(SliverVisibility), findsOneWidget); |
| expect(find.byType(SliverVisibility), paints..paragraph()); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 14.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(1)); |
| expect(log, <String>[]); |
| await tester.tap(find.byKey(anchor)); |
| expect(log, <String>['tap']); |
| log.clear(); |
| |
| // visible: false, maintain state. |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| visible: false, |
| maintainState: true, |
| ))); |
| expect(find.byType(Text, skipOffstage: false), findsOneWidget); |
| expect(find.byType(Text), findsNothing); |
| expect(find.text('a false', skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility, skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility, skipOffstage: false), paintsNothing); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 0.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a false'), hasLength(0)); |
| expect(log, <String>[]); |
| expect(find.byKey(anchor), findsNothing); |
| log.clear(); |
| |
| // visible: true, maintain state. |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| maintainState: true, |
| ))); |
| expect(find.byType(Text), findsOneWidget); |
| expect(find.text('a true', skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility, skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility, skipOffstage: false), paints..paragraph()); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 14.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(1)); |
| expect(log, <String>[]); |
| await tester.tap(find.byKey(anchor)); |
| expect(log, <String>['tap']); |
| log.clear(); |
| |
| // visible: false, maintain state. |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| visible: false, |
| maintainState: true, |
| ))); |
| expect(find.byType(Text, skipOffstage: false), findsOneWidget); |
| expect(find.byType(Text), findsNothing); |
| expect(find.text('a false', skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility, skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility, skipOffstage: false), paintsNothing); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 0.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a false'), hasLength(0)); |
| expect(log, <String>[]); |
| expect(find.byKey(anchor), findsNothing); |
| log.clear(); |
| |
| // Same but without maintainState. |
| |
| // visible: false. |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| visible: false, |
| ))); |
| expect(find.byType(Text, skipOffstage: false), findsNothing); |
| expect(find.byType(SliverVisibility, skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility, skipOffstage: false), paintsNothing); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 0.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(0)); |
| expect(log, <String>[]); |
| expect(find.byKey(anchor), findsNothing); |
| log.clear(); |
| |
| // visible: true. |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| ))); |
| expect(find.byType(Text), findsOneWidget); |
| expect(find.text('a true', skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility), findsOneWidget); |
| expect(find.byType(SliverVisibility), paints..paragraph()); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 14.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(1)); |
| expect(log, <String>['created new state']); |
| await tester.tap(find.byKey(anchor)); |
| expect(log, <String>['created new state', 'tap']); |
| log.clear(); |
| |
| //visible: false. |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| visible: false, |
| ))); |
| expect(find.byType(Text, skipOffstage: false), findsNothing); |
| expect(find.byType(SliverVisibility, skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility, skipOffstage: false), paintsNothing); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 0.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(0)); |
| expect(log, <String>[]); |
| expect(find.byKey(anchor), findsNothing); |
| log.clear(); |
| |
| // visible: true. |
| await tester.pumpWidget(_boilerPlate(SliverVisibility( |
| sliver: testChild, |
| ))); |
| expect(find.byType(Text), findsOneWidget); |
| expect(find.text('a true', skipOffstage: false), findsOneWidget); |
| expect(find.byType(SliverVisibility), findsOneWidget); |
| expect(find.byType(SliverVisibility), paints..paragraph()); |
| renderViewport = tester.renderObject(find.byType(Viewport)); |
| renderSliver = renderViewport.lastChild!; |
| expect(renderSliver.geometry!.scrollExtent, 14.0); |
| expect(renderSliver.constraints.crossAxisExtent, 800.0); |
| expect(semantics.nodesWith(label: 'a true'), hasLength(1)); |
| expect(log, <String>['created new state']); |
| await tester.tap(find.byKey(anchor)); |
| expect(log, <String>['created new state', 'tap']); |
| log.clear(); |
| |
| semantics.dispose(); |
| }); |
| } |