I have a list of checkboxes , every time puppeteer run the test I need to :
if a box is already selected then
move to next box and select it , and if the next is selected move to the next checkbox and so on
if(await page.$eval(firstcheckbox, check=>check.checked =true)) { //check if the box is selected
await page.waitForSelector(do something, ele=>elem.click())//if the checkbox is already selected , move to the second row and select a undecked box
}else if{
await page.$eval(firstcheckbox, check=>check.checked =false)){ //if the checkbox is not ticked
await page.$eval(clickcheckbox, elem=>elem.click);//tick the checkbox
You can use all the testing and changing inside one page.evaluate():
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: false, defaultViewport: null });
const html = `
<!doctype html>
<html>
<head><meta charset='UTF-8'><title>Test</title></head>
<body>
<input type="checkbox" id="checkbox1"><label for="checkbox1">checkbox1</label><br>
<input type="checkbox" id="checkbox2" checked><label for="checkbox2">checkbox2</label><br>
<input type="checkbox" id="checkbox3" checked><label for="checkbox3">checkbox3</label><br>
<input type="checkbox" id="checkbox4"><label for="checkbox4">checkbox4</label><br>
</body>
</html>`;
try {
const [page] = await browser.pages();
await page.goto(`data:text/html,${html}`);
await page.evaluate(() => {
for (const checkbox of document.querySelectorAll('input')) {
if (!checkbox.checked) checkbox.click();
}
});
console.log('Done.');
} catch (err) { console.error(err); }
Or, if you need a loop over element handles, you can try this:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: false, defaultViewport: null });
const html = `
<!doctype html>
<html>
<head><meta charset='UTF-8'><title>Test</title></head>
<body>
<input type="checkbox" id="checkbox1"><label for="checkbox1">checkbox1</label><br>
<input type="checkbox" id="checkbox2" checked><label for="checkbox2">checkbox2</label><br>
<input type="checkbox" id="checkbox3" checked><label for="checkbox3">checkbox3</label><br>
<input type="checkbox" id="checkbox4"><label for="checkbox4">checkbox4</label><br>
</body>
</html>`;
try {
const [page] = await browser.pages();
await page.goto(`data:text/html,${html}`);
for (const checkbox of await page.$$('input')) {
if (!await checkbox.evaluate(elem => elem.checked)) {
await checkbox.click();
}
}
console.log('Done.');
} catch (err) { console.error(err); }
Related
I'm clicking a button to make a call to an API to get a random fact and length. This is then displayed in two input fields which works. I'm struggling with how to change the text in the input fields to the new fact and length from the API when the button is clicked again. I know it is something simple but can't seem to find the solution. Any help would be appreciated.
<template>
<form>
<header>
<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="300" height="300" />
<br>
<br>
<input type="text" id="idFact" v-model="facts">
<br>
<br>
<input type="text" id="idLength" v-model="lengths">
<br>
<br>
<button v-on:click="callAPI" type="button">Call</button>
</header>
</form>
</template>
<script>
export default {
data() {
return {
posts: '',
facts: '{fact}',
lengths: '{length}',
};
},
methods: {
async getData() {
try {
let response = await fetch("https://catfact.ninja/fact");
this.posts = await response.json();;
} catch (error) {
console.log(error);
}
},
callAPI() {
this.facts = this.posts.fact
this.lengths = this.posts.length
}
},
created() {
this.getData();
}
}
</script>
Thanks
Invoke the getData method inside the click handler callAPI, and remove the call from created hook in order to avoid redundant calls:
<script>
export default {
data() {
return {
posts: '',
facts: '{fact}',
lengths: '{length}',
};
},
methods: {
async getData() {
try {
let response = await fetch("https://catfact.ninja/fact");
this.posts = await response.json();;
} catch (error) {
console.log(error);
}
},
callAPI() {
this.getData()
this.facts = this.posts.fact
this.lengths = this.posts.length
}
},
}
</script>
I am facing the error while trying to upload a file(image) via the form on AdonisJS (I referred to the official docs #AdonisJS4.1 File Uploads)
await profilePic.move(Helpers.tmpPath('uploads'), {
name: 'custom.jpg',
overwrite: true
})
if (!profilePic.moved()) {
console.log('file not moved')
}
Official Docs Here
HTML
<form method="POST" action="upload" enctype="multipart/form-data">
<input type="file" name="profile_pic" />
<button type="submit"> Submit </button>
</form>
JS
const Helpers = use('Helpers')
Route.post('upload', async ({ request }) => {
const profilePic = request.file('profile_pic', {
types: ['image'],
size: '2mb'
})
await profilePic.move(Helpers.tmpPath('uploads'), {
name: 'custom-name.jpg',
overwrite: true
})
if (!profilePic.moved()) {
return profilePic.error()
}
return 'File moved'
})
I'm fairly new to Vue & Vuex and am unsure on how to set up my form correctly.
<template>
<div>
<div v-if="error">{{error.message}}</div>
<form #submit.prevent>
<h1>Register</h1>
<input type="email" name="" id="" :value.sync="email" placeholder="Email">
<input type="password" :value.sync="password" placeholder="Password">
<button #click="signup">Submit</button>
Sign in
</form>
</div>
</template>
<script>
import {fireAuth} from '~/plugins/firebase.js'
export default {
data: () => ({
email: '',
password: '',
error: ''
}),
methods: {
signup() {
fireAuth.createUserWithEmailAndPassword(this.email, this.password).then(res => {
if (res) {
this.$store.commit('setCurrentUser', res.user)
this.$router.push('/')
}
}).catch(err => {
this.error = err
console.log(err)
})
}
}
}
</script>
At first I tried v-model to bind the form, it was throwing and error as I was mutating the store but I'm not storing email and password so I'm unsure how this is mutating the store? If I use :value or :value.sync then the email and password fields remain an empty string, so I'm not sure how to set up these correctly or how they differ from v-model
Edit: Adding my code from the store as requested
export const state = () => ({
currentUser: {}
})
export const mutations = {
setCurrentUser (state, obj) {
state.currentUser = obj
}
}
Vue.config.devtools = false
Vue.config.productionTip = false
const vm = new Vue({
el: "#app",
data() {
return {
email: '',
password: ''
}
},
methods: {
signup() {
console.log(this.email) // email value
console.log(this.password) // password value
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="app">
<div>
<form #submit.prevent="signup">
<h1>Register</h1>
<input type="email" v-model="email" placeholder="Email">
<input type="password" v-model="password" placeholder="Password">
<input type="submit">
</form>
</div>
</div>
</body>
</html>
I think I have found the solution, it was the way in which I was trying to use firebase. I have used v-model, but am using a firebase method onAuthStateChanged, only if that is called will I change the store. So in my firebase.js I added
const fireAuth = firebase.auth()
const fireDb = firebase.database()
export { fireAuth, fireDb }
export default async ({ store }) => {
await asyncOnAuthStateChanged(store)
}
function asyncOnAuthStateChanged (store) {
return new Promise(resolve => {
fireAuth.onAuthStateChanged(user => {
resolve(user)
store.commit('setCurrentUser', JSON.parse(JSON.stringify(user)))
})
})
}
I'm trying to get results from a simple form using PhantomJS. I'm using jQuery but don't work. I have this HTML:
<!doctype html>
<html>
<head>
<title>PhantomJS!</title>
</head>
<body>
<form method="post" id="frm">
<input type="text" name="nombre" id="nombre" />
<input type="submit" value="Publicar" id="btn-submit" />
</form>
Your name is <span id="nombrez"><?php if (isset($_POST['nombre'])) { echo $_POST['nombre'];} ?></span>
</body>
</html>
And this Javascript code:
var page = require('webpage').create();
page.open('http://localhost/phantom/', function() {
page.includeJs("https://code.jquery.com/jquery-3.1.1.slim.js", function() {
page.evaluate(function() {
$('#nombre').val('Fabian');
document.forms[0].submit();
});
page.onLoadFinished = function(){
console.log($("#nombrez").html());
phantom.exit();
};
});
});
page.onLoadFinished must not be called inside of page.evaluate, but inside the main PhantomJS script:
var page = require('webpage').create();
page.onLoadFinished = function(){
var html = page.evaluate(function(){
return document.getElementById("nombrez").innerHTML;
});
console.log(html);
phantom.exit();
};
page.open('http://localhost/phantom/', function() {
page.includeJs("https://code.jquery.com/jquery-3.1.1.slim.js", function() {
page.evaluate(function() {
$('#nombre').val('Fabian');
document.forms[0].submit();
});
});
});
However page.onLoadFinished fires every time a page is done loading and with this implementation phantom will exit the first the time page is loaded, even before the form is submitted.
You need to implement some check to distinguish between the first and the second load of the page. For example, if return html variable is empty it means that we haven't submitted page yet.
I'm trying to use ids with my input box's within my login page but I get the following error with Protractor:
Failed: No element found using locator: By css selector, *[id="signin--username"])
Here is my log-in.js
var logIn = function() {
this.navigate = function() {
browser.get(browser.params.server);
};
this.usernameInputBox = element(by.id('signin--username'));
this.passwordInputBox = element(by.id('signin--password'));
this.dontHaveAnAccountButton = element(by.id('signin--no-account-question'));
this.logInButton = element(by.id('signin--log-in'));
this.Modal = element(by.css('.modal-dialog'));
this.ModalButton = element(by.xpath('//*[#id="app"]/div[3]/div/div/form/div[3]/button'));
};
module.exports = new logIn();
Snippet from log-in.html
<div class="form-group">
<div class="input-group input-group-lg">
<span class="input-group-addon">
<span class="glyphicon glyphicon-user"></span>
</span>
<input type="text"
id="signin--username"
class="form-control"
placeholder="{{'username' | translate}}"
ng-model="username"
name="username"
required
autofocus data-autofill
>
</div>
</div>
Protractor Test Javascript File:
module.exports = function() {
describe('Login Page', function() {
var loginPage = require('../pages/log-in.js');
var saveScreenshot = require('../screenshot.js');
beforeEach(function() {
loginPage.navigate();
})
it('should log in (with correct credentials)', function() {
browser.waitForAngular();
loginPage.usernameInputBox.sendKeys('service');
loginPage.passwordInputBox.sendKeys('s5rv1c5');
loginPage.logInButton.click();
browser.waitForAngular();
expect(browser.getCurrentUrl()).toContain(browser.params.server + '#/jobs/my_jobs');
})
});
};
Any help much appreciated! Thanks.
Looks like a timing issue. Improve navigate page object method to also wait for the page to load - wait for the username field to become present:
var logIn = function() {
this.usernameInputBox = element(by.id('signin--username'));
this.passwordInputBox = element(by.id('signin--password'));
this.dontHaveAnAccountButton = element(by.id('signin--no-account-question'));
// ...
this.navigate = function() {
browser.get(browser.params.server);
var EC = protractor.ExpectedConditions;
browser.wait(EC.presenceOf(this.usernameInputBox), 5000, "Username field is still not present");
};
};
You are not giving the unique selector correctly. That is why this error occurs.
Use element(by.model('username')).sendKeys('your user name');
I assume that you gave the html of login text box.
Hope this helps. :)