Selenium + Python - Not able to interact/click with JavaScript - javascript

Problem: Not able to find/click/send.keys to any of elements on a specific webpage.
WebDriver Chrome
I can interact with that webpage until I click a certain link where a new tab is opened and from that page I'm unable to do anything.
What I've tried so far after extensive research here:
1- Since a new tab was opened, I've "forced" the code looking into the new tab using driver.switch_to.window and to be sure I've printed the current page title and it's the correct one.
2- I've tried both implicit/explicit waiting (even time.sleep) in order to wait for the page to load.
3- Research pointed me to iframe.. I don't have any iframe but nevertheless I've searched for the number of frames (2) and switched between both and tried to find elements using xpath (full xpath) and none were find.
4- Maximize window.
So I tried "everything" in the books. Inspecting the elements that I needed to interact I've found that every single one was pointing to a JS with some arguments.
href="JavaScript:SWESubmitForm(document.SWEForm2_0,s_10,"s_2_1_96_0","VRId-0")" tabindex="2997" id="s_2_1_96_0">Track Faults
Looking further found that s_10 is a variable within the script which have different options from s_0 to s_14.
var s_0 = {action:"/esales_enu/start.swe",target:"_sweview",SWECmd:"GotoView",SWEMethod:"GotoView",SWEView:"L2C Track Channel Reference View BT",SWEApplet:"L2C New CZ Home Page Applet BT",SWEReqRowId:"0",SWESP:"false",SWENeedContext:"true",SWEKeepContext:"0",SWEDIC:"false"};
var s_10 = {action:"/esales_enu/start.swe",target:"_sweview",SWECmd:"GotoView",SWEMethod:"GotoView",SWEView:"New Portal Fault Search View ORH BT",SWEApplet:"L2C New CZ Home Page Applet BT",SWEReqRowId:"0",SWESP:"false",SWENeedContext:"true",SWEKeepContext:"0",SWEDIC:"false"};
So I started searching and found driver.execute_script() and I've wrote:
driver.execute_script("SWESubmitForm(document.SWEForm2_0,s_10,'s_2_1_96_0','VRId-0')")
But this occurs:
selenium.common.exceptions.JavascriptException: Message: javascript error: SWESubmitForm is not defined
What I'm missing here? Syntax? If someone can shed some light on which direction should I go, it will be really appreciated.
Thanks.

I was able to fix this and learn a few things. The JS "theory" I was taking didn't made any sense since the driver.execute_script() isn't used the way I was thinking but rather injecting code or finding elements as well.
Second, the solution was actually frames :)
I was so focused in switching between the two frames I had found initially that for not one moment I thought that INSIDE those two frames could had been more frames!
And basically that was it, after switching to the main frame, I've switched again to the 2nd frame inside that main one and was able to find through xpath.

Related

How can I edit html inside an iframe using javascript

I am working on automating a process within my business, part of which is sending an email through SalesForce. We don't have access to the SF API and the email has to be sent through salesforce in order to keep the communication searchable for the coworkers.
I need to use a template which can be selected in SalesForce, however this function does not work in IE (which our RPA solution uses) so I need to build this email from scratch.
I see two options for this:
Use the HTML to recreate the format with the right variables. This entails inserting/injecting/manipulating HTML.
Copy the format into memory/the clipboard, edit it programatically and paste it into the SF interface
This question will be about option 1. I will post an additional question with regards to the second option separately and edit this question to include that link. EDIT: Here is the link to the other question!
Now on to the question:
We use the Blue Prism RPA software suite. It has a possibility to insert javascript fragments into a website and subsequently invoke them. I was hoping that I could create a javascript fragment that recreates the template, insert it and then invoke it. I have been working on this for the past week and have hardly gotten any further.
I now am able to add basic text into the required field, but have found that to be able to use the template structure I need to use a different, HTML based, field. This field I find lives inside an iframe.
I have had zero experience with javascript prior to this week (luckily it seems similar to c# in which I do have experience) and now this iframe has me stumped. Apparently when you use Selenium or similar you can switch the driver to the new iframe but I don't have that option, it needs to be done through surface automation. Within javascript as well as the console I can not get it to target the separate document within the iframe. Apparently the iframe contents are not incorporated in that way in the bigger webpage.
So my question is this: How can I "switch focus" to the iframe using javascript? How can I then edit the iframe contents through javascript? Any help, tips etc. would be highly appreciated!
If you go to developer tools in the browser (F12 or right-click inspect) you can use the inpsect tool to get the path you are looking for. an iframe is just another window inside the window and once you have the 'base path' you can then extend further into the window from the iframe base path.
You can access frames one of two ways I know of;
document.getElementById('the frame you are looking for goes here').contentWindow.targetFunction();
and/or
window.frames[0].otherfunctions
where 0 is the Nth order of frame on the window in case there are others.
once you find that path you can interact with sub-elements on that iframe by getting the path to it from within the iframe.
some things to watch out for. frames not loading yet so make sure the frame you want is loaded and no other frame is moving it around the screen at run time. Also make sure the child frame is in the same domain, I think calling javascript has issues when going cross-domain i.e. it doesn't work (stand to be corrected there though maybe it depends on group settings)
Supply some code or the layout of the page and could give you a code example but top of my head the format will look like this
var doc = window.frames[0]
var thing = getElementById(doc.getElementByPath('maybePath')
'perform some set operations like set innerhtml to thing you desire

Selenium - How to find and click element via xpath when page is rendered via javascript

Problem:
I am trying to find an element and then click it via xpath using selenium and python, on a web page that is rendered with JavaScript. The xpath has been confirmed to be correct, the issue is that the html isn't fully rendering due to only seeing the javascript "top level" (i think that's the right term).
I have seen methods of finding the full html code and saving it as a string, but that is not clickable via selenium
What I Am Looking For:
A method to just render all the javascript code, so that I can access the html elements I am looking for.
Code Would Look Like:
browser.render_javascript()
browser.find_element_by_xpath("//span[text()='Budget & Cost Management']/../preceding-sibling::img[2]").click()
Currently if I try to find the xpath above, it says it doesn't exist. However, if I inspect the page and search this xpath, it takes me right to the element. Obviously, selenium isn't seeing this element though because it isn't available to it (not rendered or executed, not sure which is the correct term).
I have also tried to just wait 30 seconds before searching for this element, but it doesn't look like any amount of time will render the page to selenium.
Is this possible? What kind of workarounds are available?

Selenium + PhantomJS in Python 2.7, file upload

I've been struggling with this function for a few hours now and I can't get it to work in any way shape or form.
Assume my element location and image path are correct at all times. (Seriously, I've been going over this for the past 4 hours, it's not the element location and it's not the file path.)
What I started with was a sendkeys to the input element. This gave no error but caused the script to hang for ever; it wouldn't get past it and no images were being uploaded.
I literally tried every single possible variation of the sendkeys method listed on the first 4 pages of Google when looking for "Python PhanthomJS Selenium upload file sendkeys". Back to the drawing board.
Currently I am looking into executing a bit of JavaScript through Python to upload the file, though I have no idea how to go about this.
The page which I am trying to upload to has its form set to hidden and only shows a button which opens an upload dialog on normal browsers. I feel this is why sendkeys was not working.
Can anyone give me some input or suggestions as what to try next? Or how to execute some JavaScript from Python?
EDIT:
I learned how to execute JavaScript while using selenium in python and it saved my day.
To anyone coming here from google or whatever with the same problem, let me explain what I did:
The fact that my .send_keys() was hanging when sending keys to the input[file=input] element had me wondering before I made the topic but since the webdriver was still able to find the element I wasn't thinking too much of it and shrugged it off as something random. Later however I came with a suggestion that because it had a css type display: hidden !important the webdriver might have been able to find it, but not interact with it, and for some reason selenium just decided to hang itself instead of crashing / giving an error.
With that in mind I started browsing the docs and found the .execute_script() command, turns out we can use this to run a piece of JavaScript through the webdriver. Why I wanted this, is to see if the class styling had anything to do with it at all, how you ask? Well we can use the following line of code to change the class attribute of the input[type=file] element: document.querySelector("input").className="". This is not the most elegant solution since we are basically deleting the entire class responsible for the display: hidden !important styling. If the class were to hold more important data I'd suggest changing the class instead of renaming it to "" or deleting.
Moving on and trying it out, it showed the input button just like I hoped it would! After this I simply re-tried sending the keys and found no problems at all. There is no need for a click, submit or anything. driver.find_element_by_css_selector('input[type=file]').send_keys('path/to/file') However I did note that the way you structure the path seems to be pretty important. For example I am testing on windows and path/to/file did not upload or select any image for me, using path\\to\\file however, worked completely fine.
tldr:
driver.execute_script('document.querySelector("input")').className=""
followed by:
driver.find_element_by_css_selector('input[type=file]').send_keys('path/to/file')
Is what worked for me, and if you are in any alike situation your
variation on the script should upload the image as intended.

Chrome extension for manipulating webpage by adding an icon next to matched links

Hello i want to write an extension myself and looking for guides/tutorials. I have never created one but i am good with js and html/php.
I need a tutorial/sample code, and here is what i want to do:
when an extension is loaded, i want to add icon next to the google search results (matched links). What it would do is, it will check all the link in a webpage by matching them with a database (php server mysql) and if a match of a domain is found, then it will simply add an icon next to that link (by ofcourse manipulating dom).
Seems like a fairly simple task to do. So if anybody can help me by showing me a correct path or if there is any similar extension already available to learn from, then please advice.
I would be very grateful, thanks!
http://developer.chrome.com/extensions/getstarted.html
Have a browse through this. You'll likely get the hand of it if you're proficient with JS.

Serialization of the full page DOM. Can I get at the JS code that is loaded up, or must I AJAX it separately?

I have a bug I'm trying to track down, and it is very difficult to do so because of the complexity of the web app. There are many frames, and many instances of Javascript code that is embedded into the HTML in different ways.
The thing that needs to be fixed is a sub-page created with showModalDialog (so you already know it's going to be a disaster), and I am hoping that I can find a way to serialize as much of the DOM as possible within this dialog page context, so that I may open it to the same content both when the bug is present and when it is not, in hopes of detecting missing/extra/different Javascript, which would become apparent by pumping the result through a diff.
I tried jQuery(document).children().html(). This gets a little bit of the way there (it's able to serialize one of the outer <script> tags!) but does not include the contents of the iframe (most of the page content is about 3 iframe/frame levels deep).
I do have a custom script which I'm very glad I made, as it's able to walk down into the frame hierarchy recursively, so I imagine I can use .html() in conjunction with that to obtain my "serialization" which I can then do some manual checking to see if it matches up with what the web inspector tells me.
Perhaps there exists some flag I can give to html() to get it to recurse into the iframes/frames?
The real question, though, is about how to get a dump of all the JS code that is loaded in this particular page context. Because of the significant server-side component of this situation, javascript resources can be entirely dynamic and therefore should also be checked for differences. How would I go about (in JS on the client) extracting the raw contents of a <script src='path'> tag to place into the serialization? I can work around this by manually intercepting these resources but it would be nice if everything can go into one thing for use with the diff.
Is there no way to do this other than by separately re-requesting those JS resources (not from script tags) with ajax?

Categories

Resources