Get multiline text from textarea with Selenium VBA - vba

I need to get multiline text from textarea element of web-page. I see in Chrome developer tool that text I need is stored in value property of textarea.
I marked it on screenshot
Below is fragment of page source:
<div id="team1">
<div id="lineupsPanel1" style="display: block;">
<textarea id="lineupsField1" placeholder="Enter text for analyze here"></textarea>
<button onclick="viewLineupsInTable(1,1)" title="Process text" style="cursor: pointer; font-weight: bold; color: red; padding: 3px 6px; margin: 0px 4px
0px 0px;">Process</button>
I try below code to get text from value property
Set WebElemTextBox = Chrome.FindElementById("lineupsField1")
If Not (WebElemTextBox Is Nothing) Then
TextVar = WebElemTextBox.value
End If
But so TextVar gets only first line of stored text (on screenshot example
value: "Next items are not found:↵↵Pam-pam↵↵Next items are found:↵↵Monitor"
But TextVar gets only "Next items are not found:" ).
How to get full multiline text?
I also found some answers to use something like
TextVar = WebElemTextBox.getAttribute("value")
But I get
"Run-time error: 438. Object doesn't support this property or method"
on that string while testing.
UPDATE. I figured out the problem myself:
When you watch value of the variable by moving cursor to it - then for string variable is showing only first line of text without any mark (three dots or something else). We should use Watch Window instead to not to be cheated.
So method TextVar = WebElemTextBox.value works well.

If possible posting the HTML would be helpful, but I'll try answering it anyway.
First Check your element Id for each line you wish to make into a string, I'm assuming they are sequential. Something like "lineupsField1", "lineupsField2", lineupsField3" etc.
If so you can loop through and append these values to a string. Ex:
For i = 1 to 10
Set WebElemTextBox = Chrome.FindElementById("lineupsField" & i)
If Not (WebElemTextBox Is Nothing) Then
TextVar = TextVar & WebElemTextBox.value
End If
Next
If the element Id's are not in sequential order than instead of looping just append till you reach your goal. Ex:
Set WebElemTextBox = Chrome.FindElementById("lineupsField1")
If Not (WebElemTextBox Is Nothing) Then
TextVar = TextVar & WebElemTextBox.value
End If
Set WebElemTextBox = Chrome.FindElementById("Element2")
If Not (WebElemTextBox Is Nothing) Then
TextVar = TextVar & WebElemTextBox.value
End If
As far as the other method you showed:
TextVar = WebElement.getAttribute("value")
I wouldn't recommend going down this path as you are likely going to create more work for yourself parsing through all the values in the HTML.

I figured out the problem myself:
When you watch value of the variable by moving cursor to it - then for string variable is showing only first line of text without any mark (three dots or something else). We should use Watch Window instead to not to be cheated. So method
TextVar = WebElemTextBox.value works well.

Related

Selenium VBA - Runtime Error 11 ElementyNotVisible Error element not interactable

I am using the below mentioned code for automation of Edge Browser
The code is working fine except for "If then Else" block.
The complete script is as follows
Dim Obj As New WebDriver
' search for company - SF 1cr and above
Sub EdgeAutoSF1CRA0()
Set Obj = New Selenium.EdgeDriver
Dim ele As WebElement
Dim By As New Selenium.By
Obj.SetCapability "ms:edgeOptions", "{""excludeSwitches"":[""enable-automation""]}"
Obj.Start "edge", ""
Obj.Get "https://*********************"
Obj.Window.Maximize
Obj.FindElementByName("croreAccount").SendKeys ("Search")
Obj.FindElementByXPath("//*[#id='loadSuitFiledDataSearchAction']/div[1]/div[3]/div[4]/img").Click
Obj.FindElementById("borrowerName").SendKeys (ThisWorkbook.Sheets("Sheet1").Range("C5").Value)
Obj.FindElementByXPath("//*[#id='search-button']/ul/li[1]/div/input").Click
Obj.Wait 30000
If Obj.FindElementByCss("#downloadReport").Attribute("Style" = "display") = "none" Then
Obj.FindElementByXPath("//*[#id='three-icons']/ul/li[3]/a/div").Click
Else
Obj.FindElementByXPath("//*[#id='downloadReport']/div").Click
End If
End Sub
In the If then Else statement I want to search for the style attribute of the id "downloadReport" for "display :none"
The code on website is < a href="downloadStatusReport" id="downloadReport" style="display: none;"><div class="download-icon">Download</div></a>
However, code always evaluate the statement as False and proceeds to execute the command "Obj.FindElementByXPath("//*[#id='downloadReport']/div").Click"
The attribute name is style, not capitalized Style.
You can construct the locator so that the desired style value will be a part of locator itself.
You can use FindElements instead of FindElement so it will return you a list of matching elements so as if such element found it will return a non-empty list, otherwise it would be an empty list. With this you can check if returned list is empty or not, as following:
If Not IsEmpty(Obj.FindElementsByCss("[id='downloadReport'][style*='none']")) Then
Obj.FindElementByXPath("//*[#id='three-icons']/ul/li[3]/a/div").Click
Else
Obj.FindElementByXPath("//*[#id='downloadReport']/div").Click
End If
In short, there is no merit in locating an element with style attribute set as display: none;. Even through you locate the element, you won't be able to click on it. So the If-Then-Else logic won't work as intended.
Instead find the desired element which is visible and enabled element, so you can invoke click on it.

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.

VBA IE Automation - cannot find "export" element ID

I'm working in Microsoft Excel 2010 VBA and I'm trying to automate pdf report downloads. I can navigate to where I need to be but I'm stuck on the last step;
There's an "Export" element that behaves like a link. If I were to click on it, it would initiate a pdf download. I want to automate this and direct the download to a specified folder, but when I inspect the element it doesn't appear to have an element ID by which I can call it (ie. getElementById().Click).
I'm new to VBA IE automation. Does anyone have suggestions on how to initiate that "Export" function?
I can't share the full HTML detail, as it is for a site with sensitive data, but below are snippets of the HTML, my VBA code, and a screenshot of the HTML section that is in question:
<DIV style="FONT-SIZE: 8pt; HEIGHT: 30px; FONT-FAMILY: Verdana; DISPLAY: inline"><TABLE style="DISPLAY: inline" cellSpacing=0 cellPadding=0>
<TBODY>
<TR>
<TD height=28><SELECT id=PrintFormat><OPTION value="">Select a format</OPTION><OPTION selected value=Pdf>Acrobat (PDF) file</OPTION></SELECT></TD>
<TD width=4></TD>
<TD height=28><A onclick="if (document.getElementById('PrintFormat').value != '') {var url = document.getElementById('PrintFormat').value + 'Stream.aspx'; document.location.href = url;}" style="FONT-SIZE: 8pt; TEXT-DECORATION: none; FONT-FAMILY: Verdana" href="#" shape="">Export</A></TD></TR></TBODY></TABLE></DIV>
My vba code;
Sub pdfdownloadautomation()
Set objIE = New InternetExplorer
objIE.Visible = True
objIE.navigate Sheet3.Range("A1").Value 'A1 contains url
objIE.document.getElementById("PrintFormat").Value = "Pdf"
'works fine to this point - just not sure how to call the export
objIE.document.getElementById("?").Click
End Sub
screenshot of inspected element in IE
You may try a CSS selector as follows to target the element. I can't test and don't know if there are parent frame/iframe/form tags to navigate. There appears to be one form element at least visible. Please provide the html including this form tag if possible. I have given variations without parent form and including parent form (which looks to be the case) - the assumption with the parent form element is that it is the first form element on the page.
ie.document.querySelector("td a[onclick^='if']").Click
Which might become:
ie.document.getElementsByTagName("form")(0).querySelector("td a[onclick^='if']").Click
The CSS selector is likely more complex than required but I am trying to localize using the visible cues in your image i.e. that there is an element with an a tag, that has onclick attribute starting with 'if', and is inside a parent td tag.
You could also gather all the a tag elements and loop until the Export innerText is found:
Dim list As Object, item As Object
Set list = ie.document.getElementsByTagName("a")
For Each item In list
If item.innerText = "Export" Then
item.Click
Exit For
End If
Next
Again, this may become
Set list = ie.document.getElementsByTagName("form")(0).getElementsByTagName("a")

Protractor Automation: Selection of element

I'm trying to automate selection of some products...Here's a screenshot
The user clicks on the top row of 'base' colours and then selects the desired colour from the resulting pallet beneath.
I am able to select a base colour without issue.
element(by.xpath('html/body/main-app/kf-sidebar-app/div[1]/app-container/div/dashboard/div/div/visualise/open-interface/div/div/div[2]/div[2]/digitalbridge-category-list/div/digitalbridge-category-view[2]/div/div[1]/div/div[2]')).click();
...selecting the desired colour is altogether much more maddening!!! The closest I've got has resulted in a "Element not visible" message....tried adding in 'waits' but no difference.
This code..
var EC = protractor.ExpectedConditions;
var paintSelected = element(by.xpath('.//div[#id="2386"]'));
browser.wait(EC.visibilityOf(paintSelected), 7000);
paintSelected.click();
..produces line-after-line of..
[11:27:22] W/element - more than one element found for locator By(xpath, .//div[#id="2386"]) - the first result will be used
This keeps running until the 7000ms timeout is reached. I've tried using 'first' but it's not 'recognised'....also tried [0] but again, not recognised.
Here's the line from Console...
<div _ngcontent-c63="" class="item circle" id="2386" style="background-image: url("https://shortbite.s3-eu-west-1.amazonaws.com:443/category/raw/941027c0-f6e6-434c-9ab9-66f9918c33e6.png?Signature=Zbffcvf73Nv9g2v9G3SmcYn6h24%3D&Expires=1510141234&AWSAccessKeyId=AKIAIUUATNKB37DELIXQ");"> </div>
Please try and save my sanity! Thanks
David
Try putting your selector into the console i.e $x(".//div[#id='2386']").
Just to see if you really have two elements with the same Id
Also do a find elements and debug the collection of elements.
One thing I have done with my extended framework is implemented a highlight element functionality.
IJavaScriptExecutor js = Driver as IJavaScriptExecutor;
js.ExecuteScript("arguments[0].setAttribute(arguments[1], arguments[2])", ReferenceElement, "style",
"border: 2px solid red; border-style: dashed;");
if you have id you can check all elements available with that id in chrome or firefox console like that:
$$('#2386')
$$ will return all, one $ will return the first one.
because if you have more than 1 element with the same locator, protractor will get the first one.
If there is no way to give you elements different locators you can get it by index.
for example in you code first loacte all elements and assign it to varible:
var allColors = $$('#2386'); // same as element.all(by.id('2386'))
or get them by index
var firstColor = $$('#2386').get(0); // or $$('#2386').first();
var secondColor = $$('#2386').get(1); // or $$('#2386').first();
Use firepath and find out the absolute xpath .
Then add some wait and try to click on the element using absolute xpath

Change textarea inside webbrowser

I'm trying for hours to change a text area inside a webbrowser in VB.net. I was not able to do it... This is the code from that textarea :
<textarea name="message_html" class="textCtrl MessageEditor BbCodeWysiwygEditor " id="ctrl_message_html" style="height: 260px; display: none;" data-options='{"autoSaveFrequency":"60","bbCodes":[]}' data-auto-save-url="forums/Snapchat-Girls/save-draft" data-dialog-url="index.php?editor/dialog&style=1" data-css-url="css.php?style=1&css=editor_contents&d=1447310869"><p>This is where the text will be</p></textarea>
Note : Loog for "This is where the text will be" inside the code.
Codes i tried :
For Each element As HtmlElement In Me.WebBrowser1.Document.All
If element.OuterHtml.Contains("textCtrl MessageEditor") Then
element.SetAttribute("value", "TEST")
End If
Next
WebBrowser1.Document.GetElementById("ctrl_message_html").SetAttribute("value","TEST")
For Each element As HtmlElement In Me.WebBrowser1.Document.All
element.SetAttribute("value", "TEST")
Next
None of these worked...
PS : Is not my website. So don't ask me to add ids or something.
I am sure this is not needed anymore, but for reference to those who might still be looking for an answer to this question....maybe this might help your needs
Dim Wctl as string = WebBrowser1.DocumentText.Replace("[searchvalue1]", "test1").Replace("[searchvalue2]", "test2")
Then
WebBrowser1.DocumentText = "0"
WebBrowser1.Document.OpenNew(True)
WebBrowser1.Document.Write(Wctl)
WebBrowser1.Refresh()