Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,49 @@ void main() {
await tester.pumpWidget(const example.BottomAppBarDemo());

// Trigger the SnackBar.
await tester.tap(find.byTooltip('Open popup menu'));
await tester.tap(findByTooltip('Open popup menu'));
await tester.pump();

expect(find.text('Yay! A SnackBar!'), findsOneWidget);

expect(find.text('Undo'), findsOneWidget);
});
}

/// Finds [RawTooltip] or [Tooltip] widgets with the given `message`.
///
/// ## Sample code
///
/// ```dart
/// expect(findByTooltip('Back'), findsOneWidget);
/// expect(findByTooltip(RegExp('Back.*')), findsNWidgets(2));
/// ```
///
/// If the `skipOffstage` argument is true (the default), then this skips
/// nodes that are [Offstage] or that are from inactive [Route]s.
///
/// This was copied from flutter_test, which uses flutter/material.dart.
///
Finder findByTooltip(Pattern message, {bool skipOffstage = true}) {
return find.byWidgetPredicate((Widget widget) {
// Compare RawTooltip's semantics tooltip with the given message.
// However, Tooltip's message needs to be checked directly if:
// 1. Tooltip.excludeFromSemantics is true, since in this case Tooltip
// provides no semantics tooltip to the underlying RawTooltip.
// 2. Tooltip.message and Tooltip.richMessage are empty, since in this
// case no RawTooltip is created.
if (widget is Tooltip) {
final String tooltipMessage =
widget.message ?? widget.richMessage!.toPlainText();
Comment on lines +105 to +106

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the null assertion operator ! on widget.richMessage can lead to a runtime exception if both widget.message and widget.richMessage are null. Use optional chaining ?. and a fallback empty string ?? '' to ensure defensive programming and null safety.

Suggested change
final String tooltipMessage =
widget.message ?? widget.richMessage!.toPlainText();
final String tooltipMessage =
widget.message ?? widget.richMessage?.toPlainText() ?? '';

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an assertion that enforces at least one of these is set.

if ((widget.excludeFromSemantics ?? false) || tooltipMessage.isEmpty) {
return message is RegExp
? message.hasMatch(tooltipMessage)
: tooltipMessage == message;
}
}
return widget is RawTooltip &&
(message is RegExp
? message.hasMatch(widget.semanticsTooltip ?? '')
: widget.semanticsTooltip == message);
}, skipOffstage: skipOffstage);
}
Comment on lines +82 to +118

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The findByTooltip helper function is duplicated across multiple example test files (e.g., bottom_app_bar.2_test.dart and tooltip.3_test.dart). To improve maintainability and adhere to DRY (Don't Repeat Yourself) principles, consider extracting this helper into a shared finders.dart file under packages/material_ui/example/test/ and importing it in the respective test files.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok either way here. I could make a utils file in examples/test, though it would be the first one. This is already going to be duplicated with material_ui/test/finders.dart, and we will clean them up after flutter_test migrates to material_ui.

40 changes: 39 additions & 1 deletion packages/material_ui/example/test/tooltip/tooltip.3_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,46 @@ void main() {
await tester.pump(const Duration(milliseconds: 10));
expect(find.text(tooltipText), findsOneWidget);
// Tap on the tooltip and wait for the tooltip to disappear.
await tester.tap(find.byTooltip(tooltipText));
await tester.tap(findByTooltip(tooltipText));
await tester.pump(const Duration(seconds: 1));
expect(find.text(tooltipText), findsNothing);
});
}

/// Finds [RawTooltip] or [Tooltip] widgets with the given `message`.
///
/// ## Sample code
///
/// ```dart
/// expect(findByTooltip('Back'), findsOneWidget);
/// expect(findByTooltip(RegExp('Back.*')), findsNWidgets(2));
/// ```
///
/// If the `skipOffstage` argument is true (the default), then this skips
/// nodes that are [Offstage] or that are from inactive [Route]s.
///
/// This was copied from flutter_test, which uses flutter/material.dart.
///
Finder findByTooltip(Pattern message, {bool skipOffstage = true}) {
return find.byWidgetPredicate((Widget widget) {
// Compare RawTooltip's semantics tooltip with the given message.
// However, Tooltip's message needs to be checked directly if:
// 1. Tooltip.excludeFromSemantics is true, since in this case Tooltip
// provides no semantics tooltip to the underlying RawTooltip.
// 2. Tooltip.message and Tooltip.richMessage are empty, since in this
// case no RawTooltip is created.
if (widget is Tooltip) {
final String tooltipMessage =
widget.message ?? widget.richMessage!.toPlainText();
if ((widget.excludeFromSemantics ?? false) || tooltipMessage.isEmpty) {
return message is RegExp
? message.hasMatch(tooltipMessage)
: tooltipMessage == message;
}
}
return widget is RawTooltip &&
(message is RegExp
? message.hasMatch(widget.semanticsTooltip ?? '')
: widget.semanticsTooltip == message);
}, skipOffstage: skipOffstage);
}
3 changes: 2 additions & 1 deletion packages/material_ui/test/app_bar_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:material_ui/material_ui.dart';

import 'app_bar_utils.dart';
import 'finders.dart';
import 'semantics_tester.dart';

TextStyle? _iconStyle(WidgetTester tester, IconData icon) {
Expand Down Expand Up @@ -1956,7 +1957,7 @@ void main() {
),
);

final Finder endDrawerFinder = find.byTooltip('Open navigation menu');
final Finder endDrawerFinder = findByTooltip('Open navigation menu');
await tester.tap(endDrawerFinder);
await tester.pump();

Expand Down
9 changes: 5 additions & 4 deletions packages/material_ui/test/chip_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:material_ui/material_ui.dart';

import 'feedback_tester.dart';
import 'finders.dart';
import 'semantics_tester.dart';

Finder findRenderChipElement() {
Expand Down Expand Up @@ -327,19 +328,19 @@ void main() {
),
);

expect(tester.widget(find.byTooltip('Delete chip A')), isNotNull);
expect(tester.widget(find.byTooltip('Delete chip B')), isNotNull);
expect(tester.widget(findByTooltip('Delete chip A')), isNotNull);
expect(tester.widget(findByTooltip('Delete chip B')), isNotNull);

expect(feedback.clickSoundCount, 0);

expect(deletedChipLabels, isEmpty);
await tester.tap(find.byTooltip('Delete chip A'));
await tester.tap(findByTooltip('Delete chip A'));
expect(deletedChipLabels, equals(<String>['A']));

await tester.pumpAndSettle(const Duration(seconds: 1));
expect(feedback.clickSoundCount, 1);

await tester.tap(find.byTooltip('Delete chip B'));
await tester.tap(findByTooltip('Delete chip B'));
expect(deletedChipLabels, equals(<String>['A', 'B']));

await tester.pumpAndSettle(const Duration(seconds: 1));
Expand Down
4 changes: 2 additions & 2 deletions packages/material_ui/test/finders.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import 'package:material_ui/material_ui.dart';
/// ## Sample code
///
/// ```dart
/// expect(find.byTooltip('Back'), findsOneWidget);
/// expect(find.byTooltip(RegExp('Back.*')), findsNWidgets(2));
/// expect(findByTooltip('Back'), findsOneWidget);
/// expect(findByTooltip(RegExp('Back.*')), findsNWidgets(2));
/// ```
///
/// If the `skipOffstage` argument is true (the default), then this skips
Expand Down
3 changes: 2 additions & 1 deletion packages/material_ui/test/floating_action_button_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:material_ui/material_ui.dart';

import 'feedback_tester.dart';
import 'finders.dart';
import 'semantics_tester.dart';

void main() {
Expand Down Expand Up @@ -58,7 +59,7 @@ void main() {
);

await tester.tap(find.byType(Icon));
expect(find.byTooltip('Add'), findsOneWidget);
expect(findByTooltip('Add'), findsOneWidget);
});

// Regression test for: https://github.com/flutter/flutter/pull/21084
Expand Down
5 changes: 3 additions & 2 deletions packages/material_ui/test/icon_button_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:material_ui/material_ui.dart';

import 'feedback_tester.dart';
import 'finders.dart';
import 'semantics_tester.dart';

class MockOnPressedFunction {
Expand Down Expand Up @@ -437,9 +438,9 @@ void main() {
await tester.pumpWidget(buildIconButton(tooltip: tooltipText));

expect(find.byType(Tooltip), findsOneWidget);
expect(find.byTooltip(tooltipText), findsOneWidget);
expect(findByTooltip(tooltipText), findsOneWidget);

await tester.tap(find.byTooltip(tooltipText));
await tester.tap(findByTooltip(tooltipText));
expect(mockOnPressedFunction.called, 1);

// Hovering over the button should show the tooltip.
Expand Down
3 changes: 2 additions & 1 deletion packages/material_ui/test/page_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:material_ui/material_ui.dart';
import 'finders.dart';

void main() {
testWidgets(
Expand Down Expand Up @@ -1063,7 +1064,7 @@ void main() {
expect(pageTapCount, 1);

// Tapping the "page" route's back button doesn't do anything either.
await tester.tap(find.byTooltip('Back'), warnIfMissed: false);
await tester.tap(findByTooltip('Back'), warnIfMissed: false);
await tester.pumpAndSettle();
expect(tester.getTopLeft(find.byKey(pageScaffoldKey)), const Offset(400, 0));
expect(tester.getTopLeft(find.byKey(homeScaffoldKey)).dx, lessThan(0));
Expand Down
19 changes: 10 additions & 9 deletions packages/material_ui/test/paginated_data_table_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:material_ui/material_ui.dart';

import 'data_table_test_utils.dart';
import 'finders.dart';

class TestDataSource extends DataTableSource {
TestDataSource({this.allowSelection = false});
Expand Down Expand Up @@ -94,7 +95,7 @@ void main() {
),
);

await tester.tap(find.byTooltip('Next page'));
await tester.tap(findByTooltip('Next page'));

expect(log, <String>['page-changed: 2']);
log.clear();
Expand All @@ -117,7 +118,7 @@ void main() {
expect(find.text('Gingerbread (0)'), findsNothing);

final Finder lastPageButton = find.ancestor(
of: find.byTooltip('Last page'),
of: findByTooltip('Last page'),
matching: find.byWidgetPredicate((Widget widget) => widget is IconButton),
);

Expand All @@ -137,7 +138,7 @@ void main() {
expect(find.text('KitKat (49)'), findsOneWidget);

final Finder firstPageButton = find.ancestor(
of: find.byTooltip('First page'),
of: findByTooltip('First page'),
matching: find.byWidgetPredicate((Widget widget) => widget is IconButton),
);

Expand Down Expand Up @@ -194,13 +195,13 @@ void main() {

expect(find.text('1–2 of 500'), findsOneWidget);

await tester.tap(find.byTooltip('Next page'));
await tester.tap(findByTooltip('Next page'));
await tester.pump();

expect(find.text('3–4 of 500'), findsOneWidget);

final Finder lastPageButton = find.ancestor(
of: find.byTooltip('Last page'),
of: findByTooltip('Last page'),
matching: find.byWidgetPredicate((Widget widget) => widget is IconButton),
);

Expand All @@ -220,7 +221,7 @@ void main() {

expect(find.textContaining('1–3 of 500'), findsOneWidget);

await tester.tap(find.byTooltip('Next page'));
await tester.tap(findByTooltip('Next page'));
await tester.pump();

expect(find.text('4–6 of 500'), findsOneWidget);
Expand All @@ -238,7 +239,7 @@ void main() {

expect(find.textContaining('1–4 of 500'), findsOneWidget);

await tester.tap(find.byTooltip('Next page'));
await tester.tap(findByTooltip('Next page'));
await tester.pump();

expect(find.text('5–8 of 500'), findsOneWidget);
Expand All @@ -256,7 +257,7 @@ void main() {

expect(find.textContaining('1–5 of 500'), findsOneWidget);

await tester.tap(find.byTooltip('Next page'));
await tester.tap(findByTooltip('Next page'));
await tester.pump();

expect(find.text('6–10 of 500'), findsOneWidget);
Expand All @@ -274,7 +275,7 @@ void main() {

expect(find.textContaining('1–8 of 500'), findsOneWidget);

await tester.tap(find.byTooltip('Next page'));
await tester.tap(findByTooltip('Next page'));
await tester.pump();

expect(find.text('9–16 of 500'), findsOneWidget);
Expand Down
5 changes: 3 additions & 2 deletions packages/material_ui/test/popup_menu_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:material_ui/material_ui.dart';

import 'feedback_tester.dart';
import 'finders.dart';
import 'semantics_tester.dart';

void main() {
Expand Down Expand Up @@ -2356,7 +2357,7 @@ void main() {
// The default tooltip is defined as [MaterialLocalizations.showMenuTooltip]
// and it is used when no tooltip is provided.
expect(find.byType(Tooltip), findsNWidgets(3));
expect(find.byTooltip(const DefaultMaterialLocalizations().showMenuTooltip), findsNWidgets(3));
expect(findByTooltip(const DefaultMaterialLocalizations().showMenuTooltip), findsNWidgets(3));
});

testWidgets('PopupMenuButton custom tooltip', (WidgetTester tester) async {
Expand Down Expand Up @@ -2404,7 +2405,7 @@ void main() {
);

expect(find.byType(Tooltip), findsNWidgets(3));
expect(find.byTooltip('Test tooltip'), findsNWidgets(3));
expect(findByTooltip('Test tooltip'), findsNWidgets(3));
});

testWidgets('Allow Widget for PopupMenuButton.icon', (WidgetTester tester) async {
Expand Down
Loading
Loading