3

I'm trying to unit test widgets inside a FutureBuilder but I can't figure it out.

I've got a widget that has a FutureBuilder with a builder that returns a CameraPreview widget when the connection state is done:

    body: FutureBuilder<void>(
      future: _initializeControllerFuture,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          // If the Future is complete, display the preview.
          return CameraPreview(_controller);
        } else {
          // Otherwise, display a loading indicator.
          return const Center(child: CircularProgressIndicator());
        }
      },
    ),

Here's how I created the future:

  Future<void> _initializeControllerFuture;

  @override
  void initState() {
    super.initState();
    // To display the current output from the Camera,
    // create a CameraController.
    _controller = CameraController(
      // Get a specific camera from the list of available cameras.
      widget.camera,
      // Define the resolution to use.
      ResolutionPreset.medium,
    );

    // Next, initialize the controller. This returns a Future.
    _initializeControllerFuture = _controller.initialize();
  }

And here's my test:

testWidgets('Camera preview is available',
    (WidgetTester tester) async {
  await _buildCameraScreenPage(tester);
  await tester.pump();

  expect(find.byType(CameraPreview), findsOneWidget,
      reason: 'Camera preview should be visible.');
});

I've debugged it and snapshot.connectionState is never done (always waiting) so it skips the line which returns a CameraPreview. I've tried tester.pumpAndSettle() too but it times out.

Any ideas?

Daniel
  • 452
  • 6
  • 14
  • Is the "`connectionState` never done" because it's actually in an error state? Not sure how the camera plugin behaves during tests... – Gpack May 31 '21 at 10:49
  • It's always in waiting state when I debug it – Daniel May 31 '21 at 10:53
  • And could you share the code of `_initializeControllerFuture`? Maybe this is never returning during the unit test then(?) – Gpack May 31 '21 at 10:57
  • Sure, I've added it to my post. Yes, that's what I'm thinking, it never returns but I'm not too sure how to simulate that in a unit test. – Daniel May 31 '21 at 11:00
  • Does this answer help? https://stackoverflow.com/a/57582830/3466729 – Gpack May 31 '21 at 11:10
  • Thanks @Gpack, it doesn't help unfortunately because I use `availableCameras()` in the widget which calls the widget under test if that makes sense, so it's separate. – Daniel May 31 '21 at 11:23
  • 1
    I see. Then what about creating a constructor in your parent class, annotated with @visibleForTesting, which could take a mock of the `CameraController`? This way you could override the `.initialize()` method and make sure it returns... – Gpack May 31 '21 at 12:53

0 Answers0