Minor widget_tester refactoring and docs (#3472)

This reorders some classes so that this file makes more sense, and adds
a bunch of docs. It also makes the following changes:

* Move allElements from Instrumentation to TestWidgets. (Instrumentation
  is going away.)

* Remove findElements.

* Rename byElement to byElementPredicate

* Rename byPredicate to byWidgetPredicate

* Implement _WidgetPredicateFinder so that byWidgetPredicate has good
  messages

* Fix one use of byElementPredicate to use byWidgetPredicate.
diff --git a/dev/manual_tests/test/card_collection_test.dart b/dev/manual_tests/test/card_collection_test.dart
index 377ce1c..ec7760b 100644
--- a/dev/manual_tests/test/card_collection_test.dart
+++ b/dev/manual_tests/test/card_collection_test.dart
@@ -15,8 +15,7 @@
       tester.pump(); // see https://github.com/flutter/flutter/issues/1865
       tester.pump(); // triggers a frame
 
-      Finder navigationMenu = find.byElement((Element element) {
-        Widget widget = element.widget;
+      Finder navigationMenu = find.byWidgetPredicate((Widget widget) {
         if (widget is Tooltip)
           return widget.message == 'Open navigation menu';
         return false;
diff --git a/examples/material_gallery/test/smoke_test.dart b/examples/material_gallery/test/smoke_test.dart
index 354f4a5..20224d1 100644
--- a/examples/material_gallery/test/smoke_test.dart
+++ b/examples/material_gallery/test/smoke_test.dart
@@ -14,14 +14,14 @@
 const List<String> demoCategories = const <String>['Demos', 'Components', 'Style'];
 
 Finder findGalleryItemByRouteName(WidgetTester tester, String routeName) {
-  return find.byPredicate((Widget widget) {
+  return find.byWidgetPredicate((Widget widget) {
     return widget is material_gallery.GalleryItem
         && widget.routeName == routeName;
   });
 }
 
 Finder byTooltip(WidgetTester tester, String message) {
-  return find.byPredicate((Widget widget) {
+  return find.byWidgetPredicate((Widget widget) {
     return widget is Tooltip && widget.message == message;
   });
 }
diff --git a/packages/flutter/test/widget/multichild_test.dart b/packages/flutter/test/widget/multichild_test.dart
index 9e2a39f..ce43fa5 100644
--- a/packages/flutter/test/widget/multichild_test.dart
+++ b/packages/flutter/test/widget/multichild_test.dart
@@ -10,8 +10,9 @@
 import 'test_widgets.dart';
 
 void checkTree(WidgetTester tester, List<BoxDecoration> expectedDecorations) {
-  MultiChildRenderObjectElement element =
-      tester.elementOf(find.byElement((Element element) => element is MultiChildRenderObjectElement));
+  MultiChildRenderObjectElement element = tester.elementOf(find.byElementPredicate(
+    (Element element) => element is MultiChildRenderObjectElement
+  ));
   expect(element, isNotNull);
   expect(element.renderObject is RenderStack, isTrue);
   RenderStack renderObject = element.renderObject;
diff --git a/packages/flutter/test/widget/parent_data_test.dart b/packages/flutter/test/widget/parent_data_test.dart
index da57f96..956371a 100644
--- a/packages/flutter/test/widget/parent_data_test.dart
+++ b/packages/flutter/test/widget/parent_data_test.dart
@@ -19,8 +19,9 @@
 }
 
 void checkTree(WidgetTester tester, List<TestParentData> expectedParentData) {
-  MultiChildRenderObjectElement element =
-      tester.elementOf(find.byElement((Element element) => element is MultiChildRenderObjectElement));
+  MultiChildRenderObjectElement element = tester.elementOf(
+    find.byElementPredicate((Element element) => element is MultiChildRenderObjectElement)
+  );
   expect(element, isNotNull);
   expect(element.renderObject is RenderStack, isTrue);
   RenderStack renderObject = element.renderObject;
diff --git a/packages/flutter/test/widget/stateful_component_test.dart b/packages/flutter/test/widget/stateful_component_test.dart
index 428a3d1..778219c 100644
--- a/packages/flutter/test/widget/stateful_component_test.dart
+++ b/packages/flutter/test/widget/stateful_component_test.dart
@@ -14,8 +14,9 @@
     testWidgets((WidgetTester tester) {
 
       void checkTree(BoxDecoration expectedDecoration) {
-        SingleChildRenderObjectElement element =
-            tester.elementOf(find.byElement((Element element) => element is SingleChildRenderObjectElement));
+        SingleChildRenderObjectElement element = tester.elementOf(
+          find.byElementPredicate((Element element) => element is SingleChildRenderObjectElement)
+        );
         expect(element, isNotNull);
         expect(element.renderObject is RenderDecoratedBox, isTrue);
         RenderDecoratedBox renderObject = element.renderObject;
diff --git a/packages/flutter_test/lib/src/instrumentation.dart b/packages/flutter_test/lib/src/instrumentation.dart
index d0d774e..fb35554 100644
--- a/packages/flutter_test/lib/src/instrumentation.dart
+++ b/packages/flutter_test/lib/src/instrumentation.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:collection';
-
 import 'package:flutter/gestures.dart';
 import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
@@ -63,20 +61,6 @@
     return null;
   }
 
-  /// Returns all elements ordered in a depth-first traversal fashion.
-  ///
-  /// The returned iterable is lazy. It does not walk the entire element tree
-  /// immediately, but rather a chunk at a time as the iteration progresses
-  /// using [Iterator.moveNext].
-  Iterable<Element> get allElements {
-    return new _DepthFirstChildIterable(binding.renderViewElement);
-  }
-
-  /// Returns all elements that satisfy [predicate].
-  Iterable<Element> findElements(bool predicate(Element element)) {
-    return allElements.where(predicate);
-  }
-
   /// Returns the first element that corresponds to a widget with the
   /// given [Key], or null if there is no such element.
   Element findElementByKey(Key key) {
@@ -248,42 +232,3 @@
     return result;
   }
 }
-
-class _DepthFirstChildIterable extends IterableBase<Element> {
-  _DepthFirstChildIterable(this.rootElement);
-
-  Element rootElement;
-
-  @override
-  Iterator<Element> get iterator => new _DepthFirstChildIterator(rootElement);
-}
-
-class _DepthFirstChildIterator implements Iterator<Element> {
-  _DepthFirstChildIterator(Element rootElement)
-      : _stack = _reverseChildrenOf(rootElement).toList();
-
-  Element _current;
-
-  final List<Element> _stack;
-
-  @override
-  Element get current => _current;
-
-  @override
-  bool moveNext() {
-    if (_stack.isEmpty)
-      return false;
-
-    _current = _stack.removeLast();
-    // Stack children in reverse order to traverse first branch first
-    _stack.addAll(_reverseChildrenOf(_current));
-
-    return true;
-  }
-
-  static Iterable<Element> _reverseChildrenOf(Element element) {
-    List<Element> children = <Element>[];
-    element.visitChildren(children.add);
-    return children.reversed;
-  }
-}
diff --git a/packages/flutter_test/lib/src/widget_tester.dart b/packages/flutter_test/lib/src/widget_tester.dart
index faac1c5..aa84e12 100644
--- a/packages/flutter_test/lib/src/widget_tester.dart
+++ b/packages/flutter_test/lib/src/widget_tester.dart
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'dart:collection';
+
+import 'package:flutter/gestures.dart';
 import 'package:flutter/rendering.dart';
 import 'package:flutter/widgets.dart';
 import 'package:quiver/testing/async.dart';
@@ -10,6 +13,12 @@
 import 'binding.dart';
 import 'test_pointer.dart';
 
+/// Signature for [CommonFinders.byPredicate].
+typedef bool WidgetPredicate(Widget widget);
+
+/// Signature for [CommonFinders.byElement].
+typedef bool ElementPredicate(Element element);
+
 /// Runs the [callback] inside the Flutter test environment.
 ///
 /// Use this function for testing custom [StatelessWidget]s and
@@ -30,26 +39,6 @@
   });
 }
 
-/// A convenient accessor to frequently used finders.
-///
-/// Examples:
-///
-///     tester.tap(find.text('Save'));
-///     tester.widget(find.byType(MyWidget));
-///     tester.stateOf(find.byConfig(config));
-///     tester.getSize(find.byKey(new ValueKey('save-button')));
-const CommonFinders find = const CommonFinders._();
-
-/// Asserts that [finder] locates a widget in the test element tree.
-///
-/// Example:
-///
-///     expect(tester, hasWidget(find.text('Save')));
-Matcher hasWidget(Finder finder) => new _HasWidgetMatcher(finder);
-
-/// Opposite of [hasWidget].
-Matcher doesNotHaveWidget(Finder finder) => new _DoesNotHaveWidgetMatcher(finder);
-
 /// Class that programmatically interacts with widgets and the test environment.
 class WidgetTester {
   WidgetTester._(this.elementTreeTester);
@@ -57,6 +46,8 @@
   /// Exposes the [Element] tree created from widgets.
   final ElementTreeTester elementTreeTester;
 
+  /// The binding instance that the widget tester is using when it
+  /// needs a binding (e.g. for event dispatch).
   Widgeteer get binding => elementTreeTester.binding;
 
   /// Renders the UI from the given [widget].
@@ -114,8 +105,7 @@
   /// All widgets currently live on the UI returned in a depth-first traversal
   /// order.
   Iterable<Widget> get widgets {
-    return this.elementTreeTester.allElements
-      .map((Element element) => element.widget);
+    return this.allElements.map((Element element) => element.widget);
   }
 
   /// Finds the first widget, searching in the depth-first traversal order.
@@ -233,16 +223,82 @@
     Element element = finder.findFirst(this);
     return elementTreeTester.getBottomRight(element);
   }
+
+  /// Returns all elements ordered in a depth-first traversal fashion.
+  ///
+  /// The returned iterable is lazy. It does not walk the entire element tree
+  /// immediately, but rather a chunk at a time as the iteration progresses
+  /// using [Iterator.moveNext].
+  Iterable<Element> get allElements {
+    return new _DepthFirstChildIterable(binding.renderViewElement);
+  }
 }
 
+class _DepthFirstChildIterable extends IterableBase<Element> {
+  _DepthFirstChildIterable(this.rootElement);
+
+  Element rootElement;
+
+  @override
+  Iterator<Element> get iterator => new _DepthFirstChildIterator(rootElement);
+}
+
+class _DepthFirstChildIterator implements Iterator<Element> {
+  _DepthFirstChildIterator(Element rootElement)
+      : _stack = _reverseChildrenOf(rootElement).toList();
+
+  Element _current;
+
+  final List<Element> _stack;
+
+  @override
+  Element get current => _current;
+
+  @override
+  bool moveNext() {
+    if (_stack.isEmpty)
+      return false;
+
+    _current = _stack.removeLast();
+    // Stack children in reverse order to traverse first branch first
+    _stack.addAll(_reverseChildrenOf(_current));
+
+    return true;
+  }
+
+  static Iterable<Element> _reverseChildrenOf(Element element) {
+    final List<Element> children = <Element>[];
+    element.visitChildren(children.add);
+    return children.reversed;
+  }
+}
+
+/// A convenient accessor to frequently used finders.
+///
+/// Examples:
+///
+///     tester.tap(find.text('Save'));
+///     tester.widget(find.byType(MyWidget));
+///     tester.stateOf(find.byConfig(config));
+///     tester.getSize(find.byKey(new ValueKey('save-button')));
+const CommonFinders find = const CommonFinders._();
+
 /// Provides lightweight syntax for getting frequently used widget [Finder]s.
+///
+/// This class is instantiated once, as [find].
 class CommonFinders {
   const CommonFinders._();
 
-  /// Finds [Text] widgets containing string equal to [text].
+  /// Finds [Text] widgets containing string equal to the `text`
+  /// argument.
+  ///
+  /// Example:
+  ///
+  ///     expect(tester, hasWidget(find.text('Back')));
   Finder text(String text) => new _TextFinder(text);
 
-  /// Looks for widgets that contain [Text] with [text] in it.
+  /// Looks for widgets that contain a [Text] descendant with `text`
+  /// in it.
   ///
   /// Example:
   ///
@@ -255,32 +311,67 @@
   ///     tester.tap(find.widgetWithText(Button, 'Update'));
   Finder widgetWithText(Type widgetType, String text) => new _WidgetWithTextFinder(widgetType, text);
 
-  /// Finds widgets by [key].
+  /// Finds widgets by searching for one with a particular [Key].
+  ///
+  /// Example:
+  ///
+  ///     expect(tester, hasWidget(find.byKey(backKey)));
   Finder byKey(Key key) => new _KeyFinder(key);
 
-  /// Finds widgets by [type].
+  /// Finds widgets by searching for widgehts with a particular type.
+  ///
+  /// The `type` argument must be a subclass of [Widget].
+  ///
+  /// Example:
+  ///
+  ///     expect(tester, hasWidget(find.byType(IconButton)));
   Finder byType(Type type) => new _TypeFinder(type);
 
-  /// Finds widgets equal to [config].
+  /// Finds widgets whose current widget is the instance given by the
+  /// argument.
+  ///
+  /// Example:
+  ///
+  ///     // Suppose you have a button created like this:
+  ///     Widget myButton = new Button(
+  ///       child: new Text('Update')
+  ///     );
+  ///
+  ///     // You can find and tap on it like this:
+  ///     tester.tap(find.byConfig(myButton));
   Finder byConfig(Widget config) => new _ConfigFinder(config);
 
-  /// Finds widgets using a [predicate].
-  Finder byPredicate(WidgetPredicate predicate) {
-    return new _ElementFinder((Element element) => predicate(element.widget));
-  }
+  /// Finds widgets using a widget predicate.
+  ///
+  /// Example:
+  ///
+  ///     expect(tester, hasWidget(find.byWidgetPredicate(
+  ///       (Widget widget) => widget is Tooltip && widget.message == 'Back'
+  ///     )));
+  Finder byWidgetPredicate(WidgetPredicate predicate) => new _WidgetPredicateFinder(predicate);
 
-  /// Finds widgets using an element [predicate].
-  Finder byElement(ElementPredicate predicate) => new _ElementFinder(predicate);
+  /// Finds widgets using an element predicate.
+  ///
+  /// Example:
+  ///
+  ///     expect(tester, hasWidget(find.byWidgetPredicate(
+  ///       (Element element) => element is SingleChildRenderObjectElement
+  ///     )));
+  Finder byElementPredicate(ElementPredicate predicate) => new _ElementPredicateFinder(predicate);
 }
 
 /// Finds [Element]s inside the element tree.
 abstract class Finder {
+  /// Returns all the elements that match this finder's pattern,
+  /// using the given tester to determine which element tree to look at.
   Iterable<Element> find(WidgetTester tester);
 
-  /// Describes what the finder is looking for. The description should be such
-  /// that [toString] reads as a descriptive English sentence.
+  /// Describes what the finder is looking for. The description should be
+  /// a brief English noun phrase describing the finder's pattern.
   String get description;
 
+  /// Returns the first value returned from [find], unless no value is found,
+  /// in which case it throws an [ElementNotFoundError].
   Element findFirst(WidgetTester tester) {
     Iterable<Element> results = find(tester);
     return results.isNotEmpty
@@ -316,7 +407,7 @@
 
   @override
   Iterable<Element> find(WidgetTester tester) {
-    return tester.elementTreeTester.findElements((Element element) {
+    return tester.allElements.where((Element element) {
       if (element.widget is! Text)
         return false;
       Text textWidget = element.widget;
@@ -336,7 +427,7 @@
 
   @override
   Iterable<Element> find(WidgetTester tester) {
-    return tester.elementTreeTester.allElements
+    return tester.allElements
       .map((Element textElement) {
         if (textElement.widget is! Text)
           return null;
@@ -370,7 +461,9 @@
 
   @override
   Iterable<Element> find(WidgetTester tester) {
-    return tester.elementTreeTester.findElements((Element element) => element.widget.key == key);
+    return tester.allElements.where((Element element) {
+      return element.widget.key == key;
+    });
   }
 }
 
@@ -384,7 +477,7 @@
 
   @override
   Iterable<Element> find(WidgetTester tester) {
-    return tester.elementTreeTester.allElements.where((Element element) {
+    return tester.allElements.where((Element element) {
       return element.widget.runtimeType == widgetType;
     });
   }
@@ -400,29 +493,49 @@
 
   @override
   Iterable<Element> find(WidgetTester tester) {
-    return tester.elementTreeTester.allElements.where((Element element) {
+    return tester.allElements.where((Element element) {
       return element.widget == config;
     });
   }
 }
 
-typedef bool WidgetPredicate(Widget element);
-typedef bool ElementPredicate(Element element);
+class _WidgetPredicateFinder extends Finder {
+  _WidgetPredicateFinder(this.predicate);
 
-class _ElementFinder extends Finder {
-  _ElementFinder(this.predicate);
+  final WidgetPredicate predicate;
+
+  @override
+  String get description => 'widget predicate ($predicate)';
+
+  @override
+  Iterable<Element> find(WidgetTester tester) {
+    return tester.allElements.where((Element element) {
+      return predicate(element.widget);
+    });
+  }
+}
+
+class _ElementPredicateFinder extends Finder {
+  _ElementPredicateFinder(this.predicate);
 
   final ElementPredicate predicate;
 
   @override
-  String get description => 'element satisfying given predicate ($predicate)';
+  String get description => 'element predicate ($predicate)';
 
   @override
   Iterable<Element> find(WidgetTester tester) {
-    return tester.elementTreeTester.allElements.where(predicate);
+    return tester.allElements.where(predicate);
   }
 }
 
+/// Asserts that [finder] locates a widget in the test element tree.
+///
+/// Example:
+///
+///     expect(tester, hasWidget(find.text('Save')));
+Matcher hasWidget(Finder finder) => new _HasWidgetMatcher(finder);
+
 class _HasWidgetMatcher extends Matcher {
   const _HasWidgetMatcher(this.finder);
 
@@ -445,6 +558,14 @@
   }
 }
 
+/// Asserts that [finder] does not locate a widget in the test element tree.
+/// Opposite of [hasWidget].
+///
+/// Example:
+///
+///     expect(tester, doesNotHaveWidget(find.text('Save')));
+Matcher doesNotHaveWidget(Finder finder) => new _DoesNotHaveWidgetMatcher(finder);
+
 class _DoesNotHaveWidgetMatcher extends Matcher {
   const _DoesNotHaveWidgetMatcher(this.finder);