Why pumpAndSettle timed out when assigning Future function like this

1,169

The default timeout for pumpAndSettle is ten minutes, as mentioned in the docs. Checking your code, the test should run fine. Initializing Future<void> either way shouldn't cause any issue when I tried it locally.

Here's a sample that you can also try. Text should be shown once Future.delayed() finishes. One of the Future<void> is initialized on initState().

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> 

  late Future<void> _testFuture1;

  Future<void> _testFuture2() async {
    // await Future.value(1);
    await Future.delayed(Duration(seconds: 5), () {
      debugPrint('Test 2: \"Hello from the future!\"');
    });
  }

  @override
  void initState() {
    super.initState();
    _testFuture1 = Future(() async {
      // await Future.value(1);
      await Future.delayed(Duration(seconds: 5), () {
        debugPrint('Test 1: \"Hello from the future!\"');
      });
    });
  }

  FutureBuilder _futureBuilder1() {
    return FutureBuilder(
        future: _testFuture1,
        builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
          if (snapshot.connectionState == ConnectionState.done)
            return Text('Test 1 Done!');
          else
            return Center(
              child: CircularProgressIndicator(),
            );
          // return Text('Test 1 Done!');
        });
  }

  FutureBuilder _futureBuilder2() {
    return FutureBuilder(
        future: _testFuture2(),
        builder: (BuildContext context, AsyncSnapshot<dynamic> builder) {
          return Text('Test 2 Done!');
        });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            _futureBuilder1(),
            _futureBuilder2(),
          ],
        ),
      ),
    );
  }
}

Here's the test file

void main() {
  testWidgets('Future test', (WidgetTester tester) async {
    // Build our app and trigger a frame.
    await tester.runAsync(() async{
      await tester.pumpWidget(MyApp());
      await tester.pump(); // both pump() and pumpAndSettle() works fine
    }).then((value) {
      // expect(find.text('Test 1 Done!'), findsOneWidget);
      // expect(find.text('Test 2 Done!'), findsOneWidget);
    });
  });
}

Demo

Test

Test

Here's my Flutter version for reference

[✓] Flutter (Channel stable, 2.2.1, on macOS 11.4 20F71 darwin-x64)
    • Flutter version 2.2.1
    • Framework revision 02c026b03c (6 weeks ago), 2021-05-27 12:24:44 -0700
    • Engine revision 0fdb562ac8
    • Dart version 2.13.1
Share:
1,169
Calvin Gonsalves
Author by

Calvin Gonsalves

Updated on December 01, 2022

Comments

  • Calvin Gonsalves
    Calvin Gonsalves over 1 year

    In my State class I have declared a future:

    Future<void> _testFuture;
    

    and assign it in the initState like this:

    super.initState();
    
    _testFuture = Future(() async {
          await Future.value(1); //can be any computation
        });
    

    and use it in the FutureBuilder like this:

     FutureBuilder(
                  future: _testFuture,
                  builder: (context, snapshot) {
                    if (snapshot.connectionState == ConnectionState.done)
                      return Text('Hi');
                    else
                      return Center(
                        child: CircularProgressIndicator(),
                      );
                  },
                ),
    

    This works fine when running the app normally with flutter run but when I try widget testing this using flutter test test/widget_test.dart:

    void main() {
      testWidgets('Testing', (WidgetTester tester) async {
        // Build our app and trigger a frame.
        await tester.runAsync(() async {
          await tester.pumpWidget(MyApp());
          await tester.pumpAndSettle();
        });
    }
    

    it fails with :

    ══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
    The following assertion was thrown while running async test code:
    pumpAndSettle timed out
    

    However, if I assign the future this way the same test passes with no issues:

    super.initState();
    
    Future<void> testFutures() async {
          await Future.value(1);
        }
    
    _testFuture = testFutures();
    

    What is the difference between the two ways of assigning the future ?