blob: 830431848e6533593d3628f4f85035777184b172 [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/cupertino.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
void main() {
testWidgets('Passes textAlign to underlying CupertinoTextField', (WidgetTester tester) async {
const TextAlign alignment = TextAlign.center;
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
textAlign: alignment,
),
),
),
);
final Finder textFieldFinder = find.byType(CupertinoTextField);
expect(textFieldFinder, findsOneWidget);
final CupertinoTextField textFieldWidget = tester.widget(textFieldFinder);
expect(textFieldWidget.textAlign, alignment);
});
testWidgets('Passes scrollPhysics to underlying TextField', (WidgetTester tester) async {
const ScrollPhysics scrollPhysics = ScrollPhysics();
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
scrollPhysics: scrollPhysics,
),
),
),
);
final Finder textFieldFinder = find.byType(CupertinoTextField);
expect(textFieldFinder, findsOneWidget);
final CupertinoTextField textFieldWidget = tester.widget(textFieldFinder);
expect(textFieldWidget.scrollPhysics, scrollPhysics);
});
testWidgets('Passes textAlignVertical to underlying CupertinoTextField', (WidgetTester tester) async {
const TextAlignVertical textAlignVertical = TextAlignVertical.bottom;
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
textAlignVertical: textAlignVertical,
),
),
),
);
final Finder textFieldFinder = find.byType(CupertinoTextField);
expect(textFieldFinder, findsOneWidget);
final CupertinoTextField textFieldWidget = tester.widget(textFieldFinder);
expect(textFieldWidget.textAlignVertical, textAlignVertical);
});
testWidgets('Passes textInputAction to underlying CupertinoTextField', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
textInputAction: TextInputAction.next,
),
),
),
);
final Finder textFieldFinder = find.byType(CupertinoTextField);
expect(textFieldFinder, findsOneWidget);
final CupertinoTextField textFieldWidget = tester.widget(textFieldFinder);
expect(textFieldWidget.textInputAction, TextInputAction.next);
});
testWidgets('Passes onEditingComplete to underlying CupertinoTextField', (WidgetTester tester) async {
void onEditingComplete() {}
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
onEditingComplete: onEditingComplete,
),
),
),
);
final Finder textFieldFinder = find.byType(CupertinoTextField);
expect(textFieldFinder, findsOneWidget);
final CupertinoTextField textFieldWidget = tester.widget(textFieldFinder);
expect(textFieldWidget.onEditingComplete, onEditingComplete);
});
testWidgets('Passes cursor attributes to underlying CupertinoTextField', (WidgetTester tester) async {
const double cursorWidth = 3.14;
const double cursorHeight = 6.28;
const Radius cursorRadius = Radius.circular(2);
const Color cursorColor = CupertinoColors.systemPurple;
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
cursorWidth: cursorWidth,
cursorHeight: cursorHeight,
cursorColor: cursorColor,
),
),
),
);
final Finder textFieldFinder = find.byType(CupertinoTextField);
expect(textFieldFinder, findsOneWidget);
final CupertinoTextField textFieldWidget = tester.widget(textFieldFinder);
expect(textFieldWidget.cursorWidth, cursorWidth);
expect(textFieldWidget.cursorHeight, cursorHeight);
expect(textFieldWidget.cursorRadius, cursorRadius);
expect(textFieldWidget.cursorColor, cursorColor);
});
testWidgets('onFieldSubmit callbacks are called', (WidgetTester tester) async {
bool called = false;
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
onFieldSubmitted: (String value) {
called = true;
},
),
),
),
);
await tester.showKeyboard(find.byType(CupertinoTextField));
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pump();
expect(called, true);
});
testWidgets('onChanged callbacks are called', (WidgetTester tester) async {
late String value;
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
onChanged: (String v) {
value = v;
},
),
),
),
);
await tester.enterText(find.byType(CupertinoTextField), 'Soup');
await tester.pump();
expect(value, 'Soup');
});
testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async {
int validateCalled = 0;
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
autovalidateMode: AutovalidateMode.always,
validator: (String? value) {
validateCalled++;
return null;
},
),
),
),
);
expect(validateCalled, 1);
await tester.enterText(find.byType(CupertinoTextField), 'a');
await tester.pump();
expect(validateCalled, 2);
});
testWidgets('validate is called if widget is enabled', (WidgetTester tester) async {
int validateCalled = 0;
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
enabled: true,
autovalidateMode: AutovalidateMode.always,
validator: (String? value) {
validateCalled += 1;
return null;
},
),
),
),
);
expect(validateCalled, 1);
await tester.enterText(find.byType(CupertinoTextField), 'a');
await tester.pump();
expect(validateCalled, 2);
});
testWidgets('readonly text form field will hide cursor by default', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
initialValue: 'readonly',
readOnly: true,
),
),
),
);
await tester.showKeyboard(find.byType(CupertinoTextFormFieldRow));
expect(tester.testTextInput.hasAnyClients, false);
await tester.tap(find.byType(CupertinoTextField));
await tester.pump();
expect(tester.testTextInput.hasAnyClients, false);
await tester.longPress(find.text('readonly'));
await tester.pump();
// Context menu should not have paste.
expect(find.byType(CupertinoTextSelectionToolbar), findsOneWidget);
expect(find.text('Paste'), findsNothing);
final EditableTextState editableTextState =
tester.firstState(find.byType(EditableText));
final RenderEditable renderEditable = editableTextState.renderEditable;
// Make sure it does not paint caret for a period of time.
await tester.pump(const Duration(milliseconds: 200));
expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0));
await tester.pump(const Duration(milliseconds: 200));
expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0));
await tester.pump(const Duration(milliseconds: 200));
expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0));
}, skip: isBrowser); // [intended] We do not use Flutter-rendered context menu on the Web.
testWidgets('onTap is called upon tap', (WidgetTester tester) async {
int tapCount = 0;
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
onTap: () {
tapCount += 1;
},
),
),
),
);
expect(tapCount, 0);
await tester.tap(find.byType(CupertinoTextField));
// Wait a bit so they're all single taps and not double taps.
await tester.pump(const Duration(milliseconds: 300));
await tester.tap(find.byType(CupertinoTextField));
await tester.pump(const Duration(milliseconds: 300));
await tester.tap(find.byType(CupertinoTextField));
await tester.pump(const Duration(milliseconds: 300));
expect(tapCount, 3);
});
// Regression test for https://github.com/flutter/flutter/issues/54472.
testWidgets('reset resets the text fields value to the initialValue', (WidgetTester tester) async {
await tester.pumpWidget(CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
initialValue: 'initialValue',
),
),
));
await tester.enterText(find.byType(CupertinoTextFormFieldRow), 'changedValue');
final FormFieldState<String> state = tester.state<FormFieldState<String>>(find.byType(CupertinoTextFormFieldRow));
state.reset();
expect(find.text('changedValue'), findsNothing);
expect(find.text('initialValue'), findsOneWidget);
});
// Regression test for https://github.com/flutter/flutter/issues/54472.
testWidgets('didChange changes text fields value', (WidgetTester tester) async {
await tester.pumpWidget(CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
initialValue: 'initialValue',
),
),
));
expect(find.text('initialValue'), findsOneWidget);
final FormFieldState<String> state = tester
.state<FormFieldState<String>>(find.byType(CupertinoTextFormFieldRow));
state.didChange('changedValue');
expect(find.text('initialValue'), findsNothing);
expect(find.text('changedValue'), findsOneWidget);
});
testWidgets('onChanged callbacks value and FormFieldState.value are sync', (WidgetTester tester) async {
bool called = false;
late FormFieldState<String> state;
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
onChanged: (String value) {
called = true;
expect(value, state.value);
},
),
),
),
);
state = tester
.state<FormFieldState<String>>(find.byType(CupertinoTextFormFieldRow));
await tester.enterText(find.byType(CupertinoTextField), 'Soup');
expect(called, true);
});
testWidgets('autofillHints is passed to super', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
autofillHints: const <String>[AutofillHints.countryName],
),
),
),
);
final CupertinoTextField widget =
tester.widget(find.byType(CupertinoTextField));
expect(widget.autofillHints, equals(const <String>[AutofillHints.countryName]));
});
testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async {
int validateCalled = 0;
await tester.pumpWidget(
CupertinoApp(
home: CupertinoPageScaffold(
child: CupertinoTextFormFieldRow(
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (String? value) {
validateCalled++;
return null;
},
),
),
),
);
expect(validateCalled, 0);
await tester.enterText(find.byType(CupertinoTextField), 'a');
await tester.pump();
expect(validateCalled, 1);
});
testWidgets('AutovalidateMode.always mode shows error from the start', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
initialValue: 'Value',
autovalidateMode: AutovalidateMode.always,
validator: (String? value) => 'Error',
),
),
),
);
final Finder errorTextFinder = find.byType(Text);
expect(errorTextFinder, findsOneWidget);
final Text errorText = tester.widget(errorTextFinder);
expect(errorText.data, 'Error');
});
testWidgets('Shows error text upon invalid input', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(text: '');
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
controller: controller,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (String? value) => 'Error',
),
),
),
);
expect(find.byType(Text), findsNothing);
controller.text = 'Value';
await tester.pumpAndSettle();
final Finder errorTextFinder = find.byType(Text);
expect(errorTextFinder, findsOneWidget);
final Text errorText = tester.widget(errorTextFinder);
expect(errorText.data, 'Error');
});
testWidgets('Shows prefix', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
prefix: const Text('Enter Value'),
),
),
),
);
final Finder errorTextFinder = find.byType(Text);
expect(errorTextFinder, findsOneWidget);
final Text errorText = tester.widget(errorTextFinder);
expect(errorText.data, 'Enter Value');
});
testWidgets('Passes textDirection to underlying CupertinoTextField', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
textDirection: TextDirection.ltr,
),
),
),
);
final Finder ltrTextFieldFinder = find.byType(CupertinoTextField);
expect(ltrTextFieldFinder, findsOneWidget);
final CupertinoTextField ltrTextFieldWidget = tester.widget(ltrTextFieldFinder);
expect(ltrTextFieldWidget.textDirection, TextDirection.ltr);
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: CupertinoTextFormFieldRow(
textDirection: TextDirection.rtl,
),
),
),
);
final Finder rtlTextFieldFinder = find.byType(CupertinoTextField);
expect(rtlTextFieldFinder, findsOneWidget);
final CupertinoTextField rtlTextFieldWidget = tester.widget(rtlTextFieldFinder);
expect(rtlTextFieldWidget.textDirection, TextDirection.rtl);
});
}