How to explicitly return `void`? - flutter

One flutter package has this kind of data requesting workflow:
final cancelListening = await request(
query: query,
onResponse: (response) {
streamController.add(response);
cancelListening(); // I need to cancel it here;
},
);
But this way I obviously have the error: cancelListening can't be referenced before it is declared. As request() returns Future<void Function()> I can do this:
void Function() cancelListening = () {};
cancelListening = await request(
...
And I got Omit type annotations for local variables.dart(omit_local_variable_types).
So, I write this way:
var cancelListening = () {}
cancelListening = await request(
...
But now cancelListening is Null Function() and I'm getting A value of type 'void Function()' can't be assigned to a variable of type 'Null Function()'.
So my questions is:
Is there is a way to explicitly return void in dart? Something like () => Void();
Should I simply ignore this linter rule or there is better way to handle this situation?
Thanks.

You might want to setup an intermediary function to call the received callback. VoidCallback should be a type for functions that specifically return void, instead of null.
VoidCallback? cancelListening;
void stopListening() {
cancelListening?.call();
}
void listen() async {
cancelListening = await request(
query: query,
onResponse: (response) {
streamController.add(response);
stopListening();
},
);
}
Optionally, instead of making cancelListening nullable, you could use the late keyword.
late VoidCallback cancelListening;
void stopListening() {
cancelListening(); // No optional operator `?` needed.
}

Related

Getting type 'Null' is not a subtype of type 'Future<Response>' in Flutter

I'm trying to run a text in flutter using mockito but I have been getting a error of
type 'Null' is not a subtype of type 'Future<Response>'
Below is the code
class MockClient extends Mock implements http.Client {}
void main() {
var client = MockClient();
var sut = AuthApi('http:baseUrl', client);
setUp(() {
client;
sut;
});
group('signin', () {
var credential = Credential(
type: AuthType.email,
email: 'email#email',
password: 'pass',
);
test('should return error when status is not 200', () async {
when(client.post(Uri(), body: anyNamed('body')))
.thenAnswer((_) async => http.Response('{}', 404));
var result = await sut.signIn(credential);
expect(result, isA<ErrorResult>());
});
});
}
I have tried to pass
when(client.post(any, body: anyNamed('body')))
but I got any error of: The argument type 'Null' can't be assigned to the parameter type 'Uri'
Since Mockito migrated to a null safety code, you need to Override the method with a new declaration inside the mock class. At a body of the override method call super.noSuchMethod, passing in an Invocation object which includes all of the values passed to the override, and pass a second argument to super.noSuchMethod, a value which can function as a return value.
Here is an example:
class MockClient extends Mock implements http.Client {
#override
Future<http.Response> post(Uri uri, {String body}) => super.noSuchMethod(Invocation.method(#post, [uri, body]), returnValue: http.Response('{}', 404));
}
Please note that your method parameters may be different

Dart: How to test a function that takes a function as a parameter?

i been trying to unit test a function that takes a function as a parameter the unit test returns null value on the function that im testing so may i ask how to unit test this kind of function in dart.
this is the function that i want to test
final result = await _appStateNotifier.guard(
() => _authService.requestTempPassword(username: credentials.username),
);
and this is how i test it but got an error type 'Null' is not a subtype of type 'Future<Result<ErrorObject, String>>'
when(() => mockAuthService.requestTempPassword(username: tCredentials.username))
.thenAnswer((_) async => successMessage);
when(() => mockStateNotifier.guard(
() => mockAuthService.requestTempPassword(username: tCredentials.username),
),
).thenAnswer((_) async => const Success(successMessage));
await notifier.onRequestTempPassword(credentials: tCredentials);
and this is the guard clause function
Future<Result<ErrorObject, T>> guard<T>(Future<T> Function() function) async {
try {
final data = await future();
return Success(data);
} on FailureException catch (e) {
return Error(e);
} catch (e, s) {
return Error(e);
}
}
thank you
Your Future<Result<ErrorObject, T>> excludes the possibility of having a Null result. If you want to allow Null, then you need to make it nullable, see https://dart.dev/null-safety/understanding-null-safety
I'm not fluent with Flutter, so the syntax might be off, but as far as I understand, you could change that to
Future<Result<ErrorObject, T>>?
in order to make it nullable. Let me know if I'm totally off with the syntax.
EDIT
It turns out that the solution finally applied was putting the when method in the setpup function before the test run, as #Ken Verganio described in the comment section.

Return type 'Null' is not a subtype of type 'Future<void>' in mocktail

I am trying to test cash articles with HIVE package put it throws a type 'Null' is not a subtype >of type 'Future
I stubed it but I don't know why
test:
group("cache last gotten articles", () {
test('should cache the last gotten articles', () async {
// arrange
final expectedJsonArticles = jsonEncode(fixture('cached_articles'));
when(() => mockHive.openBox(articles))
.thenAnswer((_) async => mockHiveBox);
when(() => mockHiveBox.put(articles, expectedJsonArticles)).thenAnswer((_) async =>true);
print(mockHiveBox.put(articles, expectedJsonArticles).runtimeType) ;
final x = mockHiveBox.put(articles, expectedJsonArticles);
// act
await articleLocaleDataSourceImpl.cacheArticleLocale(tArticlesList);
// assert
verify(()=>x).called(1);
verify(() => mockHive.openBox(articles)).called(1);
});
});
function:
Future<void> cacheArticleLocale(List<ArticleEntity> articles) async {
final box = await hive.openBox(LocaleDbKeys.articleBox);
final Map<String, dynamic> parsedArticles = {};
parsedArticles['articles'] =
articles.map((article) => (article as ArticleModel).toJson()).toList();
box.put(
LocaleDbKeys.articleBox, jsonEncode(parsedArticles['articles']));
}
I solve it...
the problem was with the data I put on put expectedJsonArticles on the test file and the data on the production file
mockHiveBox.put(articles, expectedJsonArticles)
box.put(LocaleDbKeys.articleBox, jsonEncode(parsedArticles['articles']));
is not the same
but the error message tells me that I didn't stub this!
in case you faced this error this will help you
another case
if you didn't stub a function it will return a null value instead
please check this:
https://pub.dev/packages/mocktail#:~:text=type%20%27Null%27%20is%20not%20a%20subtype%20of%20type%20%27Future%3Cvoid%3E%27

Flutter Future<void> vs Future<Null> vs void

What is the main difference between:
Future<void> function(){}
Future<Null> function(){}
void function() {}
funtion(){}
Sometimes I use void or future when calling the API but I don't really know what the main difference is and when is the right time to use it?
Future<void> function() {}
Defines an asynchronous function that ultimately returns nothing but can notify callers when it eventually completes. Also see: What's the difference between returning void vs returning Future?
Future<Null> function() {}
Defines an asynchronous function that ultimately returns null when it eventually completes. Don't use this; this is an archaic form of Future<void>. It predates Dart 2 and was necessary because void was not yet a proper type, and there was no mechanism for indicating that a Future should return nothing. Also see: Dart 2: Legacy of the void
void function() {}
Defines a function that returns nothing. If the function does asynchronous work, callers will not be able to directly tell when it is complete.
function() {}
Defines a function with an unspecified return type. The return type is implicitly dynamic, which means that the function can return anything. Don't do this since it does not convey intent; readers will not be able to tell if the return type was omitted intentionally or accidentally. It also will trigger the always_declare_return_types lint. If you actually want to return a dynamic type, you should explicitly use dynamic function() {} instead.
By default, a function likes function() {} returns a null pointer value.
Use this archetype when your function not return anything and it's not marked as async:
function() { // <- not async
// ... some code
// ... don't use return
}
Optionally, you can specify not return values using void function() {} sintaxis. It's same at the function() {} but if you try to assign a value after calling you will get an error in compile time:
Error: This expression has type 'void' and can't be used.
Personally, i recommend this approach if you really don't have a return value and the function it's not async.
Note that you can use void in normal and async functions.
A function likes Future<void> function() async {} is for asynchronous function thats returns a Future<void> object.
I personally recommend the void function() async {} only if you don't use await ot then on call your function, otherwise, use Future <void> function() async {}.
An examples:
Future<void> myFunction() async {
await Future.delayed(Duration(seconds: 2));
print('Hello');
}
void main() async {
print(myFunction()); // This works and prints
// Instance of '_Future<void>'
// Hello
// Use this approach if you use this:
myFunction().then(() {
print('Then myFunction call ended');
})
// or this
await myFunction();
print('Then myFunction call ended');
}
void myFunction() async {
await Future.delayed(Duration(seconds: 2));
print('Hello');
}
void main() async {
print(myFunction()); // This not works
// The compile fails and show
// Error: This expression has type 'void' and can't be used.
// In this case you only can call myFunction like this
myFunction();
// This doesn't works (Compilation Error)
myFunction().then(() {
print('Then myFunction call ended');
});
// This doesn't works (Compilation Error)
await myFunction();
print('Then myFunction call ended');
}
A function likes Future<Null> function() async {} returns a Future<null> object. Use it whenever you return null. It's not recommended to use it because class Null not extends from Object and anything you return marks an error (except statements thats returns a null or explicit null value):
Future<Null> myFunction() async {
await Future.delayed(Duration(seconds: 2));
print('Hello');
// Ok
return (() => null)();
// Ok
return null;
}

Perform async operation on list in dart

I have a problem in which I have to map some elements of a list (here types) into some other elements of the same type but with an async operation.
Future<String> getData() async {
return await "hi";
}
void main() {
List<String> types = ["", "", ""];
List<String> otherTypes = types.map((e) async {
return await getData();
}).toList();
}
But the code will not compile with the following error.
Error compiling to JavaScript:
main.dart:9:6:
Error: A value of type 'List<Future<String>>' can't be assigned to a variable of type 'List<String>'.
- 'List' is from 'dart:core'.
- 'Future' is from 'dart:async'.
}).toList();
^
Error: Compilation failed.
PS: I tried above code already on dartpad.dev.
List<Future> cannot be converted to Future<List> without using another for loop and alternatively you can create a list and use conventional for each loop. example is follows
Future<String> getData() async {
return await "hi";
}
void main() async{
List<String> types = ["", "", ""];
List<String> otherTypes = List();
for(var s in types)
otherTypes.add(await getData());
}
P.S. future value can be accessed only with async function, or else you have to use (future value).then() call back.