Flutter test future throws an error, can't test exception - flutter

I'm looking to test a function that returns a Future
however when you pass in bad parameters it throws an exception.
I'm trying to write tests for this, however when I run
test("When a new practice is created with an empty name, an exception is thrown", () async {
//arrange
//act
//assert
expect(newUserRepository.saveUser("", "Test"), throwsA(TypeMatcher<Exception>()));
});
I get the following
Expected: throws <Instance of 'TypeMatcher<Exception>'>
Actual: <Instance of 'Future<void>'>
Which: threw ?:<Exception>
Any way I can get it to pass this test?
My saveUser function
Future<void> saveUser(String username, String practiceName) async {
if (username == null || username.isEmpty || practiceName == null || practiceName.isEmpty) {
throw Exception("Unable to save empty username or pracice name");
}
var firebaseUser = await userRepository.getFirebaseUser();
var newUser = DomainUser(userName: username, email: firebaseUser.email);
await userRepository.saveUser(newUser);
var newPractice = DomainPractice(users: [newUser.email], practiceName: practiceName);
await practiceRepository.savePractice(newPractice);
return;
}

Related

Error encountered with this snippet "FirebaseDynamicLinks.instance.onLink" .The expression doesn't evaluate to a function, so it can't be invoked

Also encountered this error : Undefined class 'OnLinkErrorException'.
Try changing the name to the name of an existing class, or creating a class with the name 'OnLinkErrorException'
It only happened because earlier I wasnt able to initialize my firebase due to this error :
PlatformException (PlatformException(channel-error, Unable to establish connection on channel., null, null)).So I upgraded my firebase dependencies but now I am encountering this error.
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData? dynamicLink) async {
// ignore: prefer_final_locals
Uri? deepLink = dynamicLink?.link;
if (deepLink != null) {
// final String path = deepLink.path;
// final List<String> pathList = path.split('=');
if (itemId == '') {
final Map<String, String> queryParams = deepLink.queryParameters;
if (queryParams.isNotEmpty) {
itemId = queryParams['item_id'];
}
final ProductDetailIntentHolder holder = ProductDetailIntentHolder(
productId: itemId,
heroTagImage: '-1' + itemId! + PsConst.HERO_TAG__IMAGE,
heroTagTitle: '-1' + itemId! + PsConst.HERO_TAG__TITLE);
Navigator.pushNamed(context, RoutePaths.productDetail,
arguments: holder);
}
}
debugPrint('DynamicLinks onLink $deepLink');
}, onError: (OnLinkErrorException e) async {
debugPrint('DynamicLinks onError $e');
});

Error message when doing unit test in flutter

I am a beginer in flutter and I have to write some unit test for a project but I get an error and can't find the solution to solve it.
Here is the function that I want to test:
addUser(name, password) async{
if (name.toString().isEmpty || password.toString().isEmpty) {
return "Error";
}
return await dio.post('https://test.test.com/adduser',
data: {"name": name, "password": password},
options: Options(contentType: Headers.formUrlEncodedContentType));
}
Here is the test code:
void main() {
test('Empty field', () {
var auth = AuthService();
String result = auth.addUser("", "");
expect(result, "Error");
});
}
And I get this error:
type 'Future<dynamic>' is not a subtype of type 'String'
test\widget_test.dart 17:18 main.<fn>
Can someone help to find where I made a mistake please ? Thanks for yours answers.
There is a missing await in the auth.addUser call and also a missing async in the test function.
It should look like this:
void main() {
text('Emtpy field', () async { // <- Here
var auth = AuthService();
String result = await auth.addUser("", ""); // <- Here
expect(result, "Error");
});
}

Flutter mockito post always return null

I'm trying to test my code that makes a post to login from an API using a mocked http client, but instead of returning what I asked for, it returns null, I did the same test but changing the endpoint and method to GET and it worked perfectly. I'm currently using flutter's http to make the requests, but I've already tested it with Dio and the result was the same, below is my code
Future<String> signIn(String email, String password) async {
final Map<String, dynamic> body = {"email": email, "password": password};
final String url = url_base + Urls.auth_login;
final Map<String, String> customHeader = {
"Content-type": "application/json",
};
String returnCode;
try {
var x = jsonEncode(body);
http.Response response = await client.post(Uri.parse(url), body: x, headers: customHeader);
var parsedJson = json.decode(response.data);
if (parsedJson.containsKey("token")) {
returnCode = parsedJson["token"];
} else {
returnCode = parsedJson["non_field_errors"][0];
}
}catch (e) {
throw ServerException();
}
if (returnCode == null) {
throw ServerException();
} else {
return returnCode;
}
}
and the test case:
class ClientMock extends Mock implements http.Client {}
void main() {
RemoteData remoteData;
group('Test signIn', () {
test('Login with email and wrong password', () async {
final clientMock = ClientMock();
remoteData = RemoteData(client: clientMock);
String jsonMockResponse =
'{non_field_errors: [Unable to log in with provided credentials.]}';
when(clientMock.post(any))
.thenAnswer((_) async => http.Response(jsonMockResponse, 400));
String loginReturn =
await remoteData.signIn('test#email.com', 'password123');
expect(loginReturn,throwsA(const TypeMatcher<ServerException>()));
});
}
I've already tested some things like changing 'any' for exactly the same thing the real function gets and it didn't work either.
The actual test return 'Instance of 'ServerException'', an in debug mode i could see that the return is null, and the last if is the one who throws this exception.

Getting a document from Firestore results in "The method 'data' was called on null. Receiver: null Tried calling: data())"

I am new to Flutter and trying to get a document from a collection; there is no error in the code but, still, the document is not obtained.
I am trying to return a variable having String in the method _onPressed() but I'm stuck at that point.
Future _onPressed() async{
var msg;
await db.collection('Messages').doc(widget.brew.id).get().then((value){
print(value.data()['Message']);
return value.data()['Message'];
});
msg = msg.data()['Message'];
return msg;
}
Wrong assignment done here. change the above code
Future _onPressed() async{
var docSnap = await db.collection('Messages').doc(widget.brew.id).get();
if (docSnap.exists) {
print('Document data: ${documentSnapshot.data()}');
return docSnap.data()['Message'];
} else {
print('Document does not exist on the database');
return docSnap.data()['Message'];
}
}
In current snippet, msg.data() throws the err as the msg was null at that time.

How to test exceptions thrown from an async generator?

I have a repository class in my Flutter app with the following method that returns a Stream:
Stream<List<Product>> getProducts() async* {
var currentUser = await this._auth.currentUser();
if (currentUser == null) {
throw AuthException('not_logged_in',
'No current user found probably because user is not logged in.');
}
yield* ...
}
As per this answer on SO, the above way to throw an exception from an async generator function looks fine.
How do I write my test (with test package) so to test the exception thrown by this method?
Something like this does not work:
test('should throw exception when user is not logged in', () {
final _authSignedOut = MockFirebaseAuth(signedIn: false);
final _repoWihoutUser = FirebaseProductRepository(
storeInstance: _store,
authInstance: _authSignedOut,
);
var products = _repoWihoutUser.getProducts();
expect(products, emitsError(AuthException));
});
Nor this:
expect(callback, emitsError(throwsA(predicate((e) => e is AuthException))));
Not even this:
var callback = () {
_repoWihoutUser.getProducts();
};
expect(callback, emitsError(throwsA(predicate((e) => e is AuthException))));
You're close. Your first attempt:
expect(products, emitsError(AuthException));
doesn't work because emitsError takes a Matcher as its argument, so you can't pass it a type directly. Instead, you need to use the isA<T>() Matcher:
expect(products, emitsError(isA<AuthException>()));