Unverified Commit d25e0eb0 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Fix tapping on a test in flutter run (#13397)

Also:

* Remove find.byIcon since it's identical to find.icon. (I sent mail to flutter-dev about this.)

* Fix IconData's operator== and hashCode, which had not been updated when we added fields.

* Add the byTooltip finder to the list of suggested finders.

* Make the suggested Key finder prettier.
parent b80751cd
...@@ -11,7 +11,7 @@ final int choiceCount = app_bar_bottom_sample.choices.length; ...@@ -11,7 +11,7 @@ final int choiceCount = app_bar_bottom_sample.choices.length;
IconData iconAt(int index) => app_bar_bottom_sample.choices[index].icon; IconData iconAt(int index) => app_bar_bottom_sample.choices[index].icon;
Finder findChoiceCard(IconData icon) { Finder findChoiceCard(IconData icon) {
return find.descendant(of: find.byType(Card), matching: find.icon(icon)); return find.descendant(of: find.byType(Card), matching: find.byIcon(icon));
} }
void main() { void main() {
......
...@@ -12,11 +12,11 @@ IconData iconAt(int index) => basic_app_bar_sample.choices[index].icon; ...@@ -12,11 +12,11 @@ IconData iconAt(int index) => basic_app_bar_sample.choices[index].icon;
String titleAt(int index) => basic_app_bar_sample.choices[index].title; String titleAt(int index) => basic_app_bar_sample.choices[index].title;
Finder findAppBarIcon(IconData icon) { Finder findAppBarIcon(IconData icon) {
return find.descendant(of: find.byType(AppBar), matching: find.icon(icon)); return find.descendant(of: find.byType(AppBar), matching: find.byIcon(icon));
} }
Finder findChoiceCard(IconData icon) { Finder findChoiceCard(IconData icon) {
return find.descendant(of: find.byType(Card), matching: find.icon(icon)); return find.descendant(of: find.byType(Card), matching: find.byIcon(icon));
} }
void main() { void main() {
......
...@@ -11,11 +11,11 @@ final int choiceCount = tabbed_app_bar_sample.choices.length; ...@@ -11,11 +11,11 @@ final int choiceCount = tabbed_app_bar_sample.choices.length;
IconData iconAt(int index) => tabbed_app_bar_sample.choices[index].icon; IconData iconAt(int index) => tabbed_app_bar_sample.choices[index].icon;
Finder findChoiceCard(IconData icon) { Finder findChoiceCard(IconData icon) {
return find.descendant(of: find.byType(Card), matching: find.icon(icon)); return find.descendant(of: find.byType(Card), matching: find.byIcon(icon));
} }
Finder findTab(IconData icon) { Finder findTab(IconData icon) {
return find.descendant(of: find.byType(Tab), matching: find.icon(icon)); return find.descendant(of: find.byType(Tab), matching: find.byIcon(icon));
} }
void main() { void main() {
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' show hashValues;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
/// A description of an icon fulfilled by a font glyph. /// A description of an icon fulfilled by a font glyph.
...@@ -52,11 +54,14 @@ class IconData { ...@@ -52,11 +54,14 @@ class IconData {
if (runtimeType != other.runtimeType) if (runtimeType != other.runtimeType)
return false; return false;
final IconData typedOther = other; final IconData typedOther = other;
return codePoint == typedOther.codePoint; return codePoint == typedOther.codePoint
&& fontFamily == typedOther.fontFamily
&& fontPackage == typedOther.fontPackage
&& matchTextDirection == typedOther.matchTextDirection;
} }
@override @override
int get hashCode => codePoint.hashCode; int get hashCode => hashValues(codePoint, fontFamily, fontPackage, matchTextDirection);
@override @override
String toString() => 'IconData(U+${codePoint.toRadixString(16).toUpperCase().padLeft(5, '0')})'; String toString() => 'IconData(U+${codePoint.toRadixString(16).toUpperCase().padLeft(5, '0')})';
......
...@@ -80,7 +80,7 @@ void main() { ...@@ -80,7 +80,7 @@ void main() {
expect(find.text('Eclair (0)'), findsOneWidget); expect(find.text('Eclair (0)'), findsOneWidget);
expect(find.text('Gingerbread (0)'), findsNothing); expect(find.text('Gingerbread (0)'), findsNothing);
await tester.tap(find.icon(Icons.chevron_left)); await tester.tap(find.byIcon(Icons.chevron_left));
expect(log, <String>['page-changed: 0']); expect(log, <String>['page-changed: 0']);
log.clear(); log.clear();
...@@ -91,7 +91,7 @@ void main() { ...@@ -91,7 +91,7 @@ void main() {
expect(find.text('Eclair (0)'), findsNothing); expect(find.text('Eclair (0)'), findsNothing);
expect(find.text('Gingerbread (0)'), findsNothing); expect(find.text('Gingerbread (0)'), findsNothing);
await tester.tap(find.icon(Icons.chevron_left)); await tester.tap(find.byIcon(Icons.chevron_left));
expect(log, isEmpty); expect(log, isEmpty);
...@@ -188,7 +188,7 @@ void main() { ...@@ -188,7 +188,7 @@ void main() {
expect(find.text('Gingerbread (1)'), findsNothing); expect(find.text('Gingerbread (1)'), findsNothing);
expect(find.text('Gingerbread (2)'), findsOneWidget); expect(find.text('Gingerbread (2)'), findsOneWidget);
await tester.tap(find.icon(Icons.adjust)); await tester.tap(find.byIcon(Icons.adjust));
expect(log, <String>['action: adjust']); expect(log, <String>['action: adjust']);
log.clear(); log.clear();
}); });
......
...@@ -192,4 +192,16 @@ void main() { ...@@ -192,4 +192,16 @@ void main() {
// semanticLabel to make sure the subtree was not rebuilt. // semanticLabel to make sure the subtree was not rebuilt.
expect(richText2, same(richText1)); expect(richText2, same(richText1));
}); });
testWidgets('IconData comparison', (WidgetTester tester) async {
expect(const IconData(123), const IconData(123));
expect(const IconData(123), isNot(const IconData(123, matchTextDirection: true)));
expect(const IconData(123), isNot(const IconData(123, fontFamily: 'f')));
expect(const IconData(123), isNot(const IconData(123, fontPackage: 'p')));
expect(const IconData(123).hashCode, const IconData(123).hashCode);
expect(const IconData(123).hashCode, isNot(const IconData(123, matchTextDirection: true).hashCode));
expect(const IconData(123).hashCode, isNot(const IconData(123, fontFamily: 'f').hashCode));
expect(const IconData(123).hashCode, isNot(const IconData(123, fontPackage: 'p').hashCode));
expect(const IconData(123).toString(), 'IconData(U+0007B)');
});
} }
...@@ -984,8 +984,9 @@ class TestViewConfiguration extends ViewConfiguration { ...@@ -984,8 +984,9 @@ class TestViewConfiguration extends ViewConfiguration {
super(size: size); super(size: size);
static Matrix4 _getMatrix(Size size, double devicePixelRatio) { static Matrix4 _getMatrix(Size size, double devicePixelRatio) {
final double actualWidth = ui.window.physicalSize.width; final double inverseRatio = devicePixelRatio / ui.window.devicePixelRatio;
final double actualHeight = ui.window.physicalSize.height; final double actualWidth = ui.window.physicalSize.width * inverseRatio;
final double actualHeight = ui.window.physicalSize.height * inverseRatio;
final double desiredWidth = size.width; final double desiredWidth = size.width;
final double desiredHeight = size.height; final double desiredHeight = size.height;
double scale, shiftX, shiftY; double scale, shiftX, shiftY;
...@@ -1020,8 +1021,6 @@ class TestViewConfiguration extends ViewConfiguration { ...@@ -1020,8 +1021,6 @@ class TestViewConfiguration extends ViewConfiguration {
/// ///
/// This is useful because pointers are described in logical pixels, as /// This is useful because pointers are described in logical pixels, as
/// opposed to graphics which are expressed in physical pixels. /// opposed to graphics which are expressed in physical pixels.
// TODO(ianh): We should make graphics and pointers use the same coordinate space.
// See: https://github.com/flutter/flutter/issues/1360
Matrix4 toHitTestMatrix() => _hitTestMatrix.clone(); Matrix4 toHitTestMatrix() => _hitTestMatrix.clone();
@override @override
......
...@@ -34,17 +34,6 @@ class CommonFinders { ...@@ -34,17 +34,6 @@ class CommonFinders {
/// nodes that are [Offstage] or that are from inactive [Route]s. /// nodes that are [Offstage] or that are from inactive [Route]s.
Finder text(String text, { bool skipOffstage: true }) => new _TextFinder(text, skipOffstage: skipOffstage); Finder text(String text, { bool skipOffstage: true }) => new _TextFinder(text, skipOffstage: skipOffstage);
/// Finds [Icon] widgets containing icon data equal to the `icon`
/// argument.
///
/// Example:
///
/// expect(find.icon(Icons.chevron_left), findsOneWidget);
///
/// If the `skipOffstage` argument is true (the default), then this skips
/// nodes that are [Offstage] or that are from inactive [Route]s.
Finder icon(IconData icon, { bool skipOffstage: true }) => new _IconFinder(icon, skipOffstage: skipOffstage);
/// Looks for widgets that contain a [Text] descendant with `text` /// Looks for widgets that contain a [Text] descendant with `text`
/// in it. /// in it.
/// ///
...@@ -90,7 +79,8 @@ class CommonFinders { ...@@ -90,7 +79,8 @@ class CommonFinders {
/// nodes that are [Offstage] or that are from inactive [Route]s. /// nodes that are [Offstage] or that are from inactive [Route]s.
Finder byType(Type type, { bool skipOffstage: true }) => new _WidgetTypeFinder(type, skipOffstage: skipOffstage); Finder byType(Type type, { bool skipOffstage: true }) => new _WidgetTypeFinder(type, skipOffstage: skipOffstage);
/// Finds widgets by searching for widgets with a particular icon data. /// Finds [Icon] widgets containing icon data equal to the `icon`
/// argument.
/// ///
/// Example: /// Example:
/// ///
...@@ -421,23 +411,6 @@ class _TextFinder extends MatchFinder { ...@@ -421,23 +411,6 @@ class _TextFinder extends MatchFinder {
} }
} }
class _IconFinder extends MatchFinder {
_IconFinder(this.icon, { bool skipOffstage: true }) : super(skipOffstage: skipOffstage);
final IconData icon;
@override
String get description => 'icon "$icon"';
@override
bool matches(Element candidate) {
if (candidate.widget is! Icon)
return false;
final Icon iconWidget = candidate.widget;
return iconWidget.icon == icon;
}
}
class _WidgetWithTextFinder extends Finder { class _WidgetWithTextFinder extends Finder {
_WidgetWithTextFinder(this.widgetType, this.text, { bool skipOffstage: true }) : super(skipOffstage: skipOffstage); _WidgetWithTextFinder(this.widgetType, this.text, { bool skipOffstage: true }) : super(skipOffstage: skipOffstage);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
...@@ -306,12 +307,18 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker ...@@ -306,12 +307,18 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
if (event is PointerDownEvent) { if (event is PointerDownEvent) {
final RenderObject innerTarget = result.path.firstWhere( final RenderObject innerTarget = result.path.firstWhere(
(HitTestEntry candidate) => candidate.target is RenderObject, (HitTestEntry candidate) => candidate.target is RenderObject,
orElse: () => null ).target;
)?.target; final Element innerTargetElement = collectAllElementsFrom(
if (innerTarget == null) binding.renderViewElement,
return null; skipOffstage: true,
final Element innerTargetElement = collectAllElementsFrom(binding.renderViewElement, skipOffstage: true) ).lastWhere(
.lastWhere((Element element) => element.renderObject == innerTarget); (Element element) => element.renderObject == innerTarget,
orElse: () => null,
);
if (innerTargetElement == null) {
debugPrint('No widgets found at ${binding.globalToLocal(event.position)}.');
return;
}
final List<Element> candidates = <Element>[]; final List<Element> candidates = <Element>[];
innerTargetElement.visitAncestorElements((Element element) { innerTargetElement.visitAncestorElements((Element element) {
candidates.add(element); candidates.add(element);
...@@ -324,9 +331,18 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker ...@@ -324,9 +331,18 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
int totalNumber = 0; int totalNumber = 0;
debugPrint('Some possible finders for the widgets at ${binding.globalToLocal(event.position)}:'); debugPrint('Some possible finders for the widgets at ${binding.globalToLocal(event.position)}:');
for (Element element in candidates) { for (Element element in candidates) {
if (totalNumber > 10) if (totalNumber > 13) // an arbitrary number of finders that feels useful without being overwhelming
break; break;
totalNumber += 1; totalNumber += 1; // optimistically assume we'll be able to describe it
if (element.widget is Tooltip) {
final Tooltip widget = element.widget;
final Iterable<Element> matches = find.byTooltip(widget.message).evaluate();
if (matches.length == 1) {
debugPrint(' find.byTooltip(\'${widget.message}\')');
continue;
}
}
if (element.widget is Text) { if (element.widget is Text) {
assert(descendantText == null); assert(descendantText == null);
...@@ -347,7 +363,7 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker ...@@ -347,7 +363,7 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
key is ValueKey<bool>)) { key is ValueKey<bool>)) {
keyLabel = 'const ${element.widget.key.runtimeType}(${key.value})'; keyLabel = 'const ${element.widget.key.runtimeType}(${key.value})';
} else if (key is ValueKey<String>) { } else if (key is ValueKey<String>) {
keyLabel = 'const ${element.widget.key.runtimeType}(\'${key.value}\')'; keyLabel = 'const Key(\'${key.value}\')';
} }
if (keyLabel != null) { if (keyLabel != null) {
final Iterable<Element> matches = find.byKey(key).evaluate(); final Iterable<Element> matches = find.byKey(key).evaluate();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment