blob: bb02a1ceb6d2c101c6bd67bcb8fbfe8e3c58a0b0 [file] [log] [blame]
// 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({ super.key, required this.child, required this.log });
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>[]);
await tester.tap(find.byKey(anchor), warnIfMissed: false);
expect(log, <String>[]);
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();
});
}