Get HTML element generated from JavaScript - java

I have this input field generated by JavaScript
<input class="postal-code form-text required form-control" autocomplete="postal-code" data-drupal-selector="edit-field-client-address-0-address-postal-code" type="text" id="edit-field-client-address-0-address-postal-code--bwzakXWpxR0" name="field_client_address[0][address][postal_code]" value="" size="10" maxlength="128" required="required" aria-required="true">
As you can see every time the id String is different: id="edit-field-client-address-0-address-postal-code--bwzakXWpxR0"
What is the proper way to locate this id using Selenium?

you can try using the following
driver.findElement(By.className("postal-code")).sendKeys("your value");

There are a LOT of attributes that seem to be unique. Have you tried any of them? Potential CSS selectors
input[autocomplete='postal-code']
input[data-drupal-selector='edit-field-client-address-0-address-postal-code']
input[name='field_client_address[0][address][postal_code]']
or you can try ID starts with, e.g.
input[id^='id="edit-field-client-address-0-address-postal-code--']

You can try with other locators if the id is dynamic.
CSS Selector:
driver.findElement(By.cssSelector(input[data-drupal-selector='edit-field-client-address-0-address-postal-code'])).sendKeys("your value");

As the desired element is an <input> element so moving next you would either invoke click() or sendKeys(), so to locate the element you need to use elementToBeClickable() and you can use either of the following Locator Strategies:
cssSelector:
WebElement element = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("input.postal-code[id*='address-postal-code'][name^='field_client_address']")));
xpath:
WebElement element = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//input[#class='postal-code form-text required form-control' and contains(#id, 'address-postal-code')][starts-with(#name, 'field_client_address')]")));

Related

How to send text to elements without id or value attribute using Selenium Java

HTML:
<input type="text" placeholder="Enter name" class="form-control m-2">
I am trying to send text to this through Selenium.
This is what I tried:
driver.findElement(By.cssSelector("input.form-control m-2[placeholder='Enter name']")).sendKeys("Test");
form-control and m-2 are two different classes.
The selector should be input.form-control.m-2[placeholder='Enter name']
Use xpath to interact with the web Element.
The xpath will be -
//input[#placeholder='Enter name'][#type='text']
Use the following code -
WebElement inputName = driver.findElement(By.xpath("//input[#placeholder='Enter name'][#type='text']"));
inputName.sendKeys("Test");
To send a character sequence to the desired element with placeholder as Enter name you can use either of the following Locator Strategies:
cssSelector:
driver.findElement(By.cssSelector("input[placeholder='Enter name']")).sendKeys("Test");
xpath:
driver.findElement(By.xpath("//input[#placeholder='Enter name']")).sendKeys("Test");
Ideally, to send a character sequence within the <input> element you need to induce WebDriverWait for the elementToBeClickable() and you can use either of the following locator strategies:
cssSelector:
new WebDriverWait(driver, Duration.ofSeconds(10)).until(ExpectedConditions.elementToBeClickable(By.cssSelector("input[placeholder='Enter name']"))).sendKeys("Test");
xpath:
new WebDriverWait(driver, Duration.ofSeconds(10)).until(ExpectedConditions.elementToBeClickable(By.xpath("//input[#placeholder='Enter name']"))).sendKeys("Test");

Selenium WebDriver: Unable to locate dynamically changing React InputBase component element

I tried to locate an element with id.
The Developer tools shows this:
<input aria-invalid="false" autocomplete="off" placeholder="Partner name" type="text" class="MuiInputBase-input MuiInput-input MuiAutocomplete-input MuiAutocomplete-inputFocused MuiInputBase-inputAdornedEnd" aria-autocomplete="list" autocapitalize="none" spellcheck="false" value="" id="mui-85700">
The id always changing every time I reload the page.
I think I find a solution to locate the element:
findElement(By.xpath("//*[contains(#id,'mui')]")).click();
But now I get the following error:
(org.openqa.selenium.ElementClickInterceptedException: Element <p id="mui-51640" class="MuiTypography-root MuiTablePagination-caption MuiTypography-body2 MuiTypography-colorInherit"> is not clickable at point (1124,747) because another element <div class="MuiDialog-container MuiDialog-scrollPaper"> obscures it
How can I solve it?
Side note:
In developer tool I see 4 web elements which contains "mui" String.
On the page I only see 2 web elements: one with <input id="mui85700"...> and another one is <label id="mui85700"...>
As before I said I need the input id field.
The <input> element is a React InputBase component and a dynamic element and the trailing dynamic value of the id attribute will will get changed everytime you access the application afresh. So you have to construct a dynamic locator strategy.
Solution
To click on the <input> element you need to induce WebDriverWait for the elementToBeClickable() and you can use either of the following locator strategies:
cssSelector:
new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("input.MuiInputBase-input.MuiInput-input.MuiAutocomplete-input.MuiAutocomplete-inputFocused.MuiInputBase-inputAdornedEnd[id^='mui'][placeholder='Partner name']"))).click();
xpath:
new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//input[#class='MuiInputBase-input MuiInput-input MuiAutocomplete-input MuiAutocomplete-inputFocused MuiInputBase-inputAdornedEnd' and starts-with(#id, 'mui')][#placeholder='Partner name']"))).click();
You may use findElements and get all the elements form web page
Use a loop and check if the element is visible or element is clickable. This is solve your issue.
you can use like this,
List<WebElement> products = driver.findElements(By.xpath("xpath"));
for (int i=0; i<products.size(); i++){
String name = products.get(i).getText();
System.out.println(name);
if(name.containsAll('text')) {
driver.findElements(By.xpath("xpath")).get(i).click();
}
}

How to get following text name using xpath?

I try with following xpath
driver.findElement(By.xpath("//div[contains(#class,'ReactTags__selected')]//span[1]/text()"));
but get following error
"org.openqa.selenium.InvalidSelectorException: invalid selector: The result of the xpath expression "//div[contains(#class,'ReactTags__selected')]//span[2]/text()" is: [object Text]. It should be an element."
<div class="ReactTags__selected">
<span class="tag-wrapper ReactTags__tag" style="opacity: 1; cursor: auto;" draggable="true">
"TestName"
<a class="ReactTags__remove">×</a>
</span>
</div>
Please try the below Xpath.
Hope it helps
//div[contains(#class,'ReactTags__selected')]//span[2]/a/text()
text() in the xpath returns text node, Selenium doesn't support it. Locate the element and use getText() to get the text
WebElement element = driver.findElement(By.xpath("//div[contains(#class,'ReactTags__selected')]//span[1]"));
String text = element.getText();
As the parent element contains the attribute draggable="true" invariably it's a dynamic element, precisely React element. Additionally as the text TestName is a Text Node you need to induce WebDriverWait for the visibilityOfElementLocated() and you can use either of the following Locator Strategies:
cssSelector:
System.out.println(((JavascriptExecutor)driver).executeScript('return arguments[0].firstChild.textContent;', new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div.ReactTags__selected > span.tag-wrapper.ReactTags__tag")))).toString());
xpath:
System.out.println((String)((JavaScriptExecutor)driver).executeScript("return arguments[0].firstChild.textContent;", new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[#class='ReactTags__selected']/span[#class='tag-wrapper ReactTags__tag']")))));

Selecting a value from <md-select> tag using Selenium Webdriver

I am using Selenium Webdriver and working on automating an AngularJS Web App on Chrome. It was going pretty well until I hit a dropdown list on the app.
My test keeps crashing everytime I try to select a value from it. I have been doing my research on this and I have only seen 2 solutions (both of which I have tried but don't work)
Use the Select object. This doesn't work because the html tag is not <select>, its <md-select> and this fails the test.
I then tried to just click on the dropdown element and click on the value - driver.findElement(By.xpath("xpath to dropdown list")).click(); and driver.findElement(By.xpath("xpath do dropdown value")).click();
With example 2, I also tried creating it as a WebElement variable and calling click() separate, but this did not work either.
Any ideas on how I can solve this issue?
Update
HTML for the dropdown list
<div ng-switch-when="dropdown" class="ng-scope">
<zf-form-dropdown>
<div class="dropdown">
<div layout="row">
<div flex="50" class="quote-label">
<p ng-bind-html="::label" class="ng-binding">Title</p>
</div>
<div ng-show="false" flex="10" class="tooltip-icon ng-hide" ng-click="showToolTip(field.get('toolTip'))" role="button" tabindex="0" aria-hidden="true"><img src="img/item-question#2x.png"></div>
<md-select flex="" ng-disabled="quote.isRated() || !input.enabled" ng-change="onDropdownChange()" ng-model="input.value" class="ng-valid md-default-theme ng-touched ng-dirty" role="combobox" id="select_0Q9" aria-haspopup="true" aria-expanded="false" aria-labelledby="select_label_0I1" tabindex="0" aria-disabled="false" aria-invalid="false" aria-owns="select_menu_0Q8"><md-select-label class="md-select-label md-placeholder" id="select_label_0I1"><span></span><span class="md-select-icon" aria-hidden="true"></span></md-select-label></md-select>
</div>
</div>
</zf-form-dropdown>
</div>
HTML for the value I want to select
<md-option ng-value="::item.val" ng-selected="item.checked" ng-repeat="item in getOpts()" tabindex="0" class="ng-scope" role="option" aria-selected="false" id="select_option_0QD" value="MR">
<div class="md-text ng-binding">Mr</div>
<div class="md-ripple-container"></div>
</md-option>
The xpath for the dropdown list is //*[#id="select_0Q9"]
The xpath for the dropdown value is //*[#id="select_option_0QD"]
If you are sure that your Xpath is fine then you can also click using javascriptexecutor so try it out like below:-
WebElement element= driver.findElement(By.xpath("//md-option[#id='select_option_0QD']/div[1]"));
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("arguments[0].click();", element);
Please feel free to locate the element in above code as per your convenience .
As per me your xpath of dropdown should be like below:-
//md-option[#id='select_option_0QD']
And xpath of first div which I suppose want to click is:-
//md-option[#id='select_option_0QD']/div[1]
Change [1] to [2] if you want 2nd value.
In an another aspect you can also store all your element in the list(As you know you can't use select) and click them as per your need or all.
For that you need to use xpath like:-
//md-option[#id='select_option_0QD']/div
Now implement it into code:-
List<WebElement> allelemts = driver.findElements(By.xpath("//md-option[#id='select_option_0QD']/div"));
for(WebElement ele: allelemts){
driver.findElement(By.xpath("//md-option[#id='select_option_0QD']")).click();
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("arguments[0].click();", ele);
}
Hope it will help you :)
Since you are receiving a NoSuchElementException exception, I believe the issue lies in Selenium not able to identify the element. Try any of the following wait methods and then try to click the element.
Explicit Wait: (Most Preferred)
WebDriverWait wait = new WebDriverWait(driver, 20);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("elementID")));
or
WebDriverWait wait = new WebDriverWait(driver, 20);
WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("elementID")));
Implicit Wait:
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
Sleep: (Try to avoid this unless absolutely necessary)
Thread.sleep(1000);
EDIT: Added code to check for element's presence using findElements method.
Before using any of these wait methods you could also check for the presence of your element using findElements method.
List<WebElement> element = driver.findElements(By.id("elementId"));
if (element.size() == 0) {
System.out.println("Element not found");
} else{
System.out.println("Element found");
}
I have finally solved the issue!
I got the Selenium IDE and recorded a session where I got as far as selecting the dropdown menu and selecting my value. I then exported the file as a java test case and was able to read the lines where it selected the values, and they were;
driver.findElement(By.cssSelector("#select_08D > #select_label_005 > span.md-select-icon")).click();
driver.findElement(By.id("select_option_08H")).click();
So first off they both do not use xpath to find the elements, the dropdown menu itself is found with the cssSelector and the value is found by the id.
I am just cross referencing again and the id for the value is select_option_08H but while I am looking at Google Console I can see the id for the value is select_option_189

Finding HTML elements to use in Selenium WebDriver

Using Selenium WebDriver in a java class where I try to find that specific element and then automatically add a needed amount of that element in the input field.
I have an HTML table with each row specifying a type of element and an input field used to add X to the amount of element in the specific row.
<tr>
<td class="non-sortable-table">
<input class="required text" type="text" value="0" name="plate_order{pageFlow.plateorders[0].numberOfPlates}" tabindex="25">
</td>
<td class="non-sortable-table">
<span>20% - White plates</span>
</td>
...
</tr>
I have tried the following in my Java code in order to get that element, but with no luck:
WebElement element = (WebElement) js.executeScript("return ${\"document.getElementsByName('plate_order{pageFlow.plateorders[0].numberOfPlates}')\"");
WebElement element = driver.findElement(By.ByName('plate_order{pageFlow.plateorders[0].numberOfPlates}'))
how could i retreive that element in order to edit its input?
Is it possible when parts of the name of the element is a reference to a controller, i.e. pageFlow?
what if i wanted to retrieve the following element identified by 20% ....
I have tried to get that one using xpath and cssSelector with no luck.
Any suggestions?
To return an element from a JavaScript result, you can use the following syntax (i used jQuery as simplification):
RenderedWebElement webElement = (RenderedWebElement) ((JavascriptExecutor) webDriver).executeScript("return jQuery('input[name^=plate_order]').get(0);");
You can also pass an element which was previosly selected in Selenium:
((JavascriptExecutor) webDriver).executeScript("return doSomethingWithElement(arguments[0]);", webElement);
It looks to me like you might want to use a starts-with type operator in your XPath or CSS.
Something like:
XPath: //input[starts-with(#name, 'plate_order')]
CSS: input[name^='plate_order']
Similar things should work for the span, too (if you know the text):
XPath: //span[starts-with(., '20%')]
CSS/Sizzle*: span:contains('20%')
If you don't know the text, then something this xpath might work.
XPath: //input[starts-with(#name, 'plate_order]/../../td/span
* The contains function is not pure CSS. It's an addition provided by the Sizzle library. This may or may not work, depending on whether Selenium is using a built-in CSS library or injecting Sizzle.

Categories

Resources