blob: d6a259379774848f80de3a110ee220216b7885e5 [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 '../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);
});
});
}