E2e testing for Google Login with Puppeteer - google-oauth

I'm new to Puppeteer and trying to write an e2e test for a React app that enables logins using the GoogleLogin component from #react-oauth/google.
The code below works until the Google sign in window opens, but then I don't know how to access elements. I've looked at the element and I know that there's an input of type email, so I'd like to wait for that selector, but page doesn't seem to be the place to access it.
How do I move to the next step with this test?
const chalk = require( 'chalk' );
class LoginAccount {
constructor( page ) {
this.url = "http://localhost:3000"
this.page = page;
}
async login( username, password ) {
try {
const navigationPromise = page.waitForNavigation();
await this.page.goto( this.url );
const selector = '[role="button"]';
await this.page.waitForSelector( selector );
const button_handler = await page.$(selector);
await button_handler.evaluate(b => b.click());
await navigationPromise
const email_field = 'input[type="email"]'
await page.waitForSelector( email_field )
// Times out here
console.log("Got email input")
await this.page.type( email_field, username );
} catch ( err ) {
console.log( chalk.red( 'ERROR => ', err ) );
}
}
}
module.exports = ( page ) => new LoginAccount( page );

I was able to solve this. The browser.waitForTarget method gets me a handle to the new browser window that I need. The modified code below (starting just before the button click) works correctly:
const pageTarget = page.target();
await button_handler.evaluate(b => b.click());
const newTarget = await browser.waitForTarget(target => target.opener() === pageTarget);
const newPage = await newTarget.page();
const email_field = 'input[type="email"]'
await newPage.waitForSelector( email_field )
console.log("Got email input")

Related

I am tring to make Static Model.findByCredentials. But it is not working for mongoose, Express login system?

userSchema.statics.findByCredentials = async (email, password) =>{
const user =await User.findOne({ email })
if(!user){
throw new Error("Unable to Login!")
}
const isMatch = await bcrypt.compare(password, user.password)
if (!isMatch){
throw new Error("Invalid to Login!!")
}
return user
}
const User = new mongoose.model("User",userSchema)
module.exports = User
In users i have set the routes properly too:
router.post("/users/login", async (req,res) => {
try{
const user = await User.findByCredentials(req.body.email, req.body.password)
res.send(user)
}
catch(err){
res.status(400).send()
}
})
But i get 400 Bad request error. The route is catching the error.
findByCredentials is not working?
What is my mistake??

Can't log in through Facebook using Puppeteer - Error: Cookies required

This is my code to login using facebook to a website I'm automating:
const loginButton = await page.waitForXPath(
"//button[contains(#name, 'login')]"
);
const email = await page.waitForSelector("#email");
const pass = await page.waitForSelector("#pass");
await page.evaluate((text) => {
email.value = text;
}, "my email");
await page.evaluate((text) => {
pass.value = text;
}, "my password");
await loginButton.click();
Usually it works well, but once every 4 or 5 times, I get the following error after clicking the loginButton:
"Cookies required. Cookies are not enabled on your browser. Please enable cookies in your browser preferences to continue."
I changed from Chromium to Chrome to see if this would solve the issue, but it didn't work.
I also checked the cookies settings and they are enabled.
The problem was that the inputs were being filled to quickly and facebook was suspecting that I wasn't a real person. I solved it by introducing some delay between the login steps:
const loginButton = await page.waitForXPath(
"//button[contains(#name, 'login')]"
);
const email = await page.waitForSelector("#email");
const pass = await page.waitForSelector("#pass");
await page.waitFor(1000);
await page.evaluate((text) => {
email.value = text;
}, "casas.farach#yahoo.com");
await page.waitFor(1000);
await page.evaluate((text) => {
pass.value = text;
}, "789654123");
await page.waitFor(1000);
await loginButton.click();

React native fetch from URL every X seconds

In the page I have two things to do, first I fetch some content from API and display it. After that, I will fetch another API every 5 seconds to see whether the status of the content displayed has been changed or not.
In my MyScreen.js
const MyScreen = props => {
const dispatch = useDispatch();
const onConfirmHandler = async () => {
try {
//get content from API and display on the screen
const response1 = await dispatch(action1(param1,param2));
if(response1==='success'){
// I want to check the result of response2 every 5 seconds, how can I do this?
const response2 = await dispatch(action2(param3));
}
}catch {...}
}
return (
<Button title='confirm' onPress={onConfirmHandler}}>
)
}
The actions I fetch the API in actions.js:
export default action1 = (param1,param2) ={
return async (dispatch, getState) => {
// To call the API, I need to used token I got when login
let = getState().login.token;
const response = await fetch(url,body);
const resData = await response.json();
if (resData==='success'){
return param3
}
}
export default action2 = (param3) ={
return async (dispatch, getState) => {
// To call the API, I need to used token I got when login
let = getState().login.token;
const response = await fetch(url,body);
const resData = await response.json();
if (resData==='success'){
// if the content status changed, I change the view in MyScreen.js
return 'changed';
}
}
I have also met this problem already. Here you can't use the timeout function. Instead, you can use react-native-socketio or react-native-background-fetch packages. I prefer react-native-background-fetch. So you can fetch results at a specific interval and update the state on change of content.

Jest testing of async middleware for authentication

I'm using a static array to scaffold a user table, prior to refactoring with actual postgres db and some fetch()-ing code. At present, the tests work, but obviously they are working synchronously. Here's the placeholder API code:
// UserAPI.js
let findUserById = (credentials = {}) => {
const { userId } = credentials
if (userId) {
const foundUser = users.find(user => user.id === userId)
if (foundUser !== undefined) {
const { password: storedpassword, ...user } = foundUser
return user
}
}
return null
}
exports.byId = findUserById
And an example test as follows:
// excerpt from TokenAuth.test.js
const UserAPI = require('../lib/UserAPI')
describe('With TokenAuth middleware', () => {
beforeEach(() => {
setStatus(0)
})
it('should add user to req on authorised requests', () => {
const token = createToken(fakeUser)
const authReq = { headers: { authorization: 'Bearer ' + token } }
const myMiddleware = TokenAuth(UserAPI.byId)
myMiddleware(authReq, fakeRes, fakeNext)
// expect(authReq.user).toStrictEqual({ id: 1, username: 'smith#example.com' });
expect(authReq.user.username).toStrictEqual('smith#example.com')
expect(authReq.user.id).toStrictEqual(1)
})
})
This runs fine, and along with other tests gives me the coverage I want. However, I now want to check that the tests will deal with the async/await nature of the fetch() code I'm going to use for the proper UserAPI.js file. So I re-write the placeholder code as:
// UserAPI.js with added async/await pauses ;-)
let findUserById = async (credentials = {}) => {
const { userId } = credentials
// simulate url resolution
await new Promise(resolve => setTimeout(() => resolve(), 100)) // avoid jest open handle error
if (userId) {
const foundUser = users.find(user => user.id === userId)
if (foundUser !== undefined) {
const { password: storedpassword, ...user } = foundUser
return user
}
}
return null
}
exports.byId = findUserById
... at which point I start getting some lovely failures, due I think it's returning unresolved promises.
My problem is two-fold:
How should I alter the UserAPI.test.js tests to deal with the new async nature of findUserByCredentials() ?
Am I ok in my assumption that ExpressJS is happy with async functions as request handlers? Specifically, due to the async nature ofUserAPI.findUserByCredentials is this ok?
Main App.js uses curried UserAPI.byId() for the findUserById.
// App.js (massively simplified)
const express = require('express')
const TokenAuth = require('./middleware/TokenAuth')
const RequireAuth = require('./middleware/RequireAuth')
const UserAPI = require('./lib/UserAPI')
let router = express.Router()
const app = express()
app.use(TokenAuth(UserAPI.byId))
app.use(RequireAuth)
app.use('/users', UserRouter)
module.exports = app
My TokenAuth middleware would now run along these lines:
// TokenAuth.js (simplified)
const jwt = require('jsonwebtoken')
require('dotenv').config()
const signature = process.env.SIGNATURE
let TokenAuth = findUserById => async (req, res, next) => {
let header = req.headers.authorization || ''
let [type, token] = header.split(' ')
if (type === 'Bearer') {
let payload
try {
payload = jwt.verify(token, signature)
} catch (err) {
res.sendStatus(401)
return
}
let user = await findUserById(payload)
if (user) {
req.user = user
} else {
res.sendStatus(401)
return
}
}
next()
}
module.exports = TokenAuth
A partial answer us simply to add an async/await on the middleware call:
it('should add user to req on authorised requests', async () => {
const token = createToken(fakeUser)
const authReq = { headers: { authorization: 'Bearer ' + token } }
const myMiddleware = TokenAuth(UserAPI.byId)
await myMiddleware(authReq, fakeRes, fakeNext)
// expect(authReq.user).toStrictEqual({ id: 1, username: 'smith#example.com' });
expect(authReq.user.username).toStrictEqual('smith#example.com')
expect(authReq.user.id).toStrictEqual(1)
})

How to reuse puppeteer tests

I'm currently working with Puppeteer and Jest for end-to-end testing, for my tests to work I always need to run a login tests, but I don't know and haven't been able to find out how to export my tests so I can reuse them.
To conclude: I'm looking for a way to reuse all of my tests inside the describe by exporting them to a different file and reusing them in a beforeAll in the new files.
The complete set of login tests is below:
describe("homepage and login tests", homepageTests = () => {
test("front page loads", async (done) => {
await thePage.goto('http://localhost:3000');
expect(thePage).toBeDefined();
done();
});
test("Login button is present", async (done) => {
theLoginButton = await thePage.$("#login-button");
expect(theLoginButton).toBeDefined();
done();
})
test("Login works", async (done) => {
//the following code runs inside the popup
await theBrowser.on('targetcreated', async (target) => {
const thePopupPage = await target.page();
if (thePopupPage === null) return;
//get the input fields
const usernameField = await thePopupPage.waitFor('input[name=login]');
const passwordField = await thePopupPage.waitFor("input[name=password]");
const submitButton = await thePopupPage.waitFor('input[name=commit]');
//validate input fields
expect(usernameField).not.toBeNull();
expect(passwordField).not.toBeNull();
expect(submitButton).not.toBeNull();
//typing and clicking
await thePopupPage.waitFor(300)
await usernameField.type("USER");
await passwordField.type("PASSWORD");
await submitButton.click();
done();
})
try {
//wait for login button on homepage
theLoginButton = await thePage.waitFor('#login-button');
expect(theLoginButton).toBeDefined();
//click on login
await thePage.waitFor(200);
await theLoginButton.click();
} catch (e) { console.log(e) }
})
test("Arrive on new page after login", async () => {
//resultsButton is only shown for logged in users.
const resultsButton = await thePage.$("#resultsButton");
expect(resultsButton).toBeDefined();
})
Create a separate file name test.js
//test.js
export async function fn1(args){
// your commands
}
//file.test.js
import {fn1} from 'test.js'
describe('test 1 ', () => {
test("test", async () => {
try {
await fn1(args);
} catch (err) {
console.log('There are some unexpected errors: ' + err);
}
},5000);
});
I have the same issue and the above method will work out for you.