1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright 2017 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 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_gallery/gallery/app.dart';
/// Reports success or failure to the native code.
const MethodChannel _kTestChannel = const MethodChannel('io.flutter.examples.gallery/TestLifecycleListener');
Future<Null> main() async {
try {
runApp(const GalleryApp());
const Duration kWaitBetweenActions = const Duration(milliseconds: 250);
final _LiveWidgetController controller = new _LiveWidgetController();
for (Demo demo in demos) {
print('Testing "${demo.title}" demo');
final Finder menuItem = find.text(demo.title);
await controller.scrollIntoView(menuItem, alignment: 0.5);
await new Future<Null>.delayed(kWaitBetweenActions);
for (int i = 0; i < 2; i += 1) {
await controller.tap(menuItem); // Launch the demo
await new Future<Null>.delayed(kWaitBetweenActions);
controller.frameSync = demo.synchronized;
await controller.tap(find.byTooltip('Back'));
controller.frameSync = true;
await new Future<Null>.delayed(kWaitBetweenActions);
}
print('Success');
}
_kTestChannel.invokeMethod('success');
} catch (error) {
_kTestChannel.invokeMethod('failure');
}
}
class Demo {
const Demo(this.title, {this.synchronized = true});
/// The title of the demo.
final String title;
/// True if frameSync should be enabled for this test.
final bool synchronized;
}
// Warning: this list must be kept in sync with the value of
// kAllGalleryItems.map((GalleryItem item) => item.title).toList();
const List<Demo> demos = const <Demo>[
// Demos
const Demo('Shrine'),
const Demo('Contact profile'),
const Demo('Animation'),
// Material Components
const Demo('Bottom navigation'),
const Demo('Buttons'),
const Demo('Cards'),
const Demo('Chips'),
const Demo('Date and time pickers'),
const Demo('Dialog'),
const Demo('Drawer'),
const Demo('Expand/collapse list control'),
const Demo('Expansion panels'),
const Demo('Floating action button'),
const Demo('Grid'),
const Demo('Icons'),
const Demo('Leave-behind list items'),
const Demo('List'),
const Demo('Menus'),
const Demo('Modal bottom sheet'),
const Demo('Page selector'),
const Demo('Persistent bottom sheet'),
const Demo('Progress indicators', synchronized: false),
const Demo('Pull to refresh'),
const Demo('Scrollable tabs'),
const Demo('Selection controls'),
const Demo('Sliders'),
const Demo('Snackbar'),
const Demo('Tabs'),
const Demo('Text fields'),
const Demo('Tooltips'),
// Cupertino Components
const Demo('Activity Indicator', synchronized: false),
const Demo('Buttons'),
const Demo('Dialogs'),
const Demo('Sliders'),
const Demo('Switches'),
// Style
const Demo('Colors'),
const Demo('Typography'),
];
class _LiveWidgetController {
final WidgetController _controller = new WidgetController(WidgetsBinding.instance);
/// With [frameSync] enabled, Flutter Driver will wait to perform an action
/// until there are no pending frames in the app under test.
bool frameSync = true;
/// Waits until at the end of a frame the provided [condition] is [true].
Future<Null> _waitUntilFrame(bool condition(), [Completer<Null> completer]) {
completer ??= new Completer<Null>();
if (!condition()) {
SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
_waitUntilFrame(condition, completer);
});
} else {
completer.complete();
}
return completer.future;
}
/// Runs `finder` repeatedly until it finds one or more [Element]s.
Future<Finder> _waitForElement(Finder finder) async {
if (frameSync)
await _waitUntilFrame(() => SchedulerBinding.instance.transientCallbackCount == 0);
await _waitUntilFrame(() => finder.precache());
if (frameSync)
await _waitUntilFrame(() => SchedulerBinding.instance.transientCallbackCount == 0);
return finder;
}
Future<Null> tap(Finder finder) async {
await _controller.tap(await _waitForElement(finder));
}
Future<Null> scrollIntoView(Finder finder, {double alignment}) async {
final Finder target = await _waitForElement(finder);
await Scrollable.ensureVisible(target.evaluate().single, duration: const Duration(milliseconds: 100), alignment: alignment);
}
}