How to get result of rootBundle.loadString(key) during flutter widget test? - flutter

I want to read a file from an asset during widget build with help of rootBundle but when I tried to call rootBundle.loadString('assets/myJsonAsset.json') like below :
testWidgets('load assets', (WidgetTester tester) async {
final result = await rootBundle.loadString('assets/myJsonAsset.json');
//above loadString method never return any result
expect(result, isA<String>());
});
then it causes the error :
Unable to load asset: assets/myJsonAsset.json
And the rootBundle.loadString('assets/myJsonAsset.json') never return any result.

Try to add this line to be executed before your tests:
TestWidgetsFlutterBinding.ensureInitialized();
This function will make your assets available for tests

Related

How to get value of variable from function?

I am trying to get value from a function and store it in a variable but I am getting null.
String imgUrl='';
getUrlSP() async {
SharedPreference preferences
=await SharedPreferences.getInstance();
String Url =
preferences.getString('imageUrl').toString();
setState(() {
imgUrl=Url;
});
print('Printing Image Url inside function:${imgUrl}');
}
outside function
print('Image Url :${imgUrl}');
The results I got in the terminal are
I/flutter (32164): Image Url :
I/flutter (32164): Image Url Stored in Prefs
is:https://firebasestorage.googleapis.com/v0/b/veeluser.appspot.com/o/User%20Images%2FdCP6WEESxfYNDIMqtt57n2BsxYf1?alt=media&token=d864a502-209f-4262-9860-b9d4d3222091
_As from the above results that I got in terminal I am not getting the value of imageUrl outside the function._As I am new to flutter so if there is an error or there is any other solution please share it.
That is expected. since your getUrlSP function is declared as async, you'll need to use await when calling it to ensure it completes (and sets imgUrl) before the rest of your code runs.
So:
await getUrlSP();
print('Image Url :${imgUrl}');
I recommend taking the Flutter codelab Asynchronous programming: futures, async, await
should be used setString() to add a string value to the shared preferences .
Example :
String imgUrl='';
getUrlSP() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('imageUrl', imgUrl);
print('==> ${imgUrl} <==');
}

Flutter tests - Having two Integration tests in a same group ()

I'm trying to run two tests in a same group in one test file.
If I split them into two separate test files, they are working fine.
But if I add them in a group, the 2nd test fail with the error saying "TypeAdapter is already registered for the given id".
My app uses HiveDB and it sets up Hive boxes in the main.dart before launching the App. I understand that the 2nd test is also trying the same and fails because the setup is already done.
I followed this doc to setup and write integration tests.
Most of the youtube tutorials, medium articles, and other online resources explain so well on how to run one single test in a test file and they're outdated. I never found a resource having two tests in the same file yet.
Here's my main.dart
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await HiveDB.setup();
runApp(App());
}
test_driver/integration_test.dart
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() => integrationDriver();
test/app_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:integrationtestdemo/main.dart' as app;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Home screen tests', () {
tearDown(() async {
print("TearDown() -- called");
await HiveDB.close();
});
testWidgets('Scenario # - loreum ipsum ...', (tester) async {
// ARRANGE
await app.main();
await tester.pumpAndSettle();
// ACT
// ASSERT
expect(1 + 3, 4);
});
testWidgets('Scenario #2', (tester) async {
// ARRANGE
await app.main();
await tester.pumpAndSettle();
// ACT
// ASSERT
expect(2 + 2, 4);
});
});
}
The command I use to execute tests:
flutter drive --driver=.\test_driver\integration_test.dart --target=.\test\app_test.dart
Error I get:
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞═════════════════
The following HiveError was thrown running a test:
There is already a TypeAdapter for typeId 1.
When the exception was thrown, this was the stack:
#0 TypeRegistryImpl.registerAdapter (package:hive/src/registry/type_registry_impl.dart:104:11)
#1 HiveDB.setup (package:occasionly/src/services/hive_db.dart:80:10)
<asynchronous suspension>
Could someone please help me here? I'm stuck on this for a long time and couldn't figure out a way to isolate the state between tests?
I have found a dirty trick to solve "TypeAdapter is already registered for the given id" this error
try to put it like this, and the error will not appear anymore
Hive.registerAdapter(YourAdapter(), override: true);
But I have no idea what is the possible impact could this argument do
I also faced the same issue, but I found a workaround by referring to this ERROR in flutter: widget_test.dart cannot detect MyApp(), you could try it.
testWidgets('Scenario #1', (tester) async {
// ARRANGE
await app.main();
...
});
testWidgets('Scenario #2', (tester) async {
// ARRANGE
await tester.pumpWidget(MyApp());
});

Flutter Widget Test passes on device but not without one

I have a widget that displays a list of data from an api and I'm trying to write tests for it's various states starting with it's empty state.
Currently my test pumps the widget in question, the widget makes a network call which I'm mocking and then it checks to see if the empty state text is shown.
This test passes when I run the test on a device using
flutter run --flavor myTestApp -t test/booking/booking_list_widget_test.dart
But fails when I run it from the IDE (IntelliJ) the failure exception is:
The following TestFailure object was thrown running a test:
Expected: exactly one matching node in the widget tree
Actual: _TextFinder:<zero widgets with text "You're all caught up." (ignoring offstage widgets)>
Which: means none were found but one was expected
It seems to not be waiting for the Duration given to tester.pump and I've tried wrapping it in a tester.runAsync and using pump and settle etc but i cannot get it to pass.
Any ideas welcome I cant share the widget tree but I can share the test
void main() {
setupFirebaseAuthMocks();
setUpAll(
() async {
SharedPreferences.setMockInitialValues(
{
Constants.USER_ID: '1234567890',
},
);
},
);
testWidgets(
'emptyListTest',
(tester) async {
await _initializeDependencies(tester);
final dio = di.getIt.get<Dio>();
final dioAdapter = DioAdapter(dio: dio);
dioAdapter.onGet(
'/url/user/1234567890',
(server) => server.reply(
200,
BookingResponse(
(b) => b
..data = <Booking>[].toBuiltList().toBuilder()
..pagination = Pagination((b) => b
..last = ''
..first = ''
..next = ''
..skip = 0
..count = 0).toBuilder(),
),
),
);
final testApp = await tester.runAsync(
() => wordskiiTestApp(
widgetUnderTest: BookingView(),
),
);
await tester.pumpWidget(testApp!);
await tester.pump(const Duration(seconds: 1));
expect(find.text('AVAILABLE'), findsOneWidget);
// debugDumpApp();
expect(
find.text(
'You\'re all caught up.',
),
findsOneWidget,
);
},
);
}
Future<void> _initializeDependencies(WidgetTester tester) async {
await tester.runAsync(di.getIt.reset);
await tester.runAsync(di.initTesting);
await tester.runAsync(di.getIt.allReady);
}
On which Widget is 'You\'re all caught up' expected? I had similar issues encountered previously when I tried find.textContaining() on a ListView item. I was able to solve my issue by finding out which widget the Text should appear.
On mine, I had to use find.widgetWithText(InkWell, String). To find out the which Widget it is, you can tap on the widget displayed on screen when you've run the test (i.e. on an emulator). The logs should display the tapped Widget.

Flutter, testing future that throws an Error makes the test unloadable

I'm trying to run a flutter test where a widget displays an error page when the Future provided to it throws an error (via FutureBuilder).
However the line where I create the future seems to be making the test fail.
final futureError = Future.delayed(Duration(milliseconds: 20))
.then((value) => throw Error());
with the message
Failed to load "D:\Projects\flutter\....dart": Instance of 'Error'
Putting it inside the test function resolved the issue
testWidgets('...',
(WidgetTester tester) async {
await tester.runAsync(() async {
final futureError = Future.error('error');
// ...
(it was in the group method prior to this)

What is the proper way to load images in Flutter and handle exceptions on load

I'd like to know what is the proper way to load images from the device, and handle exceptions if the image is missing or corrupted. The user picking an image from the device and I want to open it. I'm using the image later in my code, so it is not enough for me just to show it in some widget.
Currently, I'm using the following code that works fine in most cases:
Future<ui.Image> imageLoadFromDevice(String path) async {
await askPermissionForStorage();
ImageProvider imageProvider = FileImage ( File ( path ), scale: 1 );
Completer<ImageInfo> completer = Completer();
imageProvider.resolve(ImageConfiguration()).addListener(ImageStreamListener((ImageInfo info, bool _) {
completer.complete(info);
}));
ImageInfo imageInfo = await completer.future;
return imageInfo.image;
}
But if the image is missing or corrupted, there is a print in the console "Exception caught by image resource service", but my exception catcher above this function not getting the exception.
Do I loading the image properly, or is there a better way?
In case this code is OK, how should I catch exceptions, particularly missing file or corrupted image?
I'm not sure about corrupted images, but in the case of missing files, you can store the File(path) in a variable and use varname.exists() to check before setting your ImageProvider.
Good question! :)
You can use a simpler code below, that loading an image just as you want.
import 'dart:ui' as ui;
Future<ui.Image> imageLoadFromDevice(String path) async {
await askPermissionForStorage();
File fileImage = File(path);
final Uint8List imageUint8List = await fileImage.readAsBytes();
final ui.Codec codec = await ui.instantiateImageCodec(imageUint8List);
final ui.FrameInfo frameInfo = await codec.getNextFrame();
return frameInfo.image;
}
To catch exceptions from this code you can put it inside try-catch. Any exception while loading the image, should produce a general exception that can be caught and handled.
To handle errors from an ImageStream, use the onError argument to the ImageStreamListener constructor:
imageProvider.resolve(ImageConfiguration()).addListener(ImageStreamListener(
(ImageInfo info, bool _) { }, // called for success
onError: (Object error, StackTrace? stackTrace) { }, // called for error
));