blob: c9f4953c5f95c01a71f29edc3dfa7e9bfae81fdb [file] [log] [blame]
// Copyright 2017 The Chromium 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/cupertino.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart' hide TypeMatcher;
int count = 0;
void main() {
testWidgets('Middle still in center with asymmetrical actions', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
leading: const CupertinoButton(child: const Text('Something'), onPressed: null,),
middle: const Text('Title'),
);
},
);
},
),
);
// Expect the middle of the title to be exactly in the middle of the screen.
expect(tester.getCenter(find.text('Title')).dx, 400.0);
});
testWidgets('Opaque background does not add blur effects', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
middle: const Text('Title'),
backgroundColor: const Color(0xFFE5E5E5),
);
},
);
},
),
);
expect(find.byType(BackdropFilter), findsNothing);
});
testWidgets('Non-opaque background adds blur effects', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
middle: const Text('Title'),
);
},
);
},
),
);
expect(find.byType(BackdropFilter), findsOneWidget);
});
testWidgets('Verify styles of each slot', (WidgetTester tester) async {
count = 0x000000;
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
leading: const _ExpectStyles(color: const Color(0xFF001122), index: 0x000001),
middle: const _ExpectStyles(color: const Color(0xFF000000), letterSpacing: -0.72, index: 0x000100),
trailing: const _ExpectStyles(color: const Color(0xFF001122), index: 0x010000),
actionsForegroundColor: const Color(0xFF001122),
);
},
);
},
),
);
expect(count, 0x010101);
});
testWidgets('No slivers with no large titles', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
middle: const Text('Title'),
),
child: const Center(),
);
},
);
},
),
);
expect(find.byType(SliverPersistentHeader), findsNothing);
});
testWidgets('Media padding is applied to CupertinoSliverNavigationBar', (WidgetTester tester) async {
final ScrollController scrollController = new ScrollController();
final Key leadingKey = new GlobalKey();
final Key middleKey = new GlobalKey();
final Key trailingKey = new GlobalKey();
final Key titleKey = new GlobalKey();
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new MediaQuery(
data: const MediaQueryData(
padding: const EdgeInsets.only(
top: 10.0,
left: 20.0,
bottom: 30.0,
right: 40.0,
),
),
child: new CupertinoPageScaffold(
child: new CustomScrollView(
controller: scrollController,
slivers: <Widget>[
new CupertinoSliverNavigationBar(
leading: new Placeholder(key: leadingKey),
middle: new Placeholder(key: middleKey),
largeTitle: new Text('Large Title', key: titleKey),
trailing: new Placeholder(key: trailingKey),
),
new SliverToBoxAdapter(
child: new Container(
height: 1200.0,
),
),
],
),
),
);
},
);
},
),
);
// Media padding applied to leading (T,L), middle (T), trailing (T, R).
expect(tester.getTopLeft(find.byKey(leadingKey)), const Offset(16.0 + 20.0, 10.0));
expect(tester.getRect(find.byKey(middleKey)).top, 10.0);
expect(tester.getTopRight(find.byKey(trailingKey)), const Offset(800.0 - 16.0 - 40.0, 10.0));
// Top and left padding is applied to large title.
expect(tester.getTopLeft(find.byKey(titleKey)), const Offset(16.0 + 20.0, 58.0 + 10.0));
});
testWidgets('Large title nav bar scrolls', (WidgetTester tester) async {
final ScrollController scrollController = new ScrollController();
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoPageScaffold(
child: new CustomScrollView(
controller: scrollController,
slivers: <Widget>[
const CupertinoSliverNavigationBar(
largeTitle: const Text('Title'),
),
new SliverToBoxAdapter(
child: new Container(
height: 1200.0,
),
),
],
),
);
},
);
},
),
);
expect(scrollController.offset, 0.0);
expect(tester.getTopLeft(find.byType(NavigationToolbar)).dy, 0.0);
expect(tester.getSize(find.byType(NavigationToolbar)).height, 44.0);
expect(find.text('Title'), findsNWidgets(2)); // Though only one is visible.
List<Element> titles = tester.elementList(find.text('Title'))
.toList()
..sort((Element a, Element b) {
final RenderParagraph aParagraph = a.renderObject;
final RenderParagraph bParagraph = b.renderObject;
return aParagraph.text.style.fontSize.compareTo(bParagraph.text.style.fontSize);
});
Iterable<double> opacities = titles.map((Element element) {
final RenderOpacity renderOpacity = element.ancestorRenderObjectOfType(const TypeMatcher<RenderOpacity>());
return renderOpacity.opacity;
});
expect(opacities, <double> [
0.0, // Initially the smaller font title is invisible.
1.0, // The larger font title is visible.
]);
expect(tester.getTopLeft(find.widgetWithText(OverflowBox, 'Title')).dy, 44.0);
expect(tester.getSize(find.widgetWithText(OverflowBox, 'Title')).height, 56.0);
scrollController.jumpTo(600.0);
await tester.pump(); // Once to trigger the opacity animation.
await tester.pump(const Duration(milliseconds: 300));
titles = tester.elementList(find.text('Title'))
.toList()
..sort((Element a, Element b) {
final RenderParagraph aParagraph = a.renderObject;
final RenderParagraph bParagraph = b.renderObject;
return aParagraph.text.style.fontSize.compareTo(bParagraph.text.style.fontSize);
});
opacities = titles.map((Element element) {
final RenderOpacity renderOpacity = element.ancestorRenderObjectOfType(const TypeMatcher<RenderOpacity>());
return renderOpacity.opacity;
});
expect(opacities, <double> [
1.0, // Smaller font title now visible
0.0, // Larger font title invisible.
]);
// The persistent toolbar doesn't move or change size.
expect(tester.getTopLeft(find.byType(NavigationToolbar)).dy, 0.0);
expect(tester.getSize(find.byType(NavigationToolbar)).height, 44.0);
expect(tester.getTopLeft(find.widgetWithText(OverflowBox, 'Title')).dy, 44.0);
// The OverflowBox is squished with the text in it.
expect(tester.getSize(find.widgetWithText(OverflowBox, 'Title')).height, 0.0);
});
testWidgets('Small title can be overridden', (WidgetTester tester) async {
final ScrollController scrollController = new ScrollController();
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return new CupertinoPageScaffold(
child: new CustomScrollView(
controller: scrollController,
slivers: <Widget>[
const CupertinoSliverNavigationBar(
middle: const Text('Different title'),
largeTitle: const Text('Title'),
),
new SliverToBoxAdapter(
child: new Container(
height: 1200.0,
),
),
],
),
);
},
);
},
),
);
expect(scrollController.offset, 0.0);
expect(tester.getTopLeft(find.byType(NavigationToolbar)).dy, 0.0);
expect(tester.getSize(find.byType(NavigationToolbar)).height, 44.0);
expect(find.text('Title'), findsOneWidget);
expect(find.text('Different title'), findsOneWidget);
RenderOpacity largeTitleOpacity =
tester.element(find.text('Title')).ancestorRenderObjectOfType(const TypeMatcher<RenderOpacity>());
// Large title initially visible.
expect(
largeTitleOpacity.opacity,
1.0
);
// Middle widget not even wrapped with RenderOpacity, i.e. is always visible.
expect(
tester.element(find.text('Different title')).ancestorRenderObjectOfType(const TypeMatcher<RenderOpacity>()),
isNull,
);
expect(tester.getBottomLeft(find.text('Title')).dy, 44.0 + 56.0 - 8.0); // Static part + extension - padding.
scrollController.jumpTo(600.0);
await tester.pump(); // Once to trigger the opacity animation.
await tester.pump(const Duration(milliseconds: 300));
largeTitleOpacity =
tester.element(find.text('Title')).ancestorRenderObjectOfType(const TypeMatcher<RenderOpacity>());
// Large title no longer visible.
expect(
largeTitleOpacity.opacity,
0.0
);
// The persistent toolbar doesn't move or change size.
expect(tester.getTopLeft(find.byType(NavigationToolbar)).dy, 0.0);
expect(tester.getSize(find.byType(NavigationToolbar)).height, 44.0);
expect(tester.getBottomLeft(find.text('Title')).dy, 44.0 - 8.0); // Extension gone, (static part - padding) left.
});
testWidgets('Auto back/close button', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
middle: const Text('Home page'),
);
},
);
},
),
);
expect(find.byType(CupertinoButton), findsNothing);
tester.state<NavigatorState>(find.byType(Navigator)).push(new CupertinoPageRoute<void>(
builder: (BuildContext context) {
return const CupertinoNavigationBar(
middle: const Text('Page 2'),
);
},
));
await tester.pump();
await tester.pump(const Duration(milliseconds: 200));
expect(find.byType(CupertinoButton), findsOneWidget);
expect(find.byType(Icon), findsOneWidget);
tester.state<NavigatorState>(find.byType(Navigator)).push(new CupertinoPageRoute<void>(
fullscreenDialog: true,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
middle: const Text('Dialog page'),
);
},
));
await tester.pump();
await tester.pump(const Duration(milliseconds: 200));
expect(find.byType(CupertinoButton), findsNWidgets(2));
expect(find.text('Close'), findsOneWidget);
// Test popping goes back correctly.
await tester.tap(find.text('Close'));
await tester.pump();
await tester.pump(const Duration(milliseconds: 200));
expect(find.text('Page 2'), findsOneWidget);
await tester.tap(find.byType(Icon));
await tester.pump();
await tester.pump(const Duration(milliseconds: 200));
expect(find.text('Home page'), findsOneWidget);
});
testWidgets('Border should be displayed by default', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
middle: const Text('Title'),
);
},
);
},
),
);
final DecoratedBox decoratedBox = tester.widgetList(find.byType(DecoratedBox)).elementAt(1);
expect(decoratedBox.decoration.runtimeType, BoxDecoration);
final BoxDecoration decoration = decoratedBox.decoration;
expect(decoration.border, isNotNull);
final BorderSide side = decoration.border.bottom;
expect(side, isNotNull);
});
testWidgets('Overrides border color', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
middle: const Text('Title'),
border: const Border(
bottom: const BorderSide(
color: const Color(0xFFAABBCC),
width: 0.0,
),
),
);
},
);
},
),
);
final DecoratedBox decoratedBox = tester.widgetList(find.byType(DecoratedBox)).elementAt(1);
expect(decoratedBox.decoration.runtimeType, BoxDecoration);
final BoxDecoration decoration = decoratedBox.decoration;
expect(decoration.border, isNotNull);
final BorderSide side = decoration.border.bottom;
expect(side, isNotNull);
expect(side.color, const Color(0xFFAABBCC));
});
testWidgets('Border should not be displayed when null', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
return const CupertinoNavigationBar(
middle: const Text('Title'),
border: null,
);
},
);
},
),
);
final DecoratedBox decoratedBox = tester.widgetList(find.byType(DecoratedBox)).elementAt(1);
expect(decoratedBox.decoration.runtimeType, BoxDecoration);
final BoxDecoration decoration = decoratedBox.decoration;
expect(decoration.border, isNull);
});
}
class _ExpectStyles extends StatelessWidget {
const _ExpectStyles({ this.color, this.letterSpacing, this.index });
final Color color;
final double letterSpacing;
final int index;
@override
Widget build(BuildContext context) {
final TextStyle style = DefaultTextStyle.of(context).style;
expect(style.color, color);
expect(style.fontSize, 17.0);
expect(style.letterSpacing, letterSpacing ?? -0.24);
count += index;
return new Container();
}
}