Skip to content

SchedulerBinding's framesEnabled state leaks between tests #141835

@aizatazhar

Description

@aizatazhar

Steps to reproduce

In a widget test, calling tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.paused); in an earlier test may cause subsequent tests to fail because tester.binding.framesEnabled is not reset to true

When app lifecyclestate is paused, framesEnabled is set to false but it is not reset to initial value between tests

Expected results

tester.binding.framesEnabled should be true at the start of every test

Actual results

tester.binding.framesEnabled state can be false at the start of a test due to effects from previous unrelated tests

Code sample

Code sample

Test showing framesEnabled has leaky state:

import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  var lifecycleStateChanged = false;

  testWidgets('set app lifecycle state to paused', (tester) async {
    expect(tester.binding.framesEnabled, isTrue);

    tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.paused);
    lifecycleStateChanged = true;
  });

  testWidgets('framesEnabled should be true', (tester) async {
    // In case `testWidgets` runs out of order.
    expect(lifecycleStateChanged, isTrue);

    // Should pass but actually fails because of the previous test
    expect(tester.binding.framesEnabled, isTrue);
  });
}

Example of test that fails because of framesEnabled being false:

import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  testWidgets('set app lifecycle state to paused', (tester) async {
    tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.paused);
  });

  testWidgets('fails unless comment out previous test or uncomment line 10',
      (tester) async {
    // tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed);
    await tester.createWidget(() => const SizedBox());
  });
}

extension WidgetTesterExtension on WidgetTester {
  Future<Widget> createWidget(Widget Function() builder) async {
    late Widget result;

    final testWidget = Builder(
      builder: (_) {
        result = builder();
        return result;
      },
    );

    await pumpWidget(testWidget);

    return result;
  }
}

Earlier test sets app lifecycle state to paused which causes framesEnabled to be false. This causes await pumpWidget(testWidget) in the subsequent test to not do anything which causes late Widget result to never be initialised, thus causing LateInitializationError

Screenshots or Video

No response

Logs

No response

Flutter Doctor output

Doctor output
-

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Issues that are less important to the Flutter projecta: tests"flutter test", flutter_test, or one of our testsfound in release: 3.16Found to occur in 3.16found in release: 3.19Found to occur in 3.19frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer versionteam-frameworkOwned by Framework teamtriaged-frameworkTriaged by Framework team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions