VBA with selenium throws element not visible error - vba

Upon running my script , I get stuck with element not visible error in vba with selenium. Here is the code I was trying with:
Sub Table_stuff()
Dim driver As New WebDriver
With driver
.Start "chrome", "http://apps.tga.gov.au/Prod/devices"
.get "/daen-entry.aspx"
.Timeouts.PageLoad = 20000
.FindElementById("disclaimer-accept").Click
.Timeouts.PageLoad = 20000
.FindElementById("medicine-name").SendKeys ("pump") ''Error thrown here
.FindElementById("medicines-header-text").Click
.FindElementById("submit-button").Click
.Timeouts.PageLoad = 20000
End With
End Sub
Here is the element reaching where my scraper throws that specific error:
<input type="text" name="medicine-name" id="medicine-name" value=""
placeholder="Type at least 3 characters" title="Enter medical device name"
autocomplete="off" maxlength="100" class="placeholder" style="color: rgb(0, 0, 0);">

From what I understand Timeouts.PageLoad call would not actually trigger selenium driver to wait - I think it just sets a page load timeout. Which means that your code would try to send keys to the search input at the moment of the opened license dialog - which triggers the "element not visible" error.
What you need is a Wait call (well, ideally an Explicit Wait, but I am not sure if VBA bindings have that functionality):
.Wait 3000 ''3 seconds

Related

Click OK in popup using Selenium VBA

Trying to automate an on-line order process. Once the order specification is completed you press the Save button. If the item specification (height) is >1000mm a popup is displayed. I am having problems automating Clicking it. It is not in an iframe.
On the second line of code below:
bot.FindElementById("ctl00_mainContent_ucOrderDetailBlind_btnSave").Click
'Clicking 'causes' the popup warning to display if the >1000mm condition is TRUE. It has only one button - 'OK' (coded as nbsp;OKnbsp; ). Clicking manually allows automatic progress to go to the next page but I need help to get the coding to do this automatically. At the moment the code appears to be hung displaying the popup. Debug indicates that the next instruction cannot be executed - obviously because that findElementById....Click cannot be found because the process has got stuck.
I have tried several Alternatives - please see the code for the most likely that I tried.
If ThisWorkbook.Sheets("SquareSpace").Cells(r, "F").Value > 1000 Then ' The item is more than 1000mm high
bot.FindElementById("ctl00_mainContent_ucOrderDetailBlind_btnSave").Click
'Alternative 1
bot.FindElementByXPath("//input[#ID='popup_ok' and text()=' OK ']").Click
'Alternative 2
bot.SwitchToAlert.Accept
bot.Wait 1000
Alternative 3
bot.FindElementById("popup_ok").Click
Else ' for when the item is not more than 1000mm high
bot.FindElementById("ctl00_mainContent_ucOrderDetailBlind_btnSave").Click
bot.Wait 500
End If
'Then the next instruction of the form bot.FindElementById ......Click
The HTML with some stuff removed for clarity (text and styling):
<div id="popup_container" class="ui-draggable" style="position: absolute; z-index: 99999; padding: 0px; margin: 0px; min-width: 604px; max-width: 604px; top: 0px; left: 647.5px;"><h1>Warning</h1>
<div id="popup_content" class="alert">
<div id="popup_message"><br>WARNING TEXT</div>
<div id="popup_panel"><input type="button" value=" OK " id="popup_ok"></div>
</div>
</div>
Any suggestions are appreciated. Thanks.
To click on the element with value as OK you can use either of the following Locator Strategies:
Using FindElementByCss():
bot.Wait 5000
bot.FindElementByCss("div#popup_container div#popup_panel > input#popup_ok").Click
Using FindElementByXPath():
bot.Wait 5000
bot.FindElementByXPath("//div[#id='popup_container']//div[#id='popup_panel']/input[#id='popup_ok']").Click
Try using javascript to click the button:
[edit - updated identifier]
element=bot.FindElementByXPath("//input[#id='popup_ok']")
x =bot.ExcuteScript("arguments[0].click();", element)
[code above updated - see comments]
[new below]
Had a bit of fun getting this to work as expected.
This is my little test function to give you an idea of what i used to check things:
Function selenium()
Dim driver As New WebDriver
Dim element As WebElement
driver.Start "chrome"
driver.Get "https://www.google.co.uk"
driver.FindElementByXPath("//input[#name='q']").SendKeys "hello world"
Set element = driver.FindElementByXPath("//input[#value='Google Search']")
x = driver.ExecuteScript("arguments[0].click();", element)
End Function
Not sure why i had to assign a response back from the execute script but it wouldn't work without it.
The best and simplest method I've found is to just use driver.SwitchToAlert(5).Accept. The 5 is just a number of seconds to wait before accepting the error message. You can use any number of seconds in here.

Run-time error '0': SeleniumError invalid argument using Selenium, vba and css selector to click a button

I'm trying to click a button on a webpage, and keep getting the below error (sorry, can't embed images yet apparently, otherwise I would put a screenshot on here)
Run-time error '0':
SeleniumError
invalid argument
The Http for the button is
<input type="file" name="import_file" id="import_file" accept=".csv, text/csv">
I've tried bot.FindElementById("import_file").Clickand that returned the same error, so I then tried using the name, same error.
I've just tried bot.FindElementByCss("input#import_file[type='file'][name='import_file'][accept='.csv, text/csv']").Click and that returns the same error...
Not sure what to try next; any ideas? My entire sub is below for reference (with passwords, etc, overwritten obviously)
Sub import_csv()
Dim bot As New WebDriver
bot.Start "chrome", "https://website.com"
bot.Get "/"
'log in
bot.FindElementById("user_login").SendKeys ("####")
bot.FindElementById("user_password").SendKeys ("####")
bot.FindElementByName("commit").Click
'navigate to import screen
bot.Get ("/stocks/import_stocks")
'tick 'File has header row?'
bot.FindElementById("file_has_header").Click
'Click 'Browse...' to open import screen - this is where something isn't working
bot.FindElementByCss("input#import_file[type='file'][name='import_file'][accept='.csv, text/csv']").Click
'import
bot.FindElementByName("commit").Click
bot.SendKeys ("C:\Users\Duane Humphreys\Documents\calendar.CSV")
bot.SendKeys bot.Keys.Enter
bot.FindElementByName("commit").Click
End Sub
EDIT:
The html surrounding the button I'm trying to click is below, if that's useful:
<span class="l-inline-row-block form-file">
<span class="l-inline-col" style="width: 110px;">
<a class="btn-medium btn-alt form-file-btn">
Browse… <input type="file" name="import_file" id="import_file" accept=".csv, text/csv">
</a>
</span>
<span class="l-inline-col">
<input type="text" readonly="">
</span>
</span>
I don't think this has solved the root cause of whatever is happening here, but I've managed to get round it with
bot.FindElementById("import_file").ClickAndHold
bot.SendKeys bot.Keys.Enter
I still have no idea why .ClickAndHold works and .click doesn't, but this will work for now. LMK if there's a cleaner way to achieve the same thing.
Invalid argument
The invalid argument error is a WebDriver error that occurs when the arguments passed to a command are either invalid or malformed.
This error message...
Run-time error '0': SeleniumError invalid argument
...implies that the arguments passed to a command are either invalid or malformed.
From the WebDriver - W3C Living Document:
There seems to be a minor issue with the presence of the dot character i.e. . with in the Locator Strategy you have used. In short, you need to avoid the . character in your locators. You can use either of the following solutions:
bot.FindElementByCss("input#import_file[type='file'][name='import_file'][accept*='csv']").Click
Or
bot.FindElementByCss("input#import_file[type='file'][name='import_file'][accept$='text/csv']").Click

How to click on the element as per the html through VBScript and Selenium

I'm using VbScript with Selenium driver to connect to Chrome (store.steampowered.com/app/681530/NOISZ/) and want to click the "Next in Queue" button which is a div class, but nothing happens. I know I'm on the right track because the below lines does work as expected:
(Displays the text Next in queue)
msgbox(driver.FindElementsByXPath("//div[#class='next_in_queue_area']/div[#class='btn_next_in_queue btn_next_in_queue_trigger']").Item(1).text)
(Scrolls to the Next in queue button)
driver.FindElementsByXPath("//div[#class='next_in_queue_area']").Item(1).ScrollIntoView
(But trying these ones does nothing and also no error messages)
driver.FindElementsByXPath("//div[#class='queue_actions_ctn']").Item(1).Click
driver.FindElementsByClass("next_in_queue_content").Item(1).Click
Using Chrome's Inspect when highligtning this code the Next button is highlighted entirely:
<div class="btn_next_in_queue btn_next_in_queue_trigger" data-tooltip-text="Remove this product from your queue and continue to the next item.">
<div class="next_in_queue_content">
<span>Next in Queue<br>
<span class="queue_sub_text">(11 remaining )</span>
</span>
</div>
</div>
So it is just a question of finding the correct div or span to click
To click the button with text as Next in Queue you can use either of the following solution:
FindElement with XPath:
driver.FindElementByXPath("//div[#class='btn_next_in_queue btn_next_in_queue_trigger']/div[#class='next_in_queue_content']/span").Click
FindElements with XPath:
driver.FindElementsByXPath("//div[#class='btn_next_in_queue btn_next_in_queue_trigger']/div[#class='next_in_queue_content']/span").Item(1).Click
As an alternative you can use the ExecuteScript() method as follows:
Dim js As IJavaScriptExecutor = TryCast(driver, IJavaScriptExecutor)
js.ExecuteScript("arguments[0].click();", driver.find_element_by_xpath("//span[starts-with(#id, 'button-')][#class='x-btn-inner x-btn-inner-center']"))
Or
Imports OpenQA.Selenium.Support.Extensions
driver.ExecuteJavaScript("arguments[0].click();", driver.find_element_by_xpath("//span[starts-with(#id, 'button-')][#class='x-btn-inner x-btn-inner-center']"))

Simulate Click event on a DIV element

I cannot simulate a click event on a div element. The HTML code is this one:
<div id="export" data-export="true" data-timespan="">
<button class="btn btn-default ladda-button" type="button" data-style="expand-right" data-spinner-color="#8899a6">
<span class="Icon Icon--featherDownload"></span>
<span class="ladda-label">
Exportar datos
</span>
<span class="ladda-spinner"></span></button>
<div class="hidden error server Callout Callout--danger">
<p>Ocurrió un problema al exportar tus datos, inténtalo de nuevo más tarde.</p>
</div>
</div>
In the webpage, is just a button that downloads a file when clicked. There is no URL. But after checking the code, is the div element what triggers the click event. Look the image.
Click to see image
That "g.handle" triggers a js.file form the website.
My vba code works perfect for doing other stuff in the website, but I cannot accomplish this task.
I've tried all this options:
Set div = HTMLDoc.getElementById("export")
div.FireEvent ("onclick")
div.Click
HTMLDoc.all.Item
Call HTMLDoc.parentWindow.execScript("g.handle", "JavaScript")
Nothing works. I'm kind of blocked right now and I have no idea of how to proceed. Maybe this has no solution? I have almost no idea of HTML and I have 0 idea of Javascript. But it must have a solution, because if I do it manually, i click on that DIV, wait some seconds and download my file.
Thanks in advance. Any help is welcome.
You didn't specify if the highlighted portion was the html code for the button or not, but it appears from looking at it that it isn't.
You can grab the class name for your button. The name may or may not be unique, and it's difficult to know that without seeing the entire html code, but you can set the btn variable below to the first instance of that class name. If there are multiple class names in your html code, then you will need to use a For Each...Next statement to iterate through them (unless you know the instance number off hand).
So we will go with the first instance of your class, hence the reason for the (0) appended on the end.
Sub Test()
Dim ie As New InternetExplorer, HTMLDoc As HTMLDocument, btn As Object
ie.navigate Url 'whatever this may be
' Some code to wait for your page to fully load
Set HTMLDoc = ie.document
Set btn = HTMLDoc.getElementsByClassName("btn btn-default ladda-button")(0)
btn.Click
End Sub

Trying to fill web form with VBA, can´t address element

I am trying to fill out a web form in IE with data from a workbook but I am having trouble addressing the text box since it seems to lack a name.
The site is behind a login so no link, sorry. But the element presents itself as
<input type="text" placeholder=" Søg på brugernavn, referencenummer, eller e-mail" ng-model="filterSearch.search" ng-change="filterOnSearch()" ng-model-options="{ debounce: 500 }" class="ng-pristine ng-valid ng-empty ng-touched">
when inspecting it in chrome.
I have tried
ie.document.getelementsbyclassname("ng-pristine ng-valid ng-empty ng-touched").Value = "11"
but VBA throws me a run-time error '438': Object doesn't support this property or method.
Any suggestions?
It may sound confusing but anytime you are trying to pull an element by classname you need to use the
.item(0)
after that you would use something similar to
ie.document.getelementsbyclassname("ng-pristine ng-valid ng-empty ng-touched").item(0).Value = "11"
This is assuming that you are trying to fill out an input box that has the class above and that the element is the only 1 in its class or the first one.
In the event that it does not work it may not be the first element in that class and then you may need to do item(1) or item(2) etc.