mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Test InputDecoration API examples (#148560)
Add tests for `InputDecoration` API example as part of #130459. Updates examples that use the deprecated MaterialState to use WidgetState. Tests files: `input_decoration.0.dart`, `input_decoration.1.dart`, `input_decoration.2.dart`, `input_decoration.3.dart`, `input_decoration.widget_state.0.dart`, `input_decoration.widget_state.1.dart`, `input_decoration.prefix_icon_constraints.0.dart`, `input_decoration.suffix_icon_constraints.0.dart`, and `input_decoration.label.0.dart`
This commit is contained in:
parent
bfdcb51643
commit
0674f46e9f
@ -325,15 +325,6 @@ final Set<String> _knownMissingTests = <String>{
|
||||
'examples/api/test/material/flexible_space_bar/flexible_space_bar.0_test.dart',
|
||||
'examples/api/test/material/chip/deletable_chip_attributes.on_deleted.0_test.dart',
|
||||
'examples/api/test/material/expansion_panel/expansion_panel_list.expansion_panel_list_radio.0_test.dart',
|
||||
'examples/api/test/material/input_decorator/input_decoration.1_test.dart',
|
||||
'examples/api/test/material/input_decorator/input_decoration.prefix_icon_constraints.0_test.dart',
|
||||
'examples/api/test/material/input_decorator/input_decoration.material_state.0_test.dart',
|
||||
'examples/api/test/material/input_decorator/input_decoration.2_test.dart',
|
||||
'examples/api/test/material/input_decorator/input_decoration.0_test.dart',
|
||||
'examples/api/test/material/input_decorator/input_decoration.label.0_test.dart',
|
||||
'examples/api/test/material/input_decorator/input_decoration.suffix_icon_constraints.0_test.dart',
|
||||
'examples/api/test/material/input_decorator/input_decoration.3_test.dart',
|
||||
'examples/api/test/material/input_decorator/input_decoration.material_state.1_test.dart',
|
||||
'examples/api/test/material/text_form_field/text_form_field.1_test.dart',
|
||||
'examples/api/test/material/scrollbar/scrollbar.1_test.dart',
|
||||
'examples/api/test/material/search_anchor/search_anchor.0_test.dart',
|
||||
|
@ -32,13 +32,10 @@ class MaterialStateExample extends StatelessWidget {
|
||||
initialValue: 'abc',
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(Icons.person),
|
||||
prefixIconColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
prefixIconColor: WidgetStateColor.resolveWith((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.focused)) {
|
||||
return Colors.green;
|
||||
}
|
||||
if (states.contains(MaterialState.error)) {
|
||||
return Colors.red;
|
||||
}
|
||||
return Colors.grey;
|
||||
}),
|
||||
),
|
@ -32,24 +32,31 @@ class MaterialStateExample extends StatelessWidget {
|
||||
return Theme(
|
||||
data: themeData.copyWith(
|
||||
inputDecorationTheme: themeData.inputDecorationTheme.copyWith(
|
||||
prefixIconColor: MaterialStateColor.resolveWith(
|
||||
(Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.focused)) {
|
||||
return Colors.green;
|
||||
}
|
||||
if (states.contains(MaterialState.error)) {
|
||||
prefixIconColor: WidgetStateColor.resolveWith(
|
||||
(Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.error)) {
|
||||
return Colors.red;
|
||||
}
|
||||
if (states.contains(WidgetState.focused)) {
|
||||
return Colors.blue;
|
||||
}
|
||||
return Colors.grey;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
child: TextFormField(
|
||||
initialValue: 'abc',
|
||||
initialValue: 'example.com',
|
||||
decoration: const InputDecoration(
|
||||
prefixIcon: Icon(Icons.person),
|
||||
prefixIcon: Icon(Icons.web),
|
||||
),
|
||||
autovalidateMode: AutovalidateMode.always,
|
||||
validator: (String? text) {
|
||||
if (text?.endsWith('.com') ?? false) {
|
||||
return null;
|
||||
}
|
||||
return 'No .com tld';
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
// 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_api_samples/material/input_decorator/input_decoration.0.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('TextField is decorated', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.InputDecorationExampleApp(),
|
||||
);
|
||||
expect(find.text('InputDecoration Sample'), findsOneWidget);
|
||||
|
||||
expect(find.byType(TextField), findsOneWidget);
|
||||
expect(find.text('Hint Text'), findsOneWidget);
|
||||
expect(find.text('Helper Text'), findsOneWidget);
|
||||
expect(find.text('0 characters'), findsOneWidget);
|
||||
|
||||
expect(find.byIcon(Icons.send), findsOneWidget);
|
||||
});
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
// 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_api_samples/material/input_decorator/input_decoration.1.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('TextField is decorated', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.InputDecorationExampleApp(),
|
||||
);
|
||||
expect(find.text('InputDecoration Sample'), findsOneWidget);
|
||||
|
||||
expect(find.byType(TextField), findsOneWidget);
|
||||
expect(find.text('Hint Text'), findsOneWidget);
|
||||
|
||||
expect(
|
||||
tester.widget<TextField>(find.byType(TextField)).decoration?.contentPadding,
|
||||
EdgeInsets.zero,
|
||||
);
|
||||
expect(
|
||||
tester.widget<TextField>(find.byType(TextField)).decoration?.border,
|
||||
const OutlineInputBorder(),
|
||||
);
|
||||
});
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
// 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_api_samples/material/input_decorator/input_decoration.2.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('TextField is decorated', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.InputDecorationExampleApp(),
|
||||
);
|
||||
expect(find.text('InputDecoration Sample'), findsOneWidget);
|
||||
|
||||
expect(find.byType(TextField), findsOneWidget);
|
||||
expect(find.text('Hint Text'), findsOneWidget);
|
||||
expect(find.text('Error Text'), findsOneWidget);
|
||||
|
||||
expect(
|
||||
tester.widget<TextField>(find.byType(TextField))
|
||||
.decoration
|
||||
?.border,
|
||||
isNotNull,
|
||||
);
|
||||
});
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
// 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_api_samples/material/input_decorator/input_decoration.3.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('TextFormField is decorated', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.InputDecorationExampleApp(),
|
||||
);
|
||||
expect(find.text('InputDecoration Sample'), findsOneWidget);
|
||||
|
||||
expect(find.byType(TextFormField), findsOneWidget);
|
||||
expect(find.text('Prefix'), findsOneWidget);
|
||||
expect(find.text('abc'), findsOneWidget);
|
||||
expect(find.text('Suffix'), findsOneWidget);
|
||||
expect(
|
||||
tester.widget<TextField>(find.byType(TextField)).decoration?.border,
|
||||
const OutlineInputBorder(),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Decorations are correctly ordered', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.InputDecorationExampleApp(),
|
||||
);
|
||||
expect(find.text('InputDecoration Sample'), findsOneWidget);
|
||||
|
||||
expect(find.byType(TextFormField), findsOneWidget);
|
||||
|
||||
final double prefixX = tester.getCenter(find.text('Prefix')).dx;
|
||||
final double contentX = tester.getCenter(find.text('abc')).dx;
|
||||
final double suffixX = tester.getCenter(find.text('Suffix')).dx;
|
||||
|
||||
expect(prefixX, lessThan(contentX));
|
||||
expect(contentX, lessThan(suffixX));
|
||||
});
|
||||
}
|
@ -16,7 +16,10 @@ void main() {
|
||||
await tester.tap(find.byType(TextFormField));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final AnimatedDefaultTextStyle label = tester.firstWidget(find.ancestor(of: find.text('Name'), matching: find.byType(AnimatedDefaultTextStyle)));
|
||||
final AnimatedDefaultTextStyle label = tester.firstWidget(find.ancestor(
|
||||
of: find.text('Name'),
|
||||
matching: find.byType(AnimatedDefaultTextStyle),
|
||||
));
|
||||
expect(label.style.color, theme.data.colorScheme.error);
|
||||
});
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import 'package:flutter_api_samples/material/input_decorator/input_decoration.he
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('InputDecorator helper', (WidgetTester tester) async {
|
||||
testWidgets('Shows multi element InputDecorator help decoration', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.HelperExampleApp(),
|
||||
);
|
||||
|
@ -0,0 +1,20 @@
|
||||
// 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_api_samples/material/input_decorator/input_decoration.label.0.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Decorates TextField in sample app with label', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.LabelExampleApp(),
|
||||
);
|
||||
expect(find.text('InputDecoration.label Sample'), findsOneWidget);
|
||||
|
||||
expect(find.byType(TextField), findsOneWidget);
|
||||
expect(find.text('Username'), findsOneWidget);
|
||||
expect(find.text('*'), findsOneWidget);
|
||||
});
|
||||
}
|
@ -13,7 +13,10 @@ void main() {
|
||||
);
|
||||
final Theme theme = tester.firstWidget(find.byType(Theme));
|
||||
|
||||
final AnimatedDefaultTextStyle label = tester.firstWidget(find.ancestor(of: find.text('Name'), matching: find.byType(AnimatedDefaultTextStyle)));
|
||||
final AnimatedDefaultTextStyle label = tester.firstWidget(find.ancestor(
|
||||
of: find.text('Name'),
|
||||
matching: find.byType(AnimatedDefaultTextStyle),
|
||||
));
|
||||
expect(label.style.color, theme.data.colorScheme.error);
|
||||
});
|
||||
}
|
||||
|
@ -0,0 +1,71 @@
|
||||
// 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_api_samples/material/input_decorator/input_decoration.prefix_icon_constraints.0.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Shows two TextFields decorated with prefix icon sizes matching their hint text', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.PrefixIconConstraintsExampleApp(),
|
||||
);
|
||||
expect(find.text('InputDecoration Sample'), findsOneWidget);
|
||||
|
||||
expect(find.byType(TextField), findsNWidgets(2));
|
||||
expect(find.byIcon(Icons.search), findsNWidgets(2));
|
||||
expect(find.text('Normal Icon Constraints'), findsOneWidget);
|
||||
expect(find.text('Smaller Icon Constraints'), findsOneWidget);
|
||||
|
||||
final Finder normalIcon = find.descendant(
|
||||
of: find.ancestor(
|
||||
of: find.text('Normal Icon Constraints'),
|
||||
matching: find.byType(TextField),
|
||||
),
|
||||
matching: find.byIcon(Icons.search),
|
||||
);
|
||||
final Finder smallerIcon = find.descendant(
|
||||
of: find.ancestor(
|
||||
of: find.text('Smaller Icon Constraints'),
|
||||
matching: find.byType(TextField),
|
||||
),
|
||||
matching: find.byIcon(Icons.search),
|
||||
);
|
||||
|
||||
expect(
|
||||
tester.getSize(normalIcon).longestSide,
|
||||
greaterThan(tester.getSize(smallerIcon).longestSide),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('prefixIcons are placed left of hintText', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.PrefixIconConstraintsExampleApp(),
|
||||
);
|
||||
|
||||
final Finder normalIcon = find.descendant(
|
||||
of: find.ancestor(
|
||||
of: find.text('Normal Icon Constraints'),
|
||||
matching: find.byType(TextField),
|
||||
),
|
||||
matching: find.byIcon(Icons.search),
|
||||
);
|
||||
final Finder smallerIcon = find.descendant(
|
||||
of: find.ancestor(
|
||||
of: find.text('Smaller Icon Constraints'),
|
||||
matching: find.byType(TextField),
|
||||
),
|
||||
matching: find.byIcon(Icons.search),
|
||||
);
|
||||
|
||||
expect(
|
||||
tester.getCenter(find.text('Normal Icon Constraints')).dx,
|
||||
greaterThan(tester.getCenter(normalIcon).dx),
|
||||
);
|
||||
expect(
|
||||
tester.getCenter(find.text('Smaller Icon Constraints')).dx,
|
||||
greaterThan(tester.getCenter(smallerIcon).dx),
|
||||
);
|
||||
});
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
// 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_api_samples/material/input_decorator/input_decoration.suffix_icon_constraints.0.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Shows two TextFields decorated with suffix icon sizes matching their hint text', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.SuffixIconConstraintsExampleApp(),
|
||||
);
|
||||
expect(find.text('InputDecoration Sample'), findsOneWidget);
|
||||
|
||||
expect(find.byType(TextField), findsNWidgets(2));
|
||||
expect(find.byIcon(Icons.search), findsNWidgets(2));
|
||||
expect(find.text('Normal Icon Constraints'), findsOneWidget);
|
||||
expect(find.text('Smaller Icon Constraints'), findsOneWidget);
|
||||
|
||||
final Finder normalIcon = find.descendant(
|
||||
of: find.ancestor(
|
||||
of: find.text('Normal Icon Constraints'),
|
||||
matching: find.byType(TextField),
|
||||
),
|
||||
matching: find.byIcon(Icons.search),
|
||||
);
|
||||
final Finder smallerIcon = find.descendant(
|
||||
of: find.ancestor(
|
||||
of: find.text('Smaller Icon Constraints'),
|
||||
matching: find.byType(TextField),
|
||||
),
|
||||
matching: find.byIcon(Icons.search),
|
||||
);
|
||||
|
||||
expect(tester.getSize(normalIcon).longestSide,
|
||||
greaterThan(tester.getSize(smallerIcon).longestSide));
|
||||
});
|
||||
|
||||
testWidgets('suffixIcons are placed right of hintText', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.SuffixIconConstraintsExampleApp(),
|
||||
);
|
||||
|
||||
final Finder normalIcon = find.descendant(
|
||||
of: find.ancestor(
|
||||
of: find.text('Normal Icon Constraints'),
|
||||
matching: find.byType(TextField),
|
||||
),
|
||||
matching: find.byIcon(Icons.search),
|
||||
);
|
||||
final Finder smallerIcon = find.descendant(
|
||||
of: find.ancestor(
|
||||
of: find.text('Smaller Icon Constraints'),
|
||||
matching: find.byType(TextField),
|
||||
),
|
||||
matching: find.byIcon(Icons.search),
|
||||
);
|
||||
|
||||
expect(
|
||||
tester.getCenter(find.text('Normal Icon Constraints')).dx,
|
||||
lessThan(tester.getCenter(normalIcon).dx),
|
||||
);
|
||||
expect(
|
||||
tester.getCenter(find.text('Smaller Icon Constraints')).dx,
|
||||
lessThan(tester.getCenter(smallerIcon).dx),
|
||||
);
|
||||
});
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
// 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_api_samples/material/input_decorator/input_decoration.widget_state.0.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('TextFormField updates decorations depending on state', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.MaterialStateExampleApp(),
|
||||
);
|
||||
expect(find.text('InputDecoration Sample'), findsOneWidget);
|
||||
|
||||
expect(find.byType(TextFormField), findsOneWidget);
|
||||
expect(find.text('abc'), findsOneWidget);
|
||||
expect(find.byIcon(Icons.person), findsOneWidget);
|
||||
|
||||
expect(
|
||||
tester.widget<TextField>(find.byType(TextField)).decoration?.prefixIconColor,
|
||||
isA<WidgetStateColor>()
|
||||
.having((WidgetStateColor color) => color.resolve(<WidgetState>{}), 'default', Colors.grey)
|
||||
.having((WidgetStateColor color) => color.resolve(<WidgetState>{WidgetState.focused}), 'focused', Colors.green),
|
||||
);
|
||||
});
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
// 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_api_samples/material/input_decorator/input_decoration.widget_state.1.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('TextFormField updates decorations depending on state', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.MaterialStateExampleApp(),
|
||||
);
|
||||
expect(find.text('InputDecoration Sample'), findsOneWidget);
|
||||
|
||||
expect(find.byType(TextFormField), findsOneWidget);
|
||||
expect(find.text('example.com'), findsOneWidget);
|
||||
expect(find.byIcon(Icons.web), findsOneWidget);
|
||||
|
||||
expect(
|
||||
tester.widget<TextField>(find.byType(TextField)).decoration?.prefixIconColor,
|
||||
isA<WidgetStateColor>()
|
||||
.having((WidgetStateColor color) => color.resolve(<WidgetState>{}), 'default', Colors.grey)
|
||||
.having((WidgetStateColor color) => color.resolve(<WidgetState>{WidgetState.focused}), 'focused', Colors.blue)
|
||||
.having((WidgetStateColor color) => color.resolve(<WidgetState>{WidgetState.error}), 'error', Colors.red)
|
||||
.having((WidgetStateColor color) => color.resolve(<WidgetState>{WidgetState.error, WidgetState.focused}), 'error', Colors.red),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Validates field input', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.MaterialStateExampleApp(),
|
||||
);
|
||||
|
||||
expect(find.text('No .com tld'), findsNothing);
|
||||
await tester.enterText(find.byType(TextFormField), 'noUrl');
|
||||
await tester.pump();
|
||||
expect(find.text('No .com tld'), findsOneWidget);
|
||||
});
|
||||
}
|
@ -2517,10 +2517,9 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
|
||||
///
|
||||
/// {@tool dartpad}
|
||||
/// This sample shows how to style a `TextField` with a prefixIcon that changes color
|
||||
/// based on the `MaterialState`. The color defaults to gray, be blue while focused
|
||||
/// and red if in an error state.
|
||||
/// based on the `MaterialState`. The color defaults to gray and is green while focused.
|
||||
///
|
||||
/// ** See code in examples/api/lib/material/input_decorator/input_decoration.material_state.0.dart **
|
||||
/// ** See code in examples/api/lib/material/input_decorator/input_decoration.widget_state.0.dart **
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// {@tool dartpad}
|
||||
@ -2528,7 +2527,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
|
||||
/// based on the `MaterialState` through the use of `ThemeData`. The color defaults
|
||||
/// to gray, be blue while focused and red if in an error state.
|
||||
///
|
||||
/// ** See code in examples/api/lib/material/input_decorator/input_decoration.material_state.1.dart **
|
||||
/// ** See code in examples/api/lib/material/input_decorator/input_decoration.widget_state.1.dart **
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
|
Loading…
Reference in New Issue
Block a user