How to properly test response.body is null in Flutter? - flutter

In my Flutter API I a getting an error
flutter: type 'Null' is not a subtype of type 'List' in type cast
when the response json list is empty. My API is written in Go. log.Println(mattersJSON) returns [1111 2222 3333 4444] and fmt.Println(string(mattersJSON)) returns null. This is expected as the query returns no records.
In Flutter, I have this code in my Api:
Future<List<Matter>> getMatters(BuildContext context) async {
List<Matter> matters = [];
try {
final response = await _helper.get(context, "/matters");
if (response.statusCode == 200) {
print(response.body);
if (response.body == null) {
return [];
}
print(response.body.length);
print('skipped test');
var parsed = json.decode(response.body) as List<dynamic>;
for (var matter in parsed) {
matters.add(Matter.fromJson(matter));
}
} else {
Navigator.pushNamed(context, RoutePaths.login);
return matters;
}
} catch (e) {
print(e);
return matters;
}
return matters;
}
The output is this:
flutter: null
flutter: 4
flutter: skipped test
flutter: type 'Null' is not a subtype of type 'List' in type cast
I'm tempted to assume that an empty response.body list will always have a length of 4 and that a response.body with records will always have have a length greater than 4. If so, then I could just test for a response.body.length > 4. However this is not elegant and probably fragile. I'm concerned that the error I'm seeing says the list is null and print(response.body) returns null but the response.body is not null.
How can I properly test for an empty response list and return []?

Assuming that you're talking about Response from package:http, then Response.body is non-nullable and cannot be null.
It sounds like response.body is the literal string 'null'. That would be reasonable if you're expecting JSON. Ultimately your problem is that you are performing an unconditional cast (as List<dynamic>). json.decode returns a dynamic type and not a List or a Map precisely because it might return a different types of objects, so the proper fix is to just check first:
var parsed = json.decode(response.body);
if (parsed is List<dynamic>) {
for (var matter in parsed) {
matters.add(Matter.fromJson(matter));
}
}
and then you don't need to explicitly check for response.body being the string 'null' or for json.decode returning null.

Related

[ERROR:flutter/runtime/dart_vm_initializer.cc(41) Unhandled Exception: Null check operator used on a null value

I am unable to store data in the excel sheet because of this error. Even though the data is getting stored in the variable.
I changed !. to ?. in the insert function, then I was able to move forward but the data was not getting stored in the excel sheet.
Map<String, dynamic> data = {
DataSet.imagePath: viewImage,
DataSet.option11: opt11,
DataSet.option12: opt12,
DataSet.option13: opt13,
DataSet.option14: opt14,
DataSet.option21: opt21,
DataSet.option22: opt22,
DataSet.option23: opt23,
DataSet.option24: opt24,
};
await DataSheetApi.insert([data]);
This is where I am adding storing data to the variable data.
static Future insert(List<Map<String, dynamic>> rowList) async {
dataSheet!.values.map.appendRows(rowList);
}
This is where the error is.
Screenshot of the error.
Try to check null and then procced,
static Future insert(List<Map<String, dynamic>> rowList) async {
if(dataSheet!=null) dataSheet.values.map.appendRows(rowList);
else log("got null"); //from `dart.developer`
}

How to write tests for Either<> from dartz package in flutter

I am trying to write unit tests for a flutter app and I can't get this one test case to work correctly.
Here is the function returning Future<Either<WeatherData, DataError>>:
#override
Future<Either<WeatherData, DataError>> fetchWeatherByCity({required String city}) async {
try {
var response = await apiService.fetchWeatherByCity(city: city);
if (response.statusCode == 200) {
return Left(WeatherData.fromJson(jsonDecode(response.body)));
} else {
return Right(DataError(title: "Error", description: "Desc", code: 0, url: "NoUrl"));
}
} catch (error) {
AppException exception = error as AppException;
return Right(DataError(
title: exception.title, description: exception.description, code: exception.code, url: exception.url));
}
}
Here is the code where I am trying to write the unit test:
sut = WeatherRepositoryImpl(apiService: mockWeatherApiService);
test(
"get weather by city DataError 1 - Error 404 ",
() async {
when(mockWeatherApiService.fetchWeatherByCity(city: "city"))
.thenAnswer((_) async => Future.value(weatherRepoMockData.badResponse));
final result = await sut.fetchWeatherByCity(city: "city");
verify(mockWeatherApiService.fetchWeatherByCity(city: "city")).called(1);
expect(result, isInstanceOf<DataError>);
verifyNoMoreInteractions(mockWeatherApiService);
},
);
When I run this specific test, I receive this error:
Expected: <Instance of 'DataError'>
Actual: Right<WeatherData, DataError>:<Right(Instance of 'DataError')>
Which: is not an instance of 'DataError'
What I am not getting here? What should I be expecting from the function for the test to pass successfully?
You are directly using the result which is actually a wrapper and has a type of Either<WeatherData, DataError>.
You need to unwrap the value using the fold method on the result and then expect accordingly, So in your code you can do something like this to make it work:
final result = await sut.fetchWeatherByCity(city: "city");
result.fold(
(left) => fail('test failed'),
(right) {
expect(result, isInstanceOf<DataError>);
});
verifyNoMoreInteractions(mockWeatherApiService);
Hope this helps.
You need to either make the expected value a Right(), or extract the right side of the actual value. Doing either of those will match, but as it is, you're comparing a wrapped value with an unwrapped value.

Firestore type mismatch : The argument type 'List<Null>' can't be assigned to the parameter type 'List<JobPost>'

In a flutter project, I am trying to make a CollectionGroup query. But messed up with types. Here is my code :
Stream<Either<JobPostFailure, List<JobPost>>> watchAppliedJobPosts({
required String seamanId,
}) async* {
yield* _firestore
.collectionGroup(ConstStrings.applications)
.where(ConstStrings.seamanId, isEqualTo: seamanId)
.snapshots()
.map((querySnapshot) {
return right(querySnapshot.docs.map((docSnapshot) {
final jobPostDocRef = docSnapshot.reference;
jobPostDocRef.snapshots().map((doc) {
final jobPost = JobPostDto.fromFirestore(doc).toDomain();
return jobPost;
});
}).toList());
});
}
I expect to get a List<JobPost>, but getting following error at this line return right(querySnapshot.docs.map((docSnapshot) {...:
The argument type 'List<Null>' can't be assigned to the parameter type
'List<JobPost>'.
Though I am returning List<JobPost>, error says it is List<Null>. Where is the error? How to solve this?
You are missing a return keyword:
return /* <-- */ jobPostDocRef.snapshots().map((doc) {
That said, why are you complicating this function with an Either return type, when there clearly is no other option in your method? It always returns right, so you might as well just remove the Either from the return type.

How to Solve Flutter Expected a value of type 'List<dynamic>', but got one of type 'JsonMap'

Flutter Expected a value of type 'List', but got one of type '_jsonMap'
When i'm did this same with localhost it worked fine but when i do this same with hosting it give me this error.from api side is working api is sending the data.but something wrong.
//Future is n object representing a delayed computation.
Future<List<Homes>> downloadJSON() async {
final jsonEndpoint = "https://homeshouse.000webhostapp.com/get.php";
final response = await get(Uri.parse(jsonEndpoint));
if (response.statusCode == 200) {
List homelist = json.decode(response.body);
return homelist.map((home) => new Homes.fromJson(home)).toList();
} else
throw Exception('We were not able to successfully download the json data.');
}
please help i stucked here from last 2 days and i'm not getting this
if (response.statusCode == 200) {
final json = "[" + response.body + "]";
List homelist = (jsonDecode(json) as List<dynamic>) ;
this is works for me:-
enter link description here

how do I work with file streams in dart/flutter?

I am new to dart/flutter programming. I have been trying to analyze the content of a file and return the result but couldn't. The code actually works when in the main function, but as soon as I take it out it doesn't work anymore. I have read the dart tutorial on futures, async, await, and streams as well as watched YouTube videos but still couldn't solve the problem. I believe my problem revolves around those concepts. Here is my code:
Future<String> r(String name) async {
var f = File(name);
var lines = f.readAsLines();
await lines
.then((line) => line.forEach((element) {
if (element.contains(RegExp(r'^hello'))) {
return element;
}
}))
.onError((error, stackTrace) => 'An error occured');
}
I was getting 2 errors:
The function name 'r' was underlined:
The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type.
Try adding either a return or a throw statement at the end.
The variable 'element' was underlined:
The return type 'String' isn't a 'void', as required by the closure's context.
Thanks.
Your first error says that "Whatever happens, You have to return a String"
Your second error says that you are trying to return a String in a void function, As you see List. Foreach is a void function and you can't just return something in it because the return statement matches with the closest Function
So I rewrited you're code as following
Future<String> r(String name) async {
try {
var f = File(name);
var lines = await f.readAsLines();
for (var element in lines)
if (element.contains(RegExp(r'^hello'))) {
return element;
}
return "not found";
} catch (e) {
return 'An error occurred: $e';
}
}
Since you are using File and File.readAsLines I think it would be better to just wrap everything inside a try catch bloc k.