1. 12 Mar, 2024 1 commit
  2. 11 Mar, 2024 3 commits
    • auto-submit[bot]'s avatar
      Reverts "Fail tests on exceptions raised after test completed (#144706)" (#144970) · 49f45d20
      auto-submit[bot] authored
      Reverts: flutter/flutter#144706
      Initiated by: gspencergoog
      Reason for reverting: This has broken the tree because some tests are still failing post completion. This particular one looks like it might have to do with a gold image not existing.
      Original PR Author: goderbauer
      
      Reviewed By: {Piinks}
      
      This change reverts the following previous change:
      A test was failing silently because of this (see https://github.com/flutter/flutter/issues/144353 and fixed in https://github.com/flutter/flutter/pull/144709). The failure went undetected for months. Ideally, this should have been a regular non-silent failure. This change makes that so. `package:test` can properly handle reported exceptions outside of test cases. With this change, the test fails as follows:
      
      ```
      00:03 +82: Smoke test material/color_scheme/dynamic_content_color.0.dart
      ══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
      The following assertion was thrown running a test (but after the test had completed):
      setState() called after dispose(): _DynamicColorExampleState#1cd37(lifecycle state: defunct, not
      mounted)
      This error happens if you call setState() on a State object for a widget that no longer appears in
      the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error
      can occur when code calls setState() from a timer or an animation callback.
      The preferred solution is to cancel the timer or stop listening to the animation in the dispose()
      callback. Another solution is to check the "mounted" property of this object before calling
      setState() to ensure the object is still in the tree.
      This error might indicate a memory leak if setState() is being called because another object is
      retaining a reference to this State object after it has been removed from the tree. To avoid memory
      leaks, consider breaking the reference to this object during dispose().
      
      When the exception was thrown, this was the stack:
      #0      State.setState.<anonymous closure> (package:flutter/src/widgets/framework.dart:1167:9)
      #1      State.setState (package:flutter/src/widgets/framework.dart:1202:6)
      #2      _DynamicColorExampleState._updateImage (package:flutter_api_samples/material/color_scheme/dynamic_content_color.0.dart:191:5)
      <asynchronous suspension>
      ════════════════════════════════════════════════════════════════════════════════════════════════════
      00:03 +81 -1: Smoke test material/context_menu/context_menu_controller.0.dart
      00:03 +81 -1: Smoke test material/color_scheme/dynamic_content_color.0.dart [E]
        Test failed. See exception logs above.
        The test description was: Smoke test material/color_scheme/dynamic_content_color.0.dart
        
        This test failed after it had already completed.
        Make sure to use a matching library which informs the test runner
        of pending async work.
      ```
      49f45d20
    • Michael Goderbauer's avatar
      Fail tests on exceptions raised after test completed (#144706) · 91cccc8e
      Michael Goderbauer authored
      A test was failing silently because of this (see
      https://github.com/flutter/flutter/issues/144353 and fixed in
      https://github.com/flutter/flutter/pull/144709). The failure went
      undetected for months. Ideally, this should have been a regular
      non-silent failure. This change makes that so. `package:test` can
      properly handle reported exceptions outside of test cases. With this
      change, the test fails as follows:
      
      ```
      00:03 +82: Smoke test material/color_scheme/dynamic_content_color.0.dart
      ══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
      The following assertion was thrown running a test (but after the test had completed):
      setState() called after dispose(): _DynamicColorExampleState#1cd37(lifecycle state: defunct, not
      mounted)
      This error happens if you call setState() on a State object for a widget that no longer appears in
      the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error
      can occur when code calls setState() from a timer or an animation callback.
      The preferred solution is to cancel the timer or stop listening to the animation in the dispose()
      callback. Another solution is to check the "mounted" property of this object before calling
      setState() to ensure the object is still in the tree.
      This error might indicate a memory leak if setState() is being called because another object is
      retaining a reference to this State object after it has been removed from the tree. To avoid memory
      leaks, consider breaking the reference to this object during dispose().
      
      When the exception was thrown, this was the stack:
      #0      State.setState.<anonymous closure> (package:flutter/src/widgets/framework.dart:1167:9)
      #1      State.setState (package:flutter/src/widgets/framework.dart:1202:6)
      #2      _DynamicColorExampleState._updateImage (package:flutter_api_samples/material/color_scheme/dynamic_content_color.0.dart:191:5)
      <asynchronous suspension>
      ════════════════════════════════════════════════════════════════════════════════════════════════════
      00:03 +81 -1: Smoke test material/context_menu/context_menu_controller.0.dart
      00:03 +81 -1: Smoke test material/color_scheme/dynamic_content_color.0.dart [E]
        Test failed. See exception logs above.
        The test description was: Smoke test material/color_scheme/dynamic_content_color.0.dart
        
        This test failed after it had already completed.
        Make sure to use a matching library which informs the test runner
        of pending async work.
      ```
      91cccc8e
    • Nate's avatar
      Refactoring `if` chains into `switch` statements (#144905) · 26e379e0
      Nate authored
      Based on issue #144903, this PR aims to bring the codebase more in line with the [Flutter repo style guide](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#avoid-using-if-chains-or--or--with-enum-values):
      
      > #### Avoid using `if` chains or `?:` or `==` with enum values
      
      <br>
      
      This change unfortunately increases the total line length, but it also improves readability.
      26e379e0
  3. 07 Mar, 2024 2 commits
    • Bruno Leroux's avatar
      [flutter_test] Use defaultTargetPlatform for key events simulation (#143579) · 471a8285
      Bruno Leroux authored
      ## Description
      
      This PRs changes the default value for the `platform` parameter used to simulate key events.
      
      With this PR, the default value is "web" on web, otherwise it is the operating system name retrieved from `defaultTargetPlatform`.
      
      Previously, for methods in `WidgetController`, it defaulted to “web” on web, and “android” everywhere else. And for methods in `KeyEventSimulator` it defaulted to “web” on web, and the operating system that the test was running on everywhere else. Because the operating system was based on `Platform.operatingSystem`, it usually differed from the target platform the test was running on.
      
      AFAIK, the `platform` parameter is only meaningful for simulating `RawKeyEvent`. Once `RawKeyboard` will be fully removed, the `platform` parameter won’t be needed. 
      @gspencergoog  In the meantime, do you think it is worth merging this fix?
      
      ## Related Issue
      
      Fixes to https://github.com/flutter/flutter/issues/133955
      
      ## Tests
      
      Adds one test.
      471a8285
    • Bruno Leroux's avatar
      [flutter_test] Change KeyEventSimulator default transit mode (#143847) · 8ade81fb
      Bruno Leroux authored
      ## Description
      
      This PRs changes the default value transit mode for key event simulation.
      
      The default transit mode for key event simulation is currently `KeyDataTransitMode.rawKeyData` while on the framework side `KeyDataTransitMode.keyDataThenRawKeyData` is the preferred transit mode.
      
      `KeyDataTransitMode.keyDataThenRawKeyData` is more accurate and can help detect issues.
      
      For instance the following test will fail with `KeyDataTransitMode.rawKeyData` because raw keyboard logic for modifier keys is less accurate:
      
      ```dart
        testWidgets('Press control left once', (WidgetTester tester) async {
          debugKeyEventSimulatorTransitModeOverride = KeyDataTransitMode.keyDataThenRawKeyData;
      
          final List<KeyEvent> events = <KeyEvent>[];
          final FocusNode focusNode = FocusNode();
          addTearDown(focusNode.dispose);
      
          await tester.pumpWidget(
            Focus(
              focusNode: focusNode,
              autofocus: true,
              onKeyEvent: (_, KeyEvent event) {
                events.add(event);
                return KeyEventResult.handled;
              },
              child: Container(),
            ),
          );
      
          await simulateKeyDownEvent(LogicalKeyboardKey.controlLeft);
      
          // This will fail when transit mode is KeyDataTransitMode.rawKeyData
          // because a down event for controlRight is synthesized.
          expect(events.length, 1);
      
          debugKeyEventSimulatorTransitModeOverride = null;
        });
      ```
      
      And the following this test is ok with `KeyDataTransitMode.rawKeyData` but rightly fails with `KeyDataTransitMode.keyDataThenRawKeyData`:
      
      ```dart
        testWidgets('Simulates consecutive key down events', (WidgetTester tester) async {
          debugKeyEventSimulatorTransitModeOverride = KeyDataTransitMode.rawKeyData;
      
          // Simulating several key down events without key up in between is tolerated
          // when transit mode is KeyDataTransitMode.rawKeyData, it will trigger an
          // assert on KeyDataTransitMode.keyDataThenRawKeyData.
          await simulateKeyDownEvent(LogicalKeyboardKey.arrowDown);
          await simulateKeyDownEvent(LogicalKeyboardKey.arrowDown);
      
          debugKeyEventSimulatorTransitModeOverride = null;
        });
      ```
      
      ## Related Issue
      
      Related to https://github.com/flutter/flutter/issues/143845
      
      ## Tests
      
      Adds two tests.
      8ade81fb
  4. 04 Mar, 2024 1 commit
  5. 26 Feb, 2024 1 commit
  6. 23 Feb, 2024 1 commit
  7. 22 Feb, 2024 1 commit
    • Derek Xu's avatar
      Support using lightweight Flutter Engines to run tests (#141726) · dfb5888e
      Derek Xu authored
      This PR implements the functionality described above and hides it behind
      the `--experimental-faster-testing` flag of `flutter test`.
      
      ### The following are some performance measurements from test runs
      conducted on GitHub Actions
      
      run 1 logs:
      https://github.com/derekxu16/flutter_test_ci/actions/runs/8008029772/attempts/1
      run 2 logs:
      https://github.com/derekxu16/flutter_test_ci/actions/runs/8008029772/attempts/2
      run 3 logs:
      https://github.com/derekxu16/flutter_test_ci/actions/runs/8008029772/attempts/3
      
      **length of `flutter test --reporter=expanded test/animation
      test/foundation` step**
      
      run 1: 54s
      run 2: 52s
      run 3: 56s
      
      average: 54s
      
      **length of `flutter test --experimental-faster-testing
      --reporter=expanded test/animation test/foundation` step**
      
      run 1: 27s
      run 2: 27s
      run 3: 29s
      
      average: 27.67s (~48.77% shorter than 54s)
      
      **length of `flutter test --reporter=expanded test/animation
      test/foundation test/gestures test/painting test/physics test/rendering
      test/scheduler test/semantics test/services` step**
      
      run 1: 260s
      run 2: 270s
      run 3: 305s
      
      average: 278.33s
      
      
      **length of `flutter test --experimental-faster-testing
      --reporter=expanded test/animation test/foundation test/gestures
      test/painting test/physics test/rendering test/scheduler test/semantics
      test/services` step**
      
      from a clean build (right after deleting the build folder):
      
      run 1: 215s
      run 2: 227s
      run 3: 245s
      
      average: 229s (~17.72% shorter than 278.33s)
      
      Note that in reality, `test/material` was not passed to `flutter test`
      in the trials below. All of the test files under `test/material` except
      for `test/material/icons_test.dart` were listed out individually
      
      **length of `flutter test --reporter=expanded test/material` step**
      
      run 1: 408s
      run 2: 421s
      run 3: 451s
      
      average: 426.67s
      
      **length of `flutter test --experimental-faster-testing
      --reporter=expanded test/material` step**
      
      run 1: 382s
      run 2: 373s
      run 3: 400s
      
      average: 385s (~9.77% shorter than 426.67s)
      
      ---------
      Co-authored-by: 's avatarDan Field <dnfield@google.com>
      dfb5888e
  8. 16 Feb, 2024 1 commit
  9. 15 Feb, 2024 2 commits
  10. 14 Feb, 2024 2 commits
  11. 09 Feb, 2024 1 commit
    • Kris Pypen's avatar
      Fix: performance improvement on golden test comparison (#142913) · 2f117c54
      Kris Pypen authored
      During golden test image comparison 2 lists of a different type are compared with the method "identical", so this will never be true. The test image is a _Uint8ArrayView while the master image is an Uint8List. So that results in always a heavy computation to get the difference between the test and the master image.
      
      When you run this test snippet I go from 51 seconds to 14 seconds:
      ```dart
      import 'package:flutter/material.dart';
      import 'package:flutter_test/flutter_test.dart';
      
      void main() {
        for (int i = 0; i < 100; i++) {
          testWidgets('Small test', (WidgetTester tester) async {
            await tester.pumpWidget(Directionality(textDirection: TextDirection.ltr, child: Text('jo')));
            await expectLater(find.byType(Text), matchesGoldenFile('main.png'));
          });
        }
      }
      ```
      2f117c54
  12. 07 Feb, 2024 2 commits
  13. 30 Jan, 2024 1 commit
  14. 26 Jan, 2024 3 commits
    • Michael Goderbauer's avatar
      Relands "Add runWidget to bootstrap a widget tree without a default View" (#142344) · 671d8eaf
      Michael Goderbauer authored
      Reverts flutter/flutter#142339
      
      In the original change one of the tests included the same view twice which resulted in a different failure than the expected one. The second commit contains the fix for this. I don't understand how this wasn't caught presubmit on CI.
      671d8eaf
    • auto-submit[bot]'s avatar
      Reverts "Add runWidget to bootstrap a widget tree without a default View" (#142339) · 114261a6
      auto-submit[bot] authored
      Reverts flutter/flutter#141484
      Initiated by: eliasyishak
      This change reverts the following previous change:
      Original Description:
      The existing `runApp` bootstraps the widget tree and renders the provided widget into the default view (which is currently the implicit View from `PlatformDispatcher.implicitView` and - in the future - may be a default-created window). Apps, that want more control over the View they are rendered in, need a new way to bootstrap the widget tree: `runWidget`. It does not make any assumptions about the View the provided widget is rendered into. Instead, it is up to the caller to include a View widget in the provided widget tree that specifies where content should be rendered. In the future, this may enable developers to create a custom window for their app instead of relying on the default-created one.
      114261a6
    • Michael Goderbauer's avatar
      Add runWidget to bootstrap a widget tree without a default View (#141484) · 5b44596c
      Michael Goderbauer authored
      The existing `runApp` bootstraps the widget tree and renders the provided widget into the default view (which is currently the implicit View from `PlatformDispatcher.implicitView` and - in the future - may be a default-created window). Apps, that want more control over the View they are rendered in, need a new way to bootstrap the widget tree: `runWidget`. It does not make any assumptions about the View the provided widget is rendered into. Instead, it is up to the caller to include a View widget in the provided widget tree that specifies where content should be rendered. In the future, this may enable developers to create a custom window for their app instead of relying on the default-created one.
      5b44596c
  15. 19 Jan, 2024 2 commits
    • Michael Goderbauer's avatar
      Make pumpWidget's arguments named (#141728) · cc544169
      Michael Goderbauer authored
      Much nicer calling API and simplifies evolving this API in the future.
      
      I wish we could write a dart fix for this, but that's blocked on https://github.com/dart-lang/sdk/issues/54668.
      cc544169
    • fzyzcjy's avatar
      Tiny fix inaccurate documentations about bindings (#140282) · 9e024fdf
      fzyzcjy authored
      The old doc says that, AutomatedTestWidgetsFlutterBinding for `flutter test` and LiveTestWidgetsFlutterBinding for `flutter run`. However, suppose we `flutter test integration_test/simple_test.dart` with the following code:
      
      ```
      void main() {
        testWidgets('hi', (WidgetTester tester) async {
          print('hi ${TestWidgetsFlutterBinding.instance} ${Platform.operatingSystem}');
        });
      }
      ```
      
      We will see: `hi <IntegrationTestWidgetsFlutterBinding> ios`. Therefore, we see `IntegrationTestWidgetsFlutterBinding` is used in a `flutter test` command, which is contrary to the documentation.
      9e024fdf
  16. 16 Jan, 2024 1 commit
  17. 12 Jan, 2024 1 commit
  18. 09 Jan, 2024 1 commit
    • Michael Goderbauer's avatar
      Reapply "Dynamic view sizing" (#140165) (#140918) · 4534a24c
      Michael Goderbauer authored
      This reverts commit
      https://github.com/flutter/flutter/commit/d24c01bd0c41331bd17165e0173b24c5d05d7c0a.
      
      The original change was reverted because it caused some apps to get
      stuck on the splash screen on some phones.
      
      An investigation determined that this was due to a rounding error.
      Example: The device reports a physical size of 1008.0 x 2198.0 with a
      dpr of 1.912500023841858. Flutter would translate that to a logical size
      of 527.0588169589221 x 1149.2810314243163 and use that as the input for
      its layout algorithm. Since the constraints here are tight, the layout
      algorithm would determine that the resulting logical size of the root
      render object must be 527.0588169589221 x 1149.2810314243163.
      Translating this back to physical pixels by applying the dpr resulted in
      a physical size of 1007.9999999999999 x 2198.0 for the frame. Android
      now rejected that frame because it didn't match the expected size of
      1008.0 x 2198.0 and since no frame had been rendered would never take
      down the splash screen.
      
      Prior to dynamically sized views, this wasn't an issue because we would
      hard-code the frame size to whatever the requested size was.
      
      Changes in this PR over the original PR:
      
      * The issue has been fixed now by constraining the calculated physical
      size to the input physical constraints which makes sure that we always
      end up with a size that is acceptable to the operating system.
      * The `ViewConfiguration` was refactored to use the slightly more
      convenient `BoxConstraints` over the `ViewConstraints` to represent
      constraints. Both essentially represent the same thing, but
      `BoxConstraints` are more powerful and we avoid a couple of translations
      between the two by translating the` ViewConstraints` from the
      `FlutterView` to `BoxConstraints` directly when the `ViewConfiguration`
      is created.
      
      All changes over the original PR are contained in the second commit of
      this PR.
      
      Fixes b/316813075
      Part of https://github.com/flutter/flutter/issues/134501.
      4534a24c
  19. 04 Jan, 2024 1 commit
  20. 03 Jan, 2024 2 commits
  21. 21 Dec, 2023 2 commits
  22. 20 Dec, 2023 4 commits
    • Michael Goderbauer's avatar
      Remove outdated ignores from tool (#140467) · 68e346e4
      Michael Goderbauer authored
      These were not ignoring anything (anymore).
      68e346e4
    • LongCatIsLooong's avatar
      Reland `find.textRange.ofSubstring` changes (#140469) · e2e8bcb1
      LongCatIsLooong authored
      Extracted from https://github.com/flutter/flutter/pull/139717 as-is. Landing this change first so we can avoid doing a g3fix.
      e2e8bcb1
    • auto-submit[bot]'s avatar
      Reverts "Make `TextSpan` hit testing precise." (#140468) · 9003f138
      auto-submit[bot] authored
      Reverts flutter/flutter#139717
      Initiated by: LongCatIsLooong
      This change reverts the following previous change:
      Original Description:
      Fixes https://github.com/flutter/flutter/issues/131435, #104594, #43400
      Needs https://github.com/flutter/engine/pull/48774 (to fix the web test failure).
      
      Currently the method we use for text span hit testing `TextPainter.getPositionForOffset` always returns the closest `TextPosition`, even when the given offset is far away from the text. 
      
      The new TextPaintes method tells you the layout bounds (`width =  letterspacing / 2 + x_advance + letterspacing / 2`, `height = font ascent + font descent`) of a character, the PR changes the hit testing implementation such that a TextSpan is only considered hit if the point-down event landed in one of it's character's layout bounds.
      
      Potential issues:
      
      1. In theory since the text is baseline aligned, we should use the max ascent and max descent of each character to calculate the height of the text span's hit-test region, in case some characters in the span have to fall back to a different font, but that will be slower and it typically doesn't make a huge difference. 
      
      This is a breaking change. It also introduces a new finder and a new method `WidgetTester.tapOnText`: `await tester.tapOnText('string to match')` for ease of migration.
      9003f138
    • LongCatIsLooong's avatar
      Make `TextSpan` hit testing precise. (#139717) · ea5b9728
      LongCatIsLooong authored
      Fixes https://github.com/flutter/flutter/issues/131435, #104594, #43400
      Needs https://github.com/flutter/engine/pull/48774 (to fix the web test failure).
      
      Currently the method we use for text span hit testing `TextPainter.getPositionForOffset` always returns the closest `TextPosition`, even when the given offset is far away from the text. 
      
      The new TextPaintes method tells you the layout bounds (`width =  letterspacing / 2 + x_advance + letterspacing / 2`, `height = font ascent + font descent`) of a character, the PR changes the hit testing implementation such that a TextSpan is only considered hit if the point-down event landed in one of it's character's layout bounds.
      
      Potential issues:
      
      1. In theory since the text is baseline aligned, we should use the max ascent and max descent of each character to calculate the height of the text span's hit-test region, in case some characters in the span have to fall back to a different font, but that will be slower and it typically doesn't make a huge difference. 
      
      This is a breaking change. It also introduces a new finder and a new method `WidgetTester.tapOnText`: `await tester.tapOnText('string to match')` for ease of migration.
      ea5b9728
  23. 14 Dec, 2023 1 commit
  24. 11 Dec, 2023 3 commits