Updated
I'm using:
Selenium 2.53.1
Firefox and IE11
I've been trying to click on all elements with the same selector, for example, I want to click on all the ones with the title "What I Want":
<div id="first_question">
<a class="gibberish1" title="What I Want"></a>
<a class="gibberish2" title="What I Want"></a>
<a class="gibberish3" title="What I Want"></a>
</div>
Here is what I have working so far:
browser.findElements(by.xpath("//a[#title='What I Want']")).then(function(all_tests){
for (var i = 0; i < all_tests.length; i++) {
console.log(all_tests.length);
all_tests[i].click();
}
});
It's able to recognize that I have three elements, and if I call each individual one directly then I'm able to see it click on the button. However, when I want to loop so it clicks on each button, I get an error:
"StaleElementReferenceError: Element is no longer attached to the DOM."
I also added a wait of 5 seconds in, but that didn't deter the same issue from popping up.
What am I doing wrong? I'm new to Selenium and I'm trying to figure this out in Javascript, instead of Java which is what I find examples for this situation.
You need to find them one by one, on page reload your objects will be lost and you will get stale element exception.
1) find all links
2) save an attribute/attributes in a list/array that can help you identify each link
3) create a loop where for each attribute you are searching for the element and click it
Moving my comment to an answer...
The first issue is that your code attempts are clicking a collection rather than an individual element. There are several ways to do this, one of which is doing a for loop and accessing the individual elements inside the loop, e.g. all_tests[i].click();.
The second issue with stale elements is because the DOM is being changed either through refreshing the page or navigating to a new page. If the issue is that clicking is causing navigation, you can loop through all the A tags and store the hrefs in a string array. Then you can loop through that string array and navigate to each stored href, etc.
Another way to handle this is to scrape the page using the index rather than storing the collection outside the loop. A simple example of this is
This is Java/pseudocode that you will have to translate into whatever language you are using but the concept should work.
for (int i = 0; i < driver.findElements(locator).length; i++)
{
// scrapes the page each iteration to avoid the stale element exception
driver.findElements(locator)[i].click();
// do stuff and get back to the original page, if navigated
}
I think first print the all_tests, check the output and the changes in
the for loop could work
for element in all_tests: element.click()
And to handle StaleElementReferenceError, can check here:
StaleElementReferenceException on Python Selenium
NOTE: Not Tested but handled the same concern.
Related
I am trying to loop through a series of pages (javascript) from the following webpage:
http://nh.mypublicnotices.com/PublicNotice.asp?Page=SEARCHRESULTS
I found all of the elements that I need to loop through, but I am unable to click on it. What would be the best way to loop through these javascript elements:
from selenium.webdriver.support.select import Select
next_page=driver.find_elements_by_xpath('//[#id="PublicNoticeContent"]/table[2]/tbody/tr/td/table[2]/tbody/tr[6]/td/table/tbody/tr/td/table/tbody/tr[1]/td/a')
for i in next_page:
link=i.get_attribute("href")
Select(link)
Select.click()
You need to repeat your materials on Select and working with a class.
link=i.get_attribute("href")
Select(link)
This code has just grabbed what had better be a SELECT tag, but it certainly looks as if you've grabbed only an href. You tried to create a Select object from that link ... but then, having created it, you failed to save it: you threw it away.
Select.click()
I'm not at all sure how you expect this to work: this invokes click as a direct call of a class method, but Select has no such method, so this will fail because teh attribute doesn't exist: an error message you failed to provide in your posting.
Start with this: once you work through your tutorial materials and learn to extract the proper SELECT tag from a URL i ... perhaps
select_tag = i.find_element_by_tag_name(“select”)).select_by_index(0)
clickable = Select(select_tag)
clickable.click()
You click on the object you created, not on the class.
Does that help get you going? You still need to figure out how to code that first line in your application.
I'd like to use Javascript to set up the display logic for individual rows in a single-choice matrix table question in Qualtrics. I've always done this in the past with the usual click-through method, but I often have 100+ rows to do this for, and it'd save a ton of time to be able to do this programmatically.
I've tried inserting the following into "Add JavaScript" for the question I'm trying to add the display logic to:
Qualtrics.SurveyEngine.addOnload(function()
{
/*Set display logic*/
if ('${q://QID2/SelectedAnswerRecode/1}' < 3) {'${q://QID3/ChoiceDescription/1}'.style.visibility='hidden';}
if ('${q://QID2/SelectedAnswerRecode/2}' < 3) {'${q://QID3/ChoiceDescription/2}'.style.visibility='hidden';}
});
The idea is that an answer with a value of at least 3 in row 1 of QID2 (also a single-choice matrix table) is required for row 1 of matrix table QID3 to appear, and so on. As it is, is appears unresponsive - rows in QID3 are still displayed even if selected values in the corresponding rows of QID2 are < 3.
I've also tried style.display='none' instead of style.visibility='hidden' with no success. My experience with Javascript is limited, so I suspect it's some kind of syntax issue.
The problem is indeed with your syntax. You need to hide an html element and '${q://QID3/ChoiceDescription/1}' is not an html element (it is the innerHTML of a label). Even if it were an html element, the syntax is wrong (it wouldn't be in quotes).
It is best to use prototypejs when possible, so if the element were named 'element' the command would be:
element.hide();
To find the correct elements to hide, you need to identify and find them by element id or some combination of element tag, class and attribute. It could be done using choice description, but it would take a lot more code and wouldn't be very efficient.
Use Inspect Element in the browser with the survey in Preview mode to find the element ID for the row header of the matrix where the display logic will occur. .up().hide() will grab the rest of the row as well. Quotes around the IDs are necessary because of the '~' in the ID names; otherwise I get an "unexpected token ~" error when trying to save it. Thanks to T. Gibbons for pointing me in the right direction.
Qualtrics.SurveyEngine.addOnload(function()
{
/*Set display logic*/
if ('${q://QID2/SelectedAnswerRecode/1}' < 3) {$('header~QID3~1').up().hide();}
if ('${q://QID2/SelectedAnswerRecode/2}' < 3) {$('header~QID3~2').up().hide();}
if ('${q://QID2/SelectedAnswerRecode/3}' < 3) {$('header~QID3~3').up().hide();}
if ('${q://QID2/SelectedAnswerRecode/4}' < 3) {$('header~QID3~4').up().hide();}
if ('${q://QID2/SelectedAnswerRecode/5}' < 3) {$('header~QID3~5').up().hide();}
});
Copy/paste/edit as needed.
UPDATE
Looks like things may have changed with updates, but while this works with the question itself, this can mess with the logic on subsequent questions. Use extreme caution!
note: a solution in either Selenium or API wrapper Splinter for Selenium is fine!
I have been having issues interacting with the iframes on Twitter.com using the Splinter API for Python.
For example,
with Browser('firefox', profile_preferences= proxySettings) as browser:
#...login and do other stuff here
browser.find_by_id('global-new-tweet-button').click()
this brings up a pop-up box to type in a tweet.
How do I interact with this new box using Splinter to:
1) fill in a message
2) click "tweet" (submit)
..programmatically of course.
I tried inspecting the element but it doesn't seem to be nested inside of an iframe however it targets an iframe. So I am not sure how to find/interact with the elements in this pop-up.
I tried manually typing in a message then clicking the tweet button programmatically:
browser.find_by_css('.btn.primary-btn.tweet-action.tweet-btn.js-tweet-btn').click()
..but I get the error:
ElementNotVisibleException: Message: Element is not currently visible and so may not be interacted with
Stacktrace:
at fxdriver.preconditions.visible (file:///var/folders/z1/8rqrglqn2dj8_yj1z2fv5j700000gn/T/tmppRsJvd/extensions/fxdriver#googlecode.com/components/command-processor.js:10092)
at DelayedCommand.prototype.checkPreconditions_ (file:///var/folders/z1/8rqrglqn2dj8_yj1z2fv5j700000gn/T/tmppRsJvd/extensions/fxdriver#googlecode.com/components/command-processor.js:12644)
at DelayedCommand.prototype.executeInternal_/h (file:///var/folders/z1/8rqrglqn2dj8_yj1z2fv5j700000gn/T/tmppRsJvd/extensions/fxdriver#googlecode.com/components/command-processor.js:12661)
at DelayedCommand.prototype.executeInternal_ (file:///var/folders/z1/8rqrglqn2dj8_yj1z2fv5j700000gn/T/tmppRsJvd/extensions/fxdriver#googlecode.com/components/command-processor.js:12666)
at DelayedCommand.prototype.execute/< (file:///var/folders/z1/8rqrglqn2dj8_yj1z2fv5j700000gn/T/tmppRsJvd/extensions/fxdriver#googlecode.com/components/command-processor.js:12608)
I strictly want to achieve my goal using Splinter so please do not offer alternatives, I know there are other ways.
Thank you in advance!
You primary problem seems to be that you are treating the results of browser.find_by_xxx as an element object, when in reality it is an element container object (i.e. a list of webdriver elements).
Writing to the field works for me if I reference the element explicitly:
In [51]: elems = browser.find_by_id('tweet-box-global')
In [52]: len(elems)
Out[52]: 1
In [53]: elems[0].fill("Splinter Example")
In [54]:
That will write "Splinter Example" into the field for me.
The button click is failing because your css path is returning a list of three elements, and you are implicitly clicking on the first, hidden element. In my testing, the element you actually want to click on is the second element in the list:
In [26]: elems = browser.find_by_css('.btn.primary-btn.tweet-action.tweet-btn.js-tweet-btn')
In [27]: len(elems)
Out[27]: 3
In [28]: elems[1].click()
In [29]:
When I explicitly click the second element it doesn't throw an error and the button is clicked.
If you add to the css path you can narrow the results to only the button in the visible modal:
In [42]: css_path = "div.modal-tweet-form-container button.btn.primary-btn"
In [43]: elems = browser.find_by_css(css_path)
In [44]: len(elems)
Out[44]: 1
In [45]: elems.click()
In [46]:
Note that no exception was thrown here.
I am using the Infinite Scroll plugin, for Wordpress, to load new posts on to the page when users scroll to the bottom. The problem is this has been loading duplicate posts, as the sorting changes extremely fast (due to popularity) and posts end up on different pages.
When the plugin grabs the next page, sometimes products that were originally on the FIRST page have been sorted to the SECOND page. So I end up with duplicates.
I was planning on waiting for the script to load the next page content, then loop through all of the post titles and locate the duplicates. Then I would remove the second instance of each post.
I noticed Infinite Scroll has a window in the settings labeled "Run after content is loaded/callback" so I thought I could enter a function in that field to be called.
removeDuplicates();
Then I entered something like this in the footer:
function removeDuplicates(){
var titleList = [];
$('.title').each(function(i, obj) {
/* The titles are in <h1> tags, I cycle through them,
if it's the first time seeing the title I add it to titleList.
If it's already in the array I hide the parent. */
});
});
I keep getting "undefined function" related to the .each, and it seems like it has something to do with scope but I'm not sure what's happening.
Is there an easier way to trigger the function to remove the duplicates? Am I at least on the right track?
Thanks for any insight you can provide!
It seems like jquery isn't loaded. Even if you use a selector that returns no elements, it should still have the .each() method.
Try using vanillaJS instead of jquery.
var titleNodeList = document.querySelectorAll('.title'); // get elements
var titleElArray = Array.prototype.slice(titleNodeList); // convert to array
titleElArray.forEach(function(el){...}); // iterate
I have seen the following href used in webpages from time to time. However, I don't understand what this is trying to do or the technique. Can someone elaborate please?
An <a> element is invalid HTML unless it has either an href or name attribute.
If you want it to render correctly as a link (ie underlined, hand pointer, etc), then it will only do so if it has a href attribute.
Code like this is therefore sometimes used as a way of making a link, but without having to provide an actual URL in the href attribute. The developer obviously wanted the link itself not to do anything, and this was the easiest way he knew.
He probably has some javascript event code elsewhere which is triggered when the link is clicked, and that will be what he wants to actually happen, but he wants it to look like a normal <a> tag link.
Some developers use href='#' for the same purpose, but this causes the browser to jump to the top of the page, which may not be wanted. And he couldn't simply leave the href blank, because href='' is a link back to the current page (ie it causes a page refresh).
There are ways around these things. Using an empty bit of Javascript code in the href is one of them, and although it isn't the best solution, it does work.
basically instead of using the link to move pages (or anchors), using this method launches a javascript function(s)
<script>
function doSomething() {
alert("hello")
}
</script>
click me
clicking the link will fire the alert.
There are several mechanisms to avoid a link to reach its destination. The one from the question is not much intuitive.
A cleaner option is to use href="#no" where #no is a non-defined anchor in the document.
You can use a more semantic name such as #disable, or #action to increase readability.
Benefits of the approach:
Avoids the "moving to the top" effect of the empty href="#"
Avoids the use of javascript
Drawbacks:
You must be sure the anchor name is not used in the document.
The URL changes to include the (non-existing) anchor as fragment and a new browser history entry is created. This means that clicking the "back" button after clicking the link won't behave as expected.
Since the <a> element is not acting as a link, the best option in these cases is not using an <a> element but a <div> and provide the desired link-like style.
is just shorthand for:
It's used to write js codes inside of href instead of event listeners like onclick and avoiding # links in href to make a tags valid for HTML.
Interesting fact
I had a research on how to use javascript: inside of href attribute and got the result that I can write multiple lines in it!
<a href="
javascript:
a = 4;
console.log(a++);
a += 2;
console.log(a++);
if(a < 6){
console.log('a is lower than 6');
}
else
console.log('a is greater than 6');
function log(s){
console.log(s);
}
log('function implementation working too');
">Click here</a>
Tested in chrome Version 68.0.3440.106 (Official Build) (64-bit)
Tested in Firefox Quantum 61.0.1 (64-bit)
It is a way of making a link do absolutely nothing when clicked (unless Javascript events are bound to it).
It is a way of running Javascript instead of following a link:
link
When there isn't actually javascript to run (like your example) it does nothing.
Refer to this:
Link to the website opened in different tab
Link to the div in the page(look at the chaneged url)
Nothing happens if there is no javaScript to render
javascript: tells the browser going to write javascript code
Old thread but thought I'd just add that the reason developers use this construct is not to create a dead link, but because javascript URLs for some reason do not pass references to the active html element correctly.
e.g. handler_function(this.id) works as onClick but not as a javascript URL.
Thus it's a choice between writing pedantically standards-compliant code that involves you in having to manually adjust the call for each hyperlink, or slightly non-standard code which can be written once and used everywhere.
Since it is a styling issue, instead of polluting the HTML with non valid syntax, you could/should use a W3 valid workaround:
Format the HTML properly, without href, following the W3 accessibility guide lines for buttons.
Use CSS to fix the initial goal of applying a clickable UX effect on a control.
Here's a live example for you to try the UX.
HTML
<a role="button" aria-pressed="false">Underlined + Pointer</a>
<a role="button" aria-pressed="false" class="btn">Pointer</a>
CSS
a[role="button"]:not([href]):not(.btn) { text-decoration: underline; }
a[role="button"]:not([href]) { cursor: pointer; }
I was searching for a solution that does not refresh pages but opens menu items on Ipads and phones.
I tried it on also mobile, It works well
Dr
1. Use that java script to Clear an HTML row Or Delete a row using the id set to a span and use JQuery to set a function to that span's click event.
2. Dynamically set the div html to a string variable and replace {id} with a 1 or 2 etc. cell of a larger div table and rows
<div class="table-cell">
<span id="clearRow{id}">
Clear
</span>
</div>
<div class="table-cell">
<span id="deleteRow{id}">
Delete
</span>
</div>
//JQuery - Clear row
$("#clearRow" + idNum).click(function(){
$("someIDOrWildcardSelector" + idNum).val("");
$("someIDOrWildcardSelector" + idNum).val("");
$("someIDOrWildcardSelector" + idNum).val("");
});
//JQuery to remove / delete an html row
$("#deleteRow" + idNum).click(function(){
//depending upon levels of parent / child use 1 to many .parent().parent().parent()
$(this).parent().remove();
});