I'm trying to mock firestore call with a mocked user.
Using https://pub.dev/packages/fake_cloud_firestore and https://pub.dev/packages/firebase_auth_mocks.
but im getting the error:
NoSuchMethodError: Class 'MockUser' has no instance method 'reload' with matching arguments.
Receiver: Instance of 'MockUser'
Tried calling: reload()
Found: reload() => Future
My method:
Future<String> getHistory(
FirebaseAuth firebaseAuth, FirebaseFirestore firestore) async {
String title = "";
var user = firebaseAuth.currentUser;
user.reload();
if (user != null) {
await firestore
.collection('users')
.doc(user.uid)
.collection('history')
.get()
.then((QuerySnapshot querySnapshot) {
if (querySnapshot.docs.isNotEmpty) {
title = querySnapshot.docs.single.get('title');
}
}).catchError((error) => print(error));
}
return title;
}
and the test:
test("history", () async {
final mockFirestore = FakeFirebaseFirestore();
HistoryFirebase historyFirebase;
String historyTitle="";
final user = MockUser(
isAnonymous: false,
uid: 'someuid',
email: 'bob#somedomain.com',
displayName: 'Bob',
);
var mockFirebaseAuth = MockFirebaseAuth(mockUser: user, signedIn: true);
await instance.collection('users').doc('someuid').collection('history').add({
'title': "Title num.1",
})
await historyFirebase.getHistory(mockFirebaseAuth, mockFirestore).then((value) => historyTitle=value);
expect(historyTitle, "Title num.1");
});
Is there any way to mock the user.reload() or to ignore it ?
I contacted the developer of https://pub.dev/packages/firebase_auth_mocks and he implemented the reload () method.
everything works now
Related
I built the google signin and email password signup app using flutter,
I want when user log to application then user's "uid" and "email" save in shared preference.
In google login I built when login then pass the boolean value and pass uid and email to shared preference. Then when users close app and when reopen then login in home screen and can get uid and email.
But when user signup or login using email password then can not pass the boolean value and uid and email to google login shared preference. In below I'll mentioned google login method and email password method.
googlelogin method
// handling google sigin in
Future handleGoogleSignIn() async {
final sp = context.read<SignInProvider>();
final ip = context.read<InternetProvider>();
await ip.checkInternetConnection();
if (ip.hasInternet == false) {
openSnackbar(context, 'Check your Internet connection', Colors.red);
googleController.reset();
} else {
await sp.signInWithGoogle().then((value) {
if (sp.hasError == true) {
openSnackbar(context, sp.errorCode.toString(), Colors.white);
googleController.reset();
} else {
// checking whether user exists or not
sp.checkUserExists().then((value) async {
if (value == true) {
// user exists
await sp.getUserDataFromFirestore(sp.uid).then((value) => sp
.saveDataToSharedPreferences()
.then((value) => sp.setSignIn().then((value) {
googleController.success();
handleAfterSignIn();
})));
} else {
// user does not exist
sp.saveDataToFirestore().then((value) => sp
.saveDataToSharedPreferences()
.then((value) => sp.setSignIn().then((value) {
googleController.success();
handleAfterSignIn();
})));
}
});
}
});
}
//login function
}
saveDataToSharedPreferences method and setSignIn boolean value (it has in a siginprovider class in another file)
class SignInProvider extends ChangeNotifier {
//instantiate of firebaseAuth, facebook and google
final FirebaseAuth firebaseAuth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
bool _isSignedIn = false;
bool get isSignedIn => _isSignedIn;
//hasError, errorCode, provider,uid,email,name,imageUrl
bool _hasError = false;
bool get hasError => _hasError;
String? _errorCode;
String? get errorCode => _errorCode;
String? _uid;
String? get uid => _uid;
String? _email;
String? get email => _email;
SignInProvider() {
checkSignInUser();
}
Future checkSignInUser() async {
final SharedPreferences s = await SharedPreferences.getInstance();
_isSignedIn = s.getBool('signed_in') ?? false;
notifyListeners();
}
Future setSignIn() async {
final SharedPreferences s = await SharedPreferences.getInstance();
s.setBool('signed_in', true);
_isSignedIn = true;
notifyListeners();
}
Future saveDataToSharedPreferences() async {
final SharedPreferences s = await SharedPreferences.getInstance();
await s.setString('email', _email!);
await s.setString('uid', _uid!);
notifyListeners();
}
Future getDataFromSharedPreferences() async {
final SharedPreferences s = await SharedPreferences.getInstance();
_email = s.getString('email');
_uid = s.getString('uid');
notifyListeners();
}
}
**email password signup**
void signUp(String email, String password) async {
if (_formkey.currentState!.validate()) {
await _auth
.createUserWithEmailAndPassword(email: email, password: password)
.saveDataToSharedPreferences()
.sp.setSignIn()
.then((value) => {postDetailsToFirestore()})
.catchError((e) {
Fluttertoast.showToast(msg: e!.message);
});
}
}
in email password signup has postDetailsToFirestore method
postDetailsToFirestore() async {
// calling our fireStore
//calling our user model
// sending these values
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
User? user = _auth.currentUser;
UserModel userModel = UserModel();
if (user != null) {
//writing all the values
userModel.email = user?.email;
userModel.uid = user?.uid;
await firebaseFirestore
.collection("users")
.doc(user?.uid)
.set(userModel.toMap());
Fluttertoast.showToast(msg: "Account created successfully ");
Navigator.pushAndRemoveUntil(
(context),
MaterialPageRoute(builder: (context) => HomeScreen()),
(route) => false);
}
}
in email password signup I called
these 2 methods but show this error
when signup how to pass uid and emaill to saveDataToSharedPreferences method and pass sp.setSignIn() boolean like as in google signing?
You are trying to use method saveDataToSharedPreferences from Future class, not from auth. For fix this issue, call prefs from main object:
final result = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
result.saveDataToSharedPreferences()
.sp.setSignIn()
// etc.
I am trying to login with google and have the data mapped to a firebase user. I'm using getX. So far this works HOWEVER it automatically logs me back in as the same user if I logout and then try to log back in again. I'll send the code for my login page and the page where the logout button is if needed, but I suspect this may have to do with my AuthController which I've included here
class AuthController extends GetxController {
static AuthController instance = Get.find();
GoogleSignIn googleSignIn = GoogleSignIn();
Rxn<User> firebaseUser = Rxn<User>();
Rxn<UserModel> firestoreUser = Rxn<UserModel>();
final RxBool admin = false.obs;
String usersCollection = "users";
#override
void onReady() async {
//run every time auth state changes
ever(firebaseUser, handleAuthChanged);
firebaseUser.bindStream(user);
super.onReady();
}
handleAuthChanged(firebaseUser) async {
//get user data from firestore
if (firebaseUser?.uid != null) {
firestoreUser.bindStream(streamFirestoreUser());
print("You are logged in as ${firebaseUser.email}");
await isAdmin();
}
//this is for new users
if (firebaseUser == null) {
print('Send to signin');
Get.offAll(LoginPage());
} else {
Get.offAll(AppSetup());
}
}
// Firebase user one-time fetch
Future<User> get getUser async => auth.currentUser!;
// Firebase user a realtime stream
Stream<User?> get user => auth.authStateChanges();
//Streams the firestore user from the firestore collection
Stream<UserModel> streamFirestoreUser() {
print('streamFirestoreUser()');
return firebaseFirestore
.doc('/users/${firebaseUser.value!.uid}')
.snapshots()
.map((snapshot) => UserModel.fromSnapshot(snapshot));
}
//get the firestore user from the firestore collection
Future<UserModel> getFirestoreUser() {
return firebaseFirestore
.doc('/users/${firebaseUser.value!.uid}')
.get()
.then((documentSnapshot) => UserModel.fromSnapshot(documentSnapshot));
}
//Method to handle user sign in using email and password
// User registration using email and password
googleLogin(BuildContext context) async {
final GoogleSignInAccount? googleUser = await googleSignIn.signIn();
if (googleUser != null) {
final googleAuth = await googleUser.authentication;
if (googleAuth.accessToken != null && googleAuth.idToken != null) {
try {
await auth
.signInWithCredential(
GoogleAuthProvider.credential(
idToken: googleAuth.idToken,
accessToken: googleAuth.accessToken),
)
.then((firebaseUser) async {
print('uid: ' + firebaseUser.user!.uid.toString());
print('email: ' + firebaseUser.user!.email.toString());
//create the new user object from the login modelled data
UserModel _newUser = UserModel(
id: firebaseUser.user!.uid,
email: firebaseUser.user!.email!,
name: firebaseUser.user!.email!,
photoURL: firebaseUser.user!.photoURL,
cart: [],
);
//create the user in firestore here with the _addUserToFirestore function
_updateUserFirestore(_newUser, firebaseUser.user!);
});
} on FirebaseAuthException catch (error) {
Get.snackbar('auth.signUpErrorTitle'.tr, error.message!,
snackPosition: SnackPosition.BOTTOM,
duration: Duration(seconds: 10),
backgroundColor: Get.theme.snackBarTheme.backgroundColor,
colorText: Get.theme.snackBarTheme.actionTextColor);
}
}
}
}
void _updateUserFirestore(UserModel user, User _firebaseUser) {
firebaseFirestore.doc('/users/${_firebaseUser.uid}').update(user.toJson());
update();
}
updateUserData(Map<String, dynamic> data) {
logger.i("UPDATED");
firebaseFirestore
.collection(usersCollection)
.doc(firebaseUser.value!.uid)
.update(data);
}
//check if user is an admin user
isAdmin() async {
await getUser.then((user) async {
DocumentSnapshot adminRef =
await firebaseFirestore.collection('admin').doc(user.uid).get();
if (adminRef.exists) {
admin.value = true;
} else {
admin.value = false;
}
update();
});
}
// This is the proper sign out method!
Future<void> signOut() {
return auth.signOut();
}
}
Simply add this line of code into your logout function
> await googleSignIn.signOut()
I tried this way, but i'm getting an error.
The error:
The method 'data' isn't defined for the type 'CollectionReference'. (undefined_method at [myapp] android\app\lib\useracc.dart:32)
void getData() async{
User? user = await FirebaseAuth.instance.currentUser;
var vari =FirebaseFirestore.instance.collection("users");
setState (() {
name = vari.data()['firstname'];
}
);
}
Signup/Register Page
Future<User?> _register(String fname,String lname ,String email, String password) async{
FirebaseAuth _auth = FirebaseAuth.instance;
FirebaseFirestore _firestore = FirebaseFirestore.instance;
try {
UserCredential userCrendetial = await _auth.createUserWithEmailAndPassword(email: emailController.text, password: passwordController.text);
print("Account created Succesfull");
userCrendetial.user!.updateDisplayName(fname);
userCrendetial.user!.updateDisplayName(lname);
await _firestore.collection('users').doc(_auth.currentUser!.uid).set({
"firstname": fname,
"lastname" : lname,
"email": email,
"uid": _auth.currentUser!.uid,
});
return userCrendetial.user;
} catch (e) {
print(e);
return null;
}
}
This is the user account from where i want to fetch info:
Please help. I'm struck here a long time.
You should retrieve the currentUser document then access its data:
void getData() async{
var vari = await FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser.uid)
.get();
setState (() {
name = vari.data()['firstname'];
});
}
if you've saved your user's details in firestore and its document id is the same as that of user ID (which is preferred for ease of access and control), then:
var vari =FirebaseFirestore.instance.collection("users").doc(user!.uid).get();
This gets the document of the user, and the type is DocumentSnapshot.
Map<String,dynamic> userData = vari as Map<String,dynamic>;
now userData is stored in form of Map. suppose you want to access their 'name', so the syntax now goes like userData['name'].
Similarly other fields can be accessed from variable. It's preferred to store userData in a Provider to access it's contents anywhere in your app.
Full code snippet
void getData() async{
User? user = await FirebaseAuth.instance.currentUser;
var vari =FirebaseFirestore.instance.collection("users").doc(user!.uid).get();
Map<String,dynamic> userData = vari as Map<String,dynamic>;
setState (() {
name = userData['firstname']; //or name = userData['name']
}
);
}
I'm currently facing this error message at login, my registration function works fine. but can't seem to figure out why my login keeps bringing this error. I would appreciate if I can be pointed to where my mistake is coming from.
void loginUser() async {
User user;
await _auth
.signInWithEmailAndPassword(email: email.text, password: password.text)
.then((value) {
setState(() {
loading = false;
});
return value;
}).catchError((error) {
Navigator.pop(context);
Get.defaultDialog(title: 'Error in Login');
});
if (user != null) {
readData(user).then((value) => Get.toNamed(homeRoute));
}
}
Future readData(User user) async {
FirebaseFirestore.instance
.collection('users')
.doc(user.uid)
.get()
.then((result) async {
await App.sharedPreferences.setString('uid', result.get('uid'));
await App.sharedPreferences.setString('email', result.get('email'));
await App.sharedPreferences.setString('fullname', result.get('fullname'));
await App.sharedPreferences.setString('bvn', result.get('bvn'));
});
}
Here's my Registration function
void _registerUser() async {
User user;
await _auth
.createUserWithEmailAndPassword(
email: email.text, password: password.text)
.then((value) {
user = value.user;
}).catchError((error) {
Navigator.pop(context);
Get.defaultDialog(title: 'Error in registration');
});
if (user != null) {
saveToFirestore(user).then((value) => Get.toNamed(homeRoute));
}
}
Future saveToFirestore(User user) async {
FirebaseFirestore.instance.collection('users').doc(user.uid).set({
'uid': user.uid,
'fullname': fullname.text.trim(),
'email': user.email,
'bvn': bvn.text
});
await App.sharedPreferences.setString('uid', user.uid);
await App.sharedPreferences.setString('email', user.email);
await App.sharedPreferences.setString('fullname', fullname.text);
await App.sharedPreferences.setString('bvn', bvn.text);
}
Change
User user;
await _auth
to User user = await _auth....
And in your FireStore query, use
Future readData(User user) async {
FirebaseFirestore.instance
.collection('users')
.doc(user.user.uid) // instead of user.uid
.get()
Everywhere with user.uid change it to user.user.uid.
I have created function get user and set it's data from firestore, this is the code of function getUser.
Future<User> getUser(String uid) async{
User user;
_firestore
.collection(USERS_COLLECTION)
.where("uid", isEqualTo: uid.toString())
.getDocuments()
.then((doc) {
_firestore
.document('/$USERS_COLLECTION/${doc.documents[0].documentID}')
.get()
.then((userData) {
user = User(
name: userData.data["name"],
username: userData.data["username"],
profilePhoto: userData.data["profilePic"],
);
}).catchError((e) {
print(e);
});
});
return user;
}
Then I have my profile page I have created function to set user from getUser() to current user like this:
User me;
String myUID = "t4skPFRXcLPxAWvhHpaiPOfsrPI3";
#override
void initState() {
super.initState();
setUser();
}
......
Future<void> setUser() async{
me = await userManagment.getUser(myUID);
}
But when I try to use print for example print(me.name) does not anything happen, when I try to set url of networkImage to me.profilePhoto there is an error showing tell me the url it's null.
Don't mix async-await and .then syntax. It's something that can be done, but it will more likely confuse than help. Adding the async modifier to your function is doing nothing since your function does not use await.
Consider the following options:
With .then
Future<User> getUser(String uid) {
return _firestore
.collection(USERS_COLLECTION)
.where("uid", isEqualTo: uid.toString())
.getDocuments()
.then((doc) {
return _firestore
.document('/$USERS_COLLECTION/${doc.documents[0].documentID}')
.get()
.then((userData) {
return User(
name: userData.data["name"],
username: userData.data["username"],
profilePhoto: userData.data["profilePic"],
);
}).catchError((e) {
print(e);
});
});
}
With async-await
Future<User> getUser(String uid) async{
User user;
try{
var doc = await _firestore
.collection(USERS_COLLECTION)
.where("uid", isEqualTo: uid.toString())
.getDocuments();
var userData = await _firestore
.document('/$USERS_COLLECTION/${doc.documents[0].documentID}')
.get();
user = User(
name: userData.data["name"],
username: userData.data["username"],
profilePhoto: userData.data["profilePic"],
);
}
catch(e) {
print(e);
}
return user;
}