Handling updated content in static HTML with Selenium - javascript

I am using Selenium to automate our document downloading tasks. The function I have looks like this:
def download_csv()
i = 2
while True:
try:
button_main_page=wait.until(ec.element_to_be_clickable((By.XPATH,'/.../div[{}]/button'.format(i)))
button_main_page.click()
i = i+1
button2=wait.until(ec.element_to_be_clickable((By.XPATH,'/...')))
button2.click()
download_button = wait.until(ec.element_to_be_clickable((By.XPATH,'/...')))
download_button.click()
driver.back()
driver.back()
except:
Next_Page = wait.until(ec.element_to_be_clickable((By.XPATH,'/...')))
Next_Page.click()
download_csv()
The main page has a table containing 10 elements and a button for each. To download each document, I need to navigate to the download location by doing 3 clicks and return to the main page to repeat the operation for the next element in the table, after that I am looking to repeat it on the next pages.
My issue is after I download the first element on the second page and do
driver.back()
I get returned to the original first page and start accessing the same elements again. The page url doesn't change and there is nothing I see going off in the Network tab when I click on "Next Page" button. I believe the content update is triggered when the next page button is clicked, however I have very limited knowledge of AJAX/js etc to know where to start looking.
Is it possible to bypass something like this with Selenium? And how do I look for what is triggering the table content update, if nothing is displayed in the network tab during button clicking.
Thanks!

Related

How to find the first element if Xpath returns a list of elements(selenium-python)

browser = webdriver.Chrome(path)
browser.maximize_window()
browser.get("https://www.flipkart.com")
browser.find_element_by_xpath('//button[#class="_2AkmmA _29YdH8"]').click()
browser.find_element_by_name("q").send_keys("Mobiles")
browser.find_element_by_xpath("//button[#class='vh79eN']").click()
p = browser.find_elements_by_xpath("//div[#class='_3wU53n']")
Using the above code, I have to search for Mobiles in flipkart and click on any Mobile which should that open page onto new Tab.
I am facing issue with locating a mobile as Xpath returns a list of Mobiles. I want to find the first element and click so that it opens in new tab.
Can Anyone help me with this? Thanks!
When you used browser.find_elements_by_xpath("//div[#class='_3wU53n']") p will be a lists, so you can access items as easy as p[0], more info here.
But if you only need the first element, I suggest u should use browser.find_element_by_xpath("//div[#class='_3wU53n']") without the "s" as it should select the first element in that class
You can store in List by using list class in selenium.
List lists=driver.findElements(By.xpath(".."));
lists.get(0).click();
//Above code for click first element in lists
Once you "CLICK" the SEARCH button, the webpage redirects to a new page which shows the list of mobile. However, it takes some time to load the page. So you need to add some delay to it, so as to perform the next actions.
<the code above remains the same>
browser.find_element_by_xpath("//button[#class='vh79eN']").click()
import time
time.sleep(3) # Added a delay
browser.find_element_by_xpath("//div[#class='_3wU53n']").click() # Changed the "elements" to "element"
This opens the first mobile phone in the new tab.
PS. This code works great if you need only the first mobile. If you need all the mobiles on the page, you will have to create a loop for it!

keep ajax content after press back button

I have a product page with infinite scroll pagination. More products are loaded with Ajax.
Like this: domain/books.
When the user clicks on a product it will go to the product page: domain/books/the_selected_book.html
When the browser back button is clicked, domain/books loads but not the the Ajax content.
What I'm trying to accomplish is that the previous page loads exactly as the user leaved it and in the same position, when back button is pressed on the new page.
Just like YouTube works.
I have searched the web without finding a good option to do this.
What is the best solution?
window.onbeforeunload = function(){
created_session = window.pageYOffset;
};
and in the product page just add this javascript code after loading ajax content. Also keep a variable that counts how many product loaded from database. For example 5 times new product added (12 for each for example). You should keep this in a session and multiply them 5*12 = 60. You can load the products from database by its limit property.
if (isset? created session)
window.scrollBy(0, created_session for pageYOffSet);

Livecycle designer render a blank page if the form ends with odd pages

i am designing a form in Livecycle es4 designer, the form is saved as .xdp and we have a .xml as input, based on the data stream the form extends to n number of pages, i need to end my form on an even page always,
if there are 3 pages based on the data, i need to show an blank page as the 4th page. if there are 4 pages based on data stream we need not show the extra blank page.
i have added a blank page in my designer made it hidden from layout, , wrapped in a sub form and in the layout editor :ready i have written the following script
var pageCount = xfa.layout.pageCount();
if(pageCount%2==0){Blank.presence = "hidden";}
{Blank.presence = "visible";}
but my form now which is 3 pages does not append the blank page, any direction will be very helpful.
Thanks in advance
CW
Firstly, layout:ready event fires every time the form changes. For example:
initialy 3 pages -> script adds one more -> form changed -> script fires again and removes 4th page...
Secondly, is the Blank(empty page) visible or hidden from the start? Depending on that the Blank will be included or not in the page count at the first script run.
You could set Blank as visible from the start and per script remove it if the condition is true. You won't need else-part in this case.

Chrome Extension, Append Element & Re-Append Across Page Changes

I have a Chrome Extension that, when its button is clicked, appends an element to the current page. However, I want to keep that element across pages; i.e., if the user clicks on a link, the new page loads, and then the element is appended.
I tried using window.onhashchange to detect page changes, check if the element was appended, and if not, append it, but that didn't seem to have any affect at all. Any tips on how to do this, or if it's possible? (preferably in javascript, no jquery)
some general description how would I do it, would be:
-when user clicks the button, append element and send msg to background to store that tab (ID)
-add listeners chrome.tabs.onCreated.addListener & onUpdated (in bg script)
-test newly created and updated tabs against your stored
-if newly created/updated tab is child of your stored tab (tabs), inject script for element appending or send msg to content script to append element
sample for BG script to start with:
chrome.tabs.onCreated.addListener(function(tab) {
console.log('tab id is'+tab.id);
console.log('opener is'+tab.openerTabId);
});
cople of things to be careful:
-openerTabId is undefined if link is dragged (extension for dragging links)
-those events are fired multiple times, so if you are sending msg to content script to append your element (or injecting), check it first
something like
if (yourElement) return;
else //append element
maybe there are better/simpler ways to achieve what you want... can't think of it right now
EDIT:
you actually don't need initial messaging when button is clicked, because listener for that button is already in bg script, and the whole process is very simple.

Same ID's in jQuery Tabs

I am using the jQuery Tabs library in a small application. The page has 5 tabs and the content for each page is loaded using Ajax. The problem is, once I load a tab, it remains in the browsers memory (and so do its HTML elements). So if I use lets say a DIV element with the same ID as a previously loaded tab, all JS function related to that ID try to interact with the old tab.
IN other words, lets say I have a page with 2 tabs, "Traffic Data1", "Traffic Data2". Now first, I click on the Traffic Data1 tab which makes the ajax call and loads the page just fine. This page, has 2 date input fields, id for the first field is "dateFrom" and the other field is "dateTo". Next to that is a "Go" button. Upon clicking the button, a JS function shows an alert box with the values in each of the input fields.
Now, I click on the "Traffic Data2" tab. The contents of the page are very different, but it has the identical input fields, 2 for dates (with same IDs) and Go Button. When I press the Go button on this page, I see the alert box with values form the previous tab.
So my question is, Is there a way to unload the previous tab? Or is the only alternative to use elements with unique divs (even though the pages are complete separate).
Thanks
You cannot have multiple element with the same ID. When you find an element by ID the first one found is always returned because it is expected that IDs will be unique.
Leave the name attributes for the input elements the same but change their IDs to be unique.
You can select an element by its name attribute like this: $('[name="foobar"]')
Update
In the docs for jQuery UI Tabs there is an option called cache that when set to false should remove the old tabs from the DOM after you navigate away from them:
Whether or not to cache remote tabs content, e.g. load only once or
with every click. Cached content is being lazy loaded, e.g once and
only once for the first click. Note that to prevent the actual Ajax
requests from being cached by the browser you need to provide an extra
cache: false flag to ajaxOptions.
Source: http://jqueryui.com/demos/tabs/
You are looking for jQuery Live.
Description: Attach an event handler for all elements which match the current selector, now and in the future.
If you use it jQuery will magically auto-update to match your new elements as they appear/disapear.
// code sample
$("a.offsite").live("click", function(){ alert("Goodbye!"); });
Since the tabs click event reloads your form and assuming you're using divs to contain the ajax-loaded content, add .click(function () { $(this).children('div').children.remove(); }) to your tabs() declaration.
That should remove the div content and any event handlers that are bound to it.
If you can pass a context to the jquery functions, you could make your calls relative to currently selected tab...
$("#someDuplicatedId", activeTab).doStuff();
Or if caching the content is not important, go with Jasper's answer.

Categories