Cypress login using request method - javascript

I register & login a user, however, when in my test I navigate to a page behind authentication, Cypress fails & takes me back to the login page. From the looks of it, the before function is successfully executed (as verified by the API log). Here is my code:
describe("Dashboard page", () => {
before(() => {
cy.fixture("authUserRegistrationDetail.json").then(userDetail => {
cy.fixture("authUserLoginDetail.json").then(userLoginDetail => {
cy.visit("http://localhost:3000/login");
cy.get(".cookieConsent button").click();
// create a random email for registration
userDetail.email = `${Math.random()
.toString(36)
.slice(-5)}#aaa.aaa`;
// share the email between userLogin & userRegistration obj
userLoginDetail.email = userDetail.email;
// register the user
cy.request("POST", "http://localhost:9000/users/", userDetail)
.its("body")
// login the same user
cy.request("POST", "http://localhost:9000/api-token-auth/", userLoginDetail).then($res => {
cy.request({
url: "http://localhost:9000/loggedinuser/",
headers: {
Authorization: `Token ${$res.body.token}`
}
});
});
});
});
});
// run the test
it("visits the dashboard...", () => {
cy.visit("http://localhost:3000/dashboard/");
cy.get("h2").contains("Your deals");
});
});
Once the code is run, the test fails on assertion and the user is not logged in. Here is the screenshot of the test result. I get a status code 200 when user signs up & then logs in. Why is the user login not persisting in the tests & the dashboard link fails.
EDIT:
I just realised that I am programmatically logging in, however, once logged in, how do I get Cypress browser to recognise the change in state & that the user is logged in. I.e, how do I refresh the Cypress screen to recognise the the user login?

From the above code, it doesn't look like you are preserving the cookie once logged in. Cypress automatically clears all cookies before each test to prevent state from building up. You should be able to do something similar to this:
before(() => {..cy.login() })
beforeEach(() => {
Cypress.Cookies.preserveOnce('session_id', 'remember_token')
})
This cypress doco should provide more context https://docs.cypress.io/api/cypress-api/cookies.html#Preserve-Once

Related

Navigate into 2 pages in the same test

I'm very new in Javascript and Cypress so pardon me if it's something very simple.
What I would like to do is to navigate into 2 pages inside one test.
My test.cy.js file has this code:
describe('Sitop Manager Login Page', () => {
it('opens login page, fill the form and clicks submit', () => {
cy.visit('/login')
cy.get('input[name="username"]').type('admin')
cy.get('input[name="password"]').type('admin')
cy.contains('Login').click()
})
it('Open devices page', () => {
cy.visit('/devices')
cy.wait(500)
cy.get('ix-menu ix-menu-item[tab-icon=cogwheel]').click() //css selector
})
})
The issue is that when it finishes the /login page, then it reloads to login page again so the /devices page cannot be tested. In my cypress.config.js file i have setted the baseUrl
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
baseUrl: 'http://localhost:3000', //Baseurl to be used in all accross the testing classes
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
});
If /devices is a "login required" route, then the first step in any test that accesses it must be to log in. So you will always need to visit /login first, go through the login workflow, then you can visit /devices.
it('Open devices page', () => {
cy.visit('/login')
cy.get('input[name="username"]').type('admin')
cy.get('input[name="password"]').type('admin')
cy.contains('Login').click()
cy.wait(500)
cy.visit('/devices')
cy.get('ix-menu ix-menu-item[tab-icon=cogwheel]').click() //css selector
})
The wait after logging in and before visiting /devices may not be necessary, depending on the default timeout settings for your testing environment.
As #jjhelguero mentioned in the comments, you can also intercept a network request (perhaps to your login endpoint) and wait for it to return successfully as an alternative to the wait. get will retry, but could timeout: https://docs.cypress.io/api/commands/intercept
There are things you can do to avoid needing to actually log in, like setting a session cookie, but probably you want to emulate the actual user workflow in your tests.

firebase twitter login error : auth/invalid-credential

I'm going to put a firebase-based Twitter login on a web page.
As shown in Docs, we created an app on the Twitter developer portal, put the app key and app secret in the firebase column, respectively, and added the firebase's callback URL to the Twitter app.
When you try to run by pressing the login button, a rare appears with the following error code.
auth/invalid-credential
The supplied auth credential is malformed or has expired.
Do you happen to know what I did wrong? Can I also know the solution?
JavaScript was used, and under the same conditions, Facebook and Google can log in well and retrieve user information.
Someone help me why Twitter is the only thing like this... I am desperate!
Below, I put my Twitter login code and other screenshots together in case I need it.
$(document).on('click', '#twiter', function () {
var provider = new firebase.auth.TwitterAuthProvider();
firebase.auth().useDeviceLanguage();
firebase
.auth()
.signInWithPopup(provider)
.then((res) => {
/** #type {firebase.auth.OAuthCredential} */
var token = result.credential.accessToken;
var user = result.user;
console.log(token)
console.log(user)
// ...
}).catch((error) => {
console.log(error)
console.log(error.code)
console.log(error.message)
});
});
enter image description here
enter image description here

Issues With Persistent React Native Login

I am trying to make a persistent login system with React Native and expo but am running into several issues. I read online that AsyncStorage is the way to do this. I wrote three functions for dealing with login, all seen below.
// use asyncstorage to log in the user
logInUser = async (uid) => await AsyncStorage.setItem('loggedin', uid)
// set loggedin to null in asyncstorage
logOutUser = async() => await AsyncStorage.setItem('loggedin', null)
// returns userid if user is logged in
getUserState = async() => await AsyncStorage.getItem('loggedin')
On my login screen, I use the following onPress event to log in the user.
onPress={() => {
db.logInUser(this.user[1]).then(() => {
//this.removekey(this.user[1]) // delete the user's one-time-login key
this.props.navigation.navigate('Home') // navigate to home
})
}}
Also on the login screen, I use the following componentDidMount function to send the user to the homescreen if they are already logged in.
async componentDidMount() {
db.getUserState().then(loggedin => {
if (loggedin != null) { // log the user in if they have a uid in asyncstorage
this.props.navigation.navigate('Home')
}
})
}
The app will not have a "logout" feature, and users should stay logged in until either buying a new phone or reinstalling the app. Unfortunately this code does not work, and actually automatically logs the user in. I was thinking that it could maybe relate to the user with id=0, but removing this user from the database had no effect. The code of the actual application is here.

firebase auth/operation-not-allowed

This is an angular web app.
Added the screenshot of the permission page
I'm trying to authenticate mobile using firebase.
In my firebase console > Authentication > signIn Method, I've enabled the phone and saved it.
But when I try to login It throws me an error saying that
auth/operation-not-allowed
sendLoginCode() {
const appVerifier = this.windowRef.recaptchaVerifier;
const num = this.firstFormGroup.value.mobileNo
console.log('num',num);
firebase.auth().signInWithPhoneNumber(num, appVerifier)
.then(result => {
this.windowRef.confirmationResult = result;
})
.catch(error => console.log(error));
}
verifyLoginCode() {
this.windowRef.confirmationResult
.confirm(this.verificationCode)
.then(result => {
this.user = result.user;
console.log('Login Successfull')
})
.catch(error => console.log(error, "Incorrect code entered?"));
}
It looks like you haven't enabled the Google sign in method in your firebase console. To solve the issue do the following:
Enter to the firebase console (https://console.firebase.google.com/).
Select your project.
On the right side of the screen you'll see a panel, click where it says "Authentication".
Once you've entered to the Authentication menu, go to Sign-in method.
After that look for the google access provider in the list that appears below the header and click on it.
Then click on the enable button.
It is probable that you'll have to configure a secure project ID (you'll see a dropdown below the enable button). What you have to do is, enter the android and/or ios client ID from your project, and hit save. This will tell firebase that it is secure to handle sign in operations with that client.
To be able to use the phone sign in method, you need to have a paid plan active.
Original author of answer: https://stackoverflow.com/a/65598080/6310260

Stay logged in when using msal.js

I'm building a small JS app for my Microsoft ToDo tasks and use the msal.js library to accommodate the authentication process.
This works perfectly fine, I get a popup, I authenticate my profile, the popup closes and my tasks appear on my screen.
But: It doesn't seem to remember that I authenticated before; Every time I run my webpack app and the page is booted it shows the popup and asks for authentication. Once I've authenticated and just refresh my page, it just shows me the tasks without showing the popup again. I haven't tried waiting for an hour but I think it has something to do with not properly refreshing my access token. I'm not that involved with the Outlook/Microsoft API that I can really figure out if I'm using it correctly.
In short: How can I authenticate once so that the next time I start my app the tasks are shown without having to authenticate again?
My init function
this.userAgentApplication = new Msal.UserAgentApplication(microsoftTasksClientId, null, function (errorDes, token, error, tokenType) {
// this callback is called after loginRedirect OR acquireTokenRedirect (not used for loginPopup/aquireTokenPopup)
console.log(token)
})
let user = this.userAgentApplication.getUser()
if (!user) {
const self = this
// this.userAgentApplication = new Msal.UserAgentApplication(microsoftTasksClientId)
this.userAgentApplication.loginPopup([`${this.apiRootUrl}Tasks.readwrite`]).then(function (token) {
self.idToken = token
user = self.userAgentApplication.getUser()
if (user) {
self.getSilentToken()
}
}, function (error) {
console.log(error)
})
} else {
this.getSilentToken()
}
And my getSilentToken function
const self = this
this.userAgentApplication.acquireTokenSilent([`${this.apiRootUrl}Tasks.readwrite`]).then(function (token) {
console.log('ATS promise resolved', token)
self.accessToken = token
self.getTasks()
}, function (err) {
console.log(err)
})
Please not that my code isn't refactored AT ALL! ;-)
What version of MSAL are you using?
There is a problem in 0.1.1 version that storage is 'sessionStorage' by default and can't be really changed. In that case your login is saved just for currently opened window and you will be forced to relogin even when opened new browser window.
You should use 'localStorage' to achieve what you want and pass it as a constructor parameter for UserAgentApplication.
Here is a fix in their repo for this:
https://github.com/AzureAD/microsoft-authentication-library-for-js/commit/eba99927ce6c6d24943db90dfebc62b948355f19

Categories