| // 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/cupertino.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| void main() { |
| testWidgets('default search field has a border radius', (WidgetTester tester) async { |
| await tester.pumpWidget(const CupertinoApp(home: Center(child: CupertinoSearchTextField()))); |
| |
| final decoration = |
| tester |
| .widget<DecoratedBox>( |
| find.descendant( |
| of: find.byType(CupertinoSearchTextField), |
| matching: find.byType(DecoratedBox), |
| ), |
| ) |
| .decoration |
| as BoxDecoration; |
| |
| expect(decoration.borderRadius, const BorderRadius.all(Radius.circular(9))); |
| }); |
| |
| testWidgets('decoration overrides default background color', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Center( |
| child: CupertinoSearchTextField( |
| decoration: BoxDecoration(color: Color.fromARGB(1, 1, 1, 1)), |
| ), |
| ), |
| ), |
| ); |
| |
| final decoration = |
| tester |
| .widget<DecoratedBox>( |
| find.descendant( |
| of: find.byType(CupertinoSearchTextField), |
| matching: find.byType(DecoratedBox), |
| ), |
| ) |
| .decoration |
| as BoxDecoration; |
| |
| expect(decoration.color, const Color.fromARGB(1, 1, 1, 1)); |
| }); |
| |
| testWidgets('decoration overrides default border radius', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Center( |
| child: CupertinoSearchTextField( |
| decoration: BoxDecoration(borderRadius: BorderRadius.zero), |
| ), |
| ), |
| ), |
| ); |
| |
| final decoration = |
| tester |
| .widget<DecoratedBox>( |
| find.descendant( |
| of: find.byType(CupertinoSearchTextField), |
| matching: find.byType(DecoratedBox), |
| ), |
| ) |
| .decoration |
| as BoxDecoration; |
| |
| expect(decoration.borderRadius, BorderRadius.zero); |
| }); |
| |
| testWidgets('text entries are padded by default', (WidgetTester tester) async { |
| final controller = TextEditingController(text: 'initial'); |
| addTearDown(controller.dispose); |
| await tester.pumpWidget( |
| CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(controller: controller)), |
| ), |
| ); |
| |
| expect( |
| tester.getTopLeft(find.text('initial')) - |
| tester.getTopLeft(find.byType(CupertinoSearchTextField)), |
| const Offset(31.5, 9.5), |
| ); |
| }); |
| |
| testWidgets('can change keyboard type', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(keyboardType: TextInputType.number)), |
| ), |
| ); |
| await tester.tap(find.byType(CupertinoSearchTextField)); |
| await tester.showKeyboard(find.byType(CupertinoSearchTextField)); |
| expect( |
| (tester.testTextInput.setClientArgs!['inputType'] as Map<String, dynamic>)['name'], |
| equals('TextInputType.number'), |
| ); |
| }); |
| |
| testWidgets('can control text content via controller', (WidgetTester tester) async { |
| final controller = TextEditingController(); |
| addTearDown(controller.dispose); |
| |
| await tester.pumpWidget( |
| CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(controller: controller)), |
| ), |
| ); |
| |
| controller.text = 'controller text'; |
| await tester.pump(); |
| |
| expect(find.text('controller text'), findsOneWidget); |
| |
| controller.text = ''; |
| await tester.pump(); |
| |
| expect(find.text('controller text'), findsNothing); |
| }); |
| |
| testWidgets('placeholder color', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| theme: CupertinoThemeData(brightness: Brightness.dark), |
| home: Center(child: CupertinoSearchTextField()), |
| ), |
| ); |
| |
| Text placeholder = tester.widget(find.text('Search')); |
| expect(placeholder.style!.color!.value, CupertinoColors.secondaryLabel.darkColor.value); |
| |
| await tester.pumpAndSettle(); |
| |
| await tester.pumpWidget( |
| const CupertinoApp( |
| theme: CupertinoThemeData(brightness: Brightness.light), |
| home: Center(child: CupertinoSearchTextField()), |
| ), |
| ); |
| |
| placeholder = tester.widget(find.text('Search')); |
| expect(placeholder.style!.color!.value, CupertinoColors.secondaryLabel.color.value); |
| }); |
| |
| testWidgets("placeholderStyle modifies placeholder's style and doesn't affect text's style", ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Center( |
| child: CupertinoSearchTextField( |
| placeholder: 'placeholder', |
| style: TextStyle(color: Color(0x00FFFFFF), fontWeight: FontWeight.w300), |
| placeholderStyle: TextStyle(color: Color(0xAAFFFFFF), fontWeight: FontWeight.w600), |
| ), |
| ), |
| ), |
| ); |
| |
| final Text placeholder = tester.widget(find.text('placeholder')); |
| expect(placeholder.style!.color, const Color(0xAAFFFFFF)); |
| expect(placeholder.style!.fontWeight, FontWeight.w600); |
| |
| await tester.enterText(find.byType(CupertinoSearchTextField), 'input'); |
| await tester.pump(); |
| |
| final EditableText inputText = tester.widget(find.text('input')); |
| expect(inputText.style.color, const Color(0x00FFFFFF)); |
| expect(inputText.style.fontWeight, FontWeight.w300); |
| }); |
| |
| testWidgets('prefix widget is in front of the text', (WidgetTester tester) async { |
| final controller = TextEditingController(text: 'input'); |
| addTearDown(controller.dispose); |
| |
| await tester.pumpWidget( |
| CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(controller: controller)), |
| ), |
| ); |
| |
| expect( |
| tester.getTopRight(find.byIcon(CupertinoIcons.search)).dx + 5.5, |
| tester.getTopLeft(find.byType(EditableText)).dx, |
| ); |
| |
| expect( |
| tester.getTopLeft(find.byType(EditableText)).dx, |
| tester.getTopLeft(find.byType(CupertinoSearchTextField)).dx + |
| tester.getSize(find.byIcon(CupertinoIcons.search)).width + |
| 11.5, |
| ); |
| }); |
| |
| testWidgets('suffix widget is after the text', (WidgetTester tester) async { |
| final controller = TextEditingController(text: 'Hi'); |
| addTearDown(controller.dispose); |
| |
| await tester.pumpWidget( |
| CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(controller: controller)), |
| ), |
| ); |
| |
| expect( |
| tester.getTopRight(find.byType(EditableText)).dx + 5.5, |
| tester.getTopLeft(find.byIcon(CupertinoIcons.xmark_circle_fill)).dx, |
| ); |
| |
| expect( |
| tester.getTopRight(find.byType(EditableText)).dx, |
| tester.getTopRight(find.byType(CupertinoSearchTextField)).dx - |
| tester.getSize(find.byIcon(CupertinoIcons.xmark_circle_fill)).width - |
| 10.5, |
| ); |
| }); |
| |
| testWidgets('prefix widget visibility', (WidgetTester tester) async { |
| const prefixIcon = Key('prefix'); |
| |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Center( |
| child: CupertinoSearchTextField( |
| prefixIcon: SizedBox(key: prefixIcon, width: 50, height: 50), |
| ), |
| ), |
| ), |
| ); |
| |
| expect(find.byIcon(CupertinoIcons.search), findsNothing); |
| expect(find.byKey(prefixIcon), findsOneWidget); |
| |
| await tester.enterText(find.byType(CupertinoSearchTextField), 'text input'); |
| await tester.pump(); |
| |
| expect(find.text('text input'), findsOneWidget); |
| expect(find.byIcon(CupertinoIcons.search), findsNothing); |
| expect(find.byKey(prefixIcon), findsOneWidget); |
| }); |
| |
| testWidgets('suffix widget respects visibility mode', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(suffixMode: OverlayVisibilityMode.notEditing)), |
| ), |
| ); |
| |
| expect(find.byIcon(CupertinoIcons.xmark_circle_fill), findsOneWidget); |
| |
| await tester.enterText(find.byType(CupertinoSearchTextField), 'text input'); |
| await tester.pump(); |
| |
| expect(find.text('text input'), findsOneWidget); |
| expect(find.byIcon(CupertinoIcons.xmark_circle_fill), findsNothing); |
| }); |
| |
| testWidgets('Default prefix and suffix insets are aligned', (WidgetTester tester) async { |
| await tester.pumpWidget(const CupertinoApp(home: Center(child: CupertinoSearchTextField()))); |
| |
| expect(find.byIcon(CupertinoIcons.search), findsOneWidget); |
| expect(find.byIcon(CupertinoIcons.xmark_circle_fill), findsNothing); |
| |
| await tester.enterText(find.byType(CupertinoSearchTextField), 'text input'); |
| await tester.pump(); |
| |
| expect(find.text('text input'), findsOneWidget); |
| expect(find.byIcon(CupertinoIcons.search), findsOneWidget); |
| expect(find.byIcon(CupertinoIcons.xmark_circle_fill), findsOneWidget); |
| |
| expect(tester.getTopLeft(find.byIcon(CupertinoIcons.search)), const Offset(6.0, 290.0)); |
| expect( |
| tester.getTopLeft(find.byIcon(CupertinoIcons.xmark_circle_fill)), |
| const Offset(775.0, 290.0), |
| ); |
| |
| expect(tester.getBottomRight(find.byIcon(CupertinoIcons.search)), const Offset(26.0, 310.0)); |
| expect( |
| tester.getBottomRight(find.byIcon(CupertinoIcons.xmark_circle_fill)), |
| const Offset(795.0, 310.0), |
| ); |
| }); |
| |
| testWidgets('clear button shows with right visibility mode', (WidgetTester tester) async { |
| var controller = TextEditingController(); |
| addTearDown(controller.dispose); |
| await tester.pumpWidget( |
| CupertinoApp( |
| home: Center( |
| child: CupertinoSearchTextField( |
| controller: controller, |
| placeholder: 'placeholder does not affect clear button', |
| ), |
| ), |
| ), |
| ); |
| |
| expect(find.byIcon(CupertinoIcons.xmark_circle_fill), findsNothing); |
| |
| await tester.enterText(find.byType(CupertinoSearchTextField), 'text input'); |
| await tester.pump(); |
| |
| expect(find.byIcon(CupertinoIcons.xmark_circle_fill), findsOneWidget); |
| expect(find.text('text input'), findsOneWidget); |
| |
| controller = TextEditingController(); |
| addTearDown(controller.dispose); |
| await tester.pumpWidget( |
| CupertinoApp( |
| home: Center( |
| child: CupertinoSearchTextField( |
| controller: controller, |
| placeholder: 'placeholder does not affect clear button', |
| suffixMode: OverlayVisibilityMode.notEditing, |
| ), |
| ), |
| ), |
| ); |
| expect(find.byIcon(CupertinoIcons.xmark_circle_fill), findsOneWidget); |
| |
| controller.text = 'input'; |
| await tester.pump(); |
| |
| expect(find.byIcon(CupertinoIcons.xmark_circle_fill), findsNothing); |
| }); |
| |
| testWidgets('clear button removes text', (WidgetTester tester) async { |
| final controller = TextEditingController(); |
| addTearDown(controller.dispose); |
| await tester.pumpWidget( |
| CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(controller: controller)), |
| ), |
| ); |
| |
| controller.text = 'text entry'; |
| await tester.pump(); |
| |
| await tester.tap(find.byIcon(CupertinoIcons.xmark_circle_fill)); |
| await tester.pump(); |
| |
| expect(controller.text, ''); |
| expect(find.text('Search'), findsOneWidget); |
| expect(find.text('text entry'), findsNothing); |
| expect(find.byIcon(CupertinoIcons.xmark_circle_fill), findsNothing); |
| }); |
| |
| testWidgets('tapping clear button also calls onChanged when text not empty', ( |
| WidgetTester tester, |
| ) async { |
| var value = 'text entry'; |
| final controller = TextEditingController(); |
| addTearDown(controller.dispose); |
| await tester.pumpWidget( |
| CupertinoApp( |
| home: Center( |
| child: CupertinoSearchTextField( |
| controller: controller, |
| placeholder: 'placeholder', |
| onChanged: (String newValue) => value = newValue, |
| ), |
| ), |
| ), |
| ); |
| |
| controller.text = value; |
| await tester.pump(); |
| |
| await tester.tap(find.byIcon(CupertinoIcons.xmark_circle_fill)); |
| await tester.pump(); |
| |
| expect(controller.text, isEmpty); |
| expect(find.text('text entry'), findsNothing); |
| expect(value, isEmpty); |
| }); |
| |
| testWidgets('RTL puts attachments to the right places', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Directionality( |
| textDirection: TextDirection.rtl, |
| child: Center(child: CupertinoSearchTextField(suffixMode: OverlayVisibilityMode.always)), |
| ), |
| ), |
| ); |
| |
| expect(tester.getTopLeft(find.byIcon(CupertinoIcons.search)).dx, 800.0 - 26.0); |
| |
| expect(tester.getTopRight(find.byIcon(CupertinoIcons.xmark_circle_fill)).dx, 25.0); |
| }); |
| |
| testWidgets('Can modify prefix and suffix insets', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Center( |
| child: CupertinoSearchTextField( |
| suffixMode: OverlayVisibilityMode.always, |
| prefixInsets: EdgeInsets.zero, |
| suffixInsets: EdgeInsets.zero, |
| ), |
| ), |
| ), |
| ); |
| |
| expect(tester.getTopLeft(find.byIcon(CupertinoIcons.search)).dx, 0.0); |
| |
| expect(tester.getTopRight(find.byIcon(CupertinoIcons.xmark_circle_fill)).dx, 800.0); |
| }); |
| |
| testWidgets('custom suffix onTap overrides default clearing behavior', ( |
| WidgetTester tester, |
| ) async { |
| final controller = TextEditingController(text: 'Text'); |
| addTearDown(controller.dispose); |
| await tester.pumpWidget( |
| CupertinoApp( |
| home: Center( |
| child: CupertinoSearchTextField(controller: controller, onSuffixTap: () {}), |
| ), |
| ), |
| ); |
| |
| await tester.pump(); |
| |
| await tester.tap(find.byIcon(CupertinoIcons.xmark_circle_fill)); |
| await tester.pump(); |
| |
| expect(controller.text, isNotEmpty); |
| expect(find.text('Text'), findsOneWidget); |
| }); |
| |
| testWidgets('onTap is properly forwarded to the inner text field', (WidgetTester tester) async { |
| var onTapCallCount = 0; |
| |
| // onTap can be null. |
| await tester.pumpWidget(const CupertinoApp(home: Center(child: CupertinoSearchTextField()))); |
| |
| // onTap callback is called if not null. |
| await tester.pumpWidget( |
| CupertinoApp( |
| home: Center( |
| child: CupertinoSearchTextField( |
| onTap: () { |
| onTapCallCount++; |
| }, |
| ), |
| ), |
| ), |
| ); |
| |
| expect(onTapCallCount, 0); |
| await tester.tap(find.byType(CupertinoTextField)); |
| expect(onTapCallCount, 1); |
| }); |
| |
| testWidgets('autocorrect is properly forwarded to the inner text field', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| const CupertinoApp(home: Center(child: CupertinoSearchTextField(autocorrect: false))), |
| ); |
| |
| final CupertinoTextField textField = tester.widget(find.byType(CupertinoTextField)); |
| expect(textField.autocorrect, false); |
| }); |
| |
| testWidgets('enabled is properly forwarded to the inner text field', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const CupertinoApp(home: Center(child: CupertinoSearchTextField(enabled: false))), |
| ); |
| |
| final CupertinoTextField textField = tester.widget(find.byType(CupertinoTextField)); |
| expect(textField.enabled, false); |
| }); |
| |
| testWidgets('textInputAction is set to TextInputAction.search by default', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget(const CupertinoApp(home: Center(child: CupertinoSearchTextField()))); |
| |
| final CupertinoTextField textField = tester.widget(find.byType(CupertinoTextField)); |
| expect(textField.textInputAction, TextInputAction.search); |
| }); |
| |
| testWidgets('autofocus:true gives focus to the widget', (WidgetTester tester) async { |
| final focusNode = FocusNode(); |
| addTearDown(focusNode.dispose); |
| await tester.pumpWidget( |
| CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(focusNode: focusNode, autofocus: true)), |
| ), |
| ); |
| |
| expect(focusNode.hasFocus, isTrue); |
| }); |
| |
| testWidgets('smartQuotesType is properly forwarded to the inner text field', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(smartQuotesType: SmartQuotesType.disabled)), |
| ), |
| ); |
| |
| final CupertinoTextField textField = tester.widget(find.byType(CupertinoTextField)); |
| expect(textField.smartQuotesType, SmartQuotesType.disabled); |
| }); |
| |
| testWidgets('smartDashesType is properly forwarded to the inner text field', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(smartDashesType: SmartDashesType.disabled)), |
| ), |
| ); |
| |
| final CupertinoTextField textField = tester.widget(find.byType(CupertinoTextField)); |
| expect(textField.smartDashesType, SmartDashesType.disabled); |
| }); |
| |
| testWidgets('enableIMEPersonalizedLearning is properly forwarded to the inner text field', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(enableIMEPersonalizedLearning: false)), |
| ), |
| ); |
| |
| final CupertinoTextField textField = tester.widget(find.byType(CupertinoTextField)); |
| expect(textField.enableIMEPersonalizedLearning, false); |
| }); |
| |
| testWidgets('cursorWidth is properly forwarded to the inner text field', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| const CupertinoApp(home: Center(child: CupertinoSearchTextField(cursorWidth: 1))), |
| ); |
| |
| final CupertinoTextField textField = tester.widget(find.byType(CupertinoTextField)); |
| expect(textField.cursorWidth, 1); |
| }); |
| |
| testWidgets('cursorHeight is properly forwarded to the inner text field', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| const CupertinoApp(home: Center(child: CupertinoSearchTextField(cursorHeight: 10))), |
| ); |
| |
| final CupertinoTextField textField = tester.widget(find.byType(CupertinoTextField)); |
| expect(textField.cursorHeight, 10); |
| }); |
| |
| testWidgets('cursorRadius is properly forwarded to the inner text field', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(cursorRadius: Radius.circular(1.0))), |
| ), |
| ); |
| |
| final CupertinoTextField textField = tester.widget(find.byType(CupertinoTextField)); |
| expect(textField.cursorRadius, const Radius.circular(1.0)); |
| }); |
| |
| testWidgets('cursorOpacityAnimates is properly forwarded to the inner text field', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(cursorOpacityAnimates: false)), |
| ), |
| ); |
| |
| final CupertinoTextField textField = tester.widget(find.byType(CupertinoTextField)); |
| expect(textField.cursorOpacityAnimates, false); |
| }); |
| |
| testWidgets('cursorColor is properly forwarded to the inner text field', ( |
| WidgetTester tester, |
| ) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(cursorColor: Color.fromARGB(255, 255, 0, 0))), |
| ), |
| ); |
| |
| final CupertinoTextField textField = tester.widget(find.byType(CupertinoTextField)); |
| expect(textField.cursorColor, const Color.fromARGB(255, 255, 0, 0)); |
| }); |
| |
| testWidgets('Icons and placeholder fade while resizing on scroll', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const CupertinoApp( |
| home: CupertinoPageScaffold( |
| child: CustomScrollView( |
| slivers: <Widget>[ |
| SliverResizingHeader( |
| child: CupertinoSearchTextField(suffixMode: OverlayVisibilityMode.always), |
| ), |
| SliverFillRemaining(), |
| ], |
| ), |
| ), |
| ), |
| ); |
| |
| final Finder searchTextFieldFinder = find.byType(CupertinoSearchTextField); |
| expect(searchTextFieldFinder, findsOneWidget); |
| |
| final Finder prefixIconFinder = find.descendant( |
| of: searchTextFieldFinder, |
| matching: find.byIcon(CupertinoIcons.search), |
| ); |
| final Finder suffixIconFinder = find.descendant( |
| of: searchTextFieldFinder, |
| matching: find.byIcon(CupertinoIcons.xmark_circle_fill), |
| ); |
| final Finder placeholderFinder = find.descendant( |
| of: searchTextFieldFinder, |
| matching: find.text('Search'), |
| ); |
| expect(prefixIconFinder, findsOneWidget); |
| expect(suffixIconFinder, findsOneWidget); |
| expect(placeholderFinder, findsOneWidget); |
| |
| // Initially, the icons are fully opaque. |
| expect( |
| tester |
| .widget<Opacity>(find.ancestor(of: prefixIconFinder, matching: find.byType(Opacity))) |
| .opacity, |
| equals(1.0), |
| ); |
| expect( |
| tester |
| .widget<Opacity>(find.ancestor(of: suffixIconFinder, matching: find.byType(Opacity))) |
| .opacity, |
| equals(1.0), |
| ); |
| // The default placeholder color is semi-transparent. |
| expect(tester.widget<Text>(placeholderFinder).style?.color?.a, equals(0.6)); |
| |
| final double searchTextFieldHeight = tester.getSize(searchTextFieldFinder).height; |
| |
| final TestGesture scrollGesture1 = await tester.startGesture( |
| tester.getCenter(find.byType(CustomScrollView)), |
| ); |
| await scrollGesture1.moveBy(Offset(0, -searchTextFieldHeight / 5)); |
| await scrollGesture1.up(); |
| await tester.pumpAndSettle(); |
| |
| // The icons and placeholder text start to fade. |
| expect( |
| tester |
| .widget<Opacity>(find.ancestor(of: prefixIconFinder, matching: find.byType(Opacity))) |
| .opacity, |
| greaterThan(0.0), |
| ); |
| expect( |
| tester |
| .widget<Opacity>(find.ancestor(of: prefixIconFinder, matching: find.byType(Opacity))) |
| .opacity, |
| lessThan(1.0), |
| ); |
| expect( |
| tester |
| .widget<Opacity>(find.ancestor(of: suffixIconFinder, matching: find.byType(Opacity))) |
| .opacity, |
| greaterThan(0.0), |
| ); |
| expect( |
| tester |
| .widget<Opacity>(find.ancestor(of: suffixIconFinder, matching: find.byType(Opacity))) |
| .opacity, |
| lessThan(1.0), |
| ); |
| expect(tester.widget<Text>(placeholderFinder).style?.color?.a, greaterThan(0.0)); |
| expect(tester.widget<Text>(placeholderFinder).style?.color?.a, lessThan(1.0)); |
| |
| final TestGesture scrollGesture2 = await tester.startGesture( |
| tester.getCenter(find.byType(CustomScrollView)), |
| ); |
| await scrollGesture2.moveBy(Offset(0, -4 * searchTextFieldHeight / 5)); |
| await scrollGesture2.up(); |
| await tester.pumpAndSettle(); |
| |
| // The icons and placeholder text have faded completely. |
| expect( |
| tester |
| .widget<Opacity>(find.ancestor(of: prefixIconFinder, matching: find.byType(Opacity))) |
| .opacity, |
| equals(0.0), |
| ); |
| expect( |
| tester |
| .widget<Opacity>(find.ancestor(of: suffixIconFinder, matching: find.byType(Opacity))) |
| .opacity, |
| equals(0.0), |
| ); |
| expect(tester.widget<Text>(placeholderFinder).style?.color?.a, equals(0.0)); |
| }); |
| |
| testWidgets('Top padding animates while resizing on scroll', (WidgetTester tester) async { |
| const TextDirection direction = TextDirection.ltr; |
| await tester.pumpWidget( |
| const Directionality( |
| textDirection: direction, |
| child: CupertinoApp( |
| home: CupertinoPageScaffold( |
| child: CustomScrollView( |
| slivers: <Widget>[ |
| SliverResizingHeader(child: CupertinoSearchTextField()), |
| SliverFillRemaining(), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| final Finder searchTextFieldFinder = find.byType(CupertinoSearchTextField); |
| expect(searchTextFieldFinder, findsOneWidget); |
| |
| final double initialPadding = tester |
| .widget<CupertinoTextField>( |
| find.descendant(of: searchTextFieldFinder, matching: find.byType(CupertinoTextField)), |
| ) |
| .padding |
| .resolve(direction) |
| .top; |
| expect(initialPadding, equals(8.0)); |
| |
| final double searchTextFieldHeight = tester.getSize(searchTextFieldFinder).height; |
| |
| final TestGesture scrollGesture = await tester.startGesture( |
| tester.getCenter(find.byType(CustomScrollView)), |
| ); |
| await scrollGesture.moveBy(Offset(0, -searchTextFieldHeight / 5)); |
| await scrollGesture.up(); |
| await tester.pumpAndSettle(); |
| |
| expect( |
| tester |
| .widget<CupertinoTextField>( |
| find.descendant(of: searchTextFieldFinder, matching: find.byType(CupertinoTextField)), |
| ) |
| .padding |
| .resolve(direction) |
| .top, |
| lessThan(initialPadding), |
| ); |
| }); |
| |
| testWidgets('Fades and animates insets on scroll if search field starts out collapsed', ( |
| WidgetTester tester, |
| ) async { |
| const TextDirection direction = TextDirection.ltr; |
| const double scrollOffset = 200; |
| await tester.pumpWidget( |
| const Directionality( |
| textDirection: direction, |
| child: CupertinoApp( |
| home: CupertinoPageScaffold( |
| child: CustomScrollView( |
| slivers: <Widget>[ |
| CupertinoSliverNavigationBar.search( |
| largeTitle: Text('Large title'), |
| searchField: CupertinoSearchTextField(), |
| ), |
| SliverToBoxAdapter(child: SizedBox(height: 1000)), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| final Finder searchTextFieldFinder = find.byType(CupertinoSearchTextField); |
| expect(searchTextFieldFinder, findsOneWidget); |
| |
| final double searchTextFieldHeight = tester.getSize(searchTextFieldFinder).height; |
| await tester.tap(find.widgetWithText(CupertinoSearchTextField, 'Search'), warnIfMissed: false); |
| |
| final TestGesture scrollGesture1 = await tester.startGesture( |
| tester.getCenter(find.byType(CustomScrollView)), |
| ); |
| await scrollGesture1.moveBy(const Offset(0, -scrollOffset)); |
| await scrollGesture1.up(); |
| await tester.pumpAndSettle(); |
| |
| expect(find.text('Cancel'), findsOneWidget); |
| await tester.tap(find.text('Cancel')); |
| await tester.pumpAndSettle(); |
| |
| final TestGesture scrollGesture2 = await tester.startGesture( |
| tester.getCenter(find.byType(CustomScrollView)), |
| ); |
| await scrollGesture2.moveBy(Offset(0, scrollOffset - searchTextFieldHeight / 2)); |
| await scrollGesture2.up(); |
| await tester.pump(); |
| |
| final Finder prefixIconFinder = find.descendant( |
| of: searchTextFieldFinder, |
| matching: find.byIcon(CupertinoIcons.search), |
| ); |
| |
| // The prefix icon has faded. |
| expect(prefixIconFinder, findsOneWidget); |
| expect( |
| tester |
| .widget<Opacity>(find.ancestor(of: prefixIconFinder, matching: find.byType(Opacity))) |
| .opacity, |
| lessThan(1.0), |
| ); |
| }); |
| |
| testWidgets('Focused search field hides prefix in higher accessibility text scale modes', ( |
| WidgetTester tester, |
| ) async { |
| var scaleFactor = 3.0; |
| const iconSize = 10.0; |
| final focusNode = FocusNode(); |
| addTearDown(focusNode.dispose); |
| late StateSetter setState; |
| |
| await tester.pumpWidget( |
| CupertinoApp( |
| home: StatefulBuilder( |
| builder: (BuildContext context, StateSetter setter) { |
| setState = setter; |
| return MediaQuery.withClampedTextScaling( |
| minScaleFactor: scaleFactor, |
| maxScaleFactor: scaleFactor, |
| child: CupertinoPageScaffold( |
| child: Center( |
| child: CupertinoSearchTextField( |
| placeholder: 'Search', |
| focusNode: focusNode, |
| prefixIcon: const Icon(CupertinoIcons.add), |
| suffixIcon: const Icon(CupertinoIcons.xmark), |
| suffixMode: OverlayVisibilityMode.always, |
| itemSize: iconSize, |
| ), |
| ), |
| ), |
| ); |
| }, |
| ), |
| ), |
| ); |
| |
| final Iterable<RichText> barItems = tester.widgetList<RichText>( |
| find.descendant(of: find.byType(CupertinoSearchTextField), matching: find.byType(RichText)), |
| ); |
| expect(barItems.length, greaterThan(0)); |
| |
| for (final icon in <IconData>[CupertinoIcons.add, CupertinoIcons.xmark]) { |
| expect(tester.getSize(find.byIcon(icon)), Size.square(scaleFactor * iconSize)); |
| } |
| |
| focusNode.requestFocus(); |
| await tester.pumpAndSettle(); |
| |
| // The prefix icon shrinks at higher accessibility text scale modes. |
| expect(tester.getSize(find.byIcon(CupertinoIcons.add)), Size.zero); |
| expect(tester.getSize(find.byIcon(CupertinoIcons.xmark)), Size.square(scaleFactor * iconSize)); |
| |
| setState(() { |
| scaleFactor = 2.9; |
| }); |
| await tester.pumpAndSettle(); |
| |
| // Below the threshold, the prefix icon is displayed. |
| for (final icon in <IconData>[CupertinoIcons.add, CupertinoIcons.xmark]) { |
| expect(tester.getSize(find.byIcon(icon)), Size.square(scaleFactor * iconSize)); |
| } |
| }); |
| |
| testWidgets('CupertinoSearchTextField does not crash at zero area', (WidgetTester tester) async { |
| tester.view.physicalSize = Size.zero; |
| final controller = TextEditingController(text: 'X'); |
| addTearDown(tester.view.reset); |
| addTearDown(controller.dispose); |
| await tester.pumpWidget( |
| CupertinoApp( |
| home: Center(child: CupertinoSearchTextField(controller: controller)), |
| ), |
| ); |
| expect(tester.getSize(find.byType(CupertinoSearchTextField)), Size.zero); |
| controller.selection = const TextSelection.collapsed(offset: 0); |
| await tester.pump(); |
| }); |
| } |