You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
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?
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.
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.
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.
@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).
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.
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.
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.
Activity
tvolkert commentedon Sep 25, 2017
/cc @yjbanov
Hixie commentedon Sep 25, 2017
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.
Hixie commentedon Sep 25, 2017
(If you want to wait for a particular image to be ready, you can try to load it manually and await its future.)
zzzev commentedon Sep 25, 2017
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:
... 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.
yjbanov commentedon Sep 25, 2017
This is a duplicate of #11021?
(update: turned this comment into a question)
Hixie commentedon Sep 25, 2017
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.
zzzev commentedon Sep 25, 2017
@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
enableFlutterDriverExtensionis 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).yjbanov commentedon Sep 25, 2017
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.yjbanov commentedon Nov 7, 2017
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
handlerparameter onenableFlutterDriverExtension, or a retry mechanism in the test.github-actions commentedon Sep 4, 2021
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 -vand a minimal reproduction of the issue.