How to check if there is a strikethrough on some text in selenium webdriver? - selenium

There are many planbox, which are having same class and ids, inside them there are a number of <p> tags and decorated text.
<div class="planbox">
<p class="baseprice">
<span>
<strike> $70 </strike>
</span>
</p>
<p> New discount price is etc. </p>
</div>
<div class="planbox">
<p class="baseprice">
<span> $70 </span>
</p>
</div>
Now, My test case is - if the base price is strikethrough, only then <p> 'New discount price .. </p> will show, otherwise not.
How to check whether a text is strikethrough or not? And even if we get this how will I check that <p> New discount.. </p> should not show if the text is not striked.
As there is no class in <p> tag on which I can check whether it displayed or not.
One solution in my mind was - add one dummy class in <span> tag and using findChildren('span.dummyCLass') it will result all the webelements having dummyClass.
Now I will check whether web-elements have strike tag or not, and this is the place where I got stuck.
Initially, i was thinking of a Jquery solution, but is it possible to do without adding new class and jquery?

You don't need to add a class to any element to accomplish this task. In general, you don't want to edit the HTML. Another issue is... if you can find the element to add a class, then you don't need to add the class to find the element. :)
The way I approach tasks like these is to find the outermost element that contains all the elements that you are interested in. I refer to this as a "container". What you want to do in this case is to find the containers and loop through them looking for the strikethrough price and for the "New discount price..." text.
The containers are DIVs with the planbox class. The strikethrough price is indicated by the STRIKE tag. The "New discount price..." text is in a P tag. With this info we can write some code. This is Java because I don't know what language you want and I'm not familiar with the Galen framework.
// gets the collection of containers using a CSS selector
List<WebElement> containers = driver.findElements(By.cssSelector("div.planbox"));
// loops through the containers
for (WebElement container : containers)
{
// determine if the STRIKE tag exists
boolean strikeExists = !container.findElements(By.tagName("strike")).isEmpty();
// determine if the "New discount price is..." text exists in the 2nd P tag
boolean discountPriceExists = container.findElements(By.tagName("p")).get(1).getText().trim().contains("New discount price is");
// if both are true log a pass, otherwise log a fail
if (strikeExists && discountPriceExists)
{
// log a pass
}
else
{
// log a fail
}
}

I haven't used much of selenium. But you can port this jquery code to selenium,
//if there is a strike element
if($(".baseprice span strike").length > 0){
//next() will select the sibling of the p tag with baseprice class
$("p.baseprice).next() != undefined){
return true
}else{
return false
}
}

you can use Galen for this. There you can verify certain CSS properties.

Related

Is it possible to not omit some opts on the outermost element in a custom Riot tag?

I'm using RiotJS v3.9
I've written a custom tag that accepts a few opts. The problem is that the markup it generates includes all of those opts on the outermost element, in addition to the interior tags where I explicitly deposit them. I do not want any opts to appear on the top element unless I make that happen.
In this case, my custom tag display a list of items. One of the opts it accepts is the value for a specific data- attribute on each list item. So, I want data-something={opts.itemSomething} to appear on each list item, but I do not want that to appear on the wrapper.
// my-list.tag
<my-list>
<ul data-something={ opts.something }>
<li
each={ item in opts.items }
data-something={ parent.opts.itemSomething }
>
{ item }
</li>
</ul>
</my-list>
Using it:
<my-app>
<my-list
something="parent-value"
item-something="child-value"
items={['one', 'two', 'three']}
/>
</my-app>
What it emits into the page:
<my-list something="parent-value" item-something="child-value">
<ul data-something="parent-value">
<li data-something="child-value"> one </li>
<li data-something="child-value"> two </li>
<li data-something="child-value"> three </li>
</ul>
</my-list>
I don't want the emitted <my-list> tag to have either the parent-value or the child-value on it. I only want those attributes to appear on the <ul> and <li>, like I coded it.
// bad output
<my-list something="parent-value" item-something="child-value">
// good output
<my-list>
Is this possible?
Also, I know from working with React that I'm likely to encounter future cases where I want some of the opts to appear on the wrapper while hiding others. So, ideally I'd like to know how to control this behavior on a per-opt basis.
you can remove the unwanted attributes in both the "updated" and "mount" event.
check this demo
However I strongly suggest you to switch to riot#5!!

Testing relative positions of elements

On the page under test I have the following Support link:
Which is represented with the following HTML:
<div class="ap-version-panel ap-version-support">
<i class="fa fa-external-link"></i>Support
</div>
What I'm trying to is to test that the icon is located before the "Support" text. How can I do that?
I've tried the following - locate the icon element with an XPath that additionally checks that there is "Support" text after and check if the element is present:
expect(element(by.xpath("//text()[. = 'Support']/preceding-sibling::i[contains(#class, 'fa-external-link')]")).isPresent().toBe(true);
This works but it is quite ugly and I don't like that the actual position check is hidden inside the XPath expression which is not really readable and reliable.
I recommend changing the product under test by adding a <span> and move the text "Support" into the <span>.
<div class="ap-version-panel ap-version-support">
<i class="fa fa-external-link"></i><span>Support<span>
</div>
But if you cannot change the product, you can use javascriptExecutor to get childNodes then check order of the nodes:
var aFunctionToCheckOrder = function (arguments) {
var nodes = arguments[0].childNodes;
var result;
// Check nodes[0] = <i>
// Check node [1] is textNode and its value = "Support"
return result;
}
var supportLink = element(by.linkText("Support"));
browser.executeScript(aFunctionToCheckOrder, supportLink).then(...)
As you can see, it is more uglier than your solution. You'd better change your product under test.

Using web driver (with c#) how can I verify this span class exists?

I'm testing out a third party chrome extension which allows users to speak text inside a Google document. Here is the code generated inside the Google document:
<span class="kix-wordhtmlgenerator-word-node" style="font-size:15px;font-family:Arial;color:#000000;background-color:transparent;font-weight:normal;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;">
<span>
<gpldns:gptag class="googlePLAYRTWord 0">I'm</gpldns:gptag>
<gpldns:gptag class="googlePLAYRTSpace 0"> </gpldns:gptag>
<gpldns:gptag class="googlePLAYRTWord 1">Speaking</gpldns:gptag>
<gpldns:gptag class="googlePLAYRTSpace 1"> </gpldns:gptag>
<gpldns:gptag class="googlePLAYRTWord 2">This</gpldns:gptag>
<gpldns:gptag class="googlePLAYRTSpace 2"> </gpldns:gptag>
<gpldns:gptag class="googlePLAYRTWord 3 googlehighlighted">text</gpldns:gptag>
</span>
The specific block of code I'm interested in, is the last span class in the example above:
<gpldns:gptag class="googlePLAYRTthWord 3 googlehighlighted">
What I need to be able to do is to verify that the class name contains "googlehighlighted". It doesn't matter what else the class name contains, so long as it contains "googlehighlighted". Note that in this case the class I'm interested in is the last item but it will not always be the last item
Any help would be really appreciated. Thanks
EDIT / UPDATE
For c# I can use the following:
if (driver.FindElements(By.ClassName("googlehighlighted")).Count() > 0)
{
...
}
else
{
...
}
You could test for something like:
driver.findElements(By.className("googlehighlighted")).size() > 0
Note that I am using the plural "findElements", which will not cause an Exception in your code if there are zero such elements.
I think this would work for you:
IWebElement lastElement = driver.FindElement(By.XPath("//span[#class='kix-wordhtmlgenerator-word-node']/span/*[last()]"));
if (lastElement.GetAttribute("class").Contains("googlehighlighted")
{
System.Console.WriteLine("Last element class does contain googlehighlighted");
}
else
{
System.Console.WriteLine("Last element class does not contain googlehighlighted");
}

How to check whether an Xpath is clickable?

I have an application developed in Liferay. It has a data grid which has pagination.
When ever i open the data grid for the first time Prev is not clickable and Next is clickable. Below is the html code for the same.
<section class="paginationArea">
<div id="pager">
<span id="prev" class="disablehyperlink"><< Previous Page</span>
<span id="next" class="enablehyperlink">Next Page >></span>
</div>
</section>
Please let me know how can i check whether that text is clickable or not??
You can always check it for a class attribute (assuming class change will cause enabling the button). You didn't specify a language so I will show you example in Java.
Element prevButton = driver.getElement(By.id("prev"));
if(prevButton.getAttribute("class").equals("disablehyperlink") {
// do something
}
or you can try WebDriver#isEnabled method but I don't know whether it will work because it depends how are you disabling the button
if(prevButton.isEnabled()) {
}
Generally, all the <a> anchor Tags will be clickable.
In your case, Prev is not clickable. Because prev [previous in paginator] is hidden; where else Next [next in paginator] is not hidden(enabled).
Use Firebug [firefox add-on] to track all the hidden anchor tags | href links and code accordingly.

jQuery: Select elements with Incrementing ID names?

and thanks in advance for your help!
Here's my situation: I have a set of divs whose IDs have an incrementing number applied to the end of the name using PHP. Each of these divs are added dynamically with PHP (They are a series of FAQ questions with a hidden div container with the answers, that slide down when the question is clicked.) [Live Example][1]
There is no limit to the number of questions that appear on the page, because this is being used for a Wordpress theme and my client wants to add new questions as they go along.
Here's an example of the structure for each FAQ question using the PHP:
<?php var $faqnum = 0; $faqnum++; ?>
<div id="faqwrap<?php $faqnum; ?>">
<h4>What data is shared?</h4>
<div id="faqbox<?php $faqnum; ?>" class="slidebox">
<p>Data sharing is defined by the type of service:</p>
<ul class="list">
<li>Third-party access to data (Enhanced Services only is strictly controlled and determined by the SDA)</li>
<li>All members must participate in points of contact and conjunction assessment but can choose whether to participate in other services</li>
<li>Participation in a service requires the member to provide associated data<br />
</ul>
</div>
</div>
Now this is what I have currently in jQuery, and it works, but only if I add a new one every time my client wants to add a new question.
$(document).ready(function() {
$('.slidebox*').hide();
// toggles the slidebox on clicking the noted link
$("#faqwrap1 a:not(div.slidebox a)").click(function() {
$("#faqbox1.slidebox").slideToggle('normal');
$('div.slidebox:not(#faqbox1)').slideUp('normal');
return false;
});
});
I thought of maybe doing something with a declared variable, like this:
for (var x = 0; x < 100; x++;) {
$('#[id^=faqwrap]'+ x 'a:not(div.slidebox a)')...
}
I hope this is clear enough for you! Again, I thank you in advance. :)
The best way to handle this is to not use the IDs, but use classes for the outer element. So your PHP would be altered like this:
<?php var $faqnum = 0; $faqnum++; ?>
<div id="faqwrap<?php $faqnum; ?>" class="question">
<h4>What data is shared?</h4>
<div id="faqbox<?php $faqnum; ?>" class="slidebox">
<p>Data sharing is defined by the type of service:</p>
<ul class="list">
<li>Third-party access to data (Enhanced Services only is strictly controlled and determined by the SDA)</li>
<li>All members must participate in points of contact and conjunction assessment but can choose whether to participate in other services</li>
<li>Participation in a service requires the member to provide associated data<br />
</ul>
</div>
</div>
Your JQuery would be rewritten with the selector for the class "question".
$(document).ready(function() {
$('.slidebox*').hide();
// toggles the slidebox on clicking the noted link
$(".question a:not(div.slidebox a)").click(function() {
/* close everything first */
$('div.slidebox').slideUp('normal');
/* selects and opens the the slidebox inside the div */
$(".slidebox", this).slideToggle('normal');
return false;
});
});
This will get you the effect you are looking for. The key differences in the JQuery is the way you get the slidebox inside the question that got clicked. I'm using the scoped selection $(".slidebox", this) to get just the slidebox inside the clicked ".question" element.
The subtle visual difference is that the slideUp() happens before the slideToggle(). This will essentially close any open queries before it opens the desired one. If you keep your animations fast, this will be more than fine. The advantage of this approach is that you don't have to worry about the count of questions on a page, and the selectors are most likely more optimized than the for loop.
Edit
I adjusted the PHP code to use a class for "slidetoggle" instead of an id. It's technically an HTML error to have multiple IDs that are the same. It can throw off some assistive technologies for people with dissabilities. I'm assuming that section of code was repeated several times on the page.
Without changing your current markup, this would work:
// toggles the slidebox on clicking the noted link
$("div[id=^faqwrap]").each(function () {
var $faqwrap= $(this);
$faqwrap.find("h4 > a").click(function () {
var $currentSlidebox = $faqwrap.children(".slidebox");
$currentSlidebox.slideToggle('normal');
$('div.slidebox').not($currentSlidebox).slideUp('normal');
return false;
});
});
Maybe you can find a few suggestions in the above code that help you.
Like #Berin, I'd also recommend giving a separate CSS class to the outer DIV and using that as a selector, instead of $("div[id=^faqwrap]").