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:
derdilla 2024-06-20 18:02:07 +02:00 committed by GitHub
parent bfdcb51643
commit 0674f46e9f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 375 additions and 29 deletions

View File

@ -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',

View File

@ -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;
}),
),

View File

@ -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';
}
),
);
}

View File

@ -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);
});
}

View File

@ -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(),
);
});
}

View File

@ -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,
);
});
}

View File

@ -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));
});
}

View File

@ -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);
});
}

View File

@ -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(),
);

View File

@ -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);
});
}

View File

@ -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);
});
}

View File

@ -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),
);
});
}

View File

@ -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),
);
});
}

View File

@ -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),
);
});
}

View File

@ -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);
});
}

View File

@ -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: