| // 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'; |
| |
| void main() { |
| test('MaterialBannerThemeData copyWith, ==, hashCode basics', () { |
| expect(const MaterialBannerThemeData(), const MaterialBannerThemeData().copyWith()); |
| expect(const MaterialBannerThemeData().hashCode, const MaterialBannerThemeData().copyWith().hashCode); |
| }); |
| |
| test('MaterialBannerThemeData null fields by default', () { |
| const MaterialBannerThemeData bannerTheme = MaterialBannerThemeData(); |
| expect(bannerTheme.backgroundColor, null); |
| expect(bannerTheme.surfaceTintColor, null); |
| expect(bannerTheme.shadowColor, null); |
| expect(bannerTheme.dividerColor, null); |
| expect(bannerTheme.contentTextStyle, null); |
| expect(bannerTheme.elevation, null); |
| expect(bannerTheme.padding, null); |
| expect(bannerTheme.leadingPadding, null); |
| }); |
| |
| testWidgets('Default MaterialBannerThemeData debugFillProperties', (WidgetTester tester) async { |
| final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); |
| const MaterialBannerThemeData().debugFillProperties(builder); |
| |
| final List<String> description = builder.properties |
| .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) |
| .map((DiagnosticsNode node) => node.toString()) |
| .toList(); |
| |
| expect(description, <String>[]); |
| }); |
| |
| testWidgets('MaterialBannerThemeData implements debugFillProperties', (WidgetTester tester) async { |
| final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); |
| const MaterialBannerThemeData( |
| backgroundColor: Color(0xfffffff0), |
| surfaceTintColor: Color(0xfffffff1), |
| shadowColor: Color(0xfffffff2), |
| dividerColor: Color(0xfffffff3), |
| contentTextStyle: TextStyle(color: Color(0xfffffff4)), |
| elevation: 4.0, |
| padding: EdgeInsets.all(20.0), |
| leadingPadding: EdgeInsets.only(left: 8.0), |
| ).debugFillProperties(builder); |
| |
| final List<String> description = builder.properties |
| .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) |
| .map((DiagnosticsNode node) => node.toString()) |
| .toList(); |
| |
| expect(description, <String>[ |
| 'backgroundColor: Color(0xfffffff0)', |
| 'surfaceTintColor: Color(0xfffffff1)', |
| 'shadowColor: Color(0xfffffff2)', |
| 'dividerColor: Color(0xfffffff3)', |
| 'contentTextStyle: TextStyle(inherit: true, color: Color(0xfffffff4))', |
| 'elevation: 4.0', |
| 'padding: EdgeInsets.all(20.0)', |
| 'leadingPadding: EdgeInsets(8.0, 0.0, 0.0, 0.0)', |
| ]); |
| }); |
| |
| testWidgets('Passing no MaterialBannerThemeData returns defaults', (WidgetTester tester) async { |
| const String contentText = 'Content'; |
| final ThemeData theme = ThemeData(useMaterial3: true); |
| late final ThemeData localizedTheme; |
| |
| await tester.pumpWidget(MaterialApp( |
| theme: theme, |
| builder:(BuildContext context, Widget? child) { |
| localizedTheme = Theme.of(context); |
| return child!; |
| }, |
| home: Scaffold( |
| body: MaterialBanner( |
| content: const Text(contentText), |
| leading: const Icon(Icons.umbrella), |
| actions: <Widget>[ |
| TextButton( |
| child: const Text('Action'), |
| onPressed: () { }, |
| ), |
| ], |
| ), |
| ), |
| )); |
| |
| final Material material = _getMaterialFromText(tester, contentText); |
| expect(material.color, theme.colorScheme.surface); |
| expect(material.surfaceTintColor, theme.colorScheme.surfaceTint); |
| expect(material.shadowColor, null); |
| expect(material.elevation, 0.0); |
| |
| final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); |
| expect( |
| content.text.style, |
| localizedTheme.textTheme.bodyMedium, |
| ); |
| |
| final Offset rowTopLeft = tester.getTopLeft(find.byType(Row)); |
| final Offset materialTopLeft = tester.getTopLeft(_materialFinder()); |
| final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.umbrella)); |
| expect(rowTopLeft.dy - materialTopLeft.dy, 2.0); // Default single line top padding. |
| expect(rowTopLeft.dx - materialTopLeft.dx, 16.0); // Default single line start padding. |
| expect(leadingTopLeft.dy - materialTopLeft.dy, 16); // Default leading padding. |
| expect(leadingTopLeft.dx - materialTopLeft.dx, 16); // Default leading padding. |
| |
| final Divider divider = tester.widget<Divider>(find.byType(Divider)); |
| expect(divider.color, theme.colorScheme.outlineVariant); |
| }); |
| |
| testWidgets('Passing no MaterialBannerThemeData returns defaults when presented by ScaffoldMessenger', (WidgetTester tester) async { |
| const String contentText = 'Content'; |
| const Key tapTarget = Key('tap-target'); |
| final ThemeData theme = ThemeData(useMaterial3: true); |
| late final ThemeData localizedTheme; |
| |
| await tester.pumpWidget(MaterialApp( |
| theme: theme, |
| home: Scaffold( |
| body: Builder( |
| builder: (BuildContext context) { |
| localizedTheme = Theme.of(context); |
| return GestureDetector( |
| key: tapTarget, |
| onTap: () { |
| ScaffoldMessenger.of(context).showMaterialBanner(MaterialBanner( |
| content: const Text(contentText), |
| leading: const Icon(Icons.umbrella), |
| actions: <Widget>[ |
| TextButton( |
| child: const Text('Action'), |
| onPressed: () { }, |
| ), |
| ], |
| )); |
| }, |
| behavior: HitTestBehavior.opaque, |
| child: const SizedBox( |
| height: 100.0, |
| width: 100.0, |
| ), |
| ); |
| }, |
| ), |
| ), |
| )); |
| await tester.tap(find.byKey(tapTarget)); |
| await tester.pumpAndSettle(); |
| |
| final Material material = _getMaterialFromText(tester, contentText); |
| expect(material.color, theme.colorScheme.surface); |
| expect(material.surfaceTintColor, theme.colorScheme.surfaceTint); |
| expect(material.shadowColor, null); |
| expect(material.elevation, 0.0); |
| |
| final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); |
| expect( |
| content.text.style, |
| localizedTheme.textTheme.bodyMedium, |
| ); |
| |
| final Offset rowTopLeft = tester.getTopLeft(find.byType(Row)); |
| final Offset materialTopLeft = tester.getTopLeft(_materialFinder()); |
| final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.umbrella)); |
| expect(rowTopLeft.dy - materialTopLeft.dy, 2.0); // Default single line top padding. |
| expect(rowTopLeft.dx - materialTopLeft.dx, 16.0); // Default single line start padding. |
| expect(leadingTopLeft.dy - materialTopLeft.dy, 16); // Default leading padding. |
| expect(leadingTopLeft.dx - materialTopLeft.dx, 16); // Default leading padding. |
| |
| final Divider divider = tester.widget<Divider>(find.byType(Divider)); |
| expect(divider.color, theme.colorScheme.outlineVariant); |
| }); |
| |
| testWidgets('MaterialBanner uses values from MaterialBannerThemeData', (WidgetTester tester) async { |
| final MaterialBannerThemeData bannerTheme = _bannerTheme(); |
| const String contentText = 'Content'; |
| await tester.pumpWidget(MaterialApp( |
| theme: ThemeData(bannerTheme: bannerTheme), |
| home: Scaffold( |
| body: MaterialBanner( |
| leading: const Icon(Icons.ac_unit), |
| content: const Text(contentText), |
| actions: <Widget>[ |
| TextButton( |
| child: const Text('Action'), |
| onPressed: () { }, |
| ), |
| ], |
| ), |
| ), |
| )); |
| |
| final Material material = _getMaterialFromText(tester, contentText); |
| expect(material.color, bannerTheme.backgroundColor); |
| expect(material.surfaceTintColor, bannerTheme.surfaceTintColor); |
| expect(material.shadowColor, bannerTheme.shadowColor); |
| expect(material.elevation, bannerTheme.elevation); |
| |
| final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); |
| expect(content.text.style, bannerTheme.contentTextStyle); |
| |
| final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText)); |
| final Offset materialTopLeft = tester.getTopLeft(_materialFinder()); |
| final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.ac_unit)); |
| expect(contentTopLeft.dy - materialTopLeft.dy, 24); |
| expect(contentTopLeft.dx - materialTopLeft.dx, 41); |
| expect(leadingTopLeft.dy - materialTopLeft.dy, 19); |
| expect(leadingTopLeft.dx - materialTopLeft.dx, 11); |
| |
| expect(find.byType(Divider), findsNothing); |
| }); |
| |
| testWidgets('MaterialBanner uses values from MaterialBannerThemeData when presented by ScaffoldMessenger', (WidgetTester tester) async { |
| final MaterialBannerThemeData bannerTheme = _bannerTheme(); |
| const String contentText = 'Content'; |
| const Key tapTarget = Key('tap-target'); |
| await tester.pumpWidget(MaterialApp( |
| theme: ThemeData(bannerTheme: bannerTheme), |
| home: Scaffold( |
| body: Builder( |
| builder: (BuildContext context) { |
| return GestureDetector( |
| key: tapTarget, |
| onTap: () { |
| ScaffoldMessenger.of(context).showMaterialBanner(MaterialBanner( |
| leading: const Icon(Icons.ac_unit), |
| content: const Text(contentText), |
| actions: <Widget>[ |
| TextButton( |
| child: const Text('Action'), |
| onPressed: () { }, |
| ), |
| ], |
| )); |
| }, |
| behavior: HitTestBehavior.opaque, |
| child: const SizedBox( |
| height: 100.0, |
| width: 100.0, |
| ), |
| ); |
| }, |
| ), |
| ), |
| )); |
| await tester.tap(find.byKey(tapTarget)); |
| await tester.pumpAndSettle(); |
| |
| final Material material = _getMaterialFromText(tester, contentText); |
| expect(material.color, bannerTheme.backgroundColor); |
| expect(material.surfaceTintColor, bannerTheme.surfaceTintColor); |
| expect(material.shadowColor, bannerTheme.shadowColor); |
| expect(material.elevation, bannerTheme.elevation); |
| |
| final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); |
| expect(content.text.style, bannerTheme.contentTextStyle); |
| |
| final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText)); |
| final Offset materialTopLeft = tester.getTopLeft(_materialFinder()); |
| final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.ac_unit)); |
| expect(contentTopLeft.dy - materialTopLeft.dy, 24); |
| expect(contentTopLeft.dx - materialTopLeft.dx, 41); |
| expect(leadingTopLeft.dy - materialTopLeft.dy, 19); |
| expect(leadingTopLeft.dx - materialTopLeft.dx, 11); |
| |
| expect(find.byType(Divider), findsNothing); |
| }); |
| |
| testWidgets('MaterialBanner widget properties take priority over theme', (WidgetTester tester) async { |
| const Color backgroundColor = Colors.purple; |
| const Color surfaceTintColor = Colors.red; |
| const Color shadowColor = Colors.orange; |
| const TextStyle textStyle = TextStyle(color: Colors.green); |
| final MaterialBannerThemeData bannerTheme = _bannerTheme(); |
| const String contentText = 'Content'; |
| |
| await tester.pumpWidget(MaterialApp( |
| theme: ThemeData(bannerTheme: bannerTheme), |
| home: Scaffold( |
| body: MaterialBanner( |
| backgroundColor: backgroundColor, |
| surfaceTintColor: surfaceTintColor, |
| shadowColor: shadowColor, |
| elevation: 6.0, |
| leading: const Icon(Icons.ac_unit), |
| contentTextStyle: textStyle, |
| content: const Text(contentText), |
| padding: const EdgeInsets.all(10), |
| leadingPadding: const EdgeInsets.all(12), |
| actions: <Widget>[ |
| TextButton( |
| child: const Text('Action'), |
| onPressed: () { }, |
| ), |
| ], |
| ), |
| ), |
| )); |
| |
| final Material material = _getMaterialFromText(tester, contentText); |
| expect(material.color, backgroundColor); |
| expect(material.surfaceTintColor, surfaceTintColor); |
| expect(material.shadowColor, shadowColor); |
| expect(material.elevation, 6.0); |
| |
| final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); |
| expect(content.text.style, textStyle); |
| |
| final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText)); |
| final Offset materialTopLeft = tester.getTopLeft(_materialFinder()); |
| final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.ac_unit)); |
| expect(contentTopLeft.dy - materialTopLeft.dy, 29); |
| expect(contentTopLeft.dx - materialTopLeft.dx, 58); |
| expect(leadingTopLeft.dy - materialTopLeft.dy, 24); |
| expect(leadingTopLeft.dx - materialTopLeft.dx, 22); |
| |
| expect(find.byType(Divider), findsNothing); |
| }); |
| |
| testWidgets('MaterialBanner widget properties take priority over theme when presented by ScaffoldMessenger', (WidgetTester tester) async { |
| const Color backgroundColor = Colors.purple; |
| const double elevation = 6.0; |
| const TextStyle textStyle = TextStyle(color: Colors.green); |
| final MaterialBannerThemeData bannerTheme = _bannerTheme(); |
| const String contentText = 'Content'; |
| const Key tapTarget = Key('tap-target'); |
| |
| await tester.pumpWidget(MaterialApp( |
| theme: ThemeData(bannerTheme: bannerTheme), |
| home: Scaffold( |
| body: Builder( |
| builder: (BuildContext context) { |
| return GestureDetector( |
| key: tapTarget, |
| onTap: () { |
| ScaffoldMessenger.of(context).showMaterialBanner(MaterialBanner( |
| backgroundColor: backgroundColor, |
| elevation: elevation, |
| leading: const Icon(Icons.ac_unit), |
| contentTextStyle: textStyle, |
| content: const Text(contentText), |
| padding: const EdgeInsets.all(10), |
| leadingPadding: const EdgeInsets.all(12), |
| actions: <Widget>[ |
| TextButton( |
| child: const Text('Action'), |
| onPressed: () { }, |
| ), |
| ], |
| )); |
| }, |
| behavior: HitTestBehavior.opaque, |
| child: const SizedBox( |
| height: 100.0, |
| width: 100.0, |
| ), |
| ); |
| }, |
| ), |
| ), |
| )); |
| await tester.tap(find.byKey(tapTarget)); |
| await tester.pumpAndSettle(); |
| |
| final Material material = _getMaterialFromText(tester, contentText); |
| expect(material.color, backgroundColor); |
| expect(material.elevation, elevation); |
| |
| final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); |
| expect(content.text.style, textStyle); |
| |
| final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText)); |
| final Offset materialTopLeft = tester.getTopLeft(_materialFinder()); |
| final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.ac_unit)); |
| expect(contentTopLeft.dy - materialTopLeft.dy, 29); |
| expect(contentTopLeft.dx - materialTopLeft.dx, 58); |
| expect(leadingTopLeft.dy - materialTopLeft.dy, 24); |
| expect(leadingTopLeft.dx - materialTopLeft.dx, 22); |
| |
| expect(find.byType(Divider), findsNothing); |
| }); |
| |
| testWidgets('MaterialBanner uses color scheme when necessary', (WidgetTester tester) async { |
| final ColorScheme colorScheme = const ColorScheme.light().copyWith(surface: Colors.purple); |
| const String contentText = 'Content'; |
| await tester.pumpWidget(MaterialApp( |
| theme: ThemeData(colorScheme: colorScheme), |
| home: Scaffold( |
| body: MaterialBanner( |
| content: const Text(contentText), |
| actions: <Widget>[ |
| TextButton( |
| child: const Text('Action'), |
| onPressed: () { }, |
| ), |
| ], |
| ), |
| ), |
| )); |
| |
| final Material material = _getMaterialFromText(tester, contentText); |
| expect(material.color, colorScheme.surface); |
| }); |
| |
| testWidgets('MaterialBanner uses color scheme when necessary when presented by ScaffoldMessenger', (WidgetTester tester) async { |
| final ColorScheme colorScheme = const ColorScheme.light().copyWith(surface: Colors.purple); |
| const String contentText = 'Content'; |
| const Key tapTarget = Key('tap-target'); |
| await tester.pumpWidget(MaterialApp( |
| theme: ThemeData(colorScheme: colorScheme), |
| home: Scaffold( |
| body: Builder( |
| builder: (BuildContext context) { |
| return GestureDetector( |
| key: tapTarget, |
| onTap: () { |
| ScaffoldMessenger.of(context).showMaterialBanner(MaterialBanner( |
| content: const Text(contentText), |
| actions: <Widget>[ |
| TextButton( |
| child: const Text('Action'), |
| onPressed: () { }, |
| ), |
| ], |
| )); |
| }, |
| behavior: HitTestBehavior.opaque, |
| child: const SizedBox( |
| height: 100.0, |
| width: 100.0, |
| ), |
| ); |
| }, |
| ), |
| ), |
| )); |
| await tester.tap(find.byKey(tapTarget)); |
| await tester.pumpAndSettle(); |
| |
| final Material material = _getMaterialFromText(tester, contentText); |
| expect(material.color, colorScheme.surface); |
| }); |
| |
| group('Material 2', () { |
| // Tests that are only relevant for Material 2. Once ThemeData.useMaterial3 |
| // is turned on by default, these tests can be removed. |
| |
| testWidgets('Passing no MaterialBannerThemeData returns defaults', (WidgetTester tester) async { |
| const String contentText = 'Content'; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Scaffold( |
| body: MaterialBanner( |
| content: const Text(contentText), |
| leading: const Icon(Icons.umbrella), |
| actions: <Widget>[ |
| TextButton( |
| child: const Text('Action'), |
| onPressed: () { }, |
| ), |
| ], |
| ), |
| ), |
| )); |
| |
| final Material material = _getMaterialFromText(tester, contentText); |
| expect(material.color, const Color(0xffffffff)); |
| expect(material.surfaceTintColor, null); |
| expect(material.shadowColor, null); |
| expect(material.elevation, 0.0); |
| |
| final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); |
| // Default value for ThemeData.typography is Typography.material2014() |
| expect( |
| content.text.style, |
| Typography.material2014().englishLike.bodyText2!.merge( |
| Typography.material2014().black.bodyText2, |
| ), |
| ); |
| |
| final Offset rowTopLeft = tester.getTopLeft(find.byType(Row)); |
| final Offset materialTopLeft = tester.getTopLeft(_materialFinder()); |
| final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.umbrella)); |
| expect(rowTopLeft.dy - materialTopLeft.dy, 2.0); // Default single line top padding. |
| expect(rowTopLeft.dx - materialTopLeft.dx, 16.0); // Default single line start padding. |
| expect(leadingTopLeft.dy - materialTopLeft.dy, 16); // Default leading padding. |
| expect(leadingTopLeft.dx - materialTopLeft.dx, 16); // Default leading padding. |
| |
| final Divider divider = tester.widget<Divider>(find.byType(Divider)); |
| expect(divider.color, null); |
| }); |
| |
| testWidgets('Passing no MaterialBannerThemeData returns defaults when presented by ScaffoldMessenger', (WidgetTester tester) async { |
| const String contentText = 'Content'; |
| const Key tapTarget = Key('tap-target'); |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Scaffold( |
| body: Builder( |
| builder: (BuildContext context) { |
| return GestureDetector( |
| key: tapTarget, |
| onTap: () { |
| ScaffoldMessenger.of(context).showMaterialBanner(MaterialBanner( |
| content: const Text(contentText), |
| leading: const Icon(Icons.umbrella), |
| actions: <Widget>[ |
| TextButton( |
| child: const Text('Action'), |
| onPressed: () { }, |
| ), |
| ], |
| )); |
| }, |
| behavior: HitTestBehavior.opaque, |
| child: const SizedBox( |
| height: 100.0, |
| width: 100.0, |
| ), |
| ); |
| }, |
| ), |
| ), |
| )); |
| await tester.tap(find.byKey(tapTarget)); |
| await tester.pumpAndSettle(); |
| |
| final Material material = _getMaterialFromText(tester, contentText); |
| expect(material.color, const Color(0xffffffff)); |
| expect(material.surfaceTintColor, null); |
| expect(material.shadowColor, null); |
| expect(material.elevation, 0.0); |
| |
| final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); |
| // Default value for ThemeData.typography is Typography.material2014() |
| expect( |
| content.text.style, |
| Typography.material2014().englishLike.bodyText2!.merge( |
| Typography.material2014().black.bodyText2, |
| ), |
| ); |
| |
| final Offset rowTopLeft = tester.getTopLeft(find.byType(Row)); |
| final Offset materialTopLeft = tester.getTopLeft(_materialFinder()); |
| final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.umbrella)); |
| expect(rowTopLeft.dy - materialTopLeft.dy, 2.0); // Default single line top padding. |
| expect(rowTopLeft.dx - materialTopLeft.dx, 16.0); // Default single line start padding. |
| expect(leadingTopLeft.dy - materialTopLeft.dy, 16); // Default leading padding. |
| expect(leadingTopLeft.dx - materialTopLeft.dx, 16); // Default leading padding. |
| |
| final Divider divider = tester.widget<Divider>(find.byType(Divider)); |
| expect(divider.color, null); |
| }); |
| }); |
| } |
| |
| MaterialBannerThemeData _bannerTheme() { |
| return const MaterialBannerThemeData( |
| backgroundColor: Colors.orange, |
| surfaceTintColor: Colors.yellow, |
| shadowColor: Colors.red, |
| dividerColor: Colors.green, |
| contentTextStyle: TextStyle(color: Colors.pink), |
| elevation: 4.0, |
| padding: EdgeInsets.all(5), |
| leadingPadding: EdgeInsets.all(6), |
| ); |
| } |
| |
| Material _getMaterialFromText(WidgetTester tester, String text) { |
| return tester.widget<Material>(find.widgetWithText(Material, text).first); |
| } |
| |
| Finder _materialFinder() { |
| return find.descendant(of: find.byType(MaterialBanner), matching: find.byType(Material)).first; |
| } |
| |
| RenderParagraph _getTextRenderObjectFromDialog(WidgetTester tester, String text) { |
| return tester.element<StatelessElement>(_textFinder(text)).renderObject! as RenderParagraph; |
| } |
| |
| Finder _textFinder(String text) { |
| return find.descendant(of: find.byType(MaterialBanner), matching: find.text(text)); |
| } |