// 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. // @dart = 2.8 import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:vector_math/vector_math_64.dart' show Vector3; void main() { test('BottomNavigationBarThemeData copyWith, ==, hashCode basics', () { expect(const BottomNavigationBarThemeData(), const BottomNavigationBarThemeData().copyWith()); expect(const BottomNavigationBarThemeData().hashCode, const BottomNavigationBarThemeData().copyWith().hashCode); }); test('BottomNavigationBarThemeData defaults', () { const BottomNavigationBarThemeData themeData = BottomNavigationBarThemeData(); expect(themeData.backgroundColor, null); expect(themeData.elevation, null); expect(themeData.selectedIconTheme, null); expect(themeData.unselectedIconTheme, null); expect(themeData.selectedItemColor, null); expect(themeData.unselectedItemColor, null); expect(themeData.selectedLabelStyle, null); expect(themeData.unselectedLabelStyle, null); expect(themeData.showSelectedLabels, null); expect(themeData.showUnselectedLabels, null); expect(themeData.type, null); const BottomNavigationBarTheme theme = BottomNavigationBarTheme(data: BottomNavigationBarThemeData()); expect(theme.data.backgroundColor, null); expect(theme.data.elevation, null); expect(theme.data.selectedIconTheme, null); expect(theme.data.unselectedIconTheme, null); expect(theme.data.selectedItemColor, null); expect(theme.data.unselectedItemColor, null); expect(theme.data.selectedLabelStyle, null); expect(theme.data.unselectedLabelStyle, null); expect(theme.data.showSelectedLabels, null); expect(theme.data.showUnselectedLabels, null); expect(theme.data.type, null); }); testWidgets('Default BottomNavigationBarThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const BottomNavigationBarThemeData().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('BottomNavigationBarThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const BottomNavigationBarThemeData( backgroundColor: Color(0xfffffff0), elevation: 10.0, selectedIconTheme: IconThemeData(size: 1.0), unselectedIconTheme: IconThemeData(size: 2.0), selectedItemColor: Color(0xfffffff1), unselectedItemColor: Color(0xfffffff2), selectedLabelStyle: TextStyle(fontSize: 3.0), unselectedLabelStyle: TextStyle(fontSize: 4.0), showSelectedLabels: true, showUnselectedLabels: true, type: BottomNavigationBarType.fixed, ).debugFillProperties(builder); final List<String> description = builder.properties .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) .map((DiagnosticsNode node) => node.toString()) .toList(); expect(description[0], 'backgroundColor: Color(0xfffffff0)'); expect(description[1], 'elevation: 10.0'); // Ignore instance address for IconThemeData. expect(description[2].contains('selectedIconTheme: IconThemeData'), isTrue); expect(description[2].contains('(size: 1.0)'), isTrue); expect(description[3].contains('unselectedIconTheme: IconThemeData'), isTrue); expect(description[3].contains('(size: 2.0)'), isTrue); expect(description[4], 'selectedItemColor: Color(0xfffffff1)'); expect(description[5], 'unselectedItemColor: Color(0xfffffff2)'); expect(description[6], 'selectedLabelStyle: TextStyle(inherit: true, size: 3.0)'); expect(description[7], 'unselectedLabelStyle: TextStyle(inherit: true, size: 4.0)'); expect(description[8], 'showSelectedLabels: true'); expect(description[9], 'showUnselectedLabels: true'); expect(description[10], 'type: BottomNavigationBarType.fixed'); }); testWidgets('BottomNavigationBar is themeable', (WidgetTester tester) async { const Color backgroundColor = Color(0xFF000001); const Color selectedItemColor = Color(0xFF000002); const Color unselectedItemColor = Color(0xFF000003); const IconThemeData selectedIconTheme = IconThemeData(size: 10); const IconThemeData unselectedIconTheme = IconThemeData(size: 11); const TextStyle selectedTextStyle = TextStyle(fontSize: 22); const TextStyle unselectedTextStyle = TextStyle(fontSize: 21); const double elevation = 9.0; await tester.pumpWidget( MaterialApp( theme: ThemeData( bottomNavigationBarTheme: const BottomNavigationBarThemeData( backgroundColor: backgroundColor, selectedItemColor: selectedItemColor, unselectedItemColor: unselectedItemColor, selectedIconTheme: selectedIconTheme, unselectedIconTheme: unselectedIconTheme, elevation: elevation, showUnselectedLabels: true, showSelectedLabels: true, type: BottomNavigationBarType.fixed, selectedLabelStyle: selectedTextStyle, unselectedLabelStyle: unselectedTextStyle, ), ), home: Scaffold( bottomNavigationBar: BottomNavigationBar( items: const <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(Icons.ac_unit), label: 'AC', ), BottomNavigationBarItem( icon: Icon(Icons.access_alarm), label: 'Alarm', ), ], ), ), ), ); final TextStyle selectedFontStyle = tester.renderObject<RenderParagraph>(find.text('AC')).text.style; final TextStyle selectedIcon = _iconStyle(tester, Icons.ac_unit); final TextStyle unselectedIcon = _iconStyle(tester, Icons.access_alarm); expect(selectedFontStyle.fontSize, selectedFontStyle.fontSize); // Unselected label has a font size of 22 but is scaled down to be font size 21. expect( tester.firstWidget<Transform>(find.ancestor(of: find.text('Alarm'), matching: find.byType(Transform))).transform, equals(Matrix4.diagonal3(Vector3.all(unselectedTextStyle.fontSize / selectedTextStyle.fontSize))), ); expect(selectedIcon.color, equals(selectedItemColor)); expect(selectedIcon.fontSize, equals(selectedIconTheme.size)); expect(unselectedIcon.color, equals(unselectedItemColor)); expect(unselectedIcon.fontSize, equals(unselectedIconTheme.size)); // There should not be any [Opacity] or [FadeTransition] widgets // since showUnselectedLabels and showSelectedLabels are true. final Finder findOpacity = find.descendant( of: find.byType(BottomNavigationBar), matching: find.byType(Opacity), ); final Finder findFadeTransition = find.descendant( of: find.byType(BottomNavigationBar), matching: find.byType(FadeTransition), ); expect(findOpacity, findsNothing); expect(findFadeTransition, findsNothing); expect(_material(tester).elevation, equals(elevation)); expect(_material(tester).color, equals(backgroundColor)); }); testWidgets('BottomNavigationBar properties are taken over the theme values', (WidgetTester tester) async { const Color themeBackgroundColor = Color(0xFF000001); const Color themeSelectedItemColor = Color(0xFF000002); const Color themeUnselectedItemColor = Color(0xFF000003); const IconThemeData themeSelectedIconTheme = IconThemeData(size: 10); const IconThemeData themeUnselectedIconTheme = IconThemeData(size: 11); const TextStyle themeSelectedTextStyle = TextStyle(fontSize: 22); const TextStyle themeUnselectedTextStyle = TextStyle(fontSize: 21); const double themeElevation = 9.0; const Color backgroundColor = Color(0xFF000004); const Color selectedItemColor = Color(0xFF000005); const Color unselectedItemColor = Color(0xFF000006); const IconThemeData selectedIconTheme = IconThemeData(size: 15); const IconThemeData unselectedIconTheme = IconThemeData(size: 16); const TextStyle selectedTextStyle = TextStyle(fontSize: 25); const TextStyle unselectedTextStyle = TextStyle(fontSize: 26); const double elevation = 7.0; await tester.pumpWidget( MaterialApp( theme: ThemeData( bottomNavigationBarTheme: const BottomNavigationBarThemeData( backgroundColor: themeBackgroundColor, selectedItemColor: themeSelectedItemColor, unselectedItemColor: themeUnselectedItemColor, selectedIconTheme: themeSelectedIconTheme, unselectedIconTheme: themeUnselectedIconTheme, elevation: themeElevation, showUnselectedLabels: false, showSelectedLabels: false, type: BottomNavigationBarType.shifting, selectedLabelStyle: themeSelectedTextStyle, unselectedLabelStyle: themeUnselectedTextStyle, ), ), home: Scaffold( bottomNavigationBar: BottomNavigationBar( backgroundColor: backgroundColor, selectedItemColor: selectedItemColor, unselectedItemColor: unselectedItemColor, selectedIconTheme: selectedIconTheme, unselectedIconTheme: unselectedIconTheme, elevation: elevation, showUnselectedLabels: true, showSelectedLabels: true, type: BottomNavigationBarType.fixed, selectedLabelStyle: selectedTextStyle, unselectedLabelStyle: unselectedTextStyle, items: const <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(Icons.ac_unit), label: 'AC', ), BottomNavigationBarItem( icon: Icon(Icons.access_alarm), label: 'Alarm', ), ], ), ), ), ); final TextStyle selectedFontStyle = tester.renderObject<RenderParagraph>(find.text('AC')).text.style; final TextStyle selectedIcon = _iconStyle(tester, Icons.ac_unit); final TextStyle unselectedIcon = _iconStyle(tester, Icons.access_alarm); expect(selectedFontStyle.fontSize, selectedFontStyle.fontSize); // Unselected label has a font size of 22 but is scaled down to be font size 21. expect( tester.firstWidget<Transform>(find.ancestor(of: find.text('Alarm'), matching: find.byType(Transform))).transform, equals(Matrix4.diagonal3(Vector3.all(unselectedTextStyle.fontSize / selectedTextStyle.fontSize))), ); expect(selectedIcon.color, equals(selectedItemColor)); expect(selectedIcon.fontSize, equals(selectedIconTheme.size)); expect(unselectedIcon.color, equals(unselectedItemColor)); expect(unselectedIcon.fontSize, equals(unselectedIconTheme.size)); // There should not be any [Opacity] or [FadeTransition] widgets // since showUnselectedLabels and showSelectedLabels are true. final Finder findOpacity = find.descendant( of: find.byType(BottomNavigationBar), matching: find.byType(Opacity), ); final Finder findFadeTransition = find.descendant( of: find.byType(BottomNavigationBar), matching: find.byType(FadeTransition), ); expect(findOpacity, findsNothing); expect(findFadeTransition, findsNothing); expect(_material(tester).elevation, equals(elevation)); expect(_material(tester).color, equals(backgroundColor)); }); } TextStyle _iconStyle(WidgetTester tester, IconData icon) { final RichText iconRichText = tester.widget<RichText>( find.descendant(of: find.byIcon(icon), matching: find.byType(RichText)), ); return iconRichText.text.style; } Material _material(WidgetTester tester) { return tester.firstWidget<Material>( find.descendant(of: find.byType(BottomNavigationBar), matching: find.byType(Material)), ); }