New integration_test package just shows "Test starting..." [Android]
Asked Answered
V

5

20

I tried to migrate my old flutter driver tests to the new integration_test package. I copied nearly everything from the example project and executed the integration tests of the example project locally. That worked as expected, I was able to see the app UI. But my own app just shows "Test starting..." in a purple color after the splash screen was shown.

example_test.dart:

void main() {
  group('My-App', () {
    final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;

    testWidgets('Tap on SkipAuthentication', (tester) async {
      app.main();

      await binding.traceAction(() async {
        await tester.pumpAndSettle();

        await Future.delayed(Duration(seconds: 5));

        final fab = find.byKey(ValueKey(WidgetKeys.authenticationScreenKeys.skipAuthenticationButton));
        await tester.tap(fab);

        await tester.pumpAndSettle();
      });
    });



integration_driver.dart:

Future<void> main() async {
  integrationDriver();
}

I figured out, that if I don't start the tester.pumpWidget() shows the Widget, that I pass to the method, but thats a WidgetTest and not an integration Test.

My guess is, that it's due to the fact that my main function is an async function. I also needed this workaround in my old flutter driver tests to wait for the first frame. But I couldn't figure out how to implement that with the new integration_test package.

Hope you can help me.

Velure answered 22/12, 2020 at 17:8 Comment(0)
E
9

I had this issue also and the sleep / Future.delayed did not work. Some times the integration tests were run but mostly they were not.

What ultimately fixed the issue for me was to change the framePolicy of IntegrationTestWidgetsFlutterBinding to LiveTestWidgetsFlutterBindingFramePolicy.fullyLive. Here is a full example:

void main() {
  final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;

  testWidgets("failing test example", (WidgetTester tester) async {
    app.main();
    await tester.pumpAndSettle();

    // Start testing here...
  });
}

The solution was found from Google Codelabs.

Electron answered 23/6, 2021 at 12:5 Comment(0)
E
1

Huh. I started converting my flutter_driver tests over the holidays and ran into the same thing.

My fix was to add a fixed sleep after launching the test, which allowed it to initialize properly. So one test case looks like this:

    testWidgets("Main screen loads", (WidgetTester widgetTester) async {
      app.main();
      await sleep(Duration(seconds: 10));
      await widgetTester.pumpAndSettle();

      expect(find.text("What are you looking for?"), findsOneWidget);
    });
Evaleen answered 23/12, 2020 at 14:23 Comment(4)
did the same, pumpAndSettle() has a Duration property though so you should use that over sleep()Moonwort
@Moonwort doesn't that just specify how long the engine should wait for the UI to settle, at most? So in my understanding it won't actually suspend the test execution for that long - I've had some issues with this during first trials.Poorly
from my experience it does the full time you put into the duration same as the sleep. There is a timeout property that may be used for at most.Moonwort
tried to use duration property on pumpAndSettle() with no luck, and ended up using sleep like this.. did you guys found better solution by the way?Kuykendall
H
1

I was struggling with this also for some hours and finally found the answer.

Your issue is that do not pump a widget with await tester.pumpWidget(MyApp())

Your test look like:

void main() {
    testWidgets('Tap on SkipAuthentication', (tester) async {
      app.main(); // <--- You call app.main() - This Flutter Driver style, but not integration test style

      await binding.traceAction(() async {
        await tester.pumpAndSettle();

        await Future.delayed(Duration(seconds: 5));

        final fab = find.byKey(ValueKey(WidgetKeys.authenticationScreenKeys.skipAuthenticationButton));
        await tester.tap(fab);

        await tester.pumpAndSettle();
      });
    });

You need to change your test like this:

void main() {
  testWidgets('Tap on SkipAuthentication', (tester) async {
    await tester.pumpWidget(MyApp()); // You need to call await tester.pumpWidget();
    await tester.pump(const Duration(seconds: 1));

    final fab = find.byKey(ValueKey(WidgetKeys.authenticationScreenKeys.skipAuthenticationButton));
    await tester.tap(fab);

    await tester.pump();
  });
}
Handwork answered 28/6, 2021 at 22:1 Comment(0)
S
1

I had to use a combination of commands from this thread to make my test work. At first, it was getting stuck on "Test starting..." for me as well, then it was getting stuck on the splash screen. In both cases, it could not move to the first page of the app, so I could not find any widget.

A few things I kind-of learned from all my tries:

  • apparently, using pumpAndSettle() with its Duration argument gives different results than sleep(Duration) plus pumpAndSettle() without duration. The first worked for me to "get" the app's first page, but not the latter
  • calling tester.pumpWidget(MyApp()) instead of app.main() is actually resulting in an error screen for me, I definitely need to use app.main()
  • the framePolicy setting is necessary in my case as well
  • I think that using ValueKey or Key inside find.byKey is the same: for me, both of them are working (giving them a string as argument)

In the end, the code that works for me is:

void main() {
  final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() 
    as IntegrationTestWidgetsFlutterBinding;
  binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
    
  testWidgets('Tap on SkipAuthentication', (tester) async {
    app.main();
    await tester.pumpAndSettle(Duration(seconds: 3));

    final fab = find.byKey(ValueKey(WidgetKeys.authenticationScreenKeys.skipAuthenticationButton));
    await tester.tap(fab);

    await tester.pumpAndSettle();
  });
}
Sophey answered 2/7, 2021 at 15:15 Comment(0)
P
1

Using Nils answer as a hint, I think I know partially what the issue is. If you go to the app's main.dart, and find that main() returns a Future, you have to wait for the main to finish.

// main.dart
Future<void> main() async {
...
}

If you see something like the previous in your main.dart, it means your app needs to await its startup. You cannot merely call app.main() because that function returns a Future. Calling that will not boot up your app properly (it will, but asynchronously and your next line of code will execute without the initialization being complete).

So instead of this:

testWidgets('Tap on SkipAuthentication', (tester) async {
  app.main(); // doesn't wait for initializing
  // ... next line will be executed right away
});

You will have to do something like this:

testWidgets('Tap on SkipAuthentication', (tester) async {
  await app.main(); // waits for an async app to initialize
  // ... next line will wait for app setup
});
Proportionate answered 23/1, 2023 at 16:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.