Commit 91dd9699 authored by Ian Hickson's avatar Ian Hickson

Refactor the test framework (#3622)

* Refactor widget test framework

Instead of:

```dart
  test("Card Collection smoke test", () {
    testWidgets((WidgetTester tester) {
```

...you now say:

```dart
  testWidgets("Card Collection smoke test", (WidgetTester tester) {
```

Instead of:

```dart
  expect(tester, hasWidget(find.text('hello')));
```

...you now say:

```dart
  expect(find.text('hello'), findsOneWidget);
```

Instead of the previous API (exists, widgets, widget, stateOf,
elementOf, etc), you now have the following comprehensive API. All these
are functions that take a Finder, except the all* properties.

* `any()` - true if anything matches, c.f. `Iterable.any`
* `allWidgets` - all the widgets in the tree
* `widget()` - the one and only widget that matches the finder
* `firstWidget()` - the first widget that matches the finder
* `allElements` - all the elements in the tree
* `element()` - the one and only element that matches the finder
* `firstElement()` - the first element that matches the finder
* `allStates` - all the `State`s in the tree
* `state()` - the one and only state that matches the finder
* `firstState()` - the first state that matches the finder
* `allRenderObjects` - all the render objects in the tree
* `renderObject()` - the one and only render object that matches the finder
* `firstRenderObject()` - the first render object that matches the finder

There's also `layers' which returns the list of current layers.

`tap`, `fling`, getCenter, getSize, etc, take Finders, like the APIs
above, and expect there to only be one matching widget.

The finders are:

 * `find.text(String text)`
 * `find.widgetWithText(Type widgetType, String text)`
 * `find.byKey(Key key)`
 * `find.byType(Type type)`
 * `find.byElementType(Type type)`
 * `find.byConfig(Widget config)`
 * `find.byWidgetPredicate(WidgetPredicate predicate)`
 * `find.byElementPredicate(ElementPredicate predicate)`

The matchers (for `expect`) are:

 * `findsNothing`
 * `findsWidgets`
 * `findsOneWidget`
 * `findsNWidgets(n)`
 * `isOnStage`
 * `isOffStage`
 * `isInCard`
 * `isNotInCard`

Benchmarks now use benchmarkWidgets instead of testWidgets.

Also, for those of you using mockers, `serviceMocker` now automatically
handles the binding initialization.

This patch also:

* changes how tests are run so that we can more easily swap the logic
  out for a "real" mode instead of FakeAsync.

* introduces CachingIterable.

* changes how flutter_driver interacts with the widget tree to use the
  aforementioned new API rather than ElementTreeTester, which is gone.

* removes ElementTreeTester.

* changes the semantics of a test for scrollables because we couldn't
  convince ourselves that the old semantics made sense; it only worked
  before because flushing the microtasks after every event was broken.

* fixes the flushing of microtasks after every event.

* Reindent the tests

* Fix review comments
parent e60a624a
...@@ -9,33 +9,31 @@ import 'package:test/test.dart'; ...@@ -9,33 +9,31 @@ import 'package:test/test.dart';
import '../card_collection.dart' as card_collection; import '../card_collection.dart' as card_collection;
void main() { void main() {
test("Card Collection smoke test", () { testWidgets("Card Collection smoke test", (WidgetTester tester) {
testWidgets((WidgetTester tester) { card_collection.main(); // builds the app and schedules a frame but doesn't trigger one
card_collection.main(); // builds the app and schedules a frame but doesn't trigger one tester.pump(); // see https://github.com/flutter/flutter/issues/1865
tester.pump(); // see https://github.com/flutter/flutter/issues/1865 tester.pump(); // triggers a frame
tester.pump(); // triggers a frame
Finder navigationMenu = find.byWidgetPredicate((Widget widget) { Finder navigationMenu = find.byWidgetPredicate((Widget widget) {
if (widget is Tooltip) if (widget is Tooltip)
return widget.message == 'Open navigation menu'; return widget.message == 'Open navigation menu';
return false; return false;
}); });
expect(tester, hasWidget(navigationMenu)); expect(navigationMenu, findsOneWidget);
tester.tap(navigationMenu); tester.tap(navigationMenu);
tester.pump(); // start opening menu tester.pump(); // start opening menu
tester.pump(const Duration(seconds: 1)); // wait til it's really opened tester.pump(const Duration(seconds: 1)); // wait til it's really opened
// smoke test for various checkboxes // smoke test for various checkboxes
tester.tap(find.text('Make card labels editable')); tester.tap(find.text('Make card labels editable'));
tester.pump(); tester.pump();
tester.tap(find.text('Let the sun shine')); tester.tap(find.text('Let the sun shine'));
tester.pump(); tester.pump();
tester.tap(find.text('Make card labels editable')); tester.tap(find.text('Make card labels editable'));
tester.pump(); tester.pump();
tester.tap(find.text('Vary font sizes')); tester.tap(find.text('Vary font sizes'));
tester.pump(); tester.pump();
});
}); });
} }
...@@ -8,12 +8,10 @@ import 'package:test/test.dart'; ...@@ -8,12 +8,10 @@ import 'package:test/test.dart';
import '../lib/main.dart' as hello_world; import '../lib/main.dart' as hello_world;
void main() { void main() {
test("Hello world smoke test", () { testWidgets("Hello world smoke test", (WidgetTester tester) {
testWidgets((WidgetTester tester) { hello_world.main(); // builds the app and schedules a frame but doesn't trigger one
hello_world.main(); // builds the app and schedules a frame but doesn't trigger one tester.pump(); // triggers a frame
tester.pump(); // triggers a frame
expect(tester, hasWidget(find.text('Hello, world!'))); expect(find.text('Hello, world!'), findsOneWidget);
});
}); });
} }
...@@ -35,7 +35,7 @@ Finder findBackButton(WidgetTester tester) => byTooltip(tester, 'Back'); ...@@ -35,7 +35,7 @@ Finder findBackButton(WidgetTester tester) => byTooltip(tester, 'Back');
void smokeDemo(WidgetTester tester, String routeName) { void smokeDemo(WidgetTester tester, String routeName) {
// Ensure that we're (likely to be) on the home page // Ensure that we're (likely to be) on the home page
final Finder menuItem = findGalleryItemByRouteName(tester, routeName); final Finder menuItem = findGalleryItemByRouteName(tester, routeName);
expect(tester, hasWidget(menuItem)); expect(menuItem, findsOneWidget);
tester.tap(menuItem); tester.tap(menuItem);
tester.pump(); // Launch the demo. tester.pump(); // Launch the demo.
...@@ -43,58 +43,56 @@ void smokeDemo(WidgetTester tester, String routeName) { ...@@ -43,58 +43,56 @@ void smokeDemo(WidgetTester tester, String routeName) {
// Go back // Go back
Finder backButton = findBackButton(tester); Finder backButton = findBackButton(tester);
expect(tester, hasWidget(backButton)); expect(backButton, findsOneWidget);
tester.tap(backButton); tester.tap(backButton);
tester.pump(); // Start the navigator pop "back" operation. tester.pump(); // Start the navigator pop "back" operation.
tester.pump(const Duration(seconds: 1)); // Wait until it has finished. tester.pump(const Duration(seconds: 1)); // Wait until it has finished.
} }
void main() { void main() {
test('Material Gallery app smoke test', () { testWidgets('Material Gallery app smoke test', (WidgetTester tester) {
testWidgets((WidgetTester tester) { material_gallery_main.main(); // builds the app and schedules a frame but doesn't trigger one
material_gallery_main.main(); // builds the app and schedules a frame but doesn't trigger one tester.pump(); // see https://github.com/flutter/flutter/issues/1865
tester.pump(); // see https://github.com/flutter/flutter/issues/1865 tester.pump(); // triggers a frame
tester.pump(); // triggers a frame
// Expand the demo category submenus.
// Expand the demo category submenus. for (String category in demoCategories.reversed) {
for (String category in demoCategories.reversed) { tester.tap(find.text(category));
tester.tap(find.text(category));
tester.pump();
tester.pump(const Duration(seconds: 1)); // Wait until the menu has expanded.
}
final List<double> scrollDeltas = new List<double>();
double previousY = tester.getTopRight(find.text(demoCategories[0])).y;
final List<String> routeNames = material_gallery_app.kRoutes.keys.toList();
for (String routeName in routeNames) {
final double y = tester.getTopRight(findGalleryItemByRouteName(tester, routeName)).y;
scrollDeltas.add(previousY - y);
previousY = y;
}
// Launch each demo and then scroll that item out of the way.
for (int i = 0; i < routeNames.length; i += 1) {
final String routeName = routeNames[i];
smokeDemo(tester, routeName);
tester.scroll(findGalleryItemByRouteName(tester, routeName), new Offset(0.0, scrollDeltas[i]));
tester.pump();
}
Finder navigationMenuButton = findNavigationMenuButton(tester);
expect(tester, hasWidget(navigationMenuButton));
tester.tap(navigationMenuButton);
tester.pump(); // Start opening drawer.
tester.pump(const Duration(seconds: 1)); // Wait until it's really opened.
// switch theme
tester.tap(find.text('Dark'));
tester.pump(); tester.pump();
tester.pump(const Duration(seconds: 1)); // Wait until it's changed. tester.pump(const Duration(seconds: 1)); // Wait until the menu has expanded.
}
// switch theme
tester.tap(find.text('Light')); final List<double> scrollDeltas = new List<double>();
double previousY = tester.getTopRight(find.text(demoCategories[0])).y;
final List<String> routeNames = material_gallery_app.kRoutes.keys.toList();
for (String routeName in routeNames) {
final double y = tester.getTopRight(findGalleryItemByRouteName(tester, routeName)).y;
scrollDeltas.add(previousY - y);
previousY = y;
}
// Launch each demo and then scroll that item out of the way.
for (int i = 0; i < routeNames.length; i += 1) {
final String routeName = routeNames[i];
smokeDemo(tester, routeName);
tester.scroll(findGalleryItemByRouteName(tester, routeName), new Offset(0.0, scrollDeltas[i]));
tester.pump(); tester.pump();
tester.pump(const Duration(seconds: 1)); // Wait until it's changed. }
});
Finder navigationMenuButton = findNavigationMenuButton(tester);
expect(navigationMenuButton, findsOneWidget);
tester.tap(navigationMenuButton);
tester.pump(); // Start opening drawer.
tester.pump(const Duration(seconds: 1)); // Wait until it's really opened.
// switch theme
tester.tap(find.text('Dark'));
tester.pump();
tester.pump(const Duration(seconds: 1)); // Wait until it's changed.
// switch theme
tester.tap(find.text('Light'));
tester.pump();
tester.pump(const Duration(seconds: 1)); // Wait until it's changed.
}); });
} }
...@@ -38,11 +38,11 @@ Element findElementOfExactWidgetTypeGoingUp(Element node, Type targetType) { ...@@ -38,11 +38,11 @@ Element findElementOfExactWidgetTypeGoingUp(Element node, Type targetType) {
final RegExp materialIconAssetNameColorExtractor = new RegExp(r'[^/]+/ic_.+_(white|black)_[0-9]+dp\.png'); final RegExp materialIconAssetNameColorExtractor = new RegExp(r'[^/]+/ic_.+_(white|black)_[0-9]+dp\.png');
void checkIconColor(ElementTreeTester tester, String label, Color color) { void checkIconColor(WidgetTester tester, String label, Color color) {
// The icon is going to be in the same merged semantics box as the text // The icon is going to be in the same merged semantics box as the text
// regardless of how the menu item is represented, so this is a good // regardless of how the menu item is represented, so this is a good
// way to find the menu item. I hope. // way to find the menu item. I hope.
Element semantics = findElementOfExactWidgetTypeGoingUp(tester.findText(label), MergeSemantics); Element semantics = findElementOfExactWidgetTypeGoingUp(tester.element(find.text(label)), MergeSemantics);
expect(semantics, isNotNull); expect(semantics, isNotNull);
Element asset = findElementOfExactWidgetTypeGoingDown(semantics, Text); Element asset = findElementOfExactWidgetTypeGoingDown(semantics, Text);
Text text = asset.widget; Text text = asset.widget;
...@@ -52,47 +52,44 @@ void checkIconColor(ElementTreeTester tester, String label, Color color) { ...@@ -52,47 +52,44 @@ void checkIconColor(ElementTreeTester tester, String label, Color color) {
void main() { void main() {
stock_data.StockDataFetcher.actuallyFetchData = false; stock_data.StockDataFetcher.actuallyFetchData = false;
test("Test icon colors", () { testWidgets("Test icon colors", (WidgetTester tester) {
testWidgets((WidgetTester tester) { stocks.main(); // builds the app and schedules a frame but doesn't trigger one
stocks.main(); // builds the app and schedules a frame but doesn't trigger one tester.pump(); // see https://github.com/flutter/flutter/issues/1865
tester.pump(); // see https://github.com/flutter/flutter/issues/1865 tester.pump(); // triggers a frame
tester.pump(); // triggers a frame
// sanity check // sanity check
expect(tester, hasWidget(find.text('MARKET'))); expect(find.text('MARKET'), findsOneWidget);
expect(tester, doesNotHaveWidget(find.text('Help & Feedback'))); expect(find.text('Help & Feedback'), findsNothing);
tester.pump(new Duration(seconds: 2)); tester.pump(new Duration(seconds: 2));
expect(tester, hasWidget(find.text('MARKET'))); expect(find.text('MARKET'), findsOneWidget);
expect(tester, doesNotHaveWidget(find.text('Help & Feedback'))); expect(find.text('Help & Feedback'), findsNothing);
// drag the drawer out // drag the drawer out
Point left = new Point(0.0, ui.window.size.height / 2.0); Point left = new Point(0.0, ui.window.size.height / 2.0);
Point right = new Point(ui.window.size.width, left.y); Point right = new Point(ui.window.size.width, left.y);
TestGesture gesture = tester.startGesture(left); TestGesture gesture = tester.startGesture(left);
tester.pump(); tester.pump();
gesture.moveTo(right); gesture.moveTo(right);
tester.pump(); tester.pump();
gesture.up(); gesture.up();
tester.pump(); tester.pump();
expect(tester, hasWidget(find.text('MARKET'))); expect(find.text('MARKET'), findsOneWidget);
expect(tester, hasWidget(find.text('Help & Feedback'))); expect(find.text('Help & Feedback'), findsOneWidget);
// check the colour of the icon - light mode // check the colour of the icon - light mode
checkIconColor(tester.elementTreeTester, 'Stock List', Colors.purple[500]); // theme primary color checkIconColor(tester, 'Stock List', Colors.purple[500]); // theme primary color
checkIconColor(tester.elementTreeTester, 'Account Balance', Colors.black45); // enabled checkIconColor(tester, 'Account Balance', Colors.black45); // enabled
checkIconColor(tester.elementTreeTester, 'Help & Feedback', Colors.black26); // disabled checkIconColor(tester, 'Help & Feedback', Colors.black26); // disabled
// switch to dark mode // switch to dark mode
tester.tap(find.text('Pessimistic')); tester.tap(find.text('Pessimistic'));
tester.pump(); // get the tap and send the notification that the theme has changed tester.pump(); // get the tap and send the notification that the theme has changed
tester.pump(); // start the theme transition tester.pump(); // start the theme transition
tester.pump(const Duration(seconds: 5)); // end the transition tester.pump(const Duration(seconds: 5)); // end the transition
// check the colour of the icon - dark mode // check the colour of the icon - dark mode
checkIconColor(tester.elementTreeTester, 'Stock List', Colors.redAccent[200]); // theme accent color checkIconColor(tester, 'Stock List', Colors.redAccent[200]); // theme accent color
checkIconColor(tester.elementTreeTester, 'Account Balance', Colors.white); // enabled checkIconColor(tester, 'Account Balance', Colors.white); // enabled
checkIconColor(tester.elementTreeTester, 'Help & Feedback', Colors.white30); // disabled checkIconColor(tester, 'Help & Feedback', Colors.white30); // disabled
});
}); });
} }
...@@ -10,16 +10,13 @@ import 'package:test/test.dart'; ...@@ -10,16 +10,13 @@ import 'package:test/test.dart';
void main() { void main() {
stock_data.StockDataFetcher.actuallyFetchData = false; stock_data.StockDataFetcher.actuallyFetchData = false;
test("Test changing locale", () { testWidgets("Test changing locale", (WidgetTester tester) {
testWidgets((WidgetTester tester) { stocks.main();
stocks.main(); tester.flushMicrotasks(); // see https://github.com/flutter/flutter/issues/1865
tester.flushMicrotasks(); // see https://github.com/flutter/flutter/issues/1865 tester.pump();
tester.pump(); expect(find.text('MARKET'), findsOneWidget);
tester.binding.setLocale("es", "US");
expect(tester, hasWidget(find.text('MARKET'))); tester.pump();
tester.setLocale("es", "US"); expect(find.text('MERCADO'), findsOneWidget);
tester.pump();
expect(tester, hasWidget(find.text('MERCADO')));
});
}); });
} }
...@@ -10,7 +10,6 @@ const int _kNumberOfIterations = 50000; ...@@ -10,7 +10,6 @@ const int _kNumberOfIterations = 50000;
const bool _kRunForever = false; const bool _kRunForever = false;
void main() { void main() {
assert(false); // Don't run in checked mode
stock_data.StockDataFetcher.actuallyFetchData = false; stock_data.StockDataFetcher.actuallyFetchData = false;
const Duration _kAnimationDuration = const Duration(milliseconds: 200); const Duration _kAnimationDuration = const Duration(milliseconds: 200);
...@@ -21,7 +20,7 @@ void main() { ...@@ -21,7 +20,7 @@ void main() {
Stopwatch watch = new Stopwatch() Stopwatch watch = new Stopwatch()
..start(); ..start();
testWidgets((WidgetTester tester) { benchmarkWidgets((WidgetTester tester) {
stocks.main(); stocks.main();
tester.pump(); // Start startup animation tester.pump(); // Start startup animation
tester.pump(const Duration(seconds: 1)); // Complete startup animation tester.pump(const Duration(seconds: 1)); // Complete startup animation
......
...@@ -12,19 +12,18 @@ const bool _kRunForever = false; ...@@ -12,19 +12,18 @@ const bool _kRunForever = false;
void _doNothing() { } void _doNothing() { }
void main() { void main() {
assert(false); // Don't run in checked mode
stock_data.StockDataFetcher.actuallyFetchData = false; stock_data.StockDataFetcher.actuallyFetchData = false;
stocks.StocksAppState appState; stocks.StocksAppState appState;
testWidgets((WidgetTester tester) { benchmarkWidgets((WidgetTester tester) {
stocks.main(); stocks.main();
tester.pump(); // Start startup animation tester.pump(); // Start startup animation
tester.pump(const Duration(seconds: 1)); // Complete startup animation tester.pump(const Duration(seconds: 1)); // Complete startup animation
tester.tapAt(new Point(20.0, 20.0)); // Open drawer tester.tapAt(new Point(20.0, 20.0)); // Open drawer
tester.pump(); // Start drawer animation tester.pump(); // Start drawer animation
tester.pump(const Duration(seconds: 1)); // Complete drawer animation tester.pump(const Duration(seconds: 1)); // Complete drawer animation
appState = tester.stateOf(find.byType(stocks.StocksApp)); appState = tester.state(find.byType(stocks.StocksApp));
}); });
BuildOwner buildOwner = WidgetsBinding.instance.buildOwner; BuildOwner buildOwner = WidgetsBinding.instance.buildOwner;
......
...@@ -10,10 +10,9 @@ const int _kNumberOfIterations = 100000; ...@@ -10,10 +10,9 @@ const int _kNumberOfIterations = 100000;
const bool _kRunForever = false; const bool _kRunForever = false;
void main() { void main() {
assert(false); // Don't run in checked mode
stock_data.StockDataFetcher.actuallyFetchData = false; stock_data.StockDataFetcher.actuallyFetchData = false;
testWidgets((WidgetTester tester) { benchmarkWidgets((WidgetTester tester) {
stocks.main(); stocks.main();
tester.pump(); // Start startup animation tester.pump(); // Start startup animation
tester.pump(const Duration(seconds: 1)); // Complete startup animation tester.pump(const Duration(seconds: 1)); // Complete startup animation
......
...@@ -136,10 +136,11 @@ class FlutterError extends AssertionError { ...@@ -136,10 +136,11 @@ class FlutterError extends AssertionError {
/// The first time this is called, it dumps a very verbose message to the /// The first time this is called, it dumps a very verbose message to the
/// console using [debugPrint]. /// console using [debugPrint].
/// ///
/// Subsequent calls only dump the first line of the exception. /// Subsequent calls only dump the first line of the exception, unless
/// `forceReport` is set to true (in which case it dumps the verbose message).
/// ///
/// This is the default behavior for the [onError] handler. /// The default behavior for the [onError] handler is to call this function.
static void dumpErrorToConsole(FlutterErrorDetails details) { static void dumpErrorToConsole(FlutterErrorDetails details, { bool forceReport: false }) {
assert(details != null); assert(details != null);
assert(details.exception != null); assert(details.exception != null);
bool reportError = details.silent != true; // could be null bool reportError = details.silent != true; // could be null
...@@ -148,9 +149,9 @@ class FlutterError extends AssertionError { ...@@ -148,9 +149,9 @@ class FlutterError extends AssertionError {
reportError = true; reportError = true;
return true; return true;
}); });
if (!reportError) if (!reportError && !forceReport)
return; return;
if (_errorCount == 0) { if (_errorCount == 0 || forceReport) {
final String header = '\u2550\u2550\u2561 EXCEPTION CAUGHT BY ${details.library} \u255E'.toUpperCase(); final String header = '\u2550\u2550\u2561 EXCEPTION CAUGHT BY ${details.library} \u255E'.toUpperCase();
final String footer = '\u2501' * _kWrapWidth; final String footer = '\u2501' * _kWrapWidth;
debugPrint('$header${"\u2550" * (footer.length - header.length)}'); debugPrint('$header${"\u2550" * (footer.length - header.length)}');
...@@ -186,7 +187,7 @@ class FlutterError extends AssertionError { ...@@ -186,7 +187,7 @@ class FlutterError extends AssertionError {
debugPrint(information.toString(), wrapWidth: _kWrapWidth); debugPrint(information.toString(), wrapWidth: _kWrapWidth);
} }
if (details.stack != null) { if (details.stack != null) {
debugPrint('Stack trace:', wrapWidth: _kWrapWidth); debugPrint('When the exception was thrown, this was the stack:', wrapWidth: _kWrapWidth);
debugPrint('${details.stack}$footer'); // StackTrace objects include a trailing newline debugPrint('${details.stack}$footer'); // StackTrace objects include a trailing newline
} else { } else {
debugPrint(footer); debugPrint(footer);
......
...@@ -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:collection';
export 'dart:ui' show VoidCallback; export 'dart:ui' show VoidCallback;
/// Signature for callbacks that report that an underlying value has changed. /// Signature for callbacks that report that an underlying value has changed.
...@@ -52,3 +54,153 @@ class BitField<T extends dynamic> { ...@@ -52,3 +54,153 @@ class BitField<T extends dynamic> {
_bits = value ? _kAllOnes : _kAllZeros; _bits = value ? _kAllOnes : _kAllZeros;
} }
} }
/// A lazy caching version of [Iterable].
///
/// This iterable is efficient in the following ways:
///
/// * It will not walk the given iterator more than you ask for.
///
/// * If you use it twice (e.g. you check [isNotEmpty], then
/// use [single]), it will only walk the given iterator
/// once. This caching will even work efficiently if you are
/// running two side-by-side iterators on the same iterable.
///
/// * [toList] uses its EfficientLength variant to create its
/// list quickly.
///
/// It is inefficient in the following ways:
///
/// * The first iteration through has caching overhead.
///
/// * It requires more memory than a non-caching iterator.
///
/// * the [length] and [toList] properties immediately precache the
/// entire list. Using these fields therefore loses the laziness of
/// the iterable. However, it still gets cached.
///
/// The caching behavior is propagated to the iterators that are
/// created by [map], [where], [expand], [take], [takeWhile], [skip],
/// and [skipWhile], and is used by the built-in methods that use an
/// iterator like [isNotEmpty] and [single].
///
/// Because a CachingIterable only walks the underlying data once, it
/// cannot be used multiple times with the underlying data changing
/// between each use. You must create a new iterable each time. This
/// also applies to any iterables derived from this one, e.g. as
/// returned by `where`.
class CachingIterable<E> extends IterableBase<E> {
/// Creates a CachingIterable using the given [Iterator] as the
/// source of data. The iterator must be non-null and must not throw
/// exceptions.
///
/// Since the argument is an [Iterator], not an [Iterable], it is
/// guaranteed that the underlying data set will only be walked
/// once. If you have an [Iterable], you can pass its [iterator]
/// field as the argument to this constructor.
///
/// You can use a `sync*` function with this as follows:
///
/// ```dart
/// Iterable<int> range(int start, int end) sync* {
/// for (int index = start; index <= end; index += 1)
/// yield index;
/// }
///
/// Iterable<int> i = new CachingIterable<int>(range(1, 5).iterator);
/// print(i.length); // walks the list
/// print(i.length); // efficient
/// ```
CachingIterable(this._prefillIterator);
final Iterator<E> _prefillIterator;
final List<E> _results = <E>[];
@override
Iterator<E> get iterator {
return new _LazyListIterator<E>(this);
}
@override
Iterable<dynamic/*=T*/> map/*<T>*/(/*=T*/ f(E e)) {
return new CachingIterable<dynamic/*=T*/>(super.map/*<T>*/(f).iterator);
}
@override
Iterable<E> where(bool f(E element)) {
return new CachingIterable<E>(super.where(f).iterator);
}
@override
Iterable<dynamic/*=T*/> expand/*<T>*/(Iterable/*<T>*/ f(E element)) {
return new CachingIterable<dynamic/*=T*/>(super.expand/*<T>*/(f).iterator);
}
@override
Iterable<E> take(int count) {
return new CachingIterable<E>(super.take(count).iterator);
}
@override
Iterable<E> takeWhile(bool test(E value)) {
return new CachingIterable<E>(super.takeWhile(test).iterator);
}
@override
Iterable<E> skip(int count) {
return new CachingIterable<E>(super.skip(count).iterator);
}
@override
Iterable<E> skipWhile(bool test(E value)) {
return new CachingIterable<E>(super.skipWhile(test).iterator);
}
@override
int get length {
_precacheEntireList();
return _results.length;
}
@override
List<E> toList({ bool growable: true }) {
_precacheEntireList();
return new List<E>.from(_results, growable: growable);
}
void _precacheEntireList() {
while (_fillNext()) { }
}
bool _fillNext() {
if (!_prefillIterator.moveNext())
return false;
_results.add(_prefillIterator.current);
return true;
}
}
class _LazyListIterator<E> implements Iterator<E> {
_LazyListIterator(this._owner) : _index = -1;
final CachingIterable<E> _owner;
int _index;
@override
E get current {
assert(_index >= 0); // called "current" before "moveNext()"
if (_index < 0 || _index == _owner._results.length)
return null;
return _owner._results[_index];
}
@override
bool moveNext() {
if (_index >= _owner._results.length)
return false;
_index += 1;
if (_index == _owner._results.length)
return _owner._fillNext();
return true;
}
}
...@@ -398,7 +398,8 @@ abstract class SchedulerBinding extends BindingBase { ...@@ -398,7 +398,8 @@ abstract class SchedulerBinding extends BindingBase {
library: 'scheduler library', library: 'scheduler library',
context: 'during a scheduler callback', context: 'during a scheduler callback',
informationCollector: (callbackStack == null) ? null : (StringBuffer information) { informationCollector: (callbackStack == null) ? null : (StringBuffer information) {
information.writeln('When this callback was registered, this was the stack:\n$callbackStack'); // callbackStack ends with a newline, so don't introduce one artificially here
information.write('When this callback was registered, this was the stack:\n$callbackStack');
} }
)); ));
} }
......
...@@ -361,13 +361,19 @@ class RenderObjectToWidgetElement<T extends RenderObject> extends RootRenderObje ...@@ -361,13 +361,19 @@ class RenderObjectToWidgetElement<T extends RenderObject> extends RootRenderObje
/// A concrete binding for applications based on the Widgets framework. /// A concrete binding for applications based on the Widgets framework.
/// This is the glue that binds the framework to the Flutter engine. /// This is the glue that binds the framework to the Flutter engine.
class WidgetsFlutterBinding extends BindingBase with SchedulerBinding, GestureBinding, ServicesBinding, RendererBinding, WidgetsBinding { class WidgetsFlutterBinding extends BindingBase with SchedulerBinding, GestureBinding, ServicesBinding, RendererBinding, WidgetsBinding {
/// Creates and initializes the WidgetsFlutterBinding. This function
/// is idempotent; calling it a second time will just return the /// Returns an instance of the [WidgetsBinding], creating and
/// previously-created instance. /// initializing it if necessary. If one is created, it will be a
/// [WidgetsFlutterBinding]. If one was previously initialized, then
/// it will at least implement [WidgetsBinding].
/// ///
/// You only need to call this method if you need the binding to be /// You only need to call this method if you need the binding to be
/// initialized before calling [runApp]. /// initialized before calling [runApp].
static WidgetsFlutterBinding ensureInitialized() { ///
/// In the `flutter_test` framework, [testWidgets] initializes the
/// binding instance to a [TestWidgetsFlutterBinding], not a
/// [WidgetsFlutterBinding].
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null) if (WidgetsBinding.instance == null)
new WidgetsFlutterBinding(); new WidgetsFlutterBinding();
return WidgetsBinding.instance; return WidgetsBinding.instance;
......
...@@ -662,6 +662,12 @@ class _InactiveElements { ...@@ -662,6 +662,12 @@ class _InactiveElements {
} }
} }
/// Signature for the callback to [BuildContext.visitChildElements].
///
/// The argument is the child being visited.
///
/// It is safe to call `element.visitChildElements` reentrantly within
/// this callback.
typedef void ElementVisitor(Element element); typedef void ElementVisitor(Element element);
abstract class BuildContext { abstract class BuildContext {
...@@ -672,7 +678,7 @@ abstract class BuildContext { ...@@ -672,7 +678,7 @@ abstract class BuildContext {
State ancestorStateOfType(TypeMatcher matcher); State ancestorStateOfType(TypeMatcher matcher);
RenderObject ancestorRenderObjectOfType(TypeMatcher matcher); RenderObject ancestorRenderObjectOfType(TypeMatcher matcher);
void visitAncestorElements(bool visitor(Element element)); void visitAncestorElements(bool visitor(Element element));
void visitChildElements(void visitor(Element element)); void visitChildElements(ElementVisitor visitor);
} }
class BuildOwner { class BuildOwner {
...@@ -688,8 +694,32 @@ class BuildOwner { ...@@ -688,8 +694,32 @@ class BuildOwner {
/// Adds an element to the dirty elements list so that it will be rebuilt /// Adds an element to the dirty elements list so that it will be rebuilt
/// when buildDirtyElements is called. /// when buildDirtyElements is called.
void scheduleBuildFor(BuildableElement element) { void scheduleBuildFor(BuildableElement element) {
assert(!_dirtyElements.contains(element)); assert(() {
assert(element.dirty); if (_dirtyElements.contains(element)) {
throw new FlutterError(
'scheduleBuildFor() called for a widget for which a build was already scheduled.\n'
'The method was invoked for the following element:\n'
' $element\n'
'The current dirty list consists of:\n'
' $_dirtyElements\n'
'This should not be possible and probably indicates a bug in the widgets framework. '
'Please report it: https://github.com/flutter/flutter/issues/new'
);
}
if (!element.dirty) {
throw new FlutterError(
'scheduleBuildFor() called for a widget that is not marked as dirty.\n'
'The method was invoked for the following element:\n'
' $element\n'
'This element is not current marked as dirty. Make sure to set the dirty flag before '
'calling scheduleBuildFor().\n'
'If you did not attempt to call scheduleBuildFor() yourself, then this probably '
'indicates a bug in the widgets framework. Please report it: '
'https://github.com/flutter/flutter/issues/new'
);
}
return true;
});
if (_dirtyElements.isEmpty && onBuildScheduled != null) if (_dirtyElements.isEmpty && onBuildScheduled != null)
onBuildScheduled(); onBuildScheduled();
_dirtyElements.add(element); _dirtyElements.add(element);
......
// Copyright 2016 The Chromium 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/foundation.dart';
import 'package:test/test.dart';
int yieldCount;
Iterable<int> range(int start, int end) sync* {
assert(yieldCount == 0);
for (int index = start; index <= end; index += 1) {
yieldCount += 1;
yield index;
}
}
void main() {
setUp(() {
yieldCount = 0;
});
test("The Caching Iterable: length caches", () {
Iterable<int> i = new CachingIterable<int>(range(1, 5).iterator);
expect(yieldCount, equals(0));
expect(i.length, equals(5));
expect(yieldCount, equals(5));
expect(i.length, equals(5));
expect(yieldCount, equals(5));
expect(i.last, equals(5));
expect(yieldCount, equals(5));
expect(i, equals(<int>[1, 2, 3, 4, 5]));
expect(yieldCount, equals(5));
});
test("The Caching Iterable: laziness", () {
Iterable<int> i = new CachingIterable<int>(range(1, 5).iterator);
expect(yieldCount, equals(0));
expect(i.first, equals(1));
expect(yieldCount, equals(1));
expect(i.firstWhere((int i) => i == 3), equals(3));
expect(yieldCount, equals(3));
expect(i.last, equals(5));
expect(yieldCount, equals(5));
});
test("The Caching Iterable: where and map", () {
Iterable<int> integers = new CachingIterable<int>(range(1, 5).iterator);
expect(yieldCount, equals(0));
Iterable<int> evens = integers.where((int i) => i % 2 == 0);
expect(yieldCount, equals(0));
expect(evens.first, equals(2));
expect(yieldCount, equals(2));
expect(integers.first, equals(1));
expect(yieldCount, equals(2));
expect(evens.map((int i) => i + 1), equals(<int>[3, 5]));
expect(yieldCount, equals(5));
expect(evens, equals(<int>[2, 4]));
expect(yieldCount, equals(5));
expect(integers, equals(<int>[1, 2, 3, 4, 5]));
expect(yieldCount, equals(5));
});
}
...@@ -12,59 +12,49 @@ void main() { ...@@ -12,59 +12,49 @@ void main() {
// The "can be constructed" tests that follow are primarily to ensure that any // The "can be constructed" tests that follow are primarily to ensure that any
// animations started by the progress indicators are stopped at dispose() time. // animations started by the progress indicators are stopped at dispose() time.
test('LinearProgressIndicator(value: 0.0) can be constructed', () { testWidgets('LinearProgressIndicator(value: 0.0) can be constructed', (WidgetTester tester) {
testWidgets((WidgetTester tester) { tester.pumpWidget(
tester.pumpWidget( new Center(
new Center( child: new SizedBox(
child: new SizedBox( width: 200.0,
width: 200.0, child: new LinearProgressIndicator(value: 0.0)
child: new LinearProgressIndicator(value: 0.0)
)
) )
); )
}); );
}); });
test('LinearProgressIndicator(value: null) can be constructed', () { testWidgets('LinearProgressIndicator(value: null) can be constructed', (WidgetTester tester) {
testWidgets((WidgetTester tester) { tester.pumpWidget(
tester.pumpWidget( new Center(
new Center( child: new SizedBox(
child: new SizedBox( width: 200.0,
width: 200.0, child: new LinearProgressIndicator(value: null)
child: new LinearProgressIndicator(value: null)
)
) )
); )
}); );
}); });
test('CircularProgressIndicator(value: 0.0) can be constructed', () { testWidgets('CircularProgressIndicator(value: 0.0) can be constructed', (WidgetTester tester) {
testWidgets((WidgetTester tester) { tester.pumpWidget(
tester.pumpWidget( new Center(
new Center( child: new CircularProgressIndicator(value: 0.0)
child: new CircularProgressIndicator(value: 0.0) )
) );
);
});
}); });
test('CircularProgressIndicator(value: null) can be constructed', () { testWidgets('CircularProgressIndicator(value: null) can be constructed', (WidgetTester tester) {
testWidgets((WidgetTester tester) { tester.pumpWidget(
tester.pumpWidget( new Center(
new Center( child: new CircularProgressIndicator(value: null)
child: new CircularProgressIndicator(value: null) )
) );
);
});
}); });
test('LinearProgressIndicator changes when its value changes', () { testWidgets('LinearProgressIndicator causes a repaint when it changes', (WidgetTester tester) {
testElementTree((ElementTreeTester tester) { tester.pumpWidget(new Block(children: <Widget>[new LinearProgressIndicator(value: 0.0)]));
tester.pumpWidget(new Block(children: <Widget>[new LinearProgressIndicator(value: 0.0)])); List<Layer> layers1 = tester.layers;
List<Layer> layers1 = tester.layers; tester.pumpWidget(new Block(children: <Widget>[new LinearProgressIndicator(value: 0.5)]));
tester.pumpWidget(new Block(children: <Widget>[new LinearProgressIndicator(value: 0.5)])); List<Layer> layers2 = tester.layers;
List<Layer> layers2 = tester.layers; expect(layers1, isNot(equals(layers2)));
expect(layers1, isNot(equals(layers2)));
});
}); });
} }
...@@ -17,28 +17,26 @@ void main() { ...@@ -17,28 +17,26 @@ void main() {
return new Future<Null>.value(); return new Future<Null>.value();
} }
test('RefreshIndicator', () { testWidgets('RefreshIndicator', (WidgetTester tester) {
testWidgets((WidgetTester tester) { tester.pumpWidget(
tester.pumpWidget( new RefreshIndicator(
new RefreshIndicator( refresh: refresh,
refresh: refresh, child: new Block(
child: new Block( children: <String>['A', 'B', 'C', 'D', 'E', 'F'].map((String item) {
children: <String>['A', 'B', 'C', 'D', 'E', 'F'].map((String item) { return new SizedBox(
return new SizedBox( height: 200.0,
height: 200.0, child: new Text(item)
child: new Text(item) );
); }).toList()
}).toList()
)
) )
); )
);
tester.fling(find.text('A'), const Offset(0.0, 200.0), -1000.0); tester.fling(find.text('A'), const Offset(0.0, 200.0), -1000.0);
tester.pump(); tester.pump();
tester.pump(const Duration(seconds: 1)); // finish the scroll animation tester.pump(const Duration(seconds: 1)); // finish the scroll animation
tester.pump(const Duration(seconds: 1)); // finish the indicator settle animation tester.pump(const Duration(seconds: 1)); // finish the indicator settle animation
tester.pump(const Duration(seconds: 1)); // finish the indicator hide animation tester.pump(const Duration(seconds: 1)); // finish the indicator hide animation
expect(refreshCalled, true); expect(refreshCalled, true);
});
}); });
} }
...@@ -8,39 +8,37 @@ import 'package:flutter/rendering.dart'; ...@@ -8,39 +8,37 @@ import 'package:flutter/rendering.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
test('Scaffold control test', () { testWidgets('Scaffold control test', (WidgetTester tester) {
testWidgets((WidgetTester tester) { Key bodyKey = new UniqueKey();
Key bodyKey = new UniqueKey(); tester.pumpWidget(new Scaffold(
tester.pumpWidget(new Scaffold( appBar: new AppBar(title: new Text('Title')),
appBar: new AppBar(title: new Text('Title')), body: new Container(key: bodyKey)
body: new Container(key: bodyKey) ));
));
RenderBox bodyBox = tester.renderObjectOf(find.byKey(bodyKey)); RenderBox bodyBox = tester.renderObject(find.byKey(bodyKey));
expect(bodyBox.size, equals(new Size(800.0, 544.0))); expect(bodyBox.size, equals(new Size(800.0, 544.0)));
tester.pumpWidget(new MediaQuery( tester.pumpWidget(new MediaQuery(
data: new MediaQueryData(padding: new EdgeInsets.only(bottom: 100.0)), data: new MediaQueryData(padding: new EdgeInsets.only(bottom: 100.0)),
child: new Scaffold( child: new Scaffold(
appBar: new AppBar(title: new Text('Title')), appBar: new AppBar(title: new Text('Title')),
body: new Container(key: bodyKey) body: new Container(key: bodyKey)
) )
)); ));
bodyBox = tester.renderObjectOf(find.byKey(bodyKey)); bodyBox = tester.renderObject(find.byKey(bodyKey));
expect(bodyBox.size, equals(new Size(800.0, 444.0))); expect(bodyBox.size, equals(new Size(800.0, 444.0)));
tester.pumpWidget(new MediaQuery( tester.pumpWidget(new MediaQuery(
data: new MediaQueryData(padding: new EdgeInsets.only(bottom: 100.0)), data: new MediaQueryData(padding: new EdgeInsets.only(bottom: 100.0)),
child: new Scaffold( child: new Scaffold(
appBar: new AppBar(title: new Text('Title')), appBar: new AppBar(title: new Text('Title')),
body: new Container(key: bodyKey), body: new Container(key: bodyKey),
resizeToAvoidBottomPadding: false resizeToAvoidBottomPadding: false
) )
)); ));
bodyBox = tester.renderObjectOf(find.byKey(bodyKey)); bodyBox = tester.renderObject(find.byKey(bodyKey));
expect(bodyBox.size, equals(new Size(800.0, 544.0))); expect(bodyBox.size, equals(new Size(800.0, 544.0)));
});
}); });
} }
...@@ -8,83 +8,79 @@ import 'package:flutter_test/flutter_test.dart'; ...@@ -8,83 +8,79 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
test('Slider can move when tapped', () { testWidgets('Slider can move when tapped', (WidgetTester tester) {
testWidgets((WidgetTester tester) { Key sliderKey = new UniqueKey();
Key sliderKey = new UniqueKey(); double value = 0.0;
double value = 0.0;
tester.pumpWidget( tester.pumpWidget(
new StatefulBuilder( new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) { builder: (BuildContext context, StateSetter setState) {
return new Material( return new Material(
child: new Center( child: new Center(
child: new Slider( child: new Slider(
key: sliderKey, key: sliderKey,
value: value, value: value,
onChanged: (double newValue) { onChanged: (double newValue) {
setState(() { setState(() {
value = newValue; value = newValue;
}); });
} }
)
) )
); )
} );
) }
); )
);
expect(value, equals(0.0)); expect(value, equals(0.0));
tester.tap(find.byKey(sliderKey)); tester.tap(find.byKey(sliderKey));
expect(value, equals(0.5)); expect(value, equals(0.5));
tester.pump(); // No animation should start. tester.pump(); // No animation should start.
expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
});
}); });
test('Slider take on discrete values', () { testWidgets('Slider take on discrete values', (WidgetTester tester) {
testWidgets((WidgetTester tester) { Key sliderKey = new UniqueKey();
Key sliderKey = new UniqueKey(); double value = 0.0;
double value = 0.0;
tester.pumpWidget( tester.pumpWidget(
new StatefulBuilder( new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) { builder: (BuildContext context, StateSetter setState) {
return new Material( return new Material(
child: new Center( child: new Center(
child: new Slider( child: new Slider(
key: sliderKey, key: sliderKey,
min: 0.0, min: 0.0,
max: 100.0, max: 100.0,
divisions: 10, divisions: 10,
value: value, value: value,
onChanged: (double newValue) { onChanged: (double newValue) {
setState(() { setState(() {
value = newValue; value = newValue;
}); });
} }
)
) )
); )
} );
) }
); )
);
expect(value, equals(0.0)); expect(value, equals(0.0));
tester.tap(find.byKey(sliderKey)); tester.tap(find.byKey(sliderKey));
expect(value, equals(50.0)); expect(value, equals(50.0));
tester.scroll(find.byKey(sliderKey), const Offset(5.0, 0.0)); tester.scroll(find.byKey(sliderKey), const Offset(5.0, 0.0));
expect(value, equals(50.0)); expect(value, equals(50.0));
tester.scroll(find.byKey(sliderKey), const Offset(40.0, 0.0)); tester.scroll(find.byKey(sliderKey), const Offset(40.0, 0.0));
expect(value, equals(80.0)); expect(value, equals(80.0));
tester.pump(); // Starts animation. tester.pump(); // Starts animation.
expect(SchedulerBinding.instance.transientCallbackCount, greaterThan(0)); expect(SchedulerBinding.instance.transientCallbackCount, greaterThan(0));
tester.pump(const Duration(milliseconds: 200)); tester.pump(const Duration(milliseconds: 200));
tester.pump(const Duration(milliseconds: 200)); tester.pump(const Duration(milliseconds: 200));
tester.pump(const Duration(milliseconds: 200)); tester.pump(const Duration(milliseconds: 200));
tester.pump(const Duration(milliseconds: 200)); tester.pump(const Duration(milliseconds: 200));
// Animation complete. // Animation complete.
expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
});
}); });
} }
...@@ -7,120 +7,116 @@ import 'package:flutter_test/flutter_test.dart'; ...@@ -7,120 +7,116 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
test('tap-select an hour', () { testWidgets('tap-select an hour', (WidgetTester tester) {
testWidgets((WidgetTester tester) { Key _timePickerKey = new UniqueKey();
Key _timePickerKey = new UniqueKey(); TimeOfDay _selectedTime = const TimeOfDay(hour: 7, minute: 0);
TimeOfDay _selectedTime = const TimeOfDay(hour: 7, minute: 0);
tester.pumpWidget(
tester.pumpWidget( new StatefulBuilder(
new StatefulBuilder( builder: (BuildContext context, StateSetter setState) {
builder: (BuildContext context, StateSetter setState) { return new Material(
return new Material( child: new Center(
child: new Center( child: new SizedBox(
child: new SizedBox( width: 200.0,
width: 200.0, height: 400.0,
height: 400.0, child: new TimePicker(
child: new TimePicker( key: _timePickerKey,
key: _timePickerKey, selectedTime: _selectedTime,
selectedTime: _selectedTime, onChanged: (TimeOfDay value) {
onChanged: (TimeOfDay value) { setState(() {
setState(() { _selectedTime = value;
_selectedTime = value; });
}); }
}
)
) )
) )
); )
} );
) }
); )
);
Point center = tester.getCenter(find.byKey(_timePickerKey)); Point center = tester.getCenter(find.byKey(_timePickerKey));
Point hour0 = new Point(center.x, center.y - 50.0); // 12:00 AM Point hour0 = new Point(center.x, center.y - 50.0); // 12:00 AM
tester.tapAt(hour0); tester.tapAt(hour0);
expect(_selectedTime.hour, equals(0)); expect(_selectedTime.hour, equals(0));
Point hour3 = new Point(center.x + 50.0, center.y); Point hour3 = new Point(center.x + 50.0, center.y);
tester.tapAt(hour3); tester.tapAt(hour3);
expect(_selectedTime.hour, equals(3)); expect(_selectedTime.hour, equals(3));
Point hour6 = new Point(center.x, center.y + 50.0); Point hour6 = new Point(center.x, center.y + 50.0);
tester.tapAt(hour6); tester.tapAt(hour6);
expect(_selectedTime.hour, equals(6)); expect(_selectedTime.hour, equals(6));
Point hour9 = new Point(center.x - 50.0, center.y); Point hour9 = new Point(center.x - 50.0, center.y);
tester.tapAt(hour9); tester.tapAt(hour9);
expect(_selectedTime.hour, equals(9)); expect(_selectedTime.hour, equals(9));
tester.pump(const Duration(seconds: 1)); // Finish gesture animation. tester.pump(const Duration(seconds: 1)); // Finish gesture animation.
tester.pump(const Duration(seconds: 1)); // Finish settling animation. tester.pump(const Duration(seconds: 1)); // Finish settling animation.
});
}); });
test('drag-select an hour', () { testWidgets('drag-select an hour', (WidgetTester tester) {
testWidgets((WidgetTester tester) { Key _timePickerKey = new UniqueKey();
Key _timePickerKey = new UniqueKey(); TimeOfDay _selectedTime = const TimeOfDay(hour: 7, minute: 0);
TimeOfDay _selectedTime = const TimeOfDay(hour: 7, minute: 0);
tester.pumpWidget(
tester.pumpWidget( new StatefulBuilder(
new StatefulBuilder( builder: (BuildContext context, StateSetter setState) {
builder: (BuildContext context, StateSetter setState) { return new Material(
return new Material( child: new Center(
child: new Center( child: new SizedBox(
child: new SizedBox( width: 200.0,
width: 200.0, height: 400.0,
height: 400.0, child: new TimePicker(
child: new TimePicker( key: _timePickerKey,
key: _timePickerKey, selectedTime: _selectedTime,
selectedTime: _selectedTime, onChanged: (TimeOfDay value) {
onChanged: (TimeOfDay value) { setState(() {
setState(() { _selectedTime = value;
_selectedTime = value; });
}); }
}
)
) )
) )
); )
} );
) }
); )
);
Point center = tester.getCenter(find.byKey(_timePickerKey));
Point hour0 = new Point(center.x, center.y - 50.0); // 12:00 AM Point center = tester.getCenter(find.byKey(_timePickerKey));
Point hour3 = new Point(center.x + 50.0, center.y); Point hour0 = new Point(center.x, center.y - 50.0); // 12:00 AM
Point hour6 = new Point(center.x, center.y + 50.0); Point hour3 = new Point(center.x + 50.0, center.y);
Point hour9 = new Point(center.x - 50.0, center.y); Point hour6 = new Point(center.x, center.y + 50.0);
Point hour9 = new Point(center.x - 50.0, center.y);
tester.startGesture(hour3)
..moveBy(hour0 - hour3) tester.startGesture(hour3)
..up(); ..moveBy(hour0 - hour3)
expect(_selectedTime.hour, equals(0)); ..up();
tester.pump(const Duration(seconds: 1)); // Finish gesture animation. expect(_selectedTime.hour, equals(0));
tester.pump(const Duration(seconds: 1)); // Finish settling animation. tester.pump(const Duration(seconds: 1)); // Finish gesture animation.
tester.pump(const Duration(seconds: 1)); // Finish settling animation.
tester.startGesture(hour0)
..moveBy(hour3 - hour0) tester.startGesture(hour0)
..up(); ..moveBy(hour3 - hour0)
expect(_selectedTime.hour, equals(3)); ..up();
tester.pump(const Duration(seconds: 1)); expect(_selectedTime.hour, equals(3));
tester.pump(const Duration(seconds: 1)); tester.pump(const Duration(seconds: 1));
tester.pump(const Duration(seconds: 1));
tester.startGesture(hour3)
..moveBy(hour6 - hour3) tester.startGesture(hour3)
..up(); ..moveBy(hour6 - hour3)
expect(_selectedTime.hour, equals(6)); ..up();
tester.pump(const Duration(seconds: 1)); expect(_selectedTime.hour, equals(6));
tester.pump(const Duration(seconds: 1)); tester.pump(const Duration(seconds: 1));
tester.pump(const Duration(seconds: 1));
tester.startGesture(hour6)
..moveBy(hour9 - hour6) tester.startGesture(hour6)
..up(); ..moveBy(hour9 - hour6)
expect(_selectedTime.hour, equals(9)); ..up();
tester.pump(const Duration(seconds: 1)); expect(_selectedTime.hour, equals(9));
tester.pump(const Duration(seconds: 1)); tester.pump(const Duration(seconds: 1));
}); tester.pump(const Duration(seconds: 1));
}); });
} }
...@@ -8,43 +8,39 @@ import 'package:flutter/widgets.dart'; ...@@ -8,43 +8,39 @@ import 'package:flutter/widgets.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
test('Align smoke test', () { testWidgets('Align smoke test', (WidgetTester tester) {
testWidgets((WidgetTester tester) { tester.pumpWidget(
tester.pumpWidget( new Align(
new Align( child: new Container(),
child: new Container(), alignment: const FractionalOffset(0.75, 0.75)
alignment: const FractionalOffset(0.75, 0.75) )
) );
);
tester.pumpWidget( tester.pumpWidget(
new Align( new Align(
child: new Container(), child: new Container(),
alignment: const FractionalOffset(0.5, 0.5) alignment: const FractionalOffset(0.5, 0.5)
) )
); );
});
}); });
test('Shrink wraps in finite space', () { testWidgets('Shrink wraps in finite space', (WidgetTester tester) {
testWidgets((WidgetTester tester) { GlobalKey alignKey = new GlobalKey();
GlobalKey alignKey = new GlobalKey(); tester.pumpWidget(
tester.pumpWidget( new ScrollableViewport(
new ScrollableViewport( child: new Align(
child: new Align( key: alignKey,
key: alignKey, child: new Container(
child: new Container( width: 10.0,
width: 10.0, height: 10.0
height: 10.0 ),
), alignment: const FractionalOffset(0.50, 0.50)
alignment: const FractionalOffset(0.50, 0.50)
)
) )
); )
);
RenderBox box = alignKey.currentContext.findRenderObject(); RenderBox box = alignKey.currentContext.findRenderObject();
expect(box.size.width, equals(800.0)); expect(box.size.width, equals(800.0));
expect(box.size.height, equals(10.0)); expect(box.size.height, equals(10.0));
});
}); });
} }
...@@ -8,166 +8,159 @@ import 'package:flutter/widgets.dart'; ...@@ -8,166 +8,159 @@ import 'package:flutter/widgets.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
test('AnimatedContainer control test', () { testWidgets('AnimatedContainer control test', (WidgetTester tester) {
testWidgets((WidgetTester tester) { GlobalKey key = new GlobalKey();
GlobalKey key = new GlobalKey();
BoxDecoration decorationA = new BoxDecoration(
BoxDecoration decorationA = new BoxDecoration( backgroundColor: new Color(0xFF00FF00)
backgroundColor: new Color(0xFF00FF00) );
);
BoxDecoration decorationB = new BoxDecoration(
BoxDecoration decorationB = new BoxDecoration( backgroundColor: new Color(0xFF0000FF)
backgroundColor: new Color(0xFF0000FF) );
);
BoxDecoration actualDecoration;
BoxDecoration actualDecoration;
tester.pumpWidget(
new AnimatedContainer(
key: key,
duration: const Duration(milliseconds: 200),
decoration: decorationA
)
);
RenderDecoratedBox box = key.currentContext.findRenderObject();
actualDecoration = box.decoration;
expect(actualDecoration.backgroundColor, equals(decorationA.backgroundColor));
tester.pumpWidget(
new AnimatedContainer(
key: key,
duration: const Duration(milliseconds: 200),
decoration: decorationB
)
);
expect(key.currentContext.findRenderObject(), equals(box));
actualDecoration = box.decoration;
expect(actualDecoration.backgroundColor, equals(decorationA.backgroundColor));
tester.pump(const Duration(seconds: 1));
actualDecoration = box.decoration;
expect(actualDecoration.backgroundColor, equals(decorationB.backgroundColor));
});
tester.pumpWidget( testWidgets('AnimatedContainer overanimate test', (WidgetTester tester) {
new AnimatedContainer( tester.pumpWidget(
key: key, new AnimatedContainer(
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
decoration: decorationA decoration: new BoxDecoration(
backgroundColor: new Color(0xFF00FF00)
) )
); )
);
RenderDecoratedBox box = key.currentContext.findRenderObject(); expect(tester.binding.transientCallbackCount, 0);
actualDecoration = box.decoration; tester.pump(new Duration(seconds: 1));
expect(actualDecoration.backgroundColor, equals(decorationA.backgroundColor)); expect(tester.binding.transientCallbackCount, 0);
tester.pumpWidget(
new AnimatedContainer(
duration: const Duration(milliseconds: 200),
decoration: new BoxDecoration(
backgroundColor: new Color(0xFF00FF00)
)
)
);
expect(tester.binding.transientCallbackCount, 0);
tester.pump(new Duration(seconds: 1));
expect(tester.binding.transientCallbackCount, 0);
tester.pumpWidget(
new AnimatedContainer(
duration: const Duration(milliseconds: 200),
decoration: new BoxDecoration(
backgroundColor: new Color(0xFF0000FF)
)
)
);
expect(tester.binding.transientCallbackCount, 1); // this is the only time an animation should have started!
tester.pump(new Duration(seconds: 1));
expect(tester.binding.transientCallbackCount, 0);
tester.pumpWidget(
new AnimatedContainer(
duration: const Duration(milliseconds: 200),
decoration: new BoxDecoration(
backgroundColor: new Color(0xFF0000FF)
)
)
);
expect(tester.binding.transientCallbackCount, 0);
});
tester.pumpWidget( testWidgets('Animation rerun', (WidgetTester tester) {
new AnimatedContainer( tester.pumpWidget(
key: key, new Center(
child: new AnimatedContainer(
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
decoration: decorationB width: 100.0,
height: 100.0,
child: new Text('X')
) )
); )
);
expect(key.currentContext.findRenderObject(), equals(box));
actualDecoration = box.decoration;
expect(actualDecoration.backgroundColor, equals(decorationA.backgroundColor));
tester.pump(const Duration(seconds: 1)); tester.pump();
tester.pump(new Duration(milliseconds: 100));
actualDecoration = box.decoration; RenderBox text = tester.renderObject(find.text('X'));
expect(actualDecoration.backgroundColor, equals(decorationB.backgroundColor)); expect(text.size.width, equals(100.0));
expect(text.size.height, equals(100.0));
}); tester.pump(new Duration(milliseconds: 1000));
});
test('AnimatedContainer overanimate test', () { tester.pumpWidget(
testWidgets((WidgetTester tester) { new Center(
tester.pumpWidget( child: new AnimatedContainer(
new AnimatedContainer(
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
decoration: new BoxDecoration( width: 200.0,
backgroundColor: new Color(0xFF00FF00) height: 200.0,
) child: new Text('X')
) )
); )
expect(tester.binding.transientCallbackCount, 0); );
tester.pump(new Duration(seconds: 1)); tester.pump();
expect(tester.binding.transientCallbackCount, 0); tester.pump(new Duration(milliseconds: 100));
tester.pumpWidget(
new AnimatedContainer(
duration: const Duration(milliseconds: 200),
decoration: new BoxDecoration(
backgroundColor: new Color(0xFF00FF00)
)
)
);
expect(tester.binding.transientCallbackCount, 0);
tester.pump(new Duration(seconds: 1));
expect(tester.binding.transientCallbackCount, 0);
tester.pumpWidget(
new AnimatedContainer(
duration: const Duration(milliseconds: 200),
decoration: new BoxDecoration(
backgroundColor: new Color(0xFF0000FF)
)
)
);
expect(tester.binding.transientCallbackCount, 1); // this is the only time an animation should have started!
tester.pump(new Duration(seconds: 1));
expect(tester.binding.transientCallbackCount, 0);
tester.pumpWidget(
new AnimatedContainer(
duration: const Duration(milliseconds: 200),
decoration: new BoxDecoration(
backgroundColor: new Color(0xFF0000FF)
)
)
);
expect(tester.binding.transientCallbackCount, 0);
});
});
test('Animation rerun', () {
testElementTree((ElementTreeTester tester) {
tester.pumpWidget(
new Center(
child: new AnimatedContainer(
duration: const Duration(milliseconds: 200),
width: 100.0,
height: 100.0,
child: new Text('X')
)
)
);
tester.pump(); text = tester.renderObject(find.text('X'));
tester.pump(new Duration(milliseconds: 100)); expect(text.size.width, greaterThan(110.0));
expect(text.size.width, lessThan(190.0));
expect(text.size.height, greaterThan(110.0));
expect(text.size.height, lessThan(190.0));
RenderBox text = tester.findText('X').renderObject; tester.pump(new Duration(milliseconds: 1000));
expect(text.size.width, equals(100.0));
expect(text.size.height, equals(100.0));
tester.pump(new Duration(milliseconds: 1000)); expect(text.size.width, equals(200.0));
expect(text.size.height, equals(200.0));
tester.pumpWidget( tester.pumpWidget(
new Center( new Center(
child: new AnimatedContainer( child: new AnimatedContainer(
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
width: 200.0, width: 200.0,
height: 200.0, height: 100.0,
child: new Text('X') child: new Text('X')
)
)
);
tester.pump();
tester.pump(new Duration(milliseconds: 100));
text = tester.findText('X').renderObject;
expect(text.size.width, greaterThan(110.0));
expect(text.size.width, lessThan(190.0));
expect(text.size.height, greaterThan(110.0));
expect(text.size.height, lessThan(190.0));
tester.pump(new Duration(milliseconds: 1000));
expect(text.size.width, equals(200.0));
expect(text.size.height, equals(200.0));
tester.pumpWidget(
new Center(
child: new AnimatedContainer(
duration: const Duration(milliseconds: 200),
width: 200.0,
height: 100.0,
child: new Text('X')
)
) )
); )
tester.pump(); );
tester.pump(new Duration(milliseconds: 100)); tester.pump();
tester.pump(new Duration(milliseconds: 100));
expect(text.size.width, equals(200.0)); expect(text.size.width, equals(200.0));
expect(text.size.height, greaterThan(110.0)); expect(text.size.height, greaterThan(110.0));
expect(text.size.height, lessThan(190.0)); expect(text.size.height, lessThan(190.0));
tester.pump(new Duration(milliseconds: 1000)); tester.pump(new Duration(milliseconds: 1000));
expect(text.size.width, equals(200.0)); expect(text.size.width, equals(200.0));
expect(text.size.height, equals(100.0)); expect(text.size.height, equals(100.0));
});
}); });
} }
...@@ -7,7 +7,7 @@ import 'package:flutter/rendering.dart'; ...@@ -7,7 +7,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
Size _getSize(ElementTreeTester tester, BoxConstraints constraints, double aspectRatio) { Size _getSize(WidgetTester tester, BoxConstraints constraints, double aspectRatio) {
Key childKey = new UniqueKey(); Key childKey = new UniqueKey();
tester.pumpWidget( tester.pumpWidget(
new Center( new Center(
...@@ -22,36 +22,32 @@ Size _getSize(ElementTreeTester tester, BoxConstraints constraints, double aspec ...@@ -22,36 +22,32 @@ Size _getSize(ElementTreeTester tester, BoxConstraints constraints, double aspec
) )
) )
); );
RenderBox box = tester.findElementByKey(childKey).renderObject; RenderBox box = tester.renderObject(find.byKey(childKey));
return box.size; return box.size;
} }
void main() { void main() {
test('Aspect ratio control test', () { testWidgets('Aspect ratio control test', (WidgetTester tester) {
testElementTree((ElementTreeTester tester) { expect(_getSize(tester, new BoxConstraints.loose(new Size(500.0, 500.0)), 2.0), equals(new Size(500.0, 250.0)));
expect(_getSize(tester, new BoxConstraints.loose(new Size(500.0, 500.0)), 2.0), equals(new Size(500.0, 250.0))); expect(_getSize(tester, new BoxConstraints.loose(new Size(500.0, 500.0)), 0.5), equals(new Size(250.0, 500.0)));
expect(_getSize(tester, new BoxConstraints.loose(new Size(500.0, 500.0)), 0.5), equals(new Size(250.0, 500.0)));
});
}); });
test('Aspect ratio infinite width', () { testWidgets('Aspect ratio infinite width', (WidgetTester tester) {
testElementTree((ElementTreeTester tester) { Key childKey = new UniqueKey();
Key childKey = new UniqueKey(); tester.pumpWidget(
tester.pumpWidget( new Center(
new Center( child: new Viewport(
child: new Viewport( mainAxis: Axis.horizontal,
mainAxis: Axis.horizontal, child: new AspectRatio(
child: new AspectRatio( aspectRatio: 2.0,
aspectRatio: 2.0, child: new Container(
child: new Container( key: childKey
key: childKey
)
) )
) )
) )
); )
RenderBox box = tester.findElementByKey(childKey).renderObject; );
expect(box.size, equals(new Size(1200.0, 600.0))); RenderBox box = tester.renderObject(find.byKey(childKey));
}); expect(box.size, equals(new Size(1200.0, 600.0)));
}); });
} }
...@@ -120,15 +120,14 @@ Widget buildImageAtRatio(String image, Key key, double ratio, bool inferSize) { ...@@ -120,15 +120,14 @@ Widget buildImageAtRatio(String image, Key key, double ratio, bool inferSize) {
); );
} }
RenderImage getRenderImage(ElementTreeTester tester, Key key) { RenderImage getRenderImage(WidgetTester tester, Key key) {
return tester.findElementByKey(key).renderObject; return tester.renderObject/*<RenderImage>*/(find.byKey(key));
} }
TestImage getTestImage(WidgetTester tester, Key key) {
TestImage getTestImage(ElementTreeTester tester, Key key) { return tester.renderObject/*<RenderImage>*/(find.byKey(key)).image;
return getRenderImage(tester, key).image;
} }
void pumpTreeToLayout(ElementTreeTester tester, Widget widget) { void pumpTreeToLayout(WidgetTester tester, Widget widget) {
Duration pumpDuration = const Duration(milliseconds: 0); Duration pumpDuration = const Duration(milliseconds: 0);
EnginePhase pumpPhase = EnginePhase.layout; EnginePhase pumpPhase = EnginePhase.layout;
tester.pumpWidget(widget, pumpDuration, pumpPhase); tester.pumpWidget(widget, pumpDuration, pumpPhase);
...@@ -137,102 +136,88 @@ void pumpTreeToLayout(ElementTreeTester tester, Widget widget) { ...@@ -137,102 +136,88 @@ void pumpTreeToLayout(ElementTreeTester tester, Widget widget) {
void main() { void main() {
String image = 'assets/image.png'; String image = 'assets/image.png';
test('Image for device pixel ratio 1.0', () { testWidgets('Image for device pixel ratio 1.0', (WidgetTester tester) {
const double ratio = 1.0; const double ratio = 1.0;
testElementTree((ElementTreeTester tester) { Key key = new GlobalKey();
Key key = new GlobalKey(); pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false));
pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0));
expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); expect(getTestImage(tester, key).scale, 1.0);
expect(getTestImage(tester, key).scale, 1.0); key = new GlobalKey();
key = new GlobalKey(); pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true));
pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0));
expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); expect(getTestImage(tester, key).scale, 1.0);
expect(getTestImage(tester, key).scale, 1.0);
});
}); });
test('Image for device pixel ratio 0.5', () { testWidgets('Image for device pixel ratio 0.5', (WidgetTester tester) {
const double ratio = 0.5; const double ratio = 0.5;
testElementTree((ElementTreeTester tester) { Key key = new GlobalKey();
Key key = new GlobalKey(); pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false));
pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0));
expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); expect(getTestImage(tester, key).scale, 1.0);
expect(getTestImage(tester, key).scale, 1.0); key = new GlobalKey();
key = new GlobalKey(); pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true));
pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0));
expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); expect(getTestImage(tester, key).scale, 1.0);
expect(getTestImage(tester, key).scale, 1.0);
});
}); });
test('Image for device pixel ratio 1.5', () { testWidgets('Image for device pixel ratio 1.5', (WidgetTester tester) {
const double ratio = 1.5; const double ratio = 1.5;
testElementTree((ElementTreeTester tester) { Key key = new GlobalKey();
Key key = new GlobalKey(); pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false));
pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0));
expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); expect(getTestImage(tester, key).scale, 1.5);
expect(getTestImage(tester, key).scale, 1.5); key = new GlobalKey();
key = new GlobalKey(); pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true));
pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0));
expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); expect(getTestImage(tester, key).scale, 1.5);
expect(getTestImage(tester, key).scale, 1.5);
});
}); });
test('Image for device pixel ratio 1.75', () { testWidgets('Image for device pixel ratio 1.75', (WidgetTester tester) {
const double ratio = 1.75; const double ratio = 1.75;
testElementTree((ElementTreeTester tester) { Key key = new GlobalKey();
Key key = new GlobalKey(); pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false));
pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0));
expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); expect(getTestImage(tester, key).scale, 1.5);
expect(getTestImage(tester, key).scale, 1.5); key = new GlobalKey();
key = new GlobalKey(); pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true));
pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0));
expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); expect(getTestImage(tester, key).scale, 1.5);
expect(getTestImage(tester, key).scale, 1.5);
});
}); });
test('Image for device pixel ratio 2.3', () { testWidgets('Image for device pixel ratio 2.3', (WidgetTester tester) {
const double ratio = 2.3; const double ratio = 2.3;
testElementTree((ElementTreeTester tester) { Key key = new GlobalKey();
Key key = new GlobalKey(); pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false));
pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0));
expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); expect(getTestImage(tester, key).scale, 2.0);
expect(getTestImage(tester, key).scale, 2.0); key = new GlobalKey();
key = new GlobalKey(); pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true));
pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0));
expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); expect(getTestImage(tester, key).scale, 2.0);
expect(getTestImage(tester, key).scale, 2.0);
});
}); });
test('Image for device pixel ratio 3.7', () { testWidgets('Image for device pixel ratio 3.7', (WidgetTester tester) {
const double ratio = 3.7; const double ratio = 3.7;
testElementTree((ElementTreeTester tester) { Key key = new GlobalKey();
Key key = new GlobalKey(); pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false));
pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0));
expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); expect(getTestImage(tester, key).scale, 4.0);
expect(getTestImage(tester, key).scale, 4.0); key = new GlobalKey();
key = new GlobalKey(); pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true));
pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0));
expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); expect(getTestImage(tester, key).scale, 4.0);
expect(getTestImage(tester, key).scale, 4.0);
});
}); });
test('Image for device pixel ratio 5.1', () { testWidgets('Image for device pixel ratio 5.1', (WidgetTester tester) {
const double ratio = 5.1; const double ratio = 5.1;
testElementTree((ElementTreeTester tester) { Key key = new GlobalKey();
Key key = new GlobalKey(); pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false));
pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false)); expect(getRenderImage(tester, key).size, const Size(200.0, 200.0));
expect(getRenderImage(tester, key).size, const Size(200.0, 200.0)); expect(getTestImage(tester, key).scale, 4.0);
expect(getTestImage(tester, key).scale, 4.0); key = new GlobalKey();
key = new GlobalKey(); pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true));
pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true)); expect(getRenderImage(tester, key).size, const Size(48.0, 48.0));
expect(getRenderImage(tester, key).size, const Size(48.0, 48.0)); expect(getTestImage(tester, key).scale, 4.0);
expect(getTestImage(tester, key).scale, 4.0);
});
}); });
} }
...@@ -9,107 +9,101 @@ import 'package:test/test.dart'; ...@@ -9,107 +9,101 @@ import 'package:test/test.dart';
final Key blockKey = new Key('test'); final Key blockKey = new Key('test');
void main() { void main() {
test('Cannot scroll a non-overflowing block', () { testWidgets('Cannot scroll a non-overflowing block', (WidgetTester tester) {
testWidgets((WidgetTester tester) { tester.pumpWidget(
tester.pumpWidget( new Block(
new Block( key: blockKey,
key: blockKey, children: <Widget>[
children: <Widget>[ new Container(
new Container( height: 200.0, // less than 600, the height of the test area
height: 200.0, // less than 600, the height of the test area child: new Text('Hello')
child: new Text('Hello') )
) ]
] )
) );
);
Point middleOfContainer = tester.getCenter(find.text('Hello'));
Point middleOfContainer = tester.getCenter(find.text('Hello')); Point target = tester.getCenter(find.byKey(blockKey));
Point target = tester.getCenter(find.byKey(blockKey)); TestGesture gesture = tester.startGesture(target);
TestGesture gesture = tester.startGesture(target); gesture.moveBy(const Offset(0.0, -10.0));
gesture.moveBy(const Offset(0.0, -10.0));
tester.pump(const Duration(milliseconds: 1));
tester.pump(const Duration(milliseconds: 1));
expect(tester.getCenter(find.text('Hello')) == middleOfContainer, isTrue);
expect(tester.getCenter(find.text('Hello')) == middleOfContainer, isTrue);
gesture.up();
gesture.up();
});
}); });
test('Can scroll an overflowing block', () { testWidgets('Can scroll an overflowing block', (WidgetTester tester) {
testWidgets((WidgetTester tester) { tester.pumpWidget(
tester.pumpWidget( new Block(
new Block( key: blockKey,
key: blockKey, children: <Widget>[
children: <Widget>[ new Container(
new Container( height: 2000.0, // more than 600, the height of the test area
height: 2000.0, // more than 600, the height of the test area child: new Text('Hello')
child: new Text('Hello') )
) ]
] )
) );
);
Point middleOfContainer = tester.getCenter(find.text('Hello')); Point middleOfContainer = tester.getCenter(find.text('Hello'));
expect(middleOfContainer.x, equals(400.0)); expect(middleOfContainer.x, equals(400.0));
expect(middleOfContainer.y, equals(1000.0)); expect(middleOfContainer.y, equals(1000.0));
Point target = tester.getCenter(find.byKey(blockKey)); Point target = tester.getCenter(find.byKey(blockKey));
TestGesture gesture = tester.startGesture(target); TestGesture gesture = tester.startGesture(target);
gesture.moveBy(const Offset(0.0, -10.0)); gesture.moveBy(const Offset(0.0, -10.0));
tester.pump(); // redo layout tester.pump(); // redo layout
expect(tester.getCenter(find.text('Hello')), isNot(equals(middleOfContainer))); expect(tester.getCenter(find.text('Hello')), isNot(equals(middleOfContainer)));
gesture.up(); gesture.up();
});
}); });
test('Scroll anchor', () { testWidgets('Scroll anchor', (WidgetTester tester) {
testWidgets((WidgetTester tester) { int first = 0;
int first = 0; int second = 0;
int second = 0;
Widget buildBlock(ViewportAnchor scrollAnchor) {
Widget buildBlock(ViewportAnchor scrollAnchor) { return new Block(
return new Block( key: new UniqueKey(),
key: new UniqueKey(), scrollAnchor: scrollAnchor,
scrollAnchor: scrollAnchor, children: <Widget>[
children: <Widget>[ new GestureDetector(
new GestureDetector( onTap: () { ++first; },
onTap: () { ++first; }, child: new Container(
child: new Container( height: 2000.0, // more than 600, the height of the test area
height: 2000.0, // more than 600, the height of the test area decoration: new BoxDecoration(
decoration: new BoxDecoration( backgroundColor: new Color(0xFF00FF00)
backgroundColor: new Color(0xFF00FF00)
)
) )
), )
new GestureDetector( ),
onTap: () { ++second; }, new GestureDetector(
child: new Container( onTap: () { ++second; },
height: 2000.0, // more than 600, the height of the test area child: new Container(
decoration: new BoxDecoration( height: 2000.0, // more than 600, the height of the test area
backgroundColor: new Color(0xFF0000FF) decoration: new BoxDecoration(
) backgroundColor: new Color(0xFF0000FF)
) )
) )
] )
); ]
} );
}
tester.pumpWidget(buildBlock(ViewportAnchor.end)); tester.pumpWidget(buildBlock(ViewportAnchor.end));
Point target = const Point(200.0, 200.0); Point target = const Point(200.0, 200.0);
tester.tapAt(target); tester.tapAt(target);
expect(first, equals(0)); expect(first, equals(0));
expect(second, equals(1)); expect(second, equals(1));
tester.pumpWidget(buildBlock(ViewportAnchor.start)); tester.pumpWidget(buildBlock(ViewportAnchor.start));
tester.tapAt(target); tester.tapAt(target);
expect(first, equals(1)); expect(first, equals(1));
expect(second, equals(1)); expect(second, equals(1));
});
}); });
} }
...@@ -7,35 +7,33 @@ import 'package:flutter/material.dart'; ...@@ -7,35 +7,33 @@ import 'package:flutter/material.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
test('Verify that a BottomSheet can be rebuilt with ScaffoldFeatureController.setState()', () { testWidgets('Verify that a BottomSheet can be rebuilt with ScaffoldFeatureController.setState()', (WidgetTester tester) {
testWidgets((WidgetTester tester) { final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>(); PersistentBottomSheetController<Null> bottomSheet;
PersistentBottomSheetController<Null> bottomSheet; int buildCount = 0;
int buildCount = 0;
tester.pumpWidget(new MaterialApp( tester.pumpWidget(new MaterialApp(
home: new Scaffold( home: new Scaffold(
key: scaffoldKey, key: scaffoldKey,
body: new Center(child: new Text('body')) body: new Center(child: new Text('body'))
) )
)); ));
bottomSheet = scaffoldKey.currentState.showBottomSheet/*<Null>*/((_) { bottomSheet = scaffoldKey.currentState.showBottomSheet/*<Null>*/((_) {
return new Builder( return new Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
buildCount += 1; buildCount += 1;
return new Container(height: 200.0); return new Container(height: 200.0);
} }
); );
}); });
tester.pump(); tester.pump();
expect(buildCount, equals(1)); expect(buildCount, equals(1));
bottomSheet.setState((){ }); bottomSheet.setState((){ });
tester.pump(); tester.pump();
expect(buildCount, equals(2)); expect(buildCount, equals(2));
});
}); });
} }
...@@ -8,111 +8,107 @@ import 'package:flutter/widgets.dart'; ...@@ -8,111 +8,107 @@ import 'package:flutter/widgets.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
test('Verify that a tap dismisses a modal BottomSheet', () { testWidgets('Verify that a tap dismisses a modal BottomSheet', (WidgetTester tester) {
testWidgets((WidgetTester tester) { BuildContext savedContext;
BuildContext savedContext; bool showBottomSheetThenCalled = false;
bool showBottomSheetThenCalled = false;
tester.pumpWidget(new MaterialApp(
tester.pumpWidget(new MaterialApp( home: new Builder(
home: new Builder( builder: (BuildContext context) {
builder: (BuildContext context) { savedContext = context;
savedContext = context; return new Container();
return new Container(); }
} )
) ));
));
tester.pump();
tester.pump(); expect(find.text('BottomSheet'), findsNothing);
expect(tester, doesNotHaveWidget(find.text('BottomSheet')));
showModalBottomSheet/*<Null>*/(
showModalBottomSheet/*<Null>*/( context: savedContext,
context: savedContext, builder: (BuildContext context) => new Text('BottomSheet')
builder: (BuildContext context) => new Text('BottomSheet') ).then((Null result) {
).then((Null result) { expect(result, isNull);
expect(result, isNull); showBottomSheetThenCalled = true;
showBottomSheetThenCalled = true;
});
tester.pump(); // bottom sheet show animation starts
tester.pump(new Duration(seconds: 1)); // animation done
expect(tester, hasWidget(find.text('BottomSheet')));
expect(showBottomSheetThenCalled, isFalse);
// Tap on the the bottom sheet itself to dismiss it
tester.tap(find.text('BottomSheet'));
tester.pump(); // bottom sheet dismiss animation starts
expect(showBottomSheetThenCalled, isTrue);
tester.pump(new Duration(seconds: 1)); // last frame of animation (sheet is entirely off-screen, but still present)
tester.pump(new Duration(seconds: 1)); // frame after the animation (sheet has been removed)
expect(tester, doesNotHaveWidget(find.text('BottomSheet')));
showModalBottomSheet/*<Null>*/(context: savedContext, builder: (BuildContext context) => new Text('BottomSheet'));
tester.pump(); // bottom sheet show animation starts
tester.pump(new Duration(seconds: 1)); // animation done
expect(tester, hasWidget(find.text('BottomSheet')));
// Tap above the the bottom sheet to dismiss it
tester.tapAt(new Point(20.0, 20.0));
tester.pump(); // bottom sheet dismiss animation starts
tester.pump(new Duration(seconds: 1)); // animation done
tester.pump(new Duration(seconds: 1)); // rebuild frame
expect(tester, doesNotHaveWidget(find.text('BottomSheet')));
}); });
});
test('Verify that a downwards fling dismisses a persistent BottomSheet', () {
testWidgets((WidgetTester tester) {
GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
bool showBottomSheetThenCalled = false;
tester.pumpWidget(new MaterialApp(
home: new Scaffold(
key: scaffoldKey,
body: new Center(child: new Text('body'))
)
));
expect(showBottomSheetThenCalled, isFalse); tester.pump(); // bottom sheet show animation starts
expect(tester, doesNotHaveWidget(find.text('BottomSheet'))); tester.pump(new Duration(seconds: 1)); // animation done
expect(find.text('BottomSheet'), findsOneWidget);
expect(showBottomSheetThenCalled, isFalse);
// Tap on the the bottom sheet itself to dismiss it
tester.tap(find.text('BottomSheet'));
tester.pump(); // bottom sheet dismiss animation starts
expect(showBottomSheetThenCalled, isTrue);
tester.pump(new Duration(seconds: 1)); // last frame of animation (sheet is entirely off-screen, but still present)
tester.pump(new Duration(seconds: 1)); // frame after the animation (sheet has been removed)
expect(find.text('BottomSheet'), findsNothing);
showModalBottomSheet/*<Null>*/(context: savedContext, builder: (BuildContext context) => new Text('BottomSheet'));
tester.pump(); // bottom sheet show animation starts
tester.pump(new Duration(seconds: 1)); // animation done
expect(find.text('BottomSheet'), findsOneWidget);
// Tap above the the bottom sheet to dismiss it
tester.tapAt(new Point(20.0, 20.0));
tester.pump(); // bottom sheet dismiss animation starts
tester.pump(new Duration(seconds: 1)); // animation done
tester.pump(new Duration(seconds: 1)); // rebuild frame
expect(find.text('BottomSheet'), findsNothing);
});
scaffoldKey.currentState.showBottomSheet((BuildContext context) { testWidgets('Verify that a downwards fling dismisses a persistent BottomSheet', (WidgetTester tester) {
return new Container( GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
margin: new EdgeInsets.all(40.0), bool showBottomSheetThenCalled = false;
child: new Text('BottomSheet')
); tester.pumpWidget(new MaterialApp(
}).closed.then((_) { home: new Scaffold(
showBottomSheetThenCalled = true; key: scaffoldKey,
}); body: new Center(child: new Text('body'))
)
));
expect(showBottomSheetThenCalled, isFalse);
expect(find.text('BottomSheet'), findsNothing);
scaffoldKey.currentState.showBottomSheet((BuildContext context) {
return new Container(
margin: new EdgeInsets.all(40.0),
child: new Text('BottomSheet')
);
}).closed.then((_) {
showBottomSheetThenCalled = true;
});
expect(showBottomSheetThenCalled, isFalse); expect(showBottomSheetThenCalled, isFalse);
expect(tester, doesNotHaveWidget(find.text('BottomSheet'))); expect(find.text('BottomSheet'), findsNothing);
tester.pump(); // bottom sheet show animation starts tester.pump(); // bottom sheet show animation starts
expect(showBottomSheetThenCalled, isFalse); expect(showBottomSheetThenCalled, isFalse);
expect(tester, hasWidget(find.text('BottomSheet'))); expect(find.text('BottomSheet'), findsOneWidget);
tester.pump(new Duration(seconds: 1)); // animation done tester.pump(new Duration(seconds: 1)); // animation done
expect(showBottomSheetThenCalled, isFalse); expect(showBottomSheetThenCalled, isFalse);
expect(tester, hasWidget(find.text('BottomSheet'))); expect(find.text('BottomSheet'), findsOneWidget);
tester.fling(find.text('BottomSheet'), const Offset(0.0, 20.0), 1000.0); tester.fling(find.text('BottomSheet'), const Offset(0.0, 20.0), 1000.0);
tester.pump(); // drain the microtask queue (Future completion callback) tester.pump(); // drain the microtask queue (Future completion callback)
expect(showBottomSheetThenCalled, isTrue); expect(showBottomSheetThenCalled, isTrue);
expect(tester, hasWidget(find.text('BottomSheet'))); expect(find.text('BottomSheet'), findsOneWidget);
tester.pump(); // bottom sheet dismiss animation starts tester.pump(); // bottom sheet dismiss animation starts
expect(showBottomSheetThenCalled, isTrue); expect(showBottomSheetThenCalled, isTrue);
expect(tester, hasWidget(find.text('BottomSheet'))); expect(find.text('BottomSheet'), findsOneWidget);
tester.pump(new Duration(seconds: 1)); // animation done tester.pump(new Duration(seconds: 1)); // animation done
expect(showBottomSheetThenCalled, isTrue); expect(showBottomSheetThenCalled, isTrue);
expect(tester, doesNotHaveWidget(find.text('BottomSheet'))); expect(find.text('BottomSheet'), findsNothing);
});
}); });
} }
...@@ -8,37 +8,33 @@ import 'package:flutter/widgets.dart'; ...@@ -8,37 +8,33 @@ import 'package:flutter/widgets.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
test('Circles can have uniform borders', () { testWidgets('Circles can have uniform borders', (WidgetTester tester) {
testWidgets((WidgetTester tester) { tester.pumpWidget(
tester.pumpWidget( new Container(
new Container( padding: new EdgeInsets.all(50.0),
padding: new EdgeInsets.all(50.0), decoration: new BoxDecoration(
decoration: new BoxDecoration( shape: BoxShape.circle,
shape: BoxShape.circle, border: new Border.all(width: 10.0, color: const Color(0x80FF00FF)),
border: new Border.all(width: 10.0, color: const Color(0x80FF00FF)), backgroundColor: Colors.teal[600]
backgroundColor: Colors.teal[600]
)
) )
); )
}); );
}); });
test('Bordered Container insets its child', () { testWidgets('Bordered Container insets its child', (WidgetTester tester) {
testWidgets((WidgetTester tester) { Key key = new Key('outerContainer');
Key key = new Key('outerContainer'); tester.pumpWidget(
tester.pumpWidget( new Center(
new Center( child: new Container(
key: key,
decoration: new BoxDecoration(border: new Border.all(width: 10.0)),
child: new Container( child: new Container(
key: key, width: 25.0,
decoration: new BoxDecoration(border: new Border.all(width: 10.0)), height: 25.0
child: new Container(
width: 25.0,
height: 25.0
)
) )
) )
); )
expect(tester.getSize(find.byKey(key)), equals(const Size(45.0, 45.0))); );
}); expect(tester.getSize(find.byKey(key)), equals(const Size(45.0, 45.0)));
}); });
} }
...@@ -78,47 +78,41 @@ class BadDisposeWidgetState extends State<BadDisposeWidget> { ...@@ -78,47 +78,41 @@ class BadDisposeWidgetState extends State<BadDisposeWidget> {
} }
void main() { void main() {
test('Legal times for setState', () { testWidgets('Legal times for setState', (WidgetTester tester) {
testWidgets((WidgetTester tester) { GlobalKey flipKey = new GlobalKey();
GlobalKey flipKey = new GlobalKey(); expect(ProbeWidgetState.buildCount, equals(0));
expect(ProbeWidgetState.buildCount, equals(0)); tester.pumpWidget(new ProbeWidget());
tester.pumpWidget(new ProbeWidget()); expect(ProbeWidgetState.buildCount, equals(1));
expect(ProbeWidgetState.buildCount, equals(1)); tester.pumpWidget(new ProbeWidget());
tester.pumpWidget(new ProbeWidget()); expect(ProbeWidgetState.buildCount, equals(2));
expect(ProbeWidgetState.buildCount, equals(2)); tester.pumpWidget(new FlipWidget(
tester.pumpWidget(new FlipWidget( key: flipKey,
key: flipKey, left: new Container(),
left: new Container(), right: new ProbeWidget()
right: new ProbeWidget() ));
)); expect(ProbeWidgetState.buildCount, equals(2));
expect(ProbeWidgetState.buildCount, equals(2)); FlipWidgetState flipState1 = flipKey.currentState;
FlipWidgetState flipState1 = flipKey.currentState; flipState1.flip();
flipState1.flip(); tester.pump();
tester.pump(); expect(ProbeWidgetState.buildCount, equals(3));
expect(ProbeWidgetState.buildCount, equals(3)); FlipWidgetState flipState2 = flipKey.currentState;
FlipWidgetState flipState2 = flipKey.currentState; flipState2.flip();
flipState2.flip(); tester.pump();
tester.pump(); expect(ProbeWidgetState.buildCount, equals(3));
expect(ProbeWidgetState.buildCount, equals(3)); tester.pumpWidget(new Container());
tester.pumpWidget(new Container()); expect(ProbeWidgetState.buildCount, equals(3));
expect(ProbeWidgetState.buildCount, equals(3));
});
}); });
test('Setting parent state during build is forbidden', () { testWidgets('Setting parent state during build is forbidden', (WidgetTester tester) {
testWidgets((WidgetTester tester) { tester.pumpWidget(new BadWidgetParent());
tester.pumpWidget(new BadWidgetParent()); expect(tester.takeException(), isNotNull);
expect(tester.takeException(), isNotNull); tester.pumpWidget(new Container());
tester.pumpWidget(new Container());
});
}); });
test('Setting state during dispose is forbidden', () { testWidgets('Setting state during dispose is forbidden', (WidgetTester tester) {
testWidgets((WidgetTester tester) { tester.pumpWidget(new BadDisposeWidget());
tester.pumpWidget(new BadDisposeWidget()); expect(tester.takeException(), isNull);
expect(tester.takeException(), isNull); tester.pumpWidget(new Container());
tester.pumpWidget(new Container()); expect(tester.takeException(), isNotNull);
expect(tester.takeException(), isNotNull);
});
}); });
} }
...@@ -10,45 +10,43 @@ import 'package:test/test.dart'; ...@@ -10,45 +10,43 @@ import 'package:test/test.dart';
import 'test_semantics.dart'; import 'test_semantics.dart';
void main() { void main() {
test('Does FlatButton contribute semantics', () { testWidgets('Does FlatButton contribute semantics', (WidgetTester tester) {
testWidgets((WidgetTester tester) { TestSemanticsListener client = new TestSemanticsListener();
TestSemanticsListener client = new TestSemanticsListener(); tester.pumpWidget(
tester.pumpWidget( new Material(
new Material( child: new Center(
child: new Center( child: new FlatButton(
child: new FlatButton( onPressed: () { },
onPressed: () { }, child: new Text('Hello')
child: new Text('Hello')
)
) )
) )
); )
expect(client.updates.length, equals(2)); );
expect(client.updates[0].id, equals(0)); expect(client.updates.length, equals(2));
expect(client.updates[0].flags.canBeTapped, isFalse); expect(client.updates[0].id, equals(0));
expect(client.updates[0].flags.canBeLongPressed, isFalse); expect(client.updates[0].flags.canBeTapped, isFalse);
expect(client.updates[0].flags.canBeScrolledHorizontally, isFalse); expect(client.updates[0].flags.canBeLongPressed, isFalse);
expect(client.updates[0].flags.canBeScrolledVertically, isFalse); expect(client.updates[0].flags.canBeScrolledHorizontally, isFalse);
expect(client.updates[0].flags.hasCheckedState, isFalse); expect(client.updates[0].flags.canBeScrolledVertically, isFalse);
expect(client.updates[0].flags.isChecked, isFalse); expect(client.updates[0].flags.hasCheckedState, isFalse);
expect(client.updates[0].strings.label, equals('')); expect(client.updates[0].flags.isChecked, isFalse);
expect(client.updates[0].geometry.transform, isNull); expect(client.updates[0].strings.label, equals(''));
expect(client.updates[0].geometry.left, equals(0.0)); expect(client.updates[0].geometry.transform, isNull);
expect(client.updates[0].geometry.top, equals(0.0)); expect(client.updates[0].geometry.left, equals(0.0));
expect(client.updates[0].geometry.width, equals(800.0)); expect(client.updates[0].geometry.top, equals(0.0));
expect(client.updates[0].geometry.height, equals(600.0)); expect(client.updates[0].geometry.width, equals(800.0));
expect(client.updates[0].children.length, equals(1)); expect(client.updates[0].geometry.height, equals(600.0));
expect(client.updates[0].children[0].id, equals(1)); expect(client.updates[0].children.length, equals(1));
expect(client.updates[0].children[0].flags.canBeTapped, isTrue); expect(client.updates[0].children[0].id, equals(1));
expect(client.updates[0].children[0].flags.canBeLongPressed, isFalse); expect(client.updates[0].children[0].flags.canBeTapped, isTrue);
expect(client.updates[0].children[0].flags.canBeScrolledHorizontally, isFalse); expect(client.updates[0].children[0].flags.canBeLongPressed, isFalse);
expect(client.updates[0].children[0].flags.canBeScrolledVertically, isFalse); expect(client.updates[0].children[0].flags.canBeScrolledHorizontally, isFalse);
expect(client.updates[0].children[0].flags.hasCheckedState, isFalse); expect(client.updates[0].children[0].flags.canBeScrolledVertically, isFalse);
expect(client.updates[0].children[0].flags.isChecked, isFalse); expect(client.updates[0].children[0].flags.hasCheckedState, isFalse);
expect(client.updates[0].children[0].strings.label, equals('Hello')); expect(client.updates[0].children[0].flags.isChecked, isFalse);
expect(client.updates[0].children[0].children.length, equals(0)); expect(client.updates[0].children[0].strings.label, equals('Hello'));
expect(client.updates[1], isNull); expect(client.updates[0].children[0].children.length, equals(0));
client.updates.clear(); expect(client.updates[1], isNull);
}); client.updates.clear();
}); });
} }
...@@ -4,12 +4,9 @@ ...@@ -4,12 +4,9 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:test/test.dart';
void main() { void main() {
test('Can be placed in an infinite box', () { testWidgets('Can be placed in an infinite box', (WidgetTester tester) {
testWidgets((WidgetTester tester) { tester.pumpWidget(new Block(children: <Widget>[new Center()]));
tester.pumpWidget(new Block(children: <Widget>[new Center()]));
});
}); });
} }
...@@ -8,42 +8,40 @@ import 'package:flutter/widgets.dart'; ...@@ -8,42 +8,40 @@ import 'package:flutter/widgets.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
test('Comparing coordinates', () { testWidgets('Comparing coordinates', (WidgetTester tester) {
testElementTree((ElementTreeTester tester) { Key keyA = new GlobalKey();
Key keyA = new GlobalKey(); Key keyB = new GlobalKey();
Key keyB = new GlobalKey();
tester.pumpWidget( tester.pumpWidget(
new Stack( new Stack(
children: <Widget>[ children: <Widget>[
new Positioned( new Positioned(
top: 100.0, top: 100.0,
left: 100.0, left: 100.0,
child: new SizedBox( child: new SizedBox(
key: keyA, key: keyA,
width: 10.0, width: 10.0,
height: 10.0 height: 10.0
) )
), ),
new Positioned( new Positioned(
left: 100.0, left: 100.0,
top: 200.0, top: 200.0,
child: new SizedBox( child: new SizedBox(
key: keyB, key: keyB,
width: 20.0, width: 20.0,
height: 10.0 height: 10.0
) )
), ),
] ]
) )
); );
RenderBox boxA = tester.findElementByKey(keyA).renderObject; RenderBox boxA = tester.renderObject(find.byKey(keyA));
expect(boxA.localToGlobal(const Point(0.0, 0.0)), equals(const Point(100.0, 100.0))); expect(boxA.localToGlobal(const Point(0.0, 0.0)), equals(const Point(100.0, 100.0)));
RenderBox boxB = tester.findElementByKey(keyB).renderObject; RenderBox boxB = tester.renderObject(find.byKey(keyB));
expect(boxB.localToGlobal(const Point(0.0, 0.0)), equals(const Point(100.0, 200.0))); expect(boxB.localToGlobal(const Point(0.0, 0.0)), equals(const Point(100.0, 200.0)));
expect(boxB.globalToLocal(const Point(110.0, 205.0)), equals(const Point(10.0, 5.0))); expect(boxB.globalToLocal(const Point(110.0, 205.0)), equals(const Point(10.0, 5.0)));
});
}); });
} }
...@@ -56,8 +56,7 @@ Widget buildFrame(SingleChildLayoutDelegate delegate) { ...@@ -56,8 +56,7 @@ Widget buildFrame(SingleChildLayoutDelegate delegate) {
} }
void main() { void main() {
test('Control test for CustomSingleChildLayout', () { testWidgets('Control test for CustomSingleChildLayout', (WidgetTester tester) {
testWidgets((WidgetTester tester) {
TestSingleChildLayoutDelegate delegate = new TestSingleChildLayoutDelegate(); TestSingleChildLayoutDelegate delegate = new TestSingleChildLayoutDelegate();
tester.pumpWidget(buildFrame(delegate)); tester.pumpWidget(buildFrame(delegate));
...@@ -76,11 +75,9 @@ void main() { ...@@ -76,11 +75,9 @@ void main() {
expect(delegate.childSizeFromGetPositionForChild.width, 150.0); expect(delegate.childSizeFromGetPositionForChild.width, 150.0);
expect(delegate.childSizeFromGetPositionForChild.height, 400.0); expect(delegate.childSizeFromGetPositionForChild.height, 400.0);
});
}); });
test('Test SingleChildDelegate shouldRelayout method', () { testWidgets('Test SingleChildDelegate shouldRelayout method', (WidgetTester tester) {
testWidgets((WidgetTester tester) {
TestSingleChildLayoutDelegate delegate = new TestSingleChildLayoutDelegate(); TestSingleChildLayoutDelegate delegate = new TestSingleChildLayoutDelegate();
tester.pumpWidget(buildFrame(delegate)); tester.pumpWidget(buildFrame(delegate));
...@@ -101,7 +98,6 @@ void main() { ...@@ -101,7 +98,6 @@ void main() {
tester.pumpWidget(buildFrame(delegate)); tester.pumpWidget(buildFrame(delegate));
expect(delegate.shouldRelayoutCalled, isTrue); expect(delegate.shouldRelayoutCalled, isTrue);
expect(delegate.constraintsFromGetConstraintsForChild, isNotNull); expect(delegate.constraintsFromGetConstraintsForChild, isNotNull);
});
}); });
} }
...@@ -22,27 +22,25 @@ class TestCustomPainter extends CustomPainter { ...@@ -22,27 +22,25 @@ class TestCustomPainter extends CustomPainter {
} }
void main() { void main() {
test('Control test for custom painting', () { testWidgets('Control test for custom painting', (WidgetTester tester) {
testWidgets((WidgetTester tester) { List<String> log = <String>[];
List<String> log = <String>[]; tester.pumpWidget(new CustomPaint(
tester.pumpWidget(new CustomPaint( painter: new TestCustomPainter(
log: log,
name: 'background'
),
foregroundPainter: new TestCustomPainter(
log: log,
name: 'foreground'
),
child: new CustomPaint(
painter: new TestCustomPainter( painter: new TestCustomPainter(
log: log, log: log,
name: 'background' name: 'child'
),
foregroundPainter: new TestCustomPainter(
log: log,
name: 'foreground'
),
child: new CustomPaint(
painter: new TestCustomPainter(
log: log,
name: 'child'
)
) )
)); )
));
expect(log, equals(['background', 'child', 'foreground'])); expect(log, equals(['background', 'child', 'foreground']));
});
}); });
} }
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:test/test.dart';
class Item { class Item {
GlobalKey key1 = new GlobalKey(); GlobalKey key1 = new GlobalKey();
...@@ -55,16 +54,14 @@ Widget builder() { ...@@ -55,16 +54,14 @@ Widget builder() {
} }
void main() { void main() {
test('duplicate key smoke test', () { testWidgets('duplicate key smoke test', (WidgetTester tester) {
testWidgets((WidgetTester tester) { tester.pumpWidget(builder());
tester.pumpWidget(builder()); StatefulLeafState leaf = tester.firstState(find.byType(StatefulLeaf));
StatefulLeafState leaf = tester.stateOf(find.byType(StatefulLeaf)); leaf.test();
leaf.test(); tester.pump();
tester.pump(); Item lastItem = items[1];
Item lastItem = items[1]; items.remove(lastItem);
items.remove(lastItem); items.insert(0, lastItem);
items.insert(0, lastItem); tester.pumpWidget(builder()); // this marks the app dirty and rebuilds it
tester.pumpWidget(builder()); // this marks the app dirty and rebuilds it
});
}); });
} }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -28,10 +28,8 @@ class TestWidgetState extends State<TestWidget> { ...@@ -28,10 +28,8 @@ class TestWidgetState extends State<TestWidget> {
} }
void main() { void main() {
test('initState() is called when we are in the tree', () { testWidgets('initState() is called when we are in the tree', (WidgetTester tester) {
testWidgets((WidgetTester tester) { tester.pumpWidget(new Container(child: new TestWidget()));
tester.pumpWidget(new Container(child: new TestWidget())); expect(ancestors, equals(<String>['Container', 'RenderObjectToWidgetAdapter<RenderBox>']));
expect(ancestors, equals(<String>['Container', 'RenderObjectToWidgetAdapter<RenderBox>']));
});
}); });
} }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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