blob: d9fbc8e23b8d99bf6912615d6dbb1ffc97a4b358 [file] [log] [blame]
// 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.
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:macrobenchmarks/common.dart';
import 'package:macrobenchmarks/main.dart' as app;
typedef ControlCallback = Future<void> Function(WidgetController controller);
class ScrollableButtonRoute {
ScrollableButtonRoute(this.listViewKey, this.buttonKey);
final String listViewKey;
final String buttonKey;
}
void macroPerfTestE2E(
String testName,
String routeName, {
Duration? pageDelay,
Duration duration = const Duration(seconds: 3),
ControlCallback? body,
ControlCallback? setup,
}) {
macroPerfTestMultiPageE2E(
testName,
<ScrollableButtonRoute>[
ScrollableButtonRoute(kScrollableName, routeName),
],
pageDelay: pageDelay,
duration: duration,
body: body,
setup: setup,
);
}
void macroPerfTestMultiPageE2E(
String testName,
List<ScrollableButtonRoute> routes, {
Duration? pageDelay,
Duration duration = const Duration(seconds: 3),
ControlCallback? body,
ControlCallback? setup,
}) {
final WidgetsBinding widgetsBinding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
assert(widgetsBinding is IntegrationTestWidgetsFlutterBinding);
final IntegrationTestWidgetsFlutterBinding binding = widgetsBinding as IntegrationTestWidgetsFlutterBinding;
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive;
testWidgets(testName, (WidgetTester tester) async {
assert(tester.binding == binding);
app.main();
await tester.pumpAndSettle();
// The slight initial delay avoids starting the timing during a
// period of increased load on the device. Without this delay, the
// benchmark has greater noise.
// See: https://github.com/flutter/flutter/issues/19434
await tester.binding.delayed(const Duration(microseconds: 250));
for (final ScrollableButtonRoute route in routes) {
expect(route.listViewKey, startsWith('/'));
expect(route.buttonKey, startsWith('/'));
// Make sure each list view page is settled
await tester.pumpAndSettle();
final Finder listView = find.byKey(ValueKey<String>(route.listViewKey));
// ListView is not a Scrollable, but it contains one
final Finder scrollable = find.descendant(of: listView, matching: find.byType(Scrollable));
// scrollable should find one widget as soon as the page is loaded
expect(scrollable, findsOneWidget);
final Finder button = find.byKey(ValueKey<String>(route.buttonKey), skipOffstage: false);
// button may or may not find a widget right away until we scroll to it
await tester.scrollUntilVisible(button, 50, scrollable: scrollable);
// After scrolling, button should find one Widget
expect(button, findsOneWidget);
// Allow scrolling to settle
await tester.pumpAndSettle();
await tester.tap(button);
// Cannot be pumpAndSettle because some tests have infinite animation.
await tester.pump(const Duration(milliseconds: 20));
}
if (pageDelay != null) {
// Wait for the page to load
await tester.binding.delayed(pageDelay);
}
if (setup != null) {
await setup(tester);
}
await binding.watchPerformance(() async {
final Future<void> durationFuture = tester.binding.delayed(duration);
if (body != null) {
await body(tester);
}
await durationFuture;
});
}, semanticsEnabled: false, timeout: Timeout.none);
}