How can you get an attribute using Selenium 2 and PHPUnit? - selenium

I'm trying to follow the URL of a hidden Log Out link. The HTML looks like this:
<li id="wp-admin-bar-logout"><a class="ab-item" href="http://www.ananda.org/wp-login.php?action=logout&_wpnonce=f633c2d0a4">Log Out</a> </li>
Getting the element is straightforward:
$link = $this->byXPath( '//*[#id="wp-admin-bar-logout"]/a' );
Can I get attributes?

You can get attributes of elements, apparently, though I couldn't find this documented anywhere.
Here's the complete solution I used:
protected function doLogout() {
$this->url('/wp-admin');
$link = $this->byXPath( '//*[#id="wp-admin-bar-logout"]/a' );
$this->url( $link->attribute('href') );
}

Related

Razor Pages Tag Helper with Dynamic Parameters Assigning Current Url as Href

I'm running into trouble trying to set anchor tag helper parameters dynamically and looking for some help.
I have a nav that is a view component inside the shared _Layout.cshtml page that populates departments from a model.
#model List<DepartmentModel>
<ul class="nav">
#foreach (var d in Model)
{
<li>
<a asp-page="catalog/departments" asp-route-departmentName="#d.Name" asp-route-departmentId="#d.Id">#d.Name</a>
</li>
}
</ul>
Here is the InvokeAsync() from my View Component class
public async Task<IViewComponentResult> InvokeAsync()
{
var departments = _catalogService.GetNavDepartments();
return View(departments);
}
When I first launch the page, all the hrefs are populating correctly.
"catalog/departments/department-name-1/department-id-1"
"catalog/departments/department-name-2/department-id-2"
"catalog/departments/department-name-3/department-id-3"
If I click on one of the links, like the first link for example, I go to the proper department page "catalog/departments/department-name-1/department-id-1"
However, once I click that first link and navigate to the respective page, all the nav hrefs populate to the current url "catalog/departments/department-name-1/department-id-1" instead of the originally generated hrefs. This makes it so I can't navigate to another department.
Here is my route in the Startup.cs
services.AddRazorPages().AddRazorPagesOptions(options => {
options.Conventions.AddPageRoute("/Catalog/Departments", "{dName}/{dId}");
});
Based on the convention above, it eliminates the "catalog/department" piece of the url but I added it in this description for a sense of what I'm trying to accomplish. Even if I add this template to the page that populates the "catalog/departments" url, I get the same result.
#page "{dName}/{dId}"
Can anyone help me figure out what I am missing? Thanks in advance!
******** UPDATE ********
Currently, the only way I am able to get this to work is by adding the cache tag helper.
<cache>
<ul class="nav">
#foreach (var d in Model)
{
<li>
<a asp-page="catalog/departments" asp-route-departmentName="#d.Name" asp-route-departmentId="#d.Id">#d.Name</a>
</li>
}
</ul>
</cache>
This doesn't seem like a proper fix. Seems more of a hack then anything. Anybody have any ideas? Thanks!

Finding a parent element in webdriver.io

I've seen a couple of solutions in the original webdriver that use getAttribute('xpath') and append to that '/..' but webdriver.io doesn't have an xpath attribute so I haven't been able to use that. Any ideas on how to grab the parent element?
The case I am trying to test is inside of a bootstrap layout and the element that is actually getting the class I am trying to check is one above. It looks like this:
<div class="form-group">
<input class="form-control" type="text" name="username">
<other stuff>
</div>
I am selecting by driver.element("input[name='username'"] but the error class actually hits the div
<div class="form-group error">
<input class="form-control" type="text" name="username">
<other stuff>
</div>
So I need to check if the div itself has an error class, not the input I can find (there are no uniques on the div)
Any help would be greatly appreciated.
Just searched the same and found this by inspecting Webdriver.IO source code - you can use el.$('..') to get the parent element, like this:
$('input[name="username"]').$('..') // returns the parent element
Voila! It's a part of their XPath selectors support.
I ended up solving this by using execute to get the xpath from jQuery, here is the code I used (albeit for a different test I was writing - if every label that has a * is a required field). Hopefully this is helpful to somebody in the future:
var requiredXPaths = browser.execute(function () {
var returner = [];
var $elements = $('.modal.fade.in').find("label:contains('*')");
_.each($elements, el => {
var xpath = '';
var element = el.parentElement;
for (; element && element.nodeType == 1; element = element.parentNode) {
var id = $(element.parentNode).children(element.tagName).index(element) + 1;
id > 1 ? (id = '[' + id + ']') : (id = '');
xpath = '/' + element.tagName.toLowerCase() + id + xpath;
}
returner.push(xpath);
});
return returner;
});
I got the xPath function from another stackoverflow page (How to calculate the XPath position of an element using Javascript?)
WebdriverIO actually lets you use XPath in your selectors, so any valid Xpath selector should work to find the element you want.
Alternatively, you could just use isExisting to check if the element exists on the page using the error class parent:
driver.isExisting('.error input[name="username"]');
If the element doesn't exist, then your error class didn't get added.
I've been talking about this in gitter, when the parent can be selected input[name="username"]
The parent of this element can be selected as //div[input[name="username"]]

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.

How to customize links for breadcrumbs widget for Yii?

How to customize links for breadcrumbs widget for Yii?
I can change the property tagName, but it for container. I want to change a tag for each links from a to li. How can I do it?
Well there's no setting/property value that you can specify for the default CBreadcrumbs widget class that will give you <li>. You can confirm this if you check out its run() method. In the source you can see this:
public function run(){
// code
foreach($this->links as $label=>$url)
{
if(is_string($label) || is_array($url))
$links[]=CHtml::link($this->encodeLabel ? CHtml::encode($label) : $label, $url);
else
$links[]='<span>'.($this->encodeLabel ? CHtml::encode($url) : $url).'</span>';
}
// more code
}
So what you'll have to do is extend this class and specify your own run method, where you can use <li> or CHtml::tag('li',//other options) instead of the default CHtml::link.
Edit:
Although i would suggest enclosing the <a> for each link with a <li> (instead of replacing it):
$links[]='<li>'.CHtml::link($this->encodeLabel ? CHtml::encode($label) : $label, $url).'</li>';
You can do that with 'activeLinkTemplate' and 'inactiveLinkTemplate' properties:
$this->widget('zii.widgets.CBreadcrumbs',
array('tagName'=>'ul',
'homeLink'=>'<li>'.CHtml::link('Home', array('/')).'</li>',
'activeLinkTemplate'=>'<li>{label}</li>',
'inactiveLinkTemplate'=>'<li class="active">{label}</li>',
'htmlOptions'=> array('class'=>'breadcrumb'),
'separator'=>' / ',
'links'=>$this->breadcrumbs,
));
Or U can write 'homeLink'=>false. But in this case U'll have to set Home url every time with $this->breadcrumbs.

Access Elements of a DOJO DIV

I have two Hyper Links on to a DOJO DIv
var create = dojo.create("div",{
id:"create_links",
className:"iconRow1",
innerHTML:"<a class='popupLink' href='javascript:openCreateDialog()'>Create </a> <span>|</span><a href='javascript:openUploadDialog()'>Batch </a>"
},dojo.query(".ui-jqgrid-titlebar")[0]);
On click of the Batch Hyperlink , i have a function
function openUploadDialog()
{
// Here i want to disable the Create Hyper Link tried this way
dojo.byId('create_links')[1].disabled=true; // Not working
}
See whether i can answer your question.
HTML Part:
<div id="create_links">
g
h
</div>
JS Part:
dojo.addOnLoad(function() {
var a = dojo.query("#create_links a")[1];
dojo.connect(a,'click',function(e){
console.log(e.preventDefault())
})
})
#Kiran, you are treating the return of dojo.byId('create_links') like an array when that statement will return to you a node on the dom.
Also, hyperlinks don't support a disabled attribute to prevent them from being actionable. You could probably create a click handler that returns false to accomplish this type of functionality, or like #rajkamal mentioned, calling e.preventDefault(). #rajkamal also provides a good solution to selection the link properly.