Getting nested <li> tags also.....just need the direct <li> item - selenium

I have a page structure where it includes hyperlinks with different levels of nested list items. I am writing the xpath for just the second nested list items(level 2) but it is also giving me all the list items below level 2(level 3 or below), which i don't need. It's getting really frustrating now because I have tried different xpaths and cssSelectors, everytime it is taking the level 3 list items along with level 2.
The page structure is exactly like following:
<div>
<ul class="menuBar_menu_lvl_0">
<li class="item_lvl_1">
<li class="item_lvl_1">
<ul class="menu_lvl_1">
<li class="item_lvl_2"></li>
<li class="item_lvl_2"></li>
<li class="item_lvl_2">
<ul class="menu_lvl_2">
<li class="item_lvl_3"></li>
<li class="item_lvl_3"></li>
<li class="item_lvl_3"></li>
</ul>
</li>
</ul>
<li class="item_lvl_1">
<li class="item_lvl_1">
xpath = //ul[#class="menuBar_menu_lvl_0"]//li[#class="item_lvl_1"]//ul[#class="menu_lvl_1"]//li[#class="item_lvl_2"]
This is also giving me item number 3 elements along with item level 2. I want to get each level item correctly and separately. Anybody's help would be highly appreciated

Welcome to SO.
Here is the sample that used.
<html>
<body>
<div>
<ul class="menuBar_menu_lvl_0">
<li class="item_lvl_1">
<li class="item_lvl_1">
<ul class="menu_lvl_1">
<li class="item_lvl_2">Level1-li1</li>
<li class="item_lvl_2">Level1-li2</li>
<li class="item_lvl_2">
<ul class="menu_lvl_2">
<li class="item_lvl_3">Level2-li1</li>
<li class="item_lvl_3">Level2-li2</li>
<li class="item_lvl_3">Level2-li1</li>
</ul>
Level1-li3
</li>
</ul>
<li class="item_lvl_1">
<li class="item_lvl_1">
</ul>
</div>
</body>
</html>
And below is the xpath
//ul[#class='menu_lvl_1']//li[not(parent::ul[#class='menu_lvl_2'])]
Here is the output:
Here is the method to get the text from parent element only.
def get_text_exclude_children(element):
return driver.execute_script(
"""
var parent = arguments[0];
var child = parent.firstChild;
var textValue = "";
while(child) {
if (child.nodeType === Node.TEXT_NODE)
textValue += child.textContent;
child = child.nextSibling;
}
return textValue;""",
element).strip()

Related

iterating number type in express-edge?

isn't it possible to itereate through a number type variable in express-edge? On their official docs they mentioned iteration of objects and arrays and when I tried to iterate a number type variable it didn't worked (i mean like a simple loop, will run for n times)
so basically i'm trying to impelment a pagination, my controller for this look something like this:
// get total documents in the Posts collection
const count = await Posts.countDocuments();
const tpgs = Math.ceil(count / limit);
// return response with posts, total pages, and current page
res.render("index",{
psts: posts,
totalPages: tpgs,
currentPage: page
});
and the html (with express-edge) looks something like this:
#if(totalPages > 0)
<nav aria-label="Page navigation example">
<ul class="pagination">
#each(p in totalPages)
#if(p == 1)
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">Previous</a>
</li>
#else
<li class="page-item"><a class="page-link" href="posts/{{ p - 1}}">Previous</a></li>
#endif
#if(p == currentPage)
<li class="page-item active" aria-current="page">
<a class="page-link" href="{{ p }}">{{ p }}</a>
</li>
#else
<li class="page-item"><a class="page-link" href="posts/{{ p }}">{{ p }}</a></li>
#endif
#if(p == totalPages)
<li class="page-item disabled">
<a class="page-link" href="posts/{{ p + 1}}">Next</a>
</li>
#else
<li class="page-item">
<a class="page-link" href="posts/{{ p + 1}}">Next</a>
</li>
#endif
#endeach
</ul>
</nav>
#endif

Space disabled on concatenation

I have an array which looks like this
skills: [
"HTML5",
"CSS3",
"SCSS",
"Bootstrap",
"JavaScript",
"Vue.js",
"PHP",
"MySQL",
"Symfony"
]
And in my template I'm doing something like
<ul>
<li v-for="(skill,index) of skills" :key="index">{{ skill + ', '}}</li>
</ul>
But what I get is
HTML5,CSS3,SCSS,Bootstrap,JavaScript,Vue.js,PHP,MySQL,Symfony,
How do I able the spaces?
Btw is there a better way to concatenate the elements of my array? I first used join() like that
<ul>
<li v-for="(skill,index) of skills.join(', ')" :key="index">{{ skill }}</li>
</ul>
But not only the spaces are still disabled but it returns every character of my elements, I don't know why
Like
<ul data-v-c226fde6="">
<li data-v-c226fde6="">H</li>
<li data-v-c226fde6="">T</li>
<li data-v-c226fde6="">M</li>
<li data-v-c226fde6="">L</li>
<li data-v-c226fde6="">5</li>
<li data-v-c226fde6="">,</li>
<li data-v-c226fde6=""> </li>
<li data-v-c226fde6="">C</li>
<li data-v-c226fde6="">S</li>
<li data-v-c226fde6="">S</li>
<li data-v-c226fde6="">3</li>
...
EDIT: otherwise what I could just do is
<ul>
<li v-for="(skill,index) of skills" :key="index">{{ skill + ','}}</li>
</ul>
And then adding some padding-right to the li but I don't know if it's good practice + I don't know how I would remove the comma after the last element
Inside html template such as li you have to specify space characters using ;
<ul>
<li v-for="(skill,index) of skills" :key="index">{{ skill + ','}} </li>
</ul>
also checkout https://www.w3schools.com/html/html_entities.asp
to learn more about HTML entities
With that code you will get a list of <li></li> elements with each skill looking like this:
<li>HTML5,</li><li>CSS3,</li><li>...
just add a class or even a style with a margin to the right to add a little space between the elements either:
<ul>
<li v-for="(skill,index) of skills" style="margin-right: 5px" :key="index">{{ skill }}</li>
</ul>
better:
<ul>
<li v-for="(skill,index) of skills" class="class-with-some-margin-right" :key="index">{{ skill }}</li>
</ul>
You can add the ', ' after each item using CSS like so:
var example1 = new Vue({
el: '#example-1',
data: {
skills: ["HTML5", "CSS3", "SCSS", "Bootstrap", "JavaScript",
"Vue.js", "PHP", "MySQL", "Symfony", ]
}
})
/* styling help:
Q: https://stackoverflow.com/questions/1517220/
A: https://stackoverflow.com/a/1517228/7505395 */
#example-1 {
display: inline;
list-style: none;
}
#example-1 li {
display: inline;
}
#example-1 li:after {
content: ", ";
}
#example-1 li:last-child:after {
content: "";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<ul id="example-1">
<li v-for="(sk, idx) in skills" :key="idx">{{ sk }}</li>
</ul>
This answer incorporates it into Vue, for the pure css answer, go here.
As always you can also combine normal text inside Vues {{}} like so : {{ skill + ', ' }} - not sure if thats helpfull though as it applies to all replacement and you end up having a trailing ,

Selenium - Not able to Click Dynamically Visible Menu

I have a Menu which have li
(list) elements which gets enabled after you mouse-hover a particular label.
driver.get("www.snapdeal.com"); Actions actions = new Actions(driver);
actions.moveToElement(driver.findElement(By.id("loggedOutAccount"))).build().perform();
//Wait for 5 Secs
driver.findElement(By.className("accountLink")).click();// Here it's throwing Element not visible exception
This code is doing the mouse-hover properly but not able to click the "SignIn Link" Link. Though on manually checking the element is Visible
DOM Structure -
<div id="loggedOutAccount" class="hd-rvmp-logout">
<a class="signIn" href="javascript:void(0);">
<i class="iconHeader accountUser"></i>
<label class="my-account-lang"> My Account</label>
<i class="mar_2_left right-downArrow breadcrumbArrow-down"></i>
</a>
<div class="sdNavDropWrapper accDetails" style="display: none; z-index: 999;">
<ul class="positionAbsolute pull-right">
<li class="customLoggedInState">
<div class="left triangle"></div>
<div class="right triangle"></div>
<div>
<a class="accountLink" href="javascript:void(0);">Click here to sign in ></a>
</div>
</li>
<li class="stop-event">
<li class="stop-event">
<li class="stop-event">
<li class="stop-event">
<li class="stop-event">
</ul>
</div>
</div>
Please use xpath for both element like below :
driver.get("www.snapdeal.com");
Actions actions = new Actions(driver);
actions.moveToElement(driver.findElement(By.xpath("yourxpathhere"))).build().perform();
driver.findElement(By.xpath("yourxpathhere")).click();
I think class/Id repeating for other elements also for style purpose. so Xpath is better to find unique element.

how to get url segment in yii

I am new to YII and i want to get the controller name i hit to add active class in menu item .my URL is like this www.myblog.com/news . I want to get the parameter "news" .Without params are possible in yii like codeigniter $product_id = $this->uri->segment(4);
my menu structure is like this
<ul class="nav navbar-nav">
<li class="active">News / Article</li>
<li>Players</li>
<li>Forum</li>
<li class="dropdown">
Rules <b class="caret"></b>
<ul class="dropdown-menu">
<li>Action</li>
<li>Another action</li>
</ul>
</li>
<li>Profile</li>
<li>Gallery</li>
</ul>
Controller Name -
Yii::app()->controller->id;
Action Name -
Yii::app()->controller->action->id;
Yii::$app->controller->id;
and
Yii::$app->controller->action->id;
Yii::$app->request->pathInfo
then take what you want

index of matching items in parent element even if they're in other child containers

I need to get the index of the li.play relevant to the ul.showreel_thumbnails. Is this even possible? All i seem to get is the li index inside ul.row
<ul class="showreel_thumbnails">
<li>
<ul class="row">
<li class="play_video">item</li>
<li class="play_video">item</li>
<li class="play_video">item</li>
</ul>
</li>
<li>
<ul class="row">
<li class="play_video">item 4</li>
<li class="play_video">item</li>
</ul>
</li>
</ul>
so if item 4 is clicked it should give me the index of 4 etc...
best, Dan.
It may not be valid HTML but here's how it would work (with JQuery):
function FindMyCount()
{
var item_count = 0;
$("#showreel_thumbnails li").each(function() {
++item_count;
if($(this).hasClass("igotclicked"))
return false;
});
return item_count;
}
$("#showreel_thumbnails li").click(function() {
$(this).addClass("igotclicked");
var myCount = FindMyCount(); // 1 - the # of li's under the showreel piece
$(this).removeClass("igotclicked");
// Do what you want here.
});