How can i select the div id in Selenium 2 WebDriver? - c#

I want to find a tag in selenium 2 with C#, but I can't get access to div tag with id or xpath or etc. This is my code:
driver.FindElement(By.Id("captcha"));
and the web source is:
<body id="mainBody">
<div class="top_bar" style="min-height:210px">
<div class="m_sidebar_view">
<div id="captcha" style="position: relative; float: right; margin: 6px 35px 0 0; overflow: auto;"><div/>
</div>
</div>
</body>

Captcha is often loaded within an iframe (see, for instance, the google recaptcha demo source code). Switch to it before searching for the captcha element:
driver.SwitchTo().Frame("frame_name_or_id");

Although it's unclear what your problem is, one of the most popular mistakes is not waiting for the element. So try to wait:
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>
{
return d.FindElement(By.Id("captcha"));
});

Related

Can't interact Selenium Chromedriver with Chrome extension made TextArea

I have a GoogleMeets extension that will help with attendance of persons inside the meet. (It's Google Meet Attendance - https://github.com/al-caughey/Google-Meet-Attendance)
After I open the webpage with selenium webdriver and interact with a icon element to show the textarea when I try to interact with this textarea it I get Exception: Element Not Interactable or Cannot set property of 'innerText' of null when using IJavaScriptExecutor
NOTE
Functions names are different because i made a wrapper class around the IWebDriver Object
The HTML code of page and TextArea
The HTML code of page and TextArea:
<!DOCTYPE html>
<html lang="ro" dir="ltr"> >
<head>...</head>
<body jscontroller="pjice" jsaction="rcuQ6b: npT2md; click:FAbpgf; auxclick:
Abpgf; mousedown:.CLIENT; keydown:.CLIENT;UjQMac:.CLIENT;WINJic:.CLIENT;PDJFbb:.C
LIENT; AbmZie:.CLIENT; keyup:.CLIENT; keypress:.CLIENT;nHjqDd:.CLIENT; Lhiqec:.CLIE
NT;VSCbUd:.CLIENT;GvneHb:.CLIENT;qakode:.CLIENT" class="EI1Dfe">
<script aria-hidden="true" nonce>
window.wiz_progress && window.wiz_progress();
</script> >
<div class="MCCOAC IqBFM ecJEib EwZcud cjGgHb d8Etdd LcUz9d" id="yDmHºd" style="bottom: auto; right: auto; width: 1318px; height: 870px;">...</div>
<div class="MhØNND Mp270b xbg16e mistle" jsaction="click:.CLIENT" style="vi
sibility: visible;">...</div>
<div aria-live="polite" aria-atomic="true" style="position: absolute; top:
-1000px; height: 1px; overflow: hidden;"></div>
<div id="gma-attendance-fields" data-generate-files="both" class data-auto- add="true">
<div id="gma-class-list-div"> >
<p id="gma-class-list-header" class="gma-header" style="display: block;
">...</p> >
<p id="p-attendance-summary" title="Not Monitoring Attendance!">.</p>
<textarea id="class-notes" title="If you want to add any notes related
to this class..." placeholder="Enter any notes specific to this clas
S." X/textarea> >
<p id="invited-list-help" class>...</p>
<textarea id="invited-list" title="Pick, paste or type your class list
into this field" placeholder="Your class list goes here.
Click the blue question mark below for help." classx</textarea> == $0 >
<div id="ema-class-list-buttons" class></div>
CODE
public void start_bot()
{
this.setDriverTimeout(60);
if (this.driver.WindowHandles.Count > 1)
{
this.driver.SwitchTo().Window(this.driver.WindowHandles[1]);
}
try
{
IWebElement classroom = this.findElementByXPath("//*[#id='class-list-edit']");
//classroom = this.findElementByXPath("/html/body/div[3]/div[1]/p[1]/select");
while (!classroom.Enabled && !classroom.Displayed)
{
classroom = this.findElementByXPath("//*[#id='class-list-edit']");
}
classroom.Click();
Thread.Sleep(5000);
classroom = this.findElementByClassName("being-editted");
// this.driver.SwitchTo().ActiveElement();
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
js.ExecuteScript("document.querySelector('textarea.being-eddited').innerText='Deoanca Rares'");
classroom.SendKeys("John Doe");
Console.WriteLine("Found Element");
// IJavaScriptExecutor js = new IJavaScriptExecutor();
}
catch (Exception ex)
{
IWebElement classroom = this.findElementByXPath("//*[#id='class-list-edit']");
while (!classroom.Enabled && !classroom.Displayed)
{
classroom = this.findElementByXPath("//*[#id='class-list-edit']");
}
classroom.Click();
// classroom = this.findElementByXPath("//*[#id='invited - list']");
classroom = this.findElementByClassName("being-editted");
Thread.Sleep(5000);
classroom.Click();
classroom.SendKeys("John Doe");
Console.WriteLine("Found Element");
}
}

Selenium C# - StaleElementReferenceException - Even after refreshing the page

I am getting OpenQA.Selenium.StaleElementReferenceException which is a bit strange since I am refreshing the page. So here is the detail:
The technology we are using is React.
Browser: Chrome ( latest version)
C# with Selenium Webdriver (3.X)
We have a left menu with Li items. On first time page load i can click the left menu item using xpath and it works fine. The left menu adjusts itself so that the item no longer appears inside it. I think this updates the DOM. Ok now when i try to click the next item , i get the stale reference exception. So I did following things:
1- Refresh the page and double/single click - does not work
2- Navigate to another page and come back to this page and double/single click-- does not work
3- Added thread.sleep - does not work
4- Catch the exception and try to find the element again -- does not work.
Is there something i am missng?
Here is the code:
Actions actions = new Actions(driver);
string[] ItemNames = { "OrganizationDepartment","Organization"};
foreach (String ItemName in ItemNames)
{
try
{
driver.Navigate().Refresh();
//Thread.Sleep(3000);
IWebElement source = driver.FindElement(By.XPath("//div[contains(text(),'" + ItemName+ "')]"));
actions.MoveToElement(source).Perform(); // this is where i get the exception for second element.
actions.DoubleClick(source).Perform(); // this is where i get the exception if i comment above line
}
catch (StaleElementReferenceException stale)
{IWebElement source = driver.FindElement(By.XPath("//div[contains(text(),'" + ItemName+ "')]"));
actions.DoubleClick(source).Perform(); // this is where i get the exception
}
Here is the HTML:
<div><div draggable="true"><li style="position: relative;">
<i title="OrganizationDepartment"></i>OrganizationDepartment
<a title="Drag Me" style="cursor: grab; position: absolute; right: 0px; top: 5px;">
<button type="button" class="ms-Button ms-Button--icon iconButton root-124" data-is-focusable="true" style="cursor: grab;">
<div class="ms-Button-flexContainer flexContainer-114">
<i data-icon-name="DragObject" class="ms-Button-icon icon-126" role="presentation"></i></div></button></a></li></div></div>
<div><div draggable="true"><li style="position: relative;">
<i title="Organization"></i>Organization
<a title="Drag Me" style="cursor: grab; position: absolute; right: 0px; top: 5px;">
<button type="button" class="ms-Button ms-Button--icon iconButton root-124" data-is-focusable="true" style="cursor: grab;">
<div class="ms-Button-flexContainer flexContainer-114">
<i data-icon-name="DragObject" class="ms-Button-icon icon-126" role="presentation"></i></div></button></a></li></div></div>
I found the solution. It is not the element but the actions object which was getting staled on second iteration of the loop. I had to re-create the Actions object again and then do this:
NewactionsObject.MoveToElement(source).Perform()

Elements not getting populated using Selenium C# with page scrolling in Chrome

The website I'm trying to scrape is https://hitbtc.com/market-overview/overview.
I am trying to get cryptocurrency coin pairs from the page by accessing the following html (and other similar html for other coin pairs):
<div class="ReactVirtualized__Table__row ReactVirtualized__Row__odd ReactVirtualized__Table__row ReactVirtualized__Row__odd animation__redToWhite--2EMEW" role="row" style="height: 30px; left: 0px; position: absolute; top: 0px; width: 1202px; overflow: hidden; padding-right: 0px;">
<div class="ReactVirtualized__Table__rowColumn" role="gridcell" style="flex: 0 1 200px; overflow: hidden;">
**BTC/USDT**
</div>
<div class="ReactVirtualized__Table__rowColumn" role="gridcell" style="flex: 0 1 200px; overflow: hidden;">
<div>
<div class="styles__imgUp--1O8Kn"></div>
1.92%
</div>
</div>
<div class="ReactVirtualized__Table__rowColumn" role="gridcell" title="₮ 59 843 794" style="flex: 0 1 200px; overflow: hidden;">₮ 59 843 794</div>
<div class="ReactVirtualized__Table__rowColumn" role="gridcell" title="₮ 6780.73" style="flex: 0 1 200px; overflow: hidden;">₮ 6780.73</div>
<div class="ReactVirtualized__Table__rowColumn" role="gridcell" title="₮ 6486.82" style="flex: 0 1 200px; overflow: hidden;">₮ 6486.82</div>
<div class="ReactVirtualized__Table__rowColumn" role="gridcell" title="₮ 6833.25" style="flex: 0 1 220px; overflow: hidden;">₮ 6833.25</div>
</div>
I want to get the text from the first tag, which should give me "BTC/USDT". I found that by using Selenium's Driver.FindElements() I would only get the first 29 elements (i.e. the ones that are displayed without doing any scrolling). Because of this I tried implementing a do-while loop to scroll down the page, obtaining element lists and appending them to a master list until the previously obtained list is the same as the current list (bottom of the page reached). Here is my code:
List<IWebElement> totalElemList = new List<IWebElement>();
List<IWebElement> elementList = new List<IWebElement>();
List<IWebElement> prevList = new List<IWebElement>();
do
{
prevList.Clear();
prevList.AddRange(elementList);
totalElemList.AddRange(prevList);
var infoList = RetryingFind(By.ClassName("ReactVirtualized__Table__row"));
foreach (var element in infoList)
{
elementList.Add(element.FindElement(By.TagName("a")));
}
Thread.Sleep(10000);
((IJavaScriptExecutor)Browser.Driver).ExecuteScript("arguments[0].scrollIntoView(true);", elementList[elementList.Count - 1]);
}
while (prevList != elementList);
However, elementList is not getting populated with any elements for some reason. I added the Thread.Sleep() trying different sleep times up to 10 sec but it didn't fix the issue. Then the ExecuteScript() line fails because it's trying to access index -1 of elementList, since its Count is 0.
I'm having trouble understanding why I was able to populate the element list before with at least some of the elements on the page, but when I use the do-while loop I get nothing. Any thoughts?
It should ideally work with scroll. Check if there is any job event being triggered when you scroll. If so, try to invoke that function from IJavaScripExecutor. That should also load you with your elements.

Inconsistent error message DOM betweeen jQuery validation and Postback

My error message html structure from jQuery validation and from postbacks are different causing my validation errors to display differently. I need the nested span tag within the span.field-validation-error because I use CSS to add the (x) icon before the message like the one you see on the Description error message.
This is the error message from jQuery validation.
<span class="field-validation-error" data-valmsg-for="Code" data-valmsg-replace="true">
<span id="Code-error" class="">The Description field is required.</span>
</span>
notice that on the banner url validation message, there's no span tag within the span.field-validation-error.
<span class="field-validation-error" data-valmsg-for="BannerUrl" data-valmsg-replace="true">
The Banner Image field is required.
</span>
This is the view cshtml file markup I have.
<div class="form-group">
#Html.LabelFor(x => x.Description):
#Html.TextAreaFor(x => x.Description, new { rows = 5, cols = 5, #class = "form-control", placeholder = "Enter your team description" })
#Html.ValidationMessageFor(x => x.Description)
</div>
<div class="form-group">
#Html.LabelFor(x => x.BannerUrl):
<input id="BannerUrl" name="BannerUrl" type="file" class="file-styled">
#Html.ValidationMessageFor(x => x.BannerUrl)
</div>
Why does the error message html from jquery validation different from the error message html that's generated after postback?
EDIT:
Below is the CSS that adds the (X) icon before the error message. What I really want it to do is for the icon to show up in front of the error message that comes from a postback (no nested span) and also the error message from jquery validation (nested span).
.field-validation-error > span:before {
font-family: 'icomoon';
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
min-width: 1em;
display: inline-block;
text-align: center;
font-size: 16px;
vertical-align: middle;
position: relative;
top: -1px;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
content: "\ed63";
margin-right: 5px;
}
The jquery.validate.js plugin and the MVC framework are developed by separate teams (jquery.validate is not associated with Microsoft). The MVC framework just uses jquery.validate.js for client side validation (and use jquery.validate.unobtrusive.js to add the rules to jquery.validate.js).
You could create you own HtmlHelper extension to generate the inner <span> element server side. For example, copy the ValidationExtensions.cs source code and modify the private static MvcHtmlString ValidationMessageHelper(...) method so that instead of builder.SetInnerText(validationMessage); you use builder.InnerHtml = xx; where xx is a TagBuilder that builds a <span> containing the error message.
However, it would be easier to just use some javascript to wrap the inner text inside a <span> element when the page is first loaded
// Get all the elements generated by ValidationMessageFor() that have an error
var errors = $('.field-validation-error');
$.each(errors, function (index, item) {
// Wrap the text in a span element
$(this).wrapInner('<span></span>');
})
Note that the jquery.validate plugin also adds an id attribute to the span based on the property name. It does not appear that you need that based on your css, however, if you do want to include that, then you can use
$.each(errors, function (index, item) {
var id = $(this).data('valmsg-for').replace(/[\.\[\]]/g, "_") + '-error';
var span = $('<span></span>').attr('id', id);
$(this).wrapInner(span);
})
Another option would be to wrap each ValidationMessageFor() inside an element, for example
<span class="error">
#Html.ValidationMessageFor(...)
</span>
and modify the css selector
.error > .field-validation-error:before {
font-family: 'icomoon';
....
}

How to disable the buttons of other URL opening using Iframe?

I m using iframe to open another webservice. there user can view the complete the nav of the targeted link. but i wan't to prevent the user to view the complete nav.
There are five items in the targetd URL like this:
Overview
Call Log
Terrif
Payment
Logout
<iframe id="subframe" frameborder="0" scrolling="no" src="login.aspx" style="float: left;height: 754px; margin-left: 118px; width: 727px;" ></iframe>
Now what i want is that, allow user only to view the Call Log.
How could be this possible to do?
Which steps could be taken to perform these all?
If the service is on your own domain, you can access the frames DOM like so:
var myFrame = frames["myFrame"]
var cssLink = document.createElement("link")
cssLink.href = "iframeStyles.css"; /* change this to the url for a stylesheet targetting the iframe */
cssLink .rel = "stylesheet";
cssLink .type = "text/css";
frames['myFrame'].document.body.appendChild(cssLink);
Also see this question:
How to add CSS class and control elements inside of the Iframe using javaScript.?
If the iframe loads a page from another domain, you may not alter it, because that would be against the same origin policy.
I used this a couple of months before.. Some edits might be required:
<div id="IframeWrapper">
<div id="iframeBlocker">
</div>
<iframe id="mainframe" src="http://www.xyz.com/"></iframe>
</div>
CSS:-
#IframeWrapper
{
position: relative;
}
#iframeBlocker
{
position: absolute;
top: 0;
left: 0;
width: 700px;
height: 450px;
}
#mainframe
{
overflow: hidden;
border-width: 0px;
}
OTHER ALTERNATE AND A BETTER ONE

Categories