Unverified Commit 88e49ed2 authored by Dan Field's avatar Dan Field Committed by GitHub

Load assets in flutter_test without turning event loop. (#115123)

* Load assets in flutter_test without turning event loop.

This makes it possible to load an asset without actually turning
the event loop. This is importnat because our FakeAsync zones
may cause people to sprinkle in extra pumpAndSettles in when
running tests that load assets, which is undesirable.

* fix null checking
parent 6e89042d
......@@ -38,11 +38,11 @@ class SynchronousFuture<T> implements Future<T> {
@override
Future<R> then<R>(FutureOr<R> Function(T value) onValue, { Function? onError }) {
final dynamic result = onValue(_value);
final FutureOr<R> result = onValue(_value);
if (result is Future<R>) {
return result;
}
return SynchronousFuture<R>(result as R);
return SynchronousFuture<R>(result);
}
@override
......
......@@ -247,17 +247,24 @@ abstract class CachingAssetBundle extends AssetBundle {
/// An [AssetBundle] that loads resources using platform messages.
class PlatformAssetBundle extends CachingAssetBundle {
@override
Future<ByteData> load(String key) async {
Future<ByteData> load(String key) {
final Uint8List encoded = utf8.encoder.convert(Uri(path: Uri.encodeFull(key)).path);
final ByteData? asset =
await ServicesBinding.instance.defaultBinaryMessenger.send('flutter/assets', encoded.buffer.asByteData());
if (asset == null) {
final Future<ByteData>? future = ServicesBinding.instance.defaultBinaryMessenger.send('flutter/assets', encoded.buffer.asByteData())?.then((ByteData? asset) {
if (asset == null) {
throw FlutterError.fromParts(<DiagnosticsNode>[
_errorSummaryWithKey(key),
ErrorDescription('The asset does not exist or has empty data.'),
]);
}
return asset;
});
if (future == null) {
throw FlutterError.fromParts(<DiagnosticsNode>[
_errorSummaryWithKey(key),
ErrorDescription('The asset does not exist or has empty data.'),
]);
_errorSummaryWithKey(key),
ErrorDescription('The asset does not exist or has empty data.'),
]);
}
return asset;
return future;
}
@override
......
......@@ -6,8 +6,8 @@ import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:path/path.dart' as path;
// ignore: deprecated_member_use
import 'package:test_api/test_api.dart' as test_package;
......@@ -42,7 +42,7 @@ void mockFlutterAssets() {
/// platform messages.
SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {});
ServicesBinding.instance.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) async {
ServicesBinding.instance.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) {
assert(message != null);
String key = utf8.decode(message!.buffer.asUint8List());
File asset = File(path.join(assetFolderPath, key));
......@@ -62,7 +62,7 @@ void mockFlutterAssets() {
}
final Uint8List encoded = Uint8List.fromList(asset.readAsBytesSync());
return Future<ByteData>.value(encoded.buffer.asByteData());
return SynchronousFuture<ByteData>(encoded.buffer.asByteData());
});
}
......
......@@ -10,6 +10,7 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
......@@ -90,4 +91,13 @@ void main() {
binding.idle();
});
});
testWidgets('Assets in the tester can be loaded without turning event loop', (WidgetTester tester) async {
bool responded = false;
// The particular asset does not matter, as long as it exists.
rootBundle.load('AssetManifest.json').then((ByteData data) {
responded = true;
});
expect(responded, true);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment