Using Puppeteer I can extract data and print that data on my Terminal:
Output:
{
name: 'Deep into the Jungle',
price: '$24'
}
I also know I can print only name, using the following code:
console.log(result.name);
Output:
{
'Deep into the Jungle'
}
I'm trying to pass the result.name to my form field on my website. But unsuccessfully.
I already know the form field name and can succesfully put data manually using this:
await page.$eval('input[name=wc_name]', el => el.value = 'my-manually-written-name-goes-here');
Since I know the correct field imput name and I know what value I want to pass, logically something like this should work:
await page.$eval('input[name=wc_name]', el => el.value = result.name);
But it didn't pass anything. A blank.
I have also tried the following:
await page.type('input[name=wc_name]', result.name);
A blank as well, nothing passed.
So my question is:
What I'm missing? I'm not a coder, maybe I'm just missing '' or ""
Is it actually possible to pass the result value (as soon as you grab it) into the input field?
Maybe I need to store the values using fs into the text file first, and only then (using fs again) grab them from the file and pass to the input field on my website?
Need help.
Not sure if this is enough to fix but worth trying. result variable is declared in the Node.js context. To transfer it into a callback evaluated in the browser context, you need to add it as an argument:
await page.$eval('input[name=wc_name]', (el, name) => { el.value = name; }, result.name);
Related
I am looking to extract a URL parameter from the current URL I'm testing with Cypress. I was able to basically get the answer from this SO post, however, my extracted values are not available to me when I use Cypress's .its() command.
The parameters in the url all have periods in them, and I believe this is the cause for my error.
Here is my custom Cypress Command I'm building:
Cypress.Commands.add('getParmsCommand', function(value) {
cy.url().as('url')
cy.then( () => {
cy.log(this.url)
const kvPairArray = this.url.toString().split('?')[1].toString().split('&')
const paramObj = {}
kvPairArray.forEach(param => {
cy.log(param)
//default 'value' to 0 if it doesn't exist
const [ key, value="0" ] = param.split('=')
paramObj[key] = value
})
//forcefully adding a debug element to the key value store for testing
paramObj['beverage'] = 'soda'
cy.wrap(paramObj)
.its('timeline.ws') //doesn't work
// .its(`${Cypress.$.escapeSelector('timeline.ws')}`) doesn't work
// .its('timeline\.ws') doesn't work
// .its('"timeline.ws"') doesn't work
// .its('beverage') this DOES work!
.then(parmVal => {
cy.log(parmVal)
})
Here is the relevant part of the URL that I'm trying to extract from:
timeline.ws=3600000&timeline.to&timeline.fm&timeline.ar=false
You can see from the error that Cypress is only looking for the id timeline, NOT timeline.ws; it completely ignores everything after the period, and thus, never finds my parameter.
I saw there was a similar error with Cypress's .get() function back in 2018.
I am new to both javascript and Cypress, so I hope it's just a weird easy thing I'm overlooking. Any advice or educated guesses are greatly welcome at this point!
Thank you.
.its() is just a shorthand for property extraction. Since it fails with the period, you could instead use bracket notation in a .then().
cy.wrap(paramObj)
.then(paramObj => paramObj['timeline.ws'])
or just
cy.wrap(paramObj['timeline.ws'])
Playing around with the URL constructor
const urlString = 'http://example.com?timeline.ws=3600000&timeline.to&timeline.fm&timeline.ar=false'
const url = new URL(urlString)
cy.wrap(url.searchParams.get('timeline.ws'))
.should('eq', '3600000')
cy.wrap(url.searchParams.get('timeline.to'))
.should('be.empty')
cy.wrap(url.searchParams.get('timeline.ar'))
.should('eq', 'false')
I've been working with Liferay 7 for a while and needed to create a feedback form with prefilled values. I created a feedback form and a page, where it's shown and where I could add Javascript.
The user clicks on a link ("Did you find this helpful? Yes/No") and it takes you to the feedback page with the page and answer as URL parameters.
URL: {feedback-page-url/} ?pageUrl=/services&answer=Yes
Now here's where the problems began. Liferay updates it's values very confusingly and while generic document.getElementsByName(...) etc. seemed to work at first, they updated back when clicking the page. The difficult thing is to update the right values in right elements, so they won't be overrun by Liferay.
I provided an answer to my question below. Feel free to ask me anything, I'll try to help :)
Full code block in the end!
So I found out a solution to this problem. Liferay creates an instance (_com_liferay...) and uses it's values to be up to date, so we need to get a hold of it and update it's values. You can do it manually by inspecting and finding your instance, but I have an automatic code that should get it for you.
The id we are searching for is for DDMFormPortlet and the String we get this way is close to perfect. The String that document.querySelector() finds begins with p_p_id_com..., so we can use .substring to remove the unnecessary part and then add +"form" in the end to make it complete. If you find a better way to find this, please share it :)
// _com_liferay_dynamic_data_mapping_form_web_portlet_DDMFormPortlet_INSTANCE_randomkey_form
const idFinder = function() {
const idString = document.querySelector('[id*="DDMFormPortlet"]').id;
return(idString.substring(6) + "form");
}
Now that we have the correct String text, we'll find the element, that corresponds to it:
const formFieldArray = window[idFinder()];
Now if you try it just by itself, it most likely won't find anything, because it's loads slowly. I put all of this into try-catch with setTimeout() to make sure everything works as intended. Now all we need to do is collect the information from our URL and set it to the correct places.
const params = new URLSearchParams(location.search);
const formAutoFiller = function (params) {
try {
const formFieldArray = window[idFinder()];
// make sure you have the numbers according to your form!
formFieldArray.pages[0].rows[0].columns[0].fields[0].value=params.get('pageUrl');
formFieldArray.pages[0].rows[1].columns[0].fields[0].value=params.get('answer');
// ...
}
}
And finally, as the changed values update to the form after clicking an input field, we'll move the selection focus to one of the input fields after the other code is ran:
document.getElementsByClassName("ddm-field-text")[1].focus();
A bit cleanup for myself and we're done! Full Javascript here:
const params = new URLSearchParams(location.search);
const idFinder = function() {
const idString = document.querySelector('[id*="DDMFormPortlet"]').id;
return(idString.substring(6) + "form");
}
const formAutoFiller = function (params) {
try {
const formFieldRows = window[idFinder()].pages[0].rows;
formFieldRows[0].columns[0].fields[0].value=params.get('pageUrl');
formFieldRows[1].columns[0].fields[0].value=params.get('answer');
document.getElementsByClassName("ddm-field-text")[1].focus();
} catch (e) {
setTimeout(formAutoFiller, 500, params);
}
}
formAutoFiller(params);
i have a webpage where user can select one of different packages to buy from a list. Package details are coming from a database.
HTML Code
<div data-package='2346343' class="retail-package">Cost : 10$</div>
<div data-package='5465654' class="retail-package">Cost : 20$</div>
<div data-package='3455675' class="retail-package">Cost : 30$</div>
Jquery Code
$('.retail-package').on('click', function() {
$(this).addClass("selected-package");
var selectedPackage = $(this).data("package");
});
Now above code shows how we(specially i) normally select a particular thing out of a list when clicked, In this procedure, as you can see in HTML Code, i am giving out or showing the pakcageId to users i.e. anyone can do a inspect element in a browser and view or even manipulate the data-package attribute, for safety i do a server side check of selected data.
My Question
Is there a way to hide this data exposure, or is there any other cleaner way to accomplish this, because i have seen people using Angular, Webpack etc able to implement a list selection without giving out or showing any data which can be seen by inspect element feature in a browser.
Note : i am sorry if my question is too basic, if this cannot done using jquery what are other technologies which i can use ?
You may create a Map where keys are arbitrary, auto-incremented identifiers, and values are package numbers:
const idPackageMap = new Map()
// id generator: whenever you call it, "i" is incremented and returned
const id = (() => {
let i = 0
return () => ++i
})()
const addPackage = package =>
idPackageMap.set(id(), package)
addPackage(2346343)
addPackage(5465654)
addPackage(3455675)
console.log('contents: ', [...idPackageMap.entries()])
console.log('package number for id 2: ', idPackageMap.get(2))
Now, when you insert those <div> elements you may set the arbitrary identifier, and when you need to locate the actual package number is just about using Map#get: idPackageMap.get(1) (change 1 with any arbitrary identifier).
So I'm using inquirer to ask a question from my users via terminal:
var inquirer = require('inquirer');
var question = {
name: 'name',
message: '',
validation: function(){ ... }
filter: function(){ ... }
};
but at the same time let my users pass this field via --name command line argument. (say arg.name)
Question is: How can I tell inquirer to take this arg.name value and use it as if user entered it for the answer of this question.
Note that I DO need the validation and filter to also kick-in for this value. (for example if value passed via --name is invalid, the user is presented with the error message and asked to enter another value)
I'm hoping there is a way to solve this problem without having to hack-around manually calling my validation/filter methods.
You could set up a default value to a variable from arg.name:
let argument = args.name;
const question = {
name: 'name',
message: 'Name?',
default: argument
};
I tried testing this and it works. The user just has to hit enter to use the name passed in the arguments so maybe tell them that in the prompt. Also be aware that your validation will take place AFTER your filters. You just need to make sure whatever your filters are doing will pass validation.
Very confused here.
I have a search box which reads a list of school names from my database. When I select a school, the id (from the db) gets put in a hidden textbox.
I also have a search box which reads a list of courses from my database. However, I made the query so that it only reads the courses from the selected school.
It does that, in theory.
I was planning to pass the school id, which I grab from the hidden box, to the search script which in turn passes it to my database query. However, the variable I put my school id in doesn't seem to be updating.. yet it does. Let me explain.
I come on the page. The school for my test account has id 1. The id number in my hidden box is indeed 1. I search for a school which I know has some courses assigned to it: the id number in the box changes to 3.
I have a JS variable called school_id which I declared outside of my $(document).ready. I assume that means it's global (that's what I got taught even though SO told me once it isn't really the correct way to do this. Still have to look into that). I wrote a function which updates this variable when the school search box loses focus:
$("#school").blur(function() {
school_id = $("#school_id").val();
});
A quick javascript:alert(school_id); in my browser bar also shows the updated variable: it is now 3 instead of 1.
Onto the search script part of my page (excerpt of the script):
script:"/profiel/search_richting?json=true&limit=6&id=" + school_id + "&"
As you can see, I pass the school_id variable to the script here. However, what seems to be happening is that it always passes '1', the default variable when the page loads. It simply ignores the updated variable. Does this string get parsed when the page loads? In other words, as soon as the page loads, does it actually say &id=1? That's the only idea I can come up with why it would always pass '1'.
Is there a way to make this variable update in my script string? Or what would be the best way to solve this? I'm probably missing out on something very simple here again, as usual. Thanks a lot.
EDIT
Updated per request. I added a function getTheString as was suggest and I use the value of this function to get the URL. Still doesn't work though, it still seems to be concatenating before I get a chance to update the var. HOWEVER, with this code, my ajax log says id:[object HTMLInputElement], instead of id:1. Not sure what that means.
<script type="text/javascript">
var school_id;
$(document).ready(function() {
$("#school").blur(function() {
school_id = $("#school_id").val();
});
// zoekfunctie
var scholen = {
script:"/profiel/search_school?json=true&limit=6&",
varname:"input",
json:true,
shownoresults:false,
maxresults:6,
callback: function (obj) { document.getElementById('school_id').value = obj.id; }
};
var as_json = new bsn.AutoSuggest('school', scholen);
var richtingen = {
script: getTheString(),
varname:"input",
json:true,
shownoresults:true,
maxresults:6
};
var as_json2 = new bsn.AutoSuggest('studierichting', richtingen);
});
function getTheString() {
return "/profiel/search_richting?json=true&limit=6&id=" + school_id + "&";
}
</script>
This is because the URL is static, it is not updated as the ID changes.
You should update the URL as part of the code you wrote to get the ID:
$("#school").blur(function() {
school_id = $("#school_id").val();
// update URL here ...
});
Aren't you concatenating script:"/profiel/search_richting?json=true&limit=6&id=" + school_id + "&" before the event is fired and the var updated?
Okay. So the problem was my third party plug-in instead of the code I wrote. I fixed this by editing the code of the autoSuggest plugin so it now includes my id field in the AJAX request.
var url = this.oP.script+this.oP.varname+"="+encodeURIComponent(this.sInp)+"&id="+ $("#school_id").val();
Thanks to everyone who tried to help me out!