Protractor Automation: Selection of element - selenium

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

Related

Converting SearchContext to WebElement in Selenium with Java on Chrome

Service Now has changed to using shadow root like this
<span id='s1'>
  #shadow-root
   <button>Cancel</button>
   <button>Submit</button>
</span>
I can easily get the first span:
WebElement sele = driver.findElement(By.xpath("//span[#id='s1']"));
And then get the shadow root:
SearchContext sc = sele.getShadowRoot();
But it will not let you do a
sc.findElements(By.xpath(".//button'"));
or more preferably
WebElement cancelButton = sc.findElement(By.xpath(".//button[.='Cancel']"));
You have to find with CS selector
sc.findElements(By.cssSelector(" button"));
and go through each button to get the text. To make it worse, when I try
List<WebElement> buttons = sc.findElements(By.cssSelector(" button"));
because it says there is an error with "=" and it expects "<=". No idea why. Have to do a
for (WebElement wele : sc.findElements(By.cssSelector(" button")) {
String txt = wele.getText();
if (txt.equals("Cancel")) ... // whatever you want
}
So my question is is there someway to convert "sc" to a WebElement? Even maybe someway to get itself? The equivalent of
sc.findElement(By.xpath("."));
or someway to look for xpath with SearchContext?
Looks like this discussion is exactly what you looking for.
There are several answers given there to get the Shadow Root as a WebElement object.

Not able to Enter Text in a TextBox using Selenium Webdriver

I have a TextBox that appears on Radio Button Selection and I have to enter values in a particular format(XYZ989898-99). However I am unable to do so by using the commonly used methods of entering text in selenium.
Background info related to Textbox :
TextBox appears when user clicks on Yes radio button.
TextBox has default value as XYZ already entered.
SendKeys do not concatenate the text given without XYZ as well.
TextBox is inside an Iframe to which focus is shifted correctly.
The code does not fail, it just remained clicked on textbox without entering anything.
Approach 1 :
driver.findElement(locator).SendKeys("989898-99");
Approach 2 :
driver.findElement(locator).clear();
driver.findElement(locator).SendKeys("XYZ989898-99");
Approach 3 :
WebElement element = driver.findElement(locator);
Actions action1 = new Actions(driver);
action1.movetoElement(element).click().perform();
action1.sendKeys("XYZ989898-99");
HTML Sample :
<div class="value" ng-show="selectedValue" style="">
<label class="labelAboveTextBox">XYZ Number*</label>
<input type="text" class="Value" ng-model="XYZNumber" ng-
req="XYZNumber" xyz-input="" maxlength="12" style="value"
id="value" value="XYZ" required="required">
<!-- ngIf: invalidtspmessage -->
<span style="font-family: 'NeueHaasGroteskText';font-size:
0.7rem;color: black;">
Note: Enter XYZ is this format: XXXXXXXXX-XX
</span>
</div>
I would like to know If there is any other approach that can be used to get this problem resolved and also why does the above approaches failed to work.
You have used the wrong methods for sending the keys. (in approach 1 and 2)
Instead of .SendKeys(), you have to use .sendKeys() method for writing anything on UI side
Into the third approach, you have used the wrong method .movetoElement(). The method name is .moveToElement().
For sendKeys() don't need to use Actions class. basically, it is for Keyboard events and for mouse events.
(WebElement).sendKeys("989898-99"); // first approach you can use
(WebElement).clear(); // second approach you can use
(WebElement).sendKeys("XYZ989898-99");
Hope this will help you to solve your errors.
Other way you can use is to set the text is by using the JavaScriptExecutor. Give some delay before performing the action.
Try the below sample code :
Thread.sleep(3000);
((JavascriptExecutor) driver).executeScript("document.getElementById('value').value='XYZ989898-99';");
As the id is unique, you can use the JavaScript's getElementById() function to set the value.
If you want to set the text through the sendKeys() method and before that if you want to clear the text then simple clear() may not work instead you can try to delete the XYZ values first and try to send the values like below again :
// Wait for some time
Thread.sleep(3000);
// Locate the element first and store it in some variable
WebElement element = driver.findElement(By.id("value"));
// Fetch the existing text from the field first
String existingValue = element.getAttribute("value");
// Wait for some time
Thread.sleep(3000);
// Click on that element first so the focus will shift to there
element.click();
// Wait for some time
Thread.sleep(2000);
// Loop until the existing value length
for(int i=0;i<existingValue.length();i++) {
// Remove the existing character text one by one
element.sendKeys(Keys.BACK_SPACE);
}
// Try to send the text at the end, make sure that you should append XYZ as a prefix
element.sendKeys("XYZ989898-99");
I hope it helps...

Selenium webdriver:select a "div" from many "div"s that dynamically change the absolute path

I need some help in selecting a div form many div's that for every session number of div's are changing.
For example:
one time a have the div in that position(absolute path): /html/body/div[97]
other time in that position (absolute path):/html/body/div[160]
and so on...
At a moment only one div is active and the other div's are hidden.
I attached a picture to show the code.
I try the xpath below but doesn't work,I get the error "no such element: Unable to locate element ...
driver.findElement(By.xpath(".//*[#class=\'ui-selectmenu-menu ui-selectmenu-open\']/ul/li[1]")).click();
Picture with html code is here:
XPath is great if you expect the target element to be in the exact location every time the page is displayed. However, CSS is the way to go if the content is constantly changing.
In the example below I have found the DIV and the Element that you highlighted in your screen capture.
WebElement targetElementDiv = null;
WebElement targetElement = null;
targetElementDiv = driver.findElement(By.cssSelector("[class='ui-selectmenu-menu ui-selectmenu-open']"));
if (targetElementDiv != null) {
targetElement = targetElementDiv.findElement(By.cssSelector("[class='ui-menu-item ui-state-focus'])");
}

How can i write my own xpath from the html code

I have followig HTML code and want X path for the text "Analytics & Research"
<div id="LLCompositePageContainer" class="column-wrapper">
<div id="compositePageTitleDiv">
<h1 class="page-header">Analytics & Research</h1>
</div>
I am getting following xpath using chrome, but that didnt work.
//*[#id="compositePageTitleDiv"]
this is my code
WebElement header = driver.findElement(By.xpath("//div[#id='LLCompositePageContainer']/div[#id='compositePageTitleDiv']/h1[#class='page-header']"));
String header2 = header.getText();
System.out.println(header2);
and following error I am getting
Exception in thread "main" org.openqa.selenium.NoSuchElementException:
Unable to find element with xpath ==
//div[#id='LLCompositePageContainer']/div[#id='compositePageTitleDiv']/h1[#class='page-header']
(WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 10.34 seconds For documentation on this
error, please visit:
http://seleniumhq.org/exceptions/no_such_element.html
Please try to use the below xpath:
driver.findElement(By.xpath(".//div[#id='compositePageTitleDiv']/h1")).getText();
If the element is inside the iframe. Then use the below code:
// Switching to the frame
driver.switchTo().frame(<name>);
// Storing the value of the Analytics & Research
String text = driver.findElement(By.xpath(".//div[#id='compositePageTitleDiv']/h1")).getText();
// Switching back to original window
driver.switchTo().defaultContent();
Hope this helps.
This is how it can be used :
WebElement element= driver.findElement(By.xpath("//*[#id='compositePageTitleDiv']"));
Or in case it is nested, can be accessed like this as well
WebElement element = driver.findElement(By.xpath("//html/body/div[3]/div[3]/"));
this is just a rough syntax.
No need to use Xpath here if you could simply locate the element using By.id(). Asuming are using Java, you should try as below :-
WebElement el = drive.findElement(By.id("compositePageTitleDiv"));
String text = el.getText();
Edited :- If element not found, may it is timing issues you need to implement WebDriverWait to wait for element until visible on the page as below :-
WebDriverWait wait = new WebDriverWait(webDriver, implicitWait);
WebElement el = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("compositePageTitleDiv")));
String text = el.getText();
Note :- if your element is inside any frame, you need to switch that frame before finding element as :- driver.switchTo().frame("your frame name or id");
Hope it helps..:)
You can also use
//div[#id='LLCompositePageContainer']/div[#id='compositePageTitleDiv']/
h1[contains(text(),'Analytics')]
This is the best way to reach to the specific web element, using contains minimize the chances of error.
The correct xpath is
//div[#id='LLCompositePageContainer']
/div[#id='compositePageTitleDiv']
/h1[#class='page-header']
But you could have find your answer easily with some researchs on google...

Selenium Xpath Not Matching Items

I am trying to use Selenium's Xpath ability to be able to find an set of elements. I have used FirePath on FireFox to create and test the Xpath that I have come up with and that is working just fine but when I use the Xpath in my c# test with Selenium nothing is returned.
var MiElements = this._driver.FindElements(By.XPath("//div[#class='context-menu-item' and descendant::div[text()='Action Selected Jobs']]"));
and the Html looks like this:-
Can Anyone please point me right as everything that I have read the web says to me that this Xpath is correct.
Thanking you all in-advance.
Please post the actual HTML, so we can simply "drop it in" into a HTML file and try it ourselves but I noticed that there is a trailing space at the end of the class name:
<div title="Actions Selected Jobs." class="context-menu-item " .....
So force XPath to strip the trailing spaces first:
var MiElements = this._driver.FindElements(By.XPath("//div[normalize-space(#class)='context-menu-item' and descendant::div[text()='Action Selected Jobs']]"));
Perhaps you don't take into consideration the time that the elements need to load and you look for them when they aren't yet "searchable". UPDATE I skipped examples regarding this issue. See Slanec's comment.
Anyway, Selenium recommends to avoid searching by xpath whenever it is possible, because of being slower and more "fragile".
You could find your element like this:
//see the method code below
WebElement div = findDivByTitle("Action Selected Jobs");
//example of searching for one (first found) element
if (div != null) {
WebElement myElement = div.findElement(By.className("context-menu-item"));
}
......
//example of searching for all the elements
if (div != null) {
WebElement myElement = div.findElements(By.className("context-menu-item-inner"));
}
//try to wrap the code above in convenient method/s with expressive names
//and separate it from test code
......
WebElement findDivByTitle(final String divTitle) {
List<WebElement> foundDivs = this._driver.findElements(By.tagName("div"));
for (WebElement div : foundDivs) {
if (element.getAttribute("title").equals(divTitle)) {
return element;
}
}
return null;
}
This is approximate code (based on your explanation), you should adapt it better to your purposes. Again, remember to take the load time into account and to separate your utility code from the test code.
Hope it helps.