[testing_app] Migrate the sample to the integration_test package (#633)

pull/702/head
Abdullah Deshmukh 4 years ago committed by GitHub
parent d16d35e0ac
commit f63c465ff4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -12,7 +12,7 @@ would do.
Show how to perform: Show how to perform:
- Widget Testing, - Widget Testing,
- Flutter Driver(Integration) Testing, - Integration Testing,
- Performance Testing, and - Performance Testing, and
- State Management Testing using the [Provider][] package. - State Management Testing using the [Provider][] package.
@ -27,20 +27,15 @@ The Flutter SDK can run unit tests and widget tests in a virtual machine, withou
### To run tests on a physical device/emulator: ### To run tests on a physical device/emulator:
- Widget Tests: - Widget Tests:
- Run `flutter run test/<file_path>` - Run `flutter run test/<file_path>`
- Flutter Driver Tests: - Integration Tests:
- Run `flutter drive --target=test_driver/<file_path>` - Run `flutter drive --driver=integration_test/driver.dart --target=integration_test/app_test.dart`
- eg. `flutter drive --target=test_driver/app.dart` to run the test in `test_driver/app_test.dart`
- Performance Tests: - Performance Tests:
- Run `flutter drive --target=test_driver/app.dart --driver test_driver/perf_test.dart --profile --trace-startup` - Run `flutter drive --driver=integration_test/driver.dart --target=integration_test/perf_test.dart --profile --trace-startup`
- Using a physical device and running performance tests in profile mode is recommended. - Using a physical device and running performance tests in profile mode is recommended.
- The `--trace-startup` option is used to avoid flushing older timeline events when the timeline gets long. - The `--trace-startup` option is used to avoid flushing older timeline events when the timeline gets long.
- [E2E](https://pub.dev/packages/e2e) Tests:
- Run `flutter drive --target test/perf_test_e2e.dart --driver test_driver/e2e_test.dart --profile`
- Similar to the above but the test is driven on device.
- You may also reference [E2E manual](https://github.com/flutter/plugins/tree/master/packages/e2e#firebase-test-lab) for how to run such test on Firebase Test Lab.
- State Management Tests: - State Management Tests:
- For testing state using Flutter Driver - For testing state using Flutter Integration Tests
- Run `flutter drive --target=test_driver/<file_path>` - Run `flutter drive --driver=integration_test/driver.dart --target=integration_test/state_mgmt_test.dart`
### To generate test coverage report: ### To generate test coverage report:
- Install the `lcov` tool: - Install the `lcov` tool:
@ -53,9 +48,9 @@ The Flutter SDK can run unit tests and widget tests in a virtual machine, withou
- Open `coverage/index/index.html` in your preferred browser. - Open `coverage/index/index.html` in your preferred browser.
### CI/CD ### CI/CD
- Refer [.travis.yml](../.travis.yml) and the [tool](../tool) directory to see how to test Flutter projects using Travis-CI. - Refer [.github](../.github) and the [tool](../tool) directory to see how to test Flutter projects using GitHub Actions.
Note that we aren't performing Flutter Driver tests using the Travis tool in this repo. That is because it's recommended to use physical devices to run Driver tests. You can use [Firebase Test Lab](https://firebase.google.com/docs/test-lab), [Codemagic](https://codemagic.io/) or any platform of your choice to do that. Note that tools like GitHub Actions can't run tests on a physical device, which is required to run integration tests. Instead, you can use [Firebase Test Lab](https://firebase.google.com/docs/test-lab), [Codemagic](https://docs.codemagic.io/testing/aws/) or any platform of your choice to do that.
## Questions/issues ## Questions/issues

@ -0,0 +1,92 @@
// Copyright 2020 The Flutter team. 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/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:testing_app/main.dart';
void main() {
group('Testing App Driver Tests', () {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Finding an item in the list', (tester) async {
await tester.pumpWidget(TestingApp());
// Create variables for finders that are used multiple times.
final itemFinder = find.byKey(ValueKey('text_25'));
// Scroll until the item to be found appears.
await tester.scrollUntilVisible(
itemFinder,
500.0,
);
// Check if the item contains the correct text.
expect(tester.widget<Text>(itemFinder).data, 'Item 25');
});
testWidgets('Testing IconButtons', (tester) async {
await tester.pumpWidget(TestingApp());
// Create a finder for the icon.
final iconFinder = find.byKey(ValueKey('icon_0'));
// Tap on the icon.
await tester.tap(iconFinder);
await tester.pumpAndSettle(Duration(seconds: 1));
// Verify if appropriate message appears.
expect(find.text('Added to favorites.'), findsOneWidget);
// Tap on the icon again.
await tester.tap(iconFinder);
await tester.pumpAndSettle(Duration(seconds: 1));
// Verify if appropriate message appears.
expect(find.text('Removed from favorites.'), findsOneWidget);
await tester.pumpAndSettle(Duration(seconds: 1));
});
testWidgets('Verifying whether item gets added to favorites',
(tester) async {
await tester.pumpWidget(TestingApp());
// Add item to favorites.
await tester.tap(find.byKey(ValueKey('icon_5')));
await tester.pumpAndSettle(Duration(seconds: 1));
// Tap on the favorites button on the AppBar.
// The Favorites List should appear.
await tester.tap(find.text('Favorites'));
await tester.pumpAndSettle();
// Check if the added item has appeared in the list.
expect(tester.widget<Text>(find.byKey(ValueKey('favorites_text_5'))).data,
equals('Item 5'));
});
testWidgets('Testing remove button', (tester) async {
await tester.pumpWidget(TestingApp());
// Add item to favorites.
await tester.tap(find.byKey(ValueKey('icon_5')));
await tester.pumpAndSettle(Duration(seconds: 1));
// Navigate to Favorites screen.
await tester.tap(find.text('Favorites'));
await tester.pumpAndSettle();
// Tap on the remove icon.
await tester.tap(find.byKey(ValueKey('remove_icon_5')));
await tester.pumpAndSettle();
// Verify if it disappears.
expect(find.text('Item 5'), findsNothing);
// Verify if appropriate message appears.
expect(find.text('Removed from favorites.'), findsOneWidget);
});
});
}

@ -0,0 +1,23 @@
// Copyright 2020 The Flutter team. 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:integration_test/integration_test_driver.dart';
Future<void> main() {
return integrationDriver(
responseDataCallback: (data) async {
// If the tests reported any data, save it to the disk.
if (data != null) {
for (var entry in data.entries) {
print('Writing ${entry.key} to the disk.');
// Default storage destination is the 'build' directory.
await writeResponseData(
entry.value as Map<String, dynamic>,
testOutputFilename: entry.key,
);
}
}
},
);
}

@ -0,0 +1,119 @@
// Copyright 2020 The Flutter team. 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/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:testing_app/main.dart';
void main() {
group('Testing App Performance Tests', () {
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized()
as IntegrationTestWidgetsFlutterBinding;
// The fullyLive frame policy simulates
// the way Flutter responds to animations.
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
testWidgets('Scrolling test', (tester) async {
await tester.pumpWidget(TestingApp());
// Create variables for finders that are used multiple times.
final listFinder = find.byType(ListView);
final scroller = tester.widget<ListView>(listFinder).controller;
// Record the performance timeline of the following operations.
await binding.traceAction(
() async {
// Record the performance summary as the app scrolls through
// the list of items.
await binding.watchPerformance(
() async {
// Quickly scroll all the way down.
await scroller.animateTo(
7000,
duration: const Duration(seconds: 1),
curve: Curves.linear,
);
await tester.pumpAndSettle();
// Quickly scroll back up all the way.
await scroller.animateTo(
-7000,
duration: const Duration(seconds: 1),
curve: Curves.linear,
);
await tester.pumpAndSettle();
},
// Send the performance summary to the driver.
reportKey: 'scrolling_summary',
);
},
// Send the timeline data to the driver.
// This timeline can be opened in the Chrome browser's tracing tools
// by navigating to chrome://tracing.
reportKey: 'scrolling_timeline',
);
});
testWidgets('Favorites operations test', (tester) async {
await tester.pumpWidget(TestingApp());
// Record the performance timeline of the following operations.
await binding.traceAction(
() async {
// Record the performance summary as operations are performed
// on the favorites list.
await binding.watchPerformance(
() async {
// Create a list of icon keys.
final iconKeys = [
'icon_0',
'icon_1',
'icon_2',
];
// Add first three items to favorites.
for (var icon in iconKeys) {
// Tap onto the icon.
await tester.tap(find.byKey(ValueKey(icon)));
await tester.pumpAndSettle();
// Verify if appropriate message appears.
expect(find.text('Added to favorites.'), findsOneWidget);
}
// Tap onto the favorites button on the AppBar.
// The Favorites List should appear.
await tester.tap(find.text('Favorites'));
await tester.pumpAndSettle();
final removeIconKeys = [
'remove_icon_0',
'remove_icon_1',
'remove_icon_2',
];
// Remove all the items from favorites.
for (final iconKey in removeIconKeys) {
// Tap onto the remove icon.
await tester.tap(find.byKey(ValueKey(iconKey)));
await tester.pumpAndSettle();
// Verify if appropriate message appears.
expect(find.text('Removed from favorites.'), findsOneWidget);
}
},
// Send the performance summary to the driver.
reportKey: 'favorites_operations_summary',
);
},
// Send the timeline data to the driver.
// This timeline can be opened in the Chrome browser's tracing tools
// by navigating to chrome://tracing.
reportKey: 'favorites_operations_timeline',
);
});
});
}

@ -0,0 +1,50 @@
// Copyright 2020 The Flutter team. 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/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/favorites.dart';
Favorites favoritesList;
Widget createFavoritesScreen() => ChangeNotifierProvider<Favorites>(
create: (context) {
favoritesList = Favorites();
return favoritesList;
},
child: MaterialApp(
home: FavoritesPage(),
),
);
void main() {
group('Testing App State Management Tests', () {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Verifying add method', (tester) async {
await tester.pumpWidget(createFavoritesScreen());
// Add an item to the list.
favoritesList.add(30);
await tester.pumpAndSettle();
// Check if the new item appears in the list.
expect(find.text('Item 30'), findsOneWidget);
});
testWidgets('Verifying remove method', (tester) async {
await tester.pumpWidget(createFavoritesScreen());
// Remove an item from the list.
favoritesList.remove(30);
await tester.pumpAndSettle();
// Verify if it disappears.
expect(find.text('Item 30'), findsNothing);
});
});
}

@ -106,13 +106,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.0"
e2e:
dependency: "direct dev"
description:
name: e2e
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.0+1"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -133,7 +126,7 @@ packages:
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_driver: flutter_driver:
dependency: "direct dev" dependency: transitive
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
@ -175,6 +168,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.1.4" version: "3.1.4"
integration_test:
dependency: "direct dev"
description:
name: integration_test
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
io: io:
dependency: transitive dependency: transitive
description: description:

@ -14,12 +14,10 @@ dependencies:
provider: ^4.1.3 provider: ^4.1.3
dev_dependencies: dev_dependencies:
integration_test: ^1.0.1
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_driver:
sdk: flutter
test: ^1.14.4 test: ^1.14.4
e2e: ^0.7.0
pedantic: ^1.9.0 pedantic: ^1.9.0
flutter: flutter:

@ -1,192 +0,0 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(CareF): This file should be removed after the changes goes into flutter
// stable version.
// ignore linter to keep the code consistent with its duplicate in the framework
// ignore_for_file: use_function_type_syntax_for_parameters, omit_local_variable_types, avoid_types_on_closure_parameters
import 'dart:async';
import 'dart:ui';
import 'package:e2e/e2e.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
/// The maximum amount of time considered safe to spend for a frame's build
/// phase. Anything past that is in the danger of missing the frame as 60FPS.
///
/// Changing this doesn't re-evaluate existing summary.
Duration kBuildBudget = const Duration(milliseconds: 16);
bool _firstRun = true;
const String kDebugWarning = '''
THIS BENCHMARK IS BEING RUN IN DEBUG MODE
Numbers obtained from a benchmark while asserts are
enabled will not accurately reflect the performance
that will be experienced by end users using release
builds. Benchmarks should be run using this command
line: "flutter run --profile test.dart" or
or "flutter drive --profile -t test.dart".
🐢
''';
/// watches the [FrameTiming] of `action` and report it to the e2e binding.
Future<void> watchPerformance(
E2EWidgetsFlutterBinding binding,
Future<void> action(), {
String reportKey = 'performance',
}) async {
assert(() {
if (_firstRun) {
debugPrint(kDebugWarning);
_firstRun = false;
}
return true;
}());
final List<FrameTiming> frameTimings = <FrameTiming>[];
final TimingsCallback watcher = frameTimings.addAll;
binding.addTimingsCallback(watcher);
await action();
binding.removeTimingsCallback(watcher);
final FrameTimingSummarizer frameTimes = FrameTimingSummarizer(frameTimings);
binding.reportData = <String, dynamic>{reportKey: frameTimes.summary};
}
/// This class and summarizes a list of [FrameTiming] for the performance
/// metrics.
class FrameTimingSummarizer {
factory FrameTimingSummarizer(List<FrameTiming> data) {
assert(data != null);
assert(data.isNotEmpty);
final List<Duration> frameBuildTime = List<Duration>.unmodifiable(
data.map<Duration>((FrameTiming datum) => datum.buildDuration),
);
final List<Duration> frameBuildTimeSorted =
List<Duration>.from(frameBuildTime)..sort();
final List<Duration> frameRasterizerTime = List<Duration>.unmodifiable(
data.map<Duration>((FrameTiming datum) => datum.rasterDuration),
);
final List<Duration> frameRasterizerTimeSorted =
List<Duration>.from(frameRasterizerTime)..sort();
final Duration Function(Duration, Duration) add =
(Duration a, Duration b) => a + b;
return FrameTimingSummarizer._(
frameBuildTime: frameBuildTime,
frameRasterizerTime: frameRasterizerTime,
// This avarage calculation is microsecond precision, which is fine
// because typical values of these times are milliseconds.
averageFrameBuildTime: frameBuildTime.reduce(add) ~/ data.length,
p90FrameBuildTime: _findPercentile(frameBuildTimeSorted, 0.90),
p99FrameBuildTime: _findPercentile(frameBuildTimeSorted, 0.99),
worstFrameBuildTime: frameBuildTimeSorted.last,
missedFrameBuildBudget: _countExceed(frameBuildTimeSorted, kBuildBudget),
averageFrameRasterizerTime:
frameRasterizerTime.reduce(add) ~/ data.length,
p90FrameRasterizerTime: _findPercentile(frameRasterizerTimeSorted, 0.90),
p99FrameRasterizerTime: _findPercentile(frameRasterizerTimeSorted, 0.90),
worstFrameRasterizerTime: frameRasterizerTimeSorted.last,
missedFrameRasterizerBudget:
_countExceed(frameRasterizerTimeSorted, kBuildBudget),
);
}
const FrameTimingSummarizer._(
{@required this.frameBuildTime,
@required this.frameRasterizerTime,
@required this.averageFrameBuildTime,
@required this.p90FrameBuildTime,
@required this.p99FrameBuildTime,
@required this.worstFrameBuildTime,
@required this.missedFrameBuildBudget,
@required this.averageFrameRasterizerTime,
@required this.p90FrameRasterizerTime,
@required this.p99FrameRasterizerTime,
@required this.worstFrameRasterizerTime,
@required this.missedFrameRasterizerBudget});
/// List of frame build time in microseconds
final List<Duration> frameBuildTime;
/// List of frame rasterizer time in microseconds
final List<Duration> frameRasterizerTime;
/// The average value of [frameBuildTime] in milliseconds.
final Duration averageFrameBuildTime;
/// The 90-th percentile value of [frameBuildTime] in milliseconds
final Duration p90FrameBuildTime;
/// The 99-th percentile value of [frameBuildTime] in milliseconds
final Duration p99FrameBuildTime;
/// The largest value of [frameBuildTime] in milliseconds
final Duration worstFrameBuildTime;
/// Number of items in [frameBuildTime] that's greater than [kBuildBudget]
final int missedFrameBuildBudget;
/// The average value of [frameRasterizerTime] in milliseconds.
final Duration averageFrameRasterizerTime;
/// The 90-th percentile value of [frameRasterizerTime] in milliseconds.
final Duration p90FrameRasterizerTime;
/// The 99-th percentile value of [frameRasterizerTime] in milliseconds.
final Duration p99FrameRasterizerTime;
/// The largest value of [frameRasterizerTime] in milliseconds.
final Duration worstFrameRasterizerTime;
/// Number of items in [frameRasterizerTime] that's greater than [kBuildBudget]
final int missedFrameRasterizerBudget;
Map<String, dynamic> get summary => <String, dynamic>{
'average_frame_build_time_millis':
averageFrameBuildTime.inMicroseconds / 1E3,
'90th_percentile_frame_build_time_millis':
p90FrameBuildTime.inMicroseconds / 1E3,
'99th_percentile_frame_build_time_millis':
p99FrameBuildTime.inMicroseconds / 1E3,
'worst_frame_build_time_millis':
worstFrameBuildTime.inMicroseconds / 1E3,
'missed_frame_build_budget_count': missedFrameBuildBudget,
'average_frame_rasterizer_time_millis':
averageFrameRasterizerTime.inMicroseconds / 1E3,
'90th_percentile_frame_rasterizer_time_millis':
p90FrameRasterizerTime.inMicroseconds / 1E3,
'99th_percentile_frame_rasterizer_time_millis':
p99FrameRasterizerTime.inMicroseconds / 1E3,
'worst_frame_rasterizer_time_millis':
worstFrameRasterizerTime.inMicroseconds / 1E3,
'missed_frame_rasterizer_budget_count': missedFrameRasterizerBudget,
'frame_count': frameBuildTime.length,
'frame_build_times': frameBuildTime
.map<int>((Duration datum) => datum.inMicroseconds)
.toList(),
'frame_rasterizer_times': frameRasterizerTime
.map<int>((Duration datum) => datum.inMicroseconds)
.toList(),
};
}
// The following helper functions require data sorted
// return the 100*p-th percentile of the data
T _findPercentile<T>(List<T> data, double p) {
assert(p >= 0 && p <= 1);
return data[((data.length - 1) * p).round()];
}
// return the number of items in data that > threshold
int _countExceed<T extends Comparable<T>>(List<T> data, T threshold) {
return data.length -
data.indexWhere((T datum) => datum.compareTo(threshold) > 0);
}

@ -1,87 +0,0 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file duplicates the behavior of test_driver/perf_test.dart, but uses
// the e2e package to implement a host-independent test.
import 'dart:convert' show JsonEncoder;
import 'package:e2e/e2e.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:testing_app/main.dart' as app;
import 'e2e_utils.dart';
void main() {
final binding =
E2EWidgetsFlutterBinding.ensureInitialized() as E2EWidgetsFlutterBinding;
// The fullyLive frame policy simulates the way Flutter response to animations.
// See https://github.com/flutter/flutter/issues/60237
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
group('Testing App Performance Tests on e2e', () {
testWidgets('Scrolling test', (tester) async {
app.main();
await tester.pumpAndSettle();
await watchPerformance(binding, () async {
final listFinder = find.byType(ListView);
final scroller = tester.widget<ListView>(listFinder).controller;
await scroller.animateTo(
7000,
duration: const Duration(seconds: 1),
curve: Curves.linear,
);
await tester.pumpAndSettle();
await scroller.animateTo(
-7000,
duration: const Duration(seconds: 1),
curve: Curves.linear,
);
await tester.pumpAndSettle();
}, reportKey: 'scrolling');
// The performance result is reported to `data['scrolling']`.
// See `e2e_test.dart` for detail.
print('scrolling performance test result:');
print(JsonEncoder.withIndent(' ')
.convert(binding.reportData['scrolling']));
}, semanticsEnabled: false);
testWidgets('Favorites operations test', (tester) async {
app.main();
await tester.pumpAndSettle();
await watchPerformance(binding, () async {
final iconKeys = [
'icon_0',
'icon_1',
'icon_2',
];
for (var icon in iconKeys) {
await tester.tap(find.byKey(ValueKey<String>(icon)));
await tester.pumpAndSettle();
}
await tester.tap(find.text('Favorites'));
await tester.pumpAndSettle();
final removeIconKeys = [
'remove_icon_0',
'remove_icon_1',
'remove_icon_2',
];
for (final iconKey in removeIconKeys) {
await tester.tap(find.byKey(ValueKey<String>(iconKey)));
await tester.pumpAndSettle();
}
}, reportKey: 'favorites_operations');
// The performance result is reported to `data['favorites_operations']`.
// See `e2e_test.dart` for detail.
print('favorites_operations performance test result:');
print(JsonEncoder.withIndent(' ')
.convert(binding.reportData['favorites_operations']));
}, semanticsEnabled: false);
});
}

@ -1,15 +0,0 @@
// Copyright 2020 The Flutter team. 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_driver/driver_extension.dart';
import 'package:testing_app/main.dart' as app;
void main() {
// This line enables the extension.
enableFlutterDriverExtension();
// Call the `main()` function of the app, or call `runApp` with
// any widget you are interested in testing.
app.main();
}

@ -1,86 +0,0 @@
// Copyright 2020 The Flutter team. 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_driver/flutter_driver.dart';
import 'package:test/test.dart';
void main() {
group('Testing App Driver Tests', () {
FlutterDriver driver;
// Connect to the Flutter driver before running any tests.
setUpAll(() async {
driver = await FlutterDriver.connect();
});
// Close the connection to the driver after the tests have completed.
tearDownAll(() async {
if (driver != null) {
await driver.close();
}
});
test('Finding an item in the list', () async {
// Create Finders that are used multiple times.
final listFinder = find.byType('ListView');
final itemFinder = find.byValueKey('text_25');
// Scroll until the item to be found appears.
// Use dxScroll to scroll horizontally and dyScroll
// to scroll vertically.
await driver.scrollUntilVisible(
listFinder,
itemFinder,
dyScroll: -500.0,
);
// Check if the item contains the correct text.
expect(await driver.getText(itemFinder), 'Item 25');
});
test('Testing IconButtons', () async {
// Create a finder for the icon.
final iconFinder = find.byValueKey('icon_25');
// Tap onto the icon.
await driver.tap(iconFinder);
// Verify if appropriate message appears.
await driver.waitFor(find.text('Added to favorites.'));
// Wait for the first message to disappear.
await Future<void>.delayed(Duration(seconds: 1));
// Tap the icon again.
await driver.tap(iconFinder);
// Verify if appropriate message appears.
await driver.waitFor(find.text('Removed from favorites.'));
});
test('Verifying whether item gets added to favorites', () async {
// Tap onto the icon.
await driver.tap(find.byValueKey('icon_30'));
// Tap onto the favorites button on the AppBar.
// The Favorites List should appear.
await driver.tap(find.text('Favorites'));
// Check if the added item has appeared in the list.
expect(await driver.getText(find.byValueKey('favorites_text_30')),
equals('Item 30'));
});
test('Verifying remove button', () async {
// Tap onto the remove icon.
await driver.tap(find.byValueKey('remove_icon_30'));
// Verify if it disappears.
await driver.waitForAbsent(find.text('Item 30'));
// Verify if appropriate message appears.
await driver.waitFor(find.text('Removed from favorites.'));
});
});
}

@ -1,21 +0,0 @@
// Copyright 2020 The Flutter team. 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:e2e/e2e_driver.dart' as driver;
Future<void> main() => driver.e2eDriver(responseDataCallback: (data) async {
await driver.writeResponseData(
data['scrolling'] as Map<String, dynamic>,
// This result is saved to `build/scrolling.json`.
testOutputFilename: 'scrolling',
);
await driver.writeResponseData(
data['favorites_operations'] as Map<String, dynamic>,
// This result is saved to `build/favorites_operations.json`.
testOutputFilename: 'favorites_operations',
);
});

@ -1,114 +0,0 @@
// Copyright 2020 The Flutter team. 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_driver/flutter_driver.dart';
import 'package:test/test.dart';
void main() {
group('Testing App Performance Tests', () {
FlutterDriver driver;
// Connect to the Flutter driver before running any tests.
setUpAll(() async {
driver = await FlutterDriver.connect();
});
// Close the connection to the driver after the tests have completed.
tearDownAll(() async {
if (driver != null) {
await driver.close();
}
});
test('Scrolling test', () async {
// Create Finders that are used multiple times.
final listFinder = find.byType('ListView');
// Record a performance profile as the app scrolls through
// the list of items.
final scrollingTimeline = await driver.traceAction(() async {
// Quickly scroll all the way down.
// Use dxScroll to scroll horizontally and dyScroll
// to scroll vertically.
await driver.scroll(listFinder, 0, -7000, Duration(seconds: 1));
// Quickly scroll back up all the way.
await driver.scroll(listFinder, 0, 7000, Duration(seconds: 1));
});
// Convert the Timeline into a TimelineSummary that's easier to
// read and understand.
final scrollingSummary = TimelineSummary.summarize(scrollingTimeline);
// Then, save the summary to disk.
// Results will be stored in
// the file 'build/scrolling.timeline_summary.json'.
await scrollingSummary.writeSummaryToFile('scrolling', pretty: true);
// Write the entire timeline to disk in a json format.
// Results will be stored in the file 'build/scrolling.timeline.json'.
// This file can be opened in the Chrome browser's tracing tools
// found by navigating to chrome://tracing.
await scrollingSummary.writeTimelineToFile('scrolling', pretty: true);
});
test('Favorites operations test', () async {
// Record a performance profile as operations are performed
// on the favorites list.
final operationsTimeline = await driver.traceAction(() async {
// Create a list of icon keys.
final iconKeys = [
'icon_0',
'icon_1',
'icon_2',
];
// Add first three items to favorites.
for (var icon in iconKeys) {
// Tap onto the icon.
await driver.tap(find.byValueKey(icon));
// Verify if appropriate message appears.
await driver.waitFor(find.text('Added to favorites.'));
}
// Tap onto the favorites button on the AppBar.
// The Favorites List should appear.
await driver.tap(find.text('Favorites'));
final removeIconKeys = [
'remove_icon_0',
'remove_icon_1',
'remove_icon_2',
];
// Remove all the items from favorites.
for (final iconKey in removeIconKeys) {
// Tap onto the remove icon.
await driver.tap(find.byValueKey(iconKey));
// Verify if appropriate message appears.
await driver.waitFor(find.text('Removed from favorites.'));
}
});
// Convert the Timeline into a TimelineSummary.
final operationsSummary = TimelineSummary.summarize(operationsTimeline);
// Then, save the summary to disk.
// Results will be stored in
// the file 'build/favorites_operations.timeline_summary.json'.
await operationsSummary.writeSummaryToFile('favorites_operations',
pretty: true);
// Write the entire timeline to disk in a json format.
// Results will be stored in
// the file 'build/favorites_operations.timeline.json'.
// This file can be opened in the Chrome browser's tracing tools
// found by navigating to chrome://tracing.
await operationsSummary.writeTimelineToFile('favorites_operations',
pretty: true);
});
});
}

@ -1,42 +0,0 @@
// Copyright 2020 The Flutter team. 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/material.dart';
import 'package:flutter_driver/driver_extension.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/favorites.dart';
void main() {
// Create a reference to the state
// so that we can perform operations on it manually.
Favorites favoritesList;
// This line enables the extension.
enableFlutterDriverExtension(
// This handler gets data from the test file
// and then we use it to perform operations on the state object.
handler: (command) {
if (command == 'ADD') {
favoritesList.add(30);
} else if (command == 'REMOVE') {
favoritesList.remove(30);
}
return Future.delayed(Duration(seconds: 1), () => 'DONE');
});
// Call the `main()` function of the app, or call `runApp` with
// any widget you are interested in testing.
runApp(
ChangeNotifierProvider(
create: (context) {
favoritesList = Favorites();
return favoritesList;
},
child: MaterialApp(
home: FavoritesPage(),
),
),
);
}

@ -1,45 +0,0 @@
// Copyright 2020 The Flutter team. 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_driver/flutter_driver.dart';
import 'package:test/test.dart';
void main() {
group('Testing App State Management Tests', () {
FlutterDriver driver;
// Connect to the Flutter driver before running any tests.
setUpAll(() async {
driver = await FlutterDriver.connect();
});
// Close the connection to the driver after the tests have completed.
tearDownAll(() async {
if (driver != null) {
await driver.close();
}
});
test('Verifying add method', () async {
/// This function is used for communication between
/// the driver and the application.
/// The [enableFlutterDriverExtension] call must have a [DataHandler]
/// callback to handle these requests.
/// We are currently using it to perform operations on the provider.
/// Specifically, send 'ADD' command to the handler in this case.
await driver.requestData('ADD');
// Check if the new item appears in the list.
await driver.waitFor(find.text('Item 30'));
});
test('Verifying remove method', () async {
/// Perform remove operation on the provider using the [DataHandler].
await driver.requestData('REMOVE');
// Verify if it disappears.
await driver.waitForAbsent(find.text('Item 30'));
});
});
}
Loading…
Cancel
Save