Skip to content

flutter_driver's waitUntilNoTransientCallbacks doesn't await Image asset loading #12243

Closed

Description

@zzzev

I have a screenshot test using flutter_driver where I'm taking a screenshot of a Widget which contains an Image widget which is created via new Image.asset('myasset.png', key: const Key('a')). The test code looks like this:

test('Widget with Image', () async {
      await driver.waitFor(find.byValueKey('a'));
      await driver.waitUntilNoTransientCallbacks();
      await scuba.diffScreenshot('opportunities');
    });

This takes a screenshot where the Image is in the tree (I can tell because it changes the alignment of the other elements in the Widget), but has not yet been loaded (it's blank). Very occasionally (<5% of the time), the test will take a screenshot where the image is loaded and visible.

If I add await new Future.delayed(const Duration(seconds: 1));, then the Image is always loaded, but this is likely wasting some amount of time and/or prone to flaking. I think that waitUntilNoTransientCallbacks is probably supposed to be await'ing whatever asset loading is happening in the background; if not, could we expose some other hook that would enable this?

Thanks!

Activity

  1. tvolkert commented on Sep 25, 2017

    @tvolkert
    Contributor
  2. added
    a: tests"flutter test", flutter_test, or one of our tests
    t: flutter driver"flutter driver", flutter_drive, or a driver test
    on Sep 25, 2017
  3. Hixie commented on Sep 25, 2017

    @Hixie
    Contributor

    waitUntilNoTransientCallbacks waits until there are no transient callbacks. Image loading doesn't use transient callbacks, it just calls into the engine to trigger the download or the decode and then waits for the future to complete.

  4. Hixie commented on Sep 25, 2017

    @Hixie
    Contributor

    (If you want to wait for a particular image to be ready, you can try to load it manually and await its future.)

  5. zzzev commented on Sep 25, 2017

    @zzzev
    ContributorAuthor

    The bit about waitUntilNoTransientCallbacks makes sense, so moving on to how to do this with a different API:

    My understanding is that you can't "touch" the Widgets directly from the flutter_driver, so how would you get the future that I want to await?

    Additionally, assuming I can get a handle on the Image widget, could you point me to an example of what it might look like to await the load event on an Image? It looks like I want to do something like this incomplete snippet:

    Widget myImage = new Image.asset('foo.png');
    ImageProvider provider = myImage.image;
    final key = await provider.obtainKey(myImage.getKeySomehow());
    await provider.load(key); // except this is a ImageStreamCompleter so not actually `await`able
    

    ... But even all that seems like I'm actually triggering another load, not await'ing the Image Widget's load, and feels like it's overly complicated for what I'm trying to do, so probably not right.

  6. yjbanov commented on Sep 25, 2017

    @yjbanov
    Contributor

    This is a duplicate of #11021?

    (update: turned this comment into a question)

  7. Hixie commented on Sep 25, 2017

    @Hixie
    Contributor

    To load an image you get an ImageProvider, call its resolve() method to get an ImageStream, and addListener to the stream. When that callback fires, the image is ready. If you need to make that into a Future you can use a Completer which you create before doing all this and that you complete in the listener callback.

    If you need to do this in a driver test, you could pass a callback to the driver's enableFlutterDriverExtension method then use that to ask when the screen is ready.

  8. zzzev commented on Sep 25, 2017

    @zzzev
    ContributorAuthor

    @yjbanov I think there's another problem here in addition to the issue you reference; e.g. if loading an image from the network I imagine that this issue would still exist even if #11021 were to be fixed?

    @Hixie passing this through enableFlutterDriverExtension is a kind of one-off way of fixing this; it's pretty heavy weight to set up for each screen we want to screenshot that has images on it, especially since just awaiting the image load is not a one-liner. Do you have any other suggestions or ideas for ways this might be possible to do with less effort? I think screenshotting after image assets are loaded is a common enough use case for screendiff tests that this should be easier to do than the status quo (maybe this is more of a feature request than a bug in that case).

  9. yjbanov commented on Sep 25, 2017

    @yjbanov
    Contributor

    I should have read the discussion more carefully. Yes, an image loading from the network will not count as a transient callback, so #11021 will not fix it. One way to track globally pending network activities is to overwrite the createHttpClient with a custom HTTP client. You can then use enableFlutterDriverExtension(handler:) to wait for not just images, but any pending HTTP calls.

  10. added
    toolAffects the "flutter" command-line tool. See also t: labels.
    on Oct 3, 2017
  11. yjbanov commented on Nov 7, 2017

    @yjbanov
    Contributor

    I'm going to consider that with #12896 we have a good enough solution for this problem, so I'll close it. FlutterDriver is intended for testing, and when testing we also expect that the test environment is hermetic enough to provide more-or-less predictable latency from external services, such as servers serving images. In cases when the load latency is unpredictable, you can either use the handler parameter on enableFlutterDriverExtension, or a retry mechanism in the test.

  12. github-actions commented on Sep 4, 2021

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  13. locked as resolved and limited conversation to collaborators on Sep 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: tests"flutter test", flutter_test, or one of our testsc: flakeTests that sometimes, but not always, incorrectly passt: flutter driver"flutter driver", flutter_drive, or a driver testtoolAffects the "flutter" command-line tool. See also t: labels.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions