diff --git a/packages/web_benchmarks/CHANGELOG.md b/packages/web_benchmarks/CHANGELOG.md index 434f9bee76d..9afb5e58ce2 100644 --- a/packages/web_benchmarks/CHANGELOG.md +++ b/packages/web_benchmarks/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.1.0-wip + +* Restructure the `testing/test_app` to make the example benchmarks easier to follow. + ## 2.0.2 * Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. diff --git a/packages/web_benchmarks/README.md b/packages/web_benchmarks/README.md index ce98a22b194..9b63bf815d4 100644 --- a/packages/web_benchmarks/README.md +++ b/packages/web_benchmarks/README.md @@ -5,14 +5,14 @@ benchmarks in Chrome. # Writing a benchmark -An example benchmark can be found in [testing/web_benchmark_test.dart][1]. +An example benchmark can be found in [testing/test_app/benchmark/web_benchmark_test.dart][1]. A web benchmark is made of two parts: a client and a server. The client is code that runs in the browser together with the benchmark code. The server serves the app's code and assets. Additionally, the server communicates with the browser to extract the performance traces. -[1]: https://github.com/flutter/packages/blob/master/packages/web_benchmarks/testing/web_benchmarks_test.dart +[1]: https://github.com/flutter/packages/blob/master/packages/web_benchmarks/testing/test_app/benchmark/web_benchmarks_test.dart # Analyzing benchmark results diff --git a/packages/web_benchmarks/lib/server.dart b/packages/web_benchmarks/lib/server.dart index 514b111d95f..80e5f7a4f50 100644 --- a/packages/web_benchmarks/lib/server.dart +++ b/packages/web_benchmarks/lib/server.dart @@ -32,8 +32,6 @@ const int defaultChromeDebugPort = 10000; /// can be different (and typically is) from the production entry point of the /// app. /// -/// If [useCanvasKit] is true, builds the app in CanvasKit mode. -/// /// [benchmarkServerPort] is the port this benchmark server serves the app on. /// By default uses [defaultBenchmarkServerPort]. /// @@ -42,6 +40,13 @@ const int defaultChromeDebugPort = 10000; /// /// If [headless] is true, runs Chrome without UI. In particular, this is /// useful in environments (e.g. CI) that doesn't have a display. +/// +/// If [treeShakeIcons] is false, '--no-tree-shake-icons' will be passed as a +/// build argument when building the benchmark app. +/// +/// [compilationOptions] specify the compiler and renderer to use for the +/// benchmark app. This can either use dart2wasm & skwasm or +/// dart2js & canvaskit. Future serveWebBenchmark({ required io.Directory benchmarkAppDirectory, required String entryPoint, diff --git a/packages/web_benchmarks/lib/src/runner.dart b/packages/web_benchmarks/lib/src/runner.dart index 3ad6f86c96e..0c929104622 100644 --- a/packages/web_benchmarks/lib/src/runner.dart +++ b/packages/web_benchmarks/lib/src/runner.dart @@ -39,8 +39,6 @@ class BenchmarkServer { /// can be different (and typically is) from the production entry point of the /// app. /// - /// If [useCanvasKit] is true, builds the app in CanvasKit mode. - /// /// [benchmarkServerPort] is the port this benchmark server serves the app on. /// /// [chromeDebugPort] is the port Chrome uses for DevTool Protocol used to @@ -48,6 +46,13 @@ class BenchmarkServer { /// /// If [headless] is true, runs Chrome without UI. In particular, this is /// useful in environments (e.g. CI) that doesn't have a display. + /// + /// If [treeShakeIcons] is false, '--no-tree-shake-icons' will be passed as a + /// build argument when building the benchmark app. + /// + /// [compilationOptions] specify the compiler and renderer to use for the + /// benchmark app. This can either use dart2wasm & skwasm or + /// dart2js & canvaskit. BenchmarkServer({ required this.benchmarkAppDirectory, required this.entryPoint, diff --git a/packages/web_benchmarks/pubspec.yaml b/packages/web_benchmarks/pubspec.yaml index 6386767133d..fb8f9df26df 100644 --- a/packages/web_benchmarks/pubspec.yaml +++ b/packages/web_benchmarks/pubspec.yaml @@ -2,7 +2,7 @@ name: web_benchmarks description: A benchmark harness for performance-testing Flutter apps in Chrome. repository: https://github.com/flutter/packages/tree/main/packages/web_benchmarks issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+web_benchmarks%22 -version: 2.0.2 +version: 2.1.0-wip environment: sdk: ^3.3.0 diff --git a/packages/web_benchmarks/testing/test_app/.gitignore b/packages/web_benchmarks/testing/test_app/.gitignore index 9f6b8e534c2..79c113f9b50 100644 --- a/packages/web_benchmarks/testing/test_app/.gitignore +++ b/packages/web_benchmarks/testing/test_app/.gitignore @@ -5,9 +5,12 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ +migrate_working_dir/ # IntelliJ related *.iml @@ -26,7 +29,6 @@ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies -.packages .pub-cache/ .pub/ /build/ @@ -36,3 +38,8 @@ app.*.symbols # Obfuscation related app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/packages/web_benchmarks/testing/test_app/.metadata b/packages/web_benchmarks/testing/test_app/.metadata index 5e875f26787..7dd91c1357b 100644 --- a/packages/web_benchmarks/testing/test_app/.metadata +++ b/packages/web_benchmarks/testing/test_app/.metadata @@ -4,7 +4,27 @@ # This file should be version controlled and should not be manually edited. version: - revision: d26268bb9e6d713a73d6148da7fa75936d442741 - channel: master + revision: "0cd170798c6462aec738d4c749ce3a5fff1c80cf" + channel: "master" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 0cd170798c6462aec738d4c749ce3a5fff1c80cf + base_revision: 0cd170798c6462aec738d4c749ce3a5fff1c80cf + - platform: web + create_revision: 0cd170798c6462aec738d4c749ce3a5fff1c80cf + base_revision: 0cd170798c6462aec738d4c749ce3a5fff1c80cf + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/packages/web_benchmarks/testing/test_app/benchmark/test_infra/automator.dart b/packages/web_benchmarks/testing/test_app/benchmark/test_infra/automator.dart new file mode 100644 index 00000000000..4184a8a7430 --- /dev/null +++ b/packages/web_benchmarks/testing/test_app/benchmark/test_infra/automator.dart @@ -0,0 +1,146 @@ +// Copyright 2013 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. + +// ignore_for_file: avoid_print + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:test_app/home_page.dart' show aboutPageKey, textKey; +import 'package:test_app/main.dart'; +import 'package:web/web.dart'; +import 'package:web_benchmarks/client.dart'; + +import 'common.dart'; + +/// A class that automates the test web app. +class Automator { + Automator({ + required this.benchmark, + required this.stopWarmingUpCallback, + required this.profile, + }); + + /// The current benchmark. + final BenchmarkName benchmark; + + /// A function to call when warm-up is finished. + /// + /// This function is intended to ask `Recorder` to mark the warm-up phase + /// as over. + final void Function() stopWarmingUpCallback; + + /// The profile collected for the running benchmark + final Profile profile; + + /// Whether the automation has ended. + bool finished = false; + + /// A widget controller for automation. + late LiveWidgetController controller; + + Widget createWidget() { + Future.delayed(const Duration(milliseconds: 400), automate); + return const MyApp(); + } + + Future automate() async { + await warmUp(); + + switch (benchmark) { + case BenchmarkName.appNavigate: + await _handleAppNavigate(); + case BenchmarkName.appScroll: + await _handleAppScroll(); + case BenchmarkName.appTap: + await _handleAppTap(); + case BenchmarkName.simpleCompilationCheck: + _handleSimpleCompilationCheck(); + case BenchmarkName.simpleInitialPageCheck: + _handleSimpleInitialPageCheck(); + } + + // At the end of the test, mark as finished. + finished = true; + } + + /// Warm up the animation. + Future warmUp() async { + // Let animation stop. + await animationStops(); + + // Set controller. + controller = LiveWidgetController(WidgetsBinding.instance); + + await controller.pumpAndSettle(); + + // When warm-up finishes, inform the recorder. + stopWarmingUpCallback(); + } + + Future _handleAppNavigate() async { + for (int i = 0; i < 10; ++i) { + print('Testing round $i...'); + await controller.tap(find.byKey(aboutPageKey)); + await animationStops(); + await controller.tap(find.byType(BackButton)); + await animationStops(); + } + } + + Future _handleAppScroll() async { + final ScrollableState scrollable = + Scrollable.of(find.byKey(textKey).evaluate().single); + await scrollable.position.animateTo( + 30000, + curve: Curves.linear, + duration: const Duration(seconds: 20), + ); + } + + Future _handleAppTap() async { + for (int i = 0; i < 10; ++i) { + print('Testing round $i...'); + await controller.tap(find.byIcon(Icons.add)); + await animationStops(); + } + } + + void _handleSimpleCompilationCheck() { + // Record whether we are in wasm mode or not. Ideally, we'd have a more + // first-class way to add metadata like this, but this will work for us to + // pass information about the environment back to the server for the + // purposes of our own tests. + profile.extraData['isWasm'] = kIsWasm ? 1 : 0; + } + + void _handleSimpleInitialPageCheck() { + // Record whether the URL contains the expected initial page so we can + // verify the behavior of setting the `initialPage` on the benchmark server. + final bool containsExpectedPage = + window.location.toString().contains(testBenchmarkInitialPage); + profile.extraData['expectedUrl'] = containsExpectedPage ? 1 : 0; + } +} + +const Duration _animationCheckingInterval = Duration(milliseconds: 50); + +Future animationStops() async { + if (!WidgetsBinding.instance.hasScheduledFrame) { + return; + } + + final Completer stopped = Completer(); + + Timer.periodic(_animationCheckingInterval, (Timer timer) { + if (!WidgetsBinding.instance.hasScheduledFrame) { + stopped.complete(); + timer.cancel(); + } + }); + + await stopped.future; +} diff --git a/packages/web_benchmarks/testing/test_app/benchmark/test_infra/client/app_client.dart b/packages/web_benchmarks/testing/test_app/benchmark/test_infra/client/app_client.dart new file mode 100644 index 00000000000..2887ba9b7c2 --- /dev/null +++ b/packages/web_benchmarks/testing/test_app/benchmark/test_infra/client/app_client.dart @@ -0,0 +1,21 @@ +// Copyright 2013 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:web_benchmarks/client.dart'; + +import '../common.dart'; +import '../recorder.dart'; + +Future main() async { + await runBenchmarks( + { + BenchmarkName.appNavigate.name: () => + TestAppRecorder(benchmark: BenchmarkName.appNavigate), + BenchmarkName.appScroll.name: () => + TestAppRecorder(benchmark: BenchmarkName.appScroll), + BenchmarkName.appTap.name: () => + TestAppRecorder(benchmark: BenchmarkName.appTap), + }, + ); +} diff --git a/packages/web_benchmarks/testing/test_app/benchmark/test_infra/client/simple_compilation_client.dart b/packages/web_benchmarks/testing/test_app/benchmark/test_infra/client/simple_compilation_client.dart new file mode 100644 index 00000000000..301ca2111e7 --- /dev/null +++ b/packages/web_benchmarks/testing/test_app/benchmark/test_infra/client/simple_compilation_client.dart @@ -0,0 +1,18 @@ +// Copyright 2013 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:web_benchmarks/client.dart'; + +import '../common.dart'; +import '../recorder.dart'; + +Future main() async { + await runBenchmarks( + { + BenchmarkName.simpleCompilationCheck.name: () => TestAppRecorder( + benchmark: BenchmarkName.simpleCompilationCheck, + ), + }, + ); +} diff --git a/packages/web_benchmarks/testing/test_app/benchmark/test_infra/client/simple_initial_page_client.dart b/packages/web_benchmarks/testing/test_app/benchmark/test_infra/client/simple_initial_page_client.dart new file mode 100644 index 00000000000..9bfd9cf3ae2 --- /dev/null +++ b/packages/web_benchmarks/testing/test_app/benchmark/test_infra/client/simple_initial_page_client.dart @@ -0,0 +1,18 @@ +// Copyright 2013 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:web_benchmarks/client.dart'; + +import '../common.dart'; +import '../recorder.dart'; + +Future main() async { + await runBenchmarks( + { + BenchmarkName.simpleInitialPageCheck.name: () => TestAppRecorder( + benchmark: BenchmarkName.simpleInitialPageCheck, + ), + }, + ); +} diff --git a/packages/web_benchmarks/testing/test_app/benchmark/test_infra/common.dart b/packages/web_benchmarks/testing/test_app/benchmark/test_infra/common.dart new file mode 100644 index 00000000000..eaba8cd1157 --- /dev/null +++ b/packages/web_benchmarks/testing/test_app/benchmark/test_infra/common.dart @@ -0,0 +1,13 @@ +// Copyright 2013 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. + +const String testBenchmarkInitialPage = 'index.html#about'; + +enum BenchmarkName { + appNavigate, + appScroll, + appTap, + simpleInitialPageCheck, + simpleCompilationCheck; +} diff --git a/packages/web_benchmarks/testing/test_app/benchmark/test_infra/recorder.dart b/packages/web_benchmarks/testing/test_app/benchmark/test_infra/recorder.dart new file mode 100644 index 00000000000..8b0abd0d125 --- /dev/null +++ b/packages/web_benchmarks/testing/test_app/benchmark/test_infra/recorder.dart @@ -0,0 +1,38 @@ +// Copyright 2013 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/material.dart'; +import 'package:web_benchmarks/client.dart'; + +import 'automator.dart'; +import 'common.dart'; + +/// A recorder that measures frame building durations for the test app. +class TestAppRecorder extends WidgetRecorder { + TestAppRecorder({required this.benchmark}) + : super(name: benchmark.name, useCustomWarmUp: true); + + /// The name of the benchmark to be run. + /// + /// See `common.dart` for the list of the names of all benchmarks. + final BenchmarkName benchmark; + + Automator? _automator; + bool get _finished => _automator?.finished ?? false; + + /// Whether we should continue recording. + @override + bool shouldContinue() => !_finished || profile.shouldContinue(); + + /// Creates the [Automator] widget. + @override + Widget createWidget() { + _automator = Automator( + benchmark: benchmark, + stopWarmingUpCallback: profile.stopWarmingUp, + profile: profile, + ); + return _automator!.createWidget(); + } +} diff --git a/packages/web_benchmarks/testing/web_benchmarks_test.dart b/packages/web_benchmarks/testing/test_app/benchmark/web_benchmarks_test.dart similarity index 57% rename from packages/web_benchmarks/testing/web_benchmarks_test.dart rename to packages/web_benchmarks/testing/test_app/benchmark/web_benchmarks_test.dart index 3cdefc671d7..64b4f6061c8 100644 --- a/packages/web_benchmarks/testing/web_benchmarks_test.dart +++ b/packages/web_benchmarks/testing/test_app/benchmark/web_benchmarks_test.dart @@ -10,43 +10,62 @@ import 'package:test/test.dart'; import 'package:web_benchmarks/server.dart'; import 'package:web_benchmarks/src/common.dart'; +import 'test_infra/common.dart'; + Future main() async { - test('Can run a web benchmark', () async { - await _runBenchmarks( - benchmarkNames: ['scroll', 'page', 'tap'], - entryPoint: 'lib/benchmarks/runner.dart', - ); - }, timeout: Timeout.none); + test( + 'Can run a web benchmark', + () async { + await _runBenchmarks( + benchmarkNames: [ + BenchmarkName.appNavigate.name, + BenchmarkName.appScroll.name, + BenchmarkName.appTap.name, + ], + entryPoint: 'benchmark/test_infra/client/app_client.dart', + ); + }, + timeout: Timeout.none, + ); - test('Can run a web benchmark with an alternate initial page', () async { - final BenchmarkResults results = await _runBenchmarks( - benchmarkNames: ['simple'], - entryPoint: 'lib/benchmarks/runner_simple.dart', - initialPage: 'index.html#about', - ); + test( + 'Can run a web benchmark with an alternate initial page', + () async { + final BenchmarkResults results = await _runBenchmarks( + benchmarkNames: [BenchmarkName.simpleInitialPageCheck.name], + entryPoint: + 'benchmark/test_infra/client/simple_initial_page_client.dart', + initialPage: testBenchmarkInitialPage, + ); - // The simple runner just puts an `isWasm` metric in there so we can make - // sure that we're running in the right environment. - final List? scores = results.scores['simple']; - expect(scores, isNotNull); + // The runner puts an `expectedUrl` metric in the results so that we can + // verify the initial page value that should be passed on initial load + // and on reloads. + final List? scores = + results.scores[BenchmarkName.simpleInitialPageCheck.name]; + expect(scores, isNotNull); - final BenchmarkScore isWasmScore = - scores!.firstWhere((BenchmarkScore score) => score.metric == 'isWasm'); - expect(isWasmScore.value, 0); - }, timeout: Timeout.none); + final BenchmarkScore isWasmScore = scores! + .firstWhere((BenchmarkScore score) => score.metric == 'expectedUrl'); + expect(isWasmScore.value, 1); + }, + timeout: Timeout.none, + ); test( 'Can run a web benchmark with wasm', () async { final BenchmarkResults results = await _runBenchmarks( - benchmarkNames: ['simple'], - entryPoint: 'lib/benchmarks/runner_simple.dart', + benchmarkNames: [BenchmarkName.simpleCompilationCheck.name], + entryPoint: + 'benchmark/test_infra/client/simple_compilation_client.dart', compilationOptions: const CompilationOptions.wasm(), ); - // The simple runner just puts an `isWasm` metric in there so we can make - // sure that we're running in the right environment. - final List? scores = results.scores['simple']; + // The runner puts an `isWasm` metric in the results so that we can verify + // we are running with the correct compiler and renderer. + final List? scores = + results.scores[BenchmarkName.simpleCompilationCheck.name]; expect(scores, isNotNull); final BenchmarkScore isWasmScore = scores! diff --git a/packages/web_benchmarks/testing/test_app/lib/about_page.dart b/packages/web_benchmarks/testing/test_app/lib/about_page.dart index 4147c33f8f1..a3603abeb55 100644 --- a/packages/web_benchmarks/testing/test_app/lib/about_page.dart +++ b/packages/web_benchmarks/testing/test_app/lib/about_page.dart @@ -4,8 +4,6 @@ import 'package:flutter/material.dart'; -const ValueKey backKey = ValueKey('backKey'); - class AboutPage extends StatelessWidget { const AboutPage({super.key}); @@ -14,7 +12,6 @@ class AboutPage extends StatelessWidget { return Scaffold( appBar: AppBar( leading: BackButton( - key: backKey, onPressed: () => Navigator.of(context).pop(), ), ), diff --git a/packages/web_benchmarks/testing/test_app/lib/benchmarks/runner.dart b/packages/web_benchmarks/testing/test_app/lib/benchmarks/runner.dart deleted file mode 100644 index 9a870dfca2e..00000000000 --- a/packages/web_benchmarks/testing/test_app/lib/benchmarks/runner.dart +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2013 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. - -// ignore_for_file: avoid_print - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:web_benchmarks/client.dart'; - -import '../about_page.dart' show backKey; -import '../home_page.dart' show aboutPageKey, textKey; -import '../main.dart'; - -/// A recorder that measures frame building durations. -abstract class AppRecorder extends WidgetRecorder { - AppRecorder({required this.benchmarkName}) : super(name: benchmarkName); - - final String benchmarkName; // ignore: unreachable_from_main - - Future automate(); - - @override - Widget createWidget() { - Future.delayed(const Duration(milliseconds: 400), automate); - return const MyApp(); - } - - Future animationStops() async { - while (WidgetsBinding.instance.hasScheduledFrame) { - await Future.delayed(const Duration(milliseconds: 200)); - } - } -} - -class ScrollRecorder extends AppRecorder { - ScrollRecorder() : super(benchmarkName: 'scroll'); - - @override - Future automate() async { - final ScrollableState scrollable = - Scrollable.of(find.byKey(textKey).evaluate().single); - await scrollable.position.animateTo( - 30000, - curve: Curves.linear, - duration: const Duration(seconds: 20), - ); - } -} - -class PageRecorder extends AppRecorder { - PageRecorder() : super(benchmarkName: 'page'); - - bool _completed = false; - - @override - bool shouldContinue() => profile.shouldContinue() || !_completed; - - @override - Future automate() async { - final LiveWidgetController controller = - LiveWidgetController(WidgetsBinding.instance); - for (int i = 0; i < 10; ++i) { - print('Testing round $i...'); - await controller.tap(find.byKey(aboutPageKey)); - await animationStops(); - await controller.tap(find.byKey(backKey)); - await animationStops(); - } - _completed = true; - } -} - -class TapRecorder extends AppRecorder { - TapRecorder() : super(benchmarkName: 'tap'); - - bool _completed = false; - - @override - bool shouldContinue() => profile.shouldContinue() || !_completed; - - @override - Future automate() async { - final LiveWidgetController controller = - LiveWidgetController(WidgetsBinding.instance); - for (int i = 0; i < 10; ++i) { - print('Testing round $i...'); - await controller.tap(find.byIcon(Icons.add)); - await animationStops(); - } - _completed = true; - } -} - -Future main() async { - await runBenchmarks({ - 'scroll': () => ScrollRecorder(), - 'page': () => PageRecorder(), - 'tap': () => TapRecorder(), - }); -} diff --git a/packages/web_benchmarks/testing/test_app/lib/benchmarks/runner_simple.dart b/packages/web_benchmarks/testing/test_app/lib/benchmarks/runner_simple.dart deleted file mode 100644 index c233ebe6187..00000000000 --- a/packages/web_benchmarks/testing/test_app/lib/benchmarks/runner_simple.dart +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2013 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/foundation.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:web_benchmarks/client.dart'; - -import 'runner.dart'; - -class SimpleRecorder extends AppRecorder { - SimpleRecorder() : super(benchmarkName: 'simple'); - - @override - Future automate() async { - // Record whether we are in wasm mode or not. Ideally, we'd have a more - // first-class way to add metadata like this, but this will work for us to - // pass information about the environment back to the server for the - // purposes of our own tests. - profile.extraData['isWasm'] = kIsWasm ? 1 : 0; - } -} - -Future main() async { - await runBenchmarks({ - 'simple': () => SimpleRecorder(), - }); -} diff --git a/packages/web_benchmarks/testing/test_app/lib/home_page.dart b/packages/web_benchmarks/testing/test_app/lib/home_page.dart index dee8c9d0eeb..2fecf2514e1 100644 --- a/packages/web_benchmarks/testing/test_app/lib/home_page.dart +++ b/packages/web_benchmarks/testing/test_app/lib/home_page.dart @@ -33,7 +33,7 @@ class _HomePageState extends State { actions: [ IconButton( key: aboutPageKey, - icon: const Icon(Icons.alternate_email), + icon: const Icon(Icons.help_outline), onPressed: () => Navigator.of(context).pushNamed('about'), ), ], diff --git a/packages/web_benchmarks/testing/test_app/lib/icon_page.dart b/packages/web_benchmarks/testing/test_app/lib/icon_page.dart deleted file mode 100644 index fd0da430ee0..00000000000 --- a/packages/web_benchmarks/testing/test_app/lib/icon_page.dart +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 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/material.dart'; - -class IconGeneratorPage extends StatefulWidget { - const IconGeneratorPage({super.key}); - - static int defaultIconCodePoint = int.parse('0xf03f'); - - @override - State createState() => _IconGeneratorPageState(); -} - -class _IconGeneratorPageState extends State { - int iconCodePoint = IconGeneratorPage.defaultIconCodePoint; - - @override - Widget build(BuildContext context) { - return Column( - children: [ - TextField( - onSubmitted: (String value) { - final int codePointAsInt = - int.tryParse(value) ?? IconGeneratorPage.defaultIconCodePoint; - setState(() { - iconCodePoint = codePointAsInt; - }); - }, - ), - const SizedBox(height: 24.0), - Icon(generateIcon(iconCodePoint)), - ], - ); - } - - // Unless '--no-tree-shake-icons' is passed to the flutter build command, - // the presence of this method will trigger an exception due to the use of - // non-constant invocations of [IconData]. - IconData generateIcon(int materialIconCodePoint) => IconData( - materialIconCodePoint, - fontFamily: 'MaterialIcons', - ); -} diff --git a/packages/web_benchmarks/testing/test_app/lib/main.dart b/packages/web_benchmarks/testing/test_app/lib/main.dart index e07fc56ec2a..f615e761acb 100644 --- a/packages/web_benchmarks/testing/test_app/lib/main.dart +++ b/packages/web_benchmarks/testing/test_app/lib/main.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'about_page.dart'; import 'home_page.dart'; -import 'icon_page.dart'; void main() { runApp(const MyApp()); @@ -23,11 +22,12 @@ class MyApp extends StatelessWidget { primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), + // This blocks the About page button. + debugShowCheckedModeBanner: false, initialRoute: 'home', routes: { 'home': (_) => const HomePage(title: 'Flutter Demo Home Page'), 'about': (_) => const AboutPage(), - 'icon_generator': (_) => const IconGeneratorPage(), }, ); } diff --git a/packages/web_benchmarks/testing/test_app/pubspec.yaml b/packages/web_benchmarks/testing/test_app/pubspec.yaml index e298d6defa4..953b188efce 100644 --- a/packages/web_benchmarks/testing/test_app/pubspec.yaml +++ b/packages/web_benchmarks/testing/test_app/pubspec.yaml @@ -11,8 +11,13 @@ environment: dependencies: flutter: sdk: flutter + +dev_dependencies: + flutter_lints: ^4.0.0 flutter_test: sdk: flutter + test: ^1.19.5 + web: ">=0.5.1 <2.0.0" web_benchmarks: path: ../../ diff --git a/packages/web_benchmarks/testing/test_app/web/icons/Icon-maskable-192.png b/packages/web_benchmarks/testing/test_app/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000000..eb9b4d76e52 Binary files /dev/null and b/packages/web_benchmarks/testing/test_app/web/icons/Icon-maskable-192.png differ diff --git a/packages/web_benchmarks/testing/test_app/web/icons/Icon-maskable-512.png b/packages/web_benchmarks/testing/test_app/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000000..d69c56691fb Binary files /dev/null and b/packages/web_benchmarks/testing/test_app/web/icons/Icon-maskable-512.png differ diff --git a/packages/web_benchmarks/testing/test_app/web/index.html b/packages/web_benchmarks/testing/test_app/web/index.html index 5b2c184c9a8..cc7ef836e2f 100644 --- a/packages/web_benchmarks/testing/test_app/web/index.html +++ b/packages/web_benchmarks/testing/test_app/web/index.html @@ -4,12 +4,27 @@ found in the LICENSE file. --> + + + - + @@ -21,6 +36,6 @@ - + diff --git a/packages/web_benchmarks/testing/test_app/web/manifest.json b/packages/web_benchmarks/testing/test_app/web/manifest.json index 13a23690776..8242090a0aa 100644 --- a/packages/web_benchmarks/testing/test_app/web/manifest.json +++ b/packages/web_benchmarks/testing/test_app/web/manifest.json @@ -18,6 +18,18 @@ "src": "icons/Icon-512.png", "sizes": "512x512", "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" } ] }