dart-lang/leak_tracker

StatefulElements are considered "not disposed" if an exception happens in a State lifecycle

Closed this issue · 2 comments

Hello!

Consider the following test:

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

void main() {
  testWidgets('Example', (tester) async {
    await tester.pumpWidget(const MyWidget());

    expect(tester.takeException(), isUnimplementedError);
  });
}

class MyWidget extends StatefulWidget {
  const MyWidget({Key? key}) : super(key: key);

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  @override
  void initState() {
    super.initState();
    throw UnimplementedError();
  }

  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

This will fail with:

  Expected: leak free
    Actual: <Instance of 'Leaks'>
     Which: contains leaks:
            # The text is generated by leak_tracker.
            # For leak troubleshooting tips open:
            # https://github.com/dart-lang/leak_tracker/blob/main/doc/TROUBLESHOOT.md
            notDisposed:
              total: 1
              objects:
                StatefulElement:
                  test: Example
                  identityHashCode: 470187304       

I assume the issue is that if an exception happens in initState, State.dispose never gets called.

Sorry for delay on it.
Yes, tests with exceptions do not dispose state.
Such tests should be opted out from leak tracking:

testWidgets('async onInit throws FlutterError',
  experimentalLeakTesting: LeakTesting.settings.withIgnoredAll(), // leaking by design because of exception
  (WidgetTester tester) async {
...  

Documented this: #238
Thanks for flagging!