Skip to content

Commit

Permalink
Test snack bar examples (#147774)
Browse files Browse the repository at this point in the history
Adds tests to the last two Snack Bar examples as part of #130459. Makes the [last example](https://api.flutter.dev/flutter/material/SnackBar-class.html#material.SnackBar.3) more usable through the use of standard widgets and visual hierarchy. Constraints on options that are not required by the SnackBar contract have been removed (Overflow threshold works on fixed SnackBars).
  • Loading branch information
derdilla authored May 23, 2024
1 parent 1c1516c commit aaa4d33
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 77 deletions.
2 changes: 0 additions & 2 deletions dev/bots/check_code_samples.dart
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,6 @@ final Set<String> _knownMissingTests = <String>{
'examples/api/test/material/flexible_space_bar/flexible_space_bar.0_test.dart',
'examples/api/test/material/floating_action_button_location/standard_fab_location.0_test.dart',
'examples/api/test/material/chip/deletable_chip_attributes.on_deleted.0_test.dart',
'examples/api/test/material/snack_bar/snack_bar.2_test.dart',
'examples/api/test/material/snack_bar/snack_bar.1_test.dart',
'examples/api/test/material/icon_button/icon_button.3_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',
Expand Down
139 changes: 65 additions & 74 deletions examples/api/lib/material/snack_bar/snack_bar.2.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,7 @@ class SnackBarExampleApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(useMaterial3: true),
home: Scaffold(
appBar: AppBar(title: const Text('SnackBar Sample')),
body: const Center(
child: SnackBarExample(),
),
),
home: const SnackBarExample(),
);
}
}
Expand All @@ -42,24 +37,25 @@ class _SnackBarExampleState extends State<SnackBarExample> {
bool _longActionLabel = false;
double _sliderValue = 0.25;

Padding _padRow(List<Widget> children) => Padding(
padding: const EdgeInsets.all(8.0),
child: Row(children: children),
);

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 50.0),
child: Column(
return Scaffold(
appBar: AppBar(title: const Text('SnackBar Sample')),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(_snackBar());
},
icon: const Icon(Icons.play_arrow),
label: const Text('Show Snackbar'),
),
body: ListView(
children: <Widget>[
_padRow(<Widget>[
Text('Snack Bar configuration', style: Theme.of(context).textTheme.bodyLarge),
]),
_padRow(
<Widget>[
const Text('Fixed'),
Radio<SnackBarBehavior>(
ExpansionTile(
title: const Text('Behavior'),
initiallyExpanded: true,
children: <Widget>[
RadioListTile<SnackBarBehavior>(
title: const Text('Fixed'),
value: SnackBarBehavior.fixed,
groupValue: _snackBarBehavior,
onChanged: (SnackBarBehavior? value) {
Expand All @@ -68,8 +64,8 @@ class _SnackBarExampleState extends State<SnackBarExample> {
});
},
),
const Text('Floating'),
Radio<SnackBarBehavior>(
RadioListTile<SnackBarBehavior>(
title: const Text('Floating'),
value: SnackBarBehavior.floating,
groupValue: _snackBarBehavior,
onChanged: (SnackBarBehavior? value) {
Expand All @@ -80,75 +76,65 @@ class _SnackBarExampleState extends State<SnackBarExample> {
),
],
),
_padRow(
<Widget>[
const Text('Include Icon '),
Switch(
ExpansionTile(
title: const Text('Content'),
initiallyExpanded: true,
children: <Widget>[
SwitchListTile(
title: const Text('Include close Icon'),
value: _withIcon,
onChanged: (bool value) {
setState(() {
_withIcon = !_withIcon;
_withIcon = value;
});
},
),
],
),
_padRow(
<Widget>[
const Text('Include Action '),
Switch(
SwitchListTile(
title: const Text('Multi Line Text'),
value: _multiLine,
onChanged: (bool value) {
setState(() {
_multiLine = value;
});
},
),
SwitchListTile(
title: const Text('Include Action'),
value: _withAction,
onChanged: (bool value) {
setState(() {
_withAction = !_withAction;
_withAction = value;
});
},
),
const SizedBox(width: 16.0),
const Text('Long Action Label '),
Switch(
SwitchListTile(
title: const Text('Long Action Label'),
value: _longActionLabel,
onChanged: !_withAction
? null
: (bool value) {
setState(() {
_longActionLabel = !_longActionLabel;
});
},
: (bool value) => setState(() {
_longActionLabel = value;
}),
),
],

),
_padRow(
<Widget>[
const Text('Multi Line Text'),
Switch(
value: _multiLine,
onChanged: switch (_snackBarBehavior) {
SnackBarBehavior.fixed || null => null,
SnackBarBehavior.floating => (bool value) => setState(() { _multiLine = !_multiLine; }),
},
ExpansionTile(
title: const Text('Action new-line overflow threshold'),
initiallyExpanded: true,
children: <Widget>[
Slider(
value: _sliderValue,
divisions: 20,
label: _sliderValue.toStringAsFixed(2),
onChanged: (double value) => setState(() {
_sliderValue = value;
}),
),
],
),
_padRow(<Widget>[
const Text('Action new-line overflow threshold'),
Slider(
value: _sliderValue,
divisions: 20,
label: _sliderValue.toStringAsFixed(2),
onChanged: switch (_snackBarBehavior) {
SnackBarBehavior.fixed || null => null,
SnackBarBehavior.floating => (double value) => setState(() { _sliderValue = value; }),
},
),
]),
const SizedBox(height: 16.0),
ElevatedButton(
child: const Text('Show Snackbar'),
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(_snackBar());
},
),
// Avoid hiding content behind the floating action button
const SizedBox(height: 100,),
],
),
);
Expand All @@ -163,9 +149,14 @@ class _SnackBarExampleState extends State<SnackBarExample> {
},
)
: null;
final double? width = _snackBarBehavior == SnackBarBehavior.floating && _multiLine ? 400.0 : null;
final String label =
_multiLine ? 'A Snack Bar with quite a lot of text which spans across multiple lines' : 'Single Line Snack Bar';
final double? width = _snackBarBehavior == SnackBarBehavior.floating
? 400.0
: null;
final String label = _multiLine
? 'A Snack Bar with quite a lot of text which spans across multiple '
'lines. You can look at how the Action Label moves around when trying '
'to layout this text.'
: 'Single Line Snack Bar';
return SnackBar(
content: Text(label),
showCloseIcon: _withIcon,
Expand Down
2 changes: 1 addition & 1 deletion examples/api/test/material/snack_bar/snack_bar.0_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ void main() {
expect(find.widgetWithText(AppBar, 'SnackBar Sample'), findsOneWidget);
expect(find.widgetWithText(ElevatedButton, 'Show Snackbar'), findsOneWidget);
await tester.tap(find.widgetWithText(ElevatedButton, 'Show Snackbar'));
await tester.pumpAndSettle();
await tester.pump();
expect(find.text('Awesome Snackbar!'), findsOneWidget);
expect(find.text('Action'), findsOneWidget);
});
Expand Down
60 changes: 60 additions & 0 deletions examples/api/test/material/snack_bar/snack_bar.1_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// 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/snack_bar/snack_bar.1.dart' as example;
import 'package:flutter_test/flutter_test.dart';

void main() {
testWidgets('Tapping on button shows snackbar', (WidgetTester tester) async {
await tester.pumpWidget(
const example.SnackBarExampleApp(),
);

expect(find.byType(SnackBar), findsNothing);
expect(find.widgetWithText(AppBar, 'SnackBar Sample'), findsOneWidget);

await tester.tap(find.widgetWithText(ElevatedButton, 'Show Snackbar'));
await tester.pump();

expect(find.text('Awesome SnackBar!'), findsOneWidget);
expect(find.widgetWithText(SnackBarAction, 'Action'), findsOneWidget);

final SnackBar bar = tester.widget<SnackBar>(find.ancestor(
of: find.text('Awesome SnackBar!'),
matching: find.byType(SnackBar)));
expect(bar.behavior, SnackBarBehavior.floating);
});

testWidgets('Snackbar is styled correctly', (WidgetTester tester) async {
await tester.pumpWidget(
const example.SnackBarExampleApp(),
);
await tester.tap(find.byType(ElevatedButton));
await tester.pump();

expect(find.byType(SnackBar), findsOneWidget);

final SnackBar bar = tester.widget<SnackBar>(find.byType(SnackBar));
expect(bar.behavior, SnackBarBehavior.floating);
expect(bar.width, 280.0);
expect(bar.shape, isA<RoundedRectangleBorder>()
.having((RoundedRectangleBorder b) => b.borderRadius, 'radius', BorderRadius.circular(10.0)));
});

testWidgets('Snackbar should disappear after timeout', (WidgetTester tester) async {
await tester.pumpWidget(
const example.SnackBarExampleApp(),
);
expect(find.byType(SnackBar), findsNothing);

await tester.tap(find.byType(ElevatedButton));
await tester.pumpAndSettle();
expect(find.byType(SnackBar), findsOneWidget);

await tester.pump(const Duration(milliseconds: 1500));
await tester.pumpAndSettle();
expect(find.byType(SnackBar), findsNothing);
});
}
Loading

0 comments on commit aaa4d33

Please sign in to comment.