Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test breaks when using Future.delayed

Tags:

flutter

dart

Fade in FAB

I have used a Future.delayed to show a FAB in 1 second using this code:

Future.delayed(const Duration(seconds: 1), () {
  setState(() {
    _showFab = true;
  });
});

Now the most basic smoke test has stopped working:

void main() {
  testWidgets('smoke test', (WidgetTester tester) async {
    await tester.pumpWidget(MyApp());

    expect(find.byType(MyHomePage), findsOneWidget);
  });
}

This is the error message:

══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following assertion was thrown running a test:
A Timer is still pending even after the widget tree was disposed.
'package:flutter_test/src/binding.dart': Failed assertion: line 933 pos 7:
'_currentFakeAsync.nonPeriodicTimerCount == 0'    import 'dart:async';

Here is all the code used:

import 'package:flutter/material.dart';
import 'dart:async';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

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

class _MyHomePageState extends State<MyHomePage> {
  bool _showFab = false;

  @override
  Widget build(BuildContext context) {
    Future.delayed(const Duration(seconds: 1), () {
      setState(() {
        _showFab = true;
      });
    });

    return Scaffold(
      floatingActionButton: AnimatedOpacity(
        opacity: _showFab ? 1.0 : 0.0,
        duration: Duration(milliseconds: 1400),
        child: FloatingActionButton(
          onPressed: null,
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

How can I change the unit test to make the test pass?

like image 510
S.D. Avatar asked Jan 03 '19 11:01

S.D.


People also ask

What is future delayed flutter?

Creates a future that runs its computation after a delay. The computation will be executed after the given duration has passed, and the future is completed with the result of the computation.


2 Answers

The test framework runs with FakeAsync by default, that has some limitations and might cause the error you get.

You can explicitly run with async proper like:

void main() {
  testWidgets('smoke test', (WidgetTester tester) async {
    await tester.runAsync(() async {
      await tester.pumpWidget(MyApp());

      expect(find.byType(MyHomePage), findsOneWidget);
    });
  });
}

You might still need suggestions made in other answers.

like image 130
Günter Zöchbauer Avatar answered Oct 05 '22 23:10

Günter Zöchbauer


You need to give the tester enough time to process all the async calls you have scheduled, try change your smoke test to something like this:

void main() {
    testWidgets('smoke test', (WidgetTester tester) async {
    await tester.pumpWidget(MyApp());
    // Since you wait 1 second to start the animation and another 1.4 to complete it
    await tester.pump(Duration(seconds: 3));

    expect(find.byType(MyHomePage), findsOneWidget);
  });
}

You will also need to move the Future.delayed out of the build() method, because this is causing a cyclic behaviour, every time you call setState() the build() is called again, change your state like that:

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

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

class _MyHomePageState extends State<MyHomePage> {
  bool _showFab = false;

  @override
  void initState() {
    Future.delayed(const Duration(seconds: 1), () {
      setState(() {
        _showFab = true;
      });
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: AnimatedOpacity(
        opacity: _showFab ? 1.0 : 0.0,
        duration: Duration(milliseconds: 1400),
        child: FloatingActionButton(
          onPressed: null,
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}
like image 29
Panthro Avatar answered Oct 06 '22 01:10

Panthro