| // 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 '../foundation/leak_tracking.dart'; |
| |
| void main() { |
| test('SearchBarThemeData copyWith, ==, hashCode basics', () { |
| expect(const SearchBarThemeData(), const SearchBarThemeData().copyWith()); |
| expect(const SearchBarThemeData().hashCode, const SearchBarThemeData() |
| .copyWith() |
| .hashCode); |
| }); |
| |
| test('SearchBarThemeData lerp special cases', () { |
| expect(SearchBarThemeData.lerp(null, null, 0), null); |
| const SearchBarThemeData data = SearchBarThemeData(); |
| expect(identical(SearchBarThemeData.lerp(data, data, 0.5), data), true); |
| }); |
| |
| test('SearchBarThemeData defaults', () { |
| const SearchBarThemeData themeData = SearchBarThemeData(); |
| expect(themeData.elevation, null); |
| expect(themeData.backgroundColor, null); |
| expect(themeData.shadowColor, null); |
| expect(themeData.surfaceTintColor, null); |
| expect(themeData.overlayColor, null); |
| expect(themeData.side, null); |
| expect(themeData.shape, null); |
| expect(themeData.padding, null); |
| expect(themeData.textStyle, null); |
| expect(themeData.hintStyle, null); |
| expect(themeData.constraints, null); |
| |
| const SearchBarTheme theme = SearchBarTheme(data: SearchBarThemeData(), child: SizedBox()); |
| expect(theme.data.elevation, null); |
| expect(theme.data.backgroundColor, null); |
| expect(theme.data.shadowColor, null); |
| expect(theme.data.surfaceTintColor, null); |
| expect(theme.data.overlayColor, null); |
| expect(theme.data.side, null); |
| expect(theme.data.shape, null); |
| expect(theme.data.padding, null); |
| expect(theme.data.textStyle, null); |
| expect(theme.data.hintStyle, null); |
| expect(theme.data.constraints, null); |
| }); |
| |
| testWidgetsWithLeakTracking('Default SearchBarThemeData debugFillProperties', (WidgetTester tester) async { |
| final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); |
| const SearchBarThemeData().debugFillProperties(builder); |
| |
| final List<String> description = builder.properties |
| .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) |
| .map((DiagnosticsNode node) => node.toString()) |
| .toList(); |
| |
| expect(description, <String>[]); |
| }); |
| |
| testWidgetsWithLeakTracking('SearchBarThemeData implements debugFillProperties', ( |
| WidgetTester tester) async { |
| final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); |
| const SearchBarThemeData( |
| elevation: MaterialStatePropertyAll<double>(3.0), |
| backgroundColor: MaterialStatePropertyAll<Color>(Color(0xfffffff1)), |
| shadowColor: MaterialStatePropertyAll<Color>(Color(0xfffffff2)), |
| surfaceTintColor: MaterialStatePropertyAll<Color>(Color(0xfffffff3)), |
| overlayColor: MaterialStatePropertyAll<Color>(Color(0xfffffff4)), |
| side: MaterialStatePropertyAll<BorderSide>(BorderSide(width: 2.0, color: Color(0xfffffff5))), |
| shape: MaterialStatePropertyAll<OutlinedBorder>(StadiumBorder()), |
| padding: MaterialStatePropertyAll<EdgeInsets>(EdgeInsets.all(16.0)), |
| textStyle: MaterialStatePropertyAll<TextStyle>(TextStyle(fontSize: 24.0)), |
| hintStyle: MaterialStatePropertyAll<TextStyle>(TextStyle(fontSize: 16.0)), |
| constraints: BoxConstraints(minWidth: 350, maxWidth: 850), |
| ).debugFillProperties(builder); |
| |
| final List<String> description = builder.properties |
| .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) |
| .map((DiagnosticsNode node) => node.toString()) |
| .toList(); |
| |
| expect(description[0], 'elevation: MaterialStatePropertyAll(3.0)'); |
| expect(description[1], 'backgroundColor: MaterialStatePropertyAll(Color(0xfffffff1))'); |
| expect(description[2], 'shadowColor: MaterialStatePropertyAll(Color(0xfffffff2))'); |
| expect(description[3], 'surfaceTintColor: MaterialStatePropertyAll(Color(0xfffffff3))'); |
| expect(description[4], 'overlayColor: MaterialStatePropertyAll(Color(0xfffffff4))'); |
| expect(description[5], 'side: MaterialStatePropertyAll(BorderSide(color: Color(0xfffffff5), width: 2.0))'); |
| expect(description[6], 'shape: MaterialStatePropertyAll(StadiumBorder(BorderSide(width: 0.0, style: none)))'); |
| expect(description[7], 'padding: MaterialStatePropertyAll(EdgeInsets.all(16.0))'); |
| expect(description[8], 'textStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 24.0))'); |
| expect(description[9], 'hintStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 16.0))'); |
| expect(description[10], 'constraints: BoxConstraints(350.0<=w<=850.0, 0.0<=h<=Infinity)'); |
| }); |
| |
| group('[Theme, SearchBarTheme, SearchBar properties overrides]', () { |
| const double elevationValue = 5.0; |
| const Color backgroundColorValue = Color(0xff000001); |
| const Color shadowColorValue = Color(0xff000001); |
| const Color surfaceTintColorValue = Color(0xff000001); |
| const Color overlayColorValue = Color(0xff000001); |
| const BorderSide sideValue = BorderSide(color: Color(0xff000004), width: 2.0); |
| const OutlinedBorder shapeValue = RoundedRectangleBorder(side: sideValue, borderRadius: BorderRadius.all(Radius.circular(2.0))); |
| const EdgeInsets paddingValue = EdgeInsets.symmetric(horizontal: 16.0); |
| const TextStyle textStyleValue = TextStyle(color: Color(0xff000005), fontSize: 20.0); |
| const TextStyle hintStyleValue = TextStyle(color: Color(0xff000006), fontSize: 18.0); |
| |
| const MaterialStateProperty<double?> elevation = MaterialStatePropertyAll<double>(elevationValue); |
| const MaterialStateProperty<Color?> backgroundColor = MaterialStatePropertyAll<Color>(backgroundColorValue); |
| const MaterialStateProperty<Color?> shadowColor = MaterialStatePropertyAll<Color>(shadowColorValue); |
| const MaterialStateProperty<Color?> surfaceTintColor = MaterialStatePropertyAll<Color>(surfaceTintColorValue); |
| const MaterialStateProperty<Color?> overlayColor = MaterialStatePropertyAll<Color>(overlayColorValue); |
| const MaterialStateProperty<BorderSide?> side = MaterialStatePropertyAll<BorderSide>(sideValue); |
| const MaterialStateProperty<OutlinedBorder?> shape = MaterialStatePropertyAll<OutlinedBorder>(shapeValue); |
| const MaterialStateProperty<EdgeInsetsGeometry?> padding = MaterialStatePropertyAll<EdgeInsets>(paddingValue); |
| const MaterialStateProperty<TextStyle?> textStyle = MaterialStatePropertyAll<TextStyle>(textStyleValue); |
| const MaterialStateProperty<TextStyle?> hintStyle = MaterialStatePropertyAll<TextStyle>(hintStyleValue); |
| const BoxConstraints constraints = BoxConstraints(minWidth: 250.0, maxWidth: 300.0, minHeight: 80.0); |
| |
| const SearchBarThemeData searchBarTheme = SearchBarThemeData( |
| elevation: elevation, |
| backgroundColor: backgroundColor, |
| shadowColor: shadowColor, |
| surfaceTintColor: surfaceTintColor, |
| overlayColor: overlayColor, |
| side: side, |
| shape: shape, |
| padding: padding, |
| textStyle: textStyle, |
| hintStyle: hintStyle, |
| constraints: constraints, |
| ); |
| |
| Widget buildFrame({ |
| bool useSearchBarProperties = false, |
| SearchBarThemeData? searchBarThemeData, |
| SearchBarThemeData? overallTheme |
| }) { |
| final Widget child = Builder( |
| builder: (BuildContext context) { |
| if (!useSearchBarProperties) { |
| return const SearchBar( |
| hintText: 'hint', |
| leading: Icon(Icons.search), |
| trailing: <Widget>[ Icon(Icons.menu)], |
| ); |
| } |
| return const SearchBar( |
| hintText: 'hint', |
| leading: Icon(Icons.search), |
| trailing: <Widget>[ Icon(Icons.menu)], |
| elevation: elevation, |
| backgroundColor: backgroundColor, |
| shadowColor: shadowColor, |
| surfaceTintColor: surfaceTintColor, |
| overlayColor: overlayColor, |
| side: side, |
| shape: shape, |
| padding: padding, |
| textStyle: textStyle, |
| hintStyle: hintStyle, |
| constraints: constraints, |
| ); |
| }, |
| ); |
| return MaterialApp( |
| theme: ThemeData.from( |
| colorScheme: const ColorScheme.light(), useMaterial3: true) |
| .copyWith( |
| searchBarTheme: overallTheme, |
| ), |
| home: Scaffold( |
| body: Center( |
| // If the SearchBarThemeData widget is present, it's used |
| // instead of the Theme's ThemeData.searchBarTheme. |
| child: searchBarThemeData == null ? child : SearchBarTheme( |
| data: searchBarThemeData, |
| child: child, |
| ), |
| ), |
| ), |
| ); |
| } |
| |
| final Finder findMaterial = find.descendant( |
| of: find.byType(SearchBar), |
| matching: find.byType(Material), |
| ); |
| |
| final Finder findInkWell = find.descendant( |
| of: find.byType(SearchBar), |
| matching: find.byType(InkWell), |
| ); |
| |
| const Set<MaterialState> hovered = <MaterialState>{ MaterialState.hovered}; |
| const Set<MaterialState> focused = <MaterialState>{ MaterialState.focused}; |
| const Set<MaterialState> pressed = <MaterialState>{ MaterialState.pressed}; |
| |
| Future<void> checkSearchBar(WidgetTester tester) async { |
| final Material material = tester.widget<Material>(findMaterial); |
| final InkWell inkWell = tester.widget<InkWell>(findInkWell); |
| expect(material.elevation, elevationValue); |
| expect(material.color, backgroundColorValue); |
| expect(material.shadowColor, shadowColorValue); |
| expect(material.surfaceTintColor, surfaceTintColorValue); |
| expect(material.shape, shapeValue); |
| expect(inkWell.overlayColor!.resolve(hovered), overlayColor.resolve(hovered)); |
| expect(inkWell.overlayColor!.resolve(focused), overlayColor.resolve(focused)); |
| expect(inkWell.overlayColor!.resolve(pressed), overlayColor.resolve(pressed)); |
| expect(inkWell.customBorder, shapeValue); |
| |
| expect(tester.getSize(find.byType(SearchBar)), const Size(300.0, 80.0)); |
| |
| final Text hintText = tester.widget(find.text('hint')); |
| expect(hintText.style?.color, hintStyleValue.color); |
| expect(hintText.style?.fontSize, hintStyleValue.fontSize); |
| |
| await tester.enterText(find.byType(TextField), 'input'); |
| final EditableText inputText = tester.widget(find.text('input')); |
| expect(inputText.style.color, textStyleValue.color); |
| expect(inputText.style.fontSize, textStyleValue.fontSize); |
| |
| final Rect barRect = tester.getRect(find.byType(SearchBar)); |
| final Rect leadingRect = tester.getRect(find.byIcon(Icons.search)); |
| final Rect textFieldRect = tester.getRect(find.byType(TextField)); |
| final Rect trailingRect = tester.getRect(find.byIcon(Icons.menu)); |
| |
| expect(barRect.left, leadingRect.left - 16.0); |
| expect(leadingRect.right, textFieldRect.left - 16.0); |
| expect(textFieldRect.right, trailingRect.left - 16.0); |
| expect(trailingRect.right, barRect.right - 16.0); |
| } |
| |
| testWidgetsWithLeakTracking('SearchBar properties overrides defaults', (WidgetTester tester) async { |
| await tester.pumpWidget(buildFrame(useSearchBarProperties: true)); |
| await tester.pumpAndSettle(); // allow the animations to finish |
| checkSearchBar(tester); |
| }); |
| |
| testWidgetsWithLeakTracking('SearchBar theme data overrides defaults', (WidgetTester tester) async { |
| await tester.pumpWidget(buildFrame(searchBarThemeData: searchBarTheme)); |
| await tester.pumpAndSettle(); |
| checkSearchBar(tester); |
| }); |
| |
| testWidgetsWithLeakTracking('Overall Theme SearchBar theme overrides defaults', (WidgetTester tester) async { |
| await tester.pumpWidget(buildFrame(overallTheme: searchBarTheme)); |
| await tester.pumpAndSettle(); |
| checkSearchBar(tester); |
| }); |
| |
| // Same as the previous tests with empty SearchBarThemeData's instead of null. |
| |
| testWidgetsWithLeakTracking('SearchBar properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { |
| await tester.pumpWidget(buildFrame(useSearchBarProperties: true, |
| searchBarThemeData: const SearchBarThemeData(), |
| overallTheme: const SearchBarThemeData())); |
| await tester.pumpAndSettle(); // allow the animations to finish |
| checkSearchBar(tester); |
| }); |
| |
| testWidgetsWithLeakTracking('SearchBar theme overrides defaults and overall theme', (WidgetTester tester) async { |
| await tester.pumpWidget(buildFrame(searchBarThemeData: searchBarTheme, |
| overallTheme: const SearchBarThemeData())); |
| await tester.pumpAndSettle(); // allow the animations to finish |
| checkSearchBar(tester); |
| }); |
| |
| testWidgetsWithLeakTracking('Overall Theme SearchBar theme overrides defaults and null theme', (WidgetTester tester) async { |
| await tester.pumpWidget(buildFrame(overallTheme: searchBarTheme)); |
| await tester.pumpAndSettle(); // allow the animations to finish |
| checkSearchBar(tester); |
| }); |
| }); |
| } |