How to Perform E2E login process and test more pages - reactjs

I'm using testcafe in an Electron-React app trying to integrate some basic e2e tests.
The test works, however it's not relevant.
I would like to know i can pass the login page and have extra clicks on the other pages.
App.e2e.js
import { Selector } from 'testcafe';
import { getPageTitle, getPageUrl, fixture, test, login } from './helpers';
const assertNoConsoleErrors = async browser => {
const { error } = await browser.getBrowserConsoleMessages();
await browser.expect(error).eql([]);
};
fixture`Electron Client`.page('../../app/app.html').afterEach(assertNoConsoleErrors);
test('should atempt login without credentials', async browser => {
await login({
email: 'name#name.com',
password: '123456',
browser,
});
await browser
.click('button[type=submit]')
.expect(getPageUrl())
.contains('/login');
const email = Selector('[name="email"]');
const password = Selector('[name="password"]');
await browser.expect(email.value).eql('name#name.com');
await browser.expect(password.value).eql('123456');
});
helpers.js
import { ClientFunction } from 'testcafe';
export const getPageTitle = ClientFunction(() => document.title);
export const fixture = (...args) => global.fixture(...args);
export const test = (...args) => global.test(...args);
export const getPageUrl = ClientFunction(() => window.location.href);
export const login = async ({ email, password, browser }) => {
await browser.typeText('[data-test="email"]', email);
await browser.typeText('[data-test="password"]', password);
await browser.click('button[type=submit]');
};

You can use the User Roles API to meet your requirements.
See an example below.
const loginAsTestUser = Role('../../app/app.html', async t => {
await t
.typeText('[data-test="email"]', email)
.typeText('[data-test="password"]', password)
.click('button[type=submit]');
});
fixture`Electron Client`
.page('../../app/app.html')
.beforeEach(async t => {
await t.useRole(loginAsTestUser);
});
.afterEach(assertNoConsoleErrors);
test('should atempt login without credentials', async browser => {
await browser
.click('button[type=submit]')
.expect(getPageUrl())
.contains('/login');
const email = Selector('[name="email"]');
const password = Selector('[name="password"]');
await browser.expect(email.value).eql('name#name.com');
await browser.expect(password.value).eql('123456');
});

Related

How to mock AWS Auth.sign up/in API inside reactJs project

I'm starting with AWS-Cognito and the reactJs app, the service is working very well.
I want to test this function using react-testing-library and Jest.
I don't know how to mock the response Promise received from Auth.signUp(email, password) API
const Handelsregister = async (event) => {
event.preventDefault();
try {
const user = await Auth.signUp(email, password);
console.log("Registred user info", user);
} catch (e) {
console.log(e)
}
}
My test file looks like this :
it('should render sign up component', async function () {
const handleRegisterSpy = jest.fn();
const user = {
email: 'test#PWDil.com',
pwd: 'SignUp#2022'
};
const {getByTestId} = render(<Authentication screen={1} setScreen={setScreenSpy()} handleRegister={handleRegisterSpy()}/>);
const email = getByTestId("email");
const passwd = getByTestId("pwd");
const signUp = getByTestId("btnSignUpField");
expect(email).toBeInTheDocument();
expect(passwd).toBeInTheDocument();
expect(signUp).toBeInTheDocument();
fireEvent.change(email, {target: {value: user.emailValue}});
fireEvent.change(passwd, {target: {value: user.pwdValue}});
expect(email).toHaveAttribute("type", "email");
expect(email.value).toEqual("test#gmail.com");
expect(passwd).toHaveAttribute("type", "password");
expect(passwd.value).toEqual("SignUp#2022");
fireEvent.click(signUp);
expect(handleRegisterSpy).toHaveBeenCalled();
});
My question is, how can I mock the Auth.SignUp behavior to test both responses
mockResolvedValue and mockRejectedValue

How to add phone number to a logged in user(created with email and password) in firebase Auth in react?

I am using firebasev9 authentication for my react project. I have used email authentication for logging in/signing up a user. I want to add phone number too in the user but I am doing all the right steps but when I call updatePhoneNumber with user and phone crediential it throws an error and doesnt add phone number. I am updating the displayName too within the same function which works fine.
I have enabled phone signin in firebase dashboard
The error I am getting is this:
(https://i.postimg.cc/yY55Qzg2/Screenshot-2022-06-25-200735.jpg)
This is my signup function:
const signup = async (email, password, displayName, phoneNumber,phoneCrediential, userType) => {
setError(null);
setIsPending(true);
try {
const res = await createUserWithEmailAndPassword(
auth,
email,
password
);
console.log(res.user);
if (!res) {
throw new Error("Could not complete signUp");
}
debugger;
await updateProfile(res.user, { displayName });
**This updatePhonenumber function throws this error flow moves to catch block**
const resPhone = await updatePhoneNumber(auth.currentUser, phoneCrediential );
console.log(resPhone)
dispatch({ type: "LOGIN", payload: res.user });
console.log(res.user)
addDocument({
name: res.user.displayName,
email: res.user.email,
uid: res.user.uid,
type: userType,
});
if (!isCancelled) {
setError(null);
setIsPending(false);
}
} catch (err) {
if (!isCancelled) {
console.log(err.message);
setError(err.message);
setIsPending(false);
}
}
};
In my component, I take phone number, generate Otp, and take otp and pass phoneCredential to the signup function:
const [verificationIdState, setVerificationIdState] = useState(null);
const [phoneCredientialState, setPhoneCredientialState] = useState(null);
const handleRecaptcha = () => {
window.recaptchaVerifier = new RecaptchaVerifier(
"sign-in-button",
{
size: "invisible",
callback: (response) => {
// reCAPTCHA solved
},
},
auth
);
};
const handleGetOTP = () => {
handleRecaptcha();
const phoneNumber = "+91" + userPhoneNumber;
const applicationVerifier = window.recaptchaVerifier;
const provider = new PhoneAuthProvider(auth);
const verificationId = provider.verifyPhoneNumber(
phoneNumber,
applicationVerifier
);
if (verificationId) {
setVerificationIdState(verificationId);
}
};
const handleOTPSubmit = () => {
const phoneCredential = PhoneAuthProvider.credential(
verificationIdState,
userOTP
);
if (phoneCredential) {
setPhoneCredientialState(phoneCredential);
console.log(phoneCredential);
}
};
//Base Register
const handleRegisterSubmit = (e) => {
e.preventDefault();
signup(
userEmail,
userPassword,
userName,
userPhoneNumber,
phoneCredientialState,
userType
);
};

reactjs firebase authentication update profile does not refresh

In my reactJS app, I am using firebase authentication. I can login successfully. I tried to update user profile, like photoUrl and displayName as follows. Data is updated but I can't get the latest update data unless refresh the page.
Please ignore updateCurrentUser function. it is an API call to update display name and photo URL to database.
after updateCurrentUser function callback, I call again
const auth = getAuth();
const currentUser = getAuth().currentUser;
But updated display name and photo is still old data in currentUser. I want to know how can I update profile. I am showing the user info in the header section as well.
updateUser function
async function updateUser(updateUserId, displayName, photoUrl) {
const auth = getAuth();
const currentUser = getAuth().currentUser;
return await updateProfile(auth.currentUser, {
displayName: displayName,
photoUrl: photoUrl,
})
.then(async function () {
const auth = getAuth();
if (auth.currentUser != null) {
updateCurrentUser(updateUserId, displayName, photoUrl)
.then((updatedUser) => {
if (updatedUser) {
const auth = getAuth();
const currentUser = getAuth().currentUser;
setUser(currentUser);
setAccessToken(currentUser.getIdToken(true));
store.dispatch(saveUser(currentUser));
} else {
setUser(null);
setAccessToken(null);
store.dispatch(saveUser(null));
}
})
.catch((error) => {
throw error;
});
}
})
.catch((error) => {
throw error;
});
}
Firebase show updates of user profile only after refresh and automatically after login/logout operation. The only way you can do this will be by using the same values you submitted
async function updateUser(updateUserId, displayName, photoUrl) {
const auth = getAuth();
const currentUser = getAuth().currentUser;
return await updateProfile(auth.currentUser, {
displayName: displayName,
photoUrl: photoUrl,
})
.then(async function () {
const auth = getAuth();
if (auth.currentUser != null) {
updateCurrentUser(updateUserId, displayName, photoUrl)
.then((updatedUser) => {
if (updatedUser) {
const auth = getAuth();
let currentUser = getAuth().currentUser;
currentUser.displayName = displayName;
currentUser.photoUrl = photoUrl
setUser(currentUser);
setAccessToken(currentUser.getIdToken(true));
store.dispatch(saveUser(currentUser));
} else {
setUser(null);
setAccessToken(null);
store.dispatch(saveUser(null));
}
})
.catch((error) => {
throw error;
});
}
})
.catch((error) => {
throw error;
});
}
I make a silly mistake. It is wrong spelling. It should be photoURL instead of photoUrl. It is working when refresh because, at api server side, need to update user info again. At server side, variable name is correct.

Nextjs - Get protected reuqests from getServerSideProps

I am working with next js app. For backend I use laravel with sanctum autentication. I want to implement credential authentication (username, password) using laravel sanctum and nextjs SPA app. All these working with client side. But I can not access to protected request in getServerSideProps. It requires crsf token.
pages/login.js
import React, { useState } from 'react';
import api from '#/util/api';
import { logIn } from '#/util/auth';
const LogInPage = () => {
const [formInput, setFormInput] = useState({ username: '', password: '' });
const signIn = (e) => {
e.preventDefault();
api()
.get('/sanctum/csrf-cookie')
.then(() => {
api()
.post('/api/login', formInput)
.then((response) => {
if (response.data.error) {
console.log(response.data.error);
} else {
router.push('/')
}
});
});
};
pages/index.js (protected route)
const Home = ({ user }) => {
const [users, setUsers] = useState([]);
useEffect(() => {
api()
.get('/api/users')
.then((response) => {
setUsers(response.data);
});
}, []);
}
Question: How to do it with getServerSideProps? Or how to use this implementation using NextAuth.js? Or maybe need bridge between client to server
export async function getServerSideProps() {
let users = [];
api()
.get('/api/users')
.then((response) => {
users = response.data;
})
.catch((error) => {
console.error(error);
});
return {
props: { users },
};
}
'/api/users' route is protected, requires authentication, so it responds 401 unauthorized

Sending verification email with Firebase and React Native

I am trying to send the validation email upon the account registration, using firebase. The registration is being done successfully but whenever I try to code email verification it gives me an error. Probably because I don't know where to place it. All my firebase methods are on Fire.js, which are the following:
import firebaseKeys from './Config';
import firebase from 'firebase';
require("firebase/firestore");
class Fire {
constructor() {
if (!firebase.apps.length) {
firebase.initializeApp(firebaseKeys);
}
}
addPost = async ({ text, localUri }) => {
const remoteUri = await this.uploadPhotoAsync(localUri, 'photos/${this.uid}/${Date.now()}');
return new Promise((res, rej) => {
this.firestore.collection('posts').add({
text,
uid: this.uid,
timestamp: this.timestamp,
image: remoteUri
})
.then(ref => {
res(ref);
})
.catch(error => {
rej(error);
});
});
}
uploadPhotoAsync = async (uri, filename) => {
return new Promise(async (res, rej) => {
const response = await fetch(uri);
const file = await response.blob();
let upload = firebase
.storage()
.ref(filename)
.put(file);
upload.on(
"state_changed",
snapshot => {},
err => {
rej(err);
},
async () => {
const url = await upload.snapshot.ref.getDownloadURL();
res(url);
}
);
});
}
createUser = async user => {
let remoteUri = null
try {
await firebase.auth().createUserWithEmailAndPassword(user.email, user.password)
//I tried to code it here with user.sendEmailVerification();
let db = this.firestore.collection("users").doc(this.uid)
db.set({
name: user.name,
email: user.email,
avatar: null
})
if (user.avatar) {
remoteUri = await this.uploadPhotoAsync(user.avatar, 'avatars/${this.uid}')
db.set({avatar: remoteUri}, {merge: true});
}
} catch (error) {
alert("Error: ", error);
}
};
get firestore() {
return firebase.firestore();
}
get uid() {
return (firebase.auth().currentUser || {}).uid;
}
get timestamp() {
return Date.now();
}
}
Fire.shared = new Fire();
export default Fire;
The createUserWithEmailAndPassword() method returns a Promise which resolves with a UserCredential AND (as the the doc indicates) "on successful creation of the user account, this user will also be signed in to your application."
So you can easily get the signed in user by using the user property of the UserCredential, and call the sendEmailVerification() method, as follows:
try {
const userCredential = await firebase.auth().createUserWithEmailAndPassword(user.email, user.password);
await userCredential.user.sendEmailVerification();
//In the next line, you should most probably use userCredential.user.uid as the ID of the Firestore document (instead of this.uid)
cont db = this.firestore.collection("users").doc(this.uid);
//...
} catch (...)
Note that you may pass an ActionCodeSettings object to the sendEmailVerification() method, see the doc.

Resources