More than one element found for locator by.repeater - testing

Protractor Code to access the repeater which i am using is below
element.all(by.repeater('x in parked'));
HTML Code
<div class="row content">
<div class="col-sm-2">
<div ng-show="role != 3">
<label for="parked" style="color:#0000ff;font-weight:bold">PARKED</label>
<ul style="color:#006400;font-weight:bold" class="arriv-depart">
<li ng-repeat="x in parked" popover-placement="top" data-popover-template="dynamicPopover3.templateUrl" data-popover-trigger="mouseenter">{{ deviceData[x[0]].boatName + ':' + deviceData[x[0]].ownerName}}</li>
</ul>
</div>
</div>
</div>
The problem is, protractor throws a warning:
W/element - more than one element found for locator by.repeater("x in parked") - the first result will be used.
I need to display all the elements present in Parked.

It looks like you have multiple "x in parked" repeaters so the warning isn't telling you that it found multiple "x's", but that it found multiple "x in parked".
Protractor docs say to avoid Xpath, but I have found it to solve countless problems for me especially when it comes to repeaters.

Related

Materialize: Cannot set property 'tabIndex' of null at Dropdown._makeDropdownFocusable

I am trying to test my vuejs component via jest that contains materialize select.
When performing a component test, I get the following error in materialize.js:
TypeError: Cannot set property 'tabIndex' of null at Dropdown._makeDropdownFocusable
How fix this error?
This problem can happen when the input field is not wrapped inside a div with the class input-field:
<div class="input-field">
<input type="text" class="autocomplete"></input>
</div>
Adding a div with the class "input-field might solve this problem.
use id selector instead class selector. for example call dropdown like this :
html :
<a class='dropdown-trigger' id="dropdowner" href='#' data-target='dropdown1'>Drop Me!</a>
<!-- Dropdown Structure -->
<ul id='dropdown1' class='dropdown-content'>
<li>one</li>
<li>two</li>
<li class="divider" tabindex="-1"></li>
<li>three</li>
<li><i class="material-icons">view_module</i>four</li>
<li><i class="material-icons">cloud</i>five</li>
</ul>
js:
$('#dropdowner').dropdown();
Can only be used once.
data-target="name_target" must not be repeated
Exam1.❌
<nav>
<div class="nav-wrapper">
<ul class="right hide-on-med-and-down">
<li><a class="dropdown-trigger" href="#!" data-target="name_target1">Dropdown<i class="material-icons right">arrow_drop_down</i></a></li>
<li><a class="dropdown-trigger" href="#!" data-target="name_target1">Dropdown<i class="material-icons right">arrow_drop_down</i></a></li>
</ul>
</div>
</nav>
<!-- Dropdown Structure -->
<ul id="name_target1" class="dropdown-content">
<li>one</li>
<li>two</li>
</ul>
Exam2.✔️
<nav> <div class="nav-wrapper">
Logo
<ul class="right hide-on-med-and-down">
<li><a class="dropdown-trigger" href="#!" data-target="name_target2">Dropdown<i enter code here class="material-icons right">arrow_drop_down</i></a></li>
</ul> </div> </nav> <ul id="name_target2" class="dropdown-content"> <li>one</li> <li>two</li> </ul>
When I ran into this issue I was trying to create the whole dropdown list dynamically in JS. The fix for me was creating the list and any default list elements in HTML:
<div id="select1" class=\"input-field col s12\">
<select>
<option value="" selected>Default</option>
</select>
<label>Test</label>
</div>
Then appending any dynamic values in JS:
contents.forEach(function(content) {
var buffer = "<option></option>";
var template = $(buffer);
$(template).text(content);
$("select1").find("select").append(template);
});
$("select").formSelect();
pre 1.0.0 you would use data-activates, if data-target is not specified you will get this error
My problem was, that jQuery object was not attached to the DOM yet, so inner materialise code could not init element due to inability to find element by ID:
// materializecss initing dropdown (in my case for input autocomplete), where `t` is the input element
i.id = M.getIdFromTrigger(t),
i.dropdownEl = document.getElementById(i.id),
i.$dropdownEl = h(i.dropdownEl),
M.getIdFromTrigger(t) returned some random ID (not the one I provided) and dropdownEl was inited with null, and later method _makeDropdownFocusable failed on using it `this.dropdownEl.tabIndex = 0
So my problem code looked like this:
let root = $('#root'); // root in the DOM already
let wrapper = $('<div>'); // wrapper is just created and NOT attached to the DOM yet
let input = $('<input>').appendTo(wrapper); // creating input and attaching to the wrapper, but still not in DOM
initAutocomplete(input) // M.Autocomplete.init logic here FAILS
root.append(wrapper) // too late, error above
So the quick fix is to append elements first and only than do M.Autocomplete.init
I just stumbled this issue too while using Materializecss for my Vue project. As mentioned by sajjad, using id selector instead of class works. However, this is problem for initializing multiple dropdown, since each dropdown must have unique ID.
The way I solve this is just by selecting all the elements with the '.dropdown-trigger' class, and initialize every each of those. It works for me.
$.each($('.dropdown-trigger'), function(index, value) {
$(value).dropdown();
});

PyCharm warn: Closing tag matches nothing for <p> tag

After inspect code from my PyCharm. It warns me as
Closing tag matches nothing at last </p> tag
But I didn't find any wrong my code. p tag is closed correctly.
<p v-if="files.length">
<ul>
<li v-for="file in files">
{{file.name}} <span v-if="file.success"> - success. </span><span v-if="file.error"> - fail. </span>
<span v-if="file.success || file.error">{{file.xhr.responseText}}</span>
</li>
</ul>
</p>
How can I resolve this warning correctly?
This warning is caused by invalid HTML. The ul element is not allowed within the p element. The warning may be resolved by refactoring the source to follow the HTML specification.
Remove p element:
<ul>
<li v-for="file in files">
{{file.name}} <span v-if="file.success"> - success. </span><span v-if="file.error"> - fail. </span>
<span v-if="file.success || file.error">{{file.xhr.responseText}}</span>
</li>
</ul>
Convert p element to div element:
<div v-if="files.length">
<ul>
<li v-for="file in files">
{{file.name}} <span v-if="file.success"> - success. </span><span v-if="file.error"> - fail. </span>
<span v-if="file.success || file.error">{{file.xhr.responseText}}</span>
</li>
</ul>
</div>
There is an excellent summary of the relevant portions of the spec in the answer https://stackoverflow.com/a/5681796. Note that the answer specifically addresses ol rather than ul, but is still applicable because their Categories and Content Model are the same.
It would be better if the PyCharm warning message was more specific. This can be done in the paid version of PyCharm via custom inspections, but is not possible in the Community Edition. https://www.jetbrains.com/help/pycharm/creating-custom-inspections.html
I have met this issue, too in my project.
My DOM structure is like:
<p>test<div>test2</div></p>
And, if i write the DOM structure as above, the WebStorm will alert 'closing tag matches nothing'
While, when i change this structure, e.g.: change the div block elements into inline elements span, then it works fine.
So, my advice is changing your DOM struture. e.g. Using div to replace p or using some inline elements in p tag.
One more thing, as i checked in this document https://www.w3.org/TR/html4/sgml/dtd.html
The doc said that the tag p normally includes inline elements. So, i think this is the root cause for your and my issues as mentioned above. So, using inline elements in tag p or use like div or other elements to replace tag p.

Selenium webdriver: clicking not working for xpath

I'm trying to get the webdriver to click on the text "Breaking Things" through xpath/css selectors to no avail. Here is the HTML
<div class="org-option" ng-repeat="Org in Organizations" aria-label="Select Breaking Things Organization" ng-click="Org.SelectOrg()" role="button" tabindex="0">
<div class="data">
<div class="data-relative">
<!---->
<div class="image-wrapper" ng-show="Org.HasImage" ng-if="Org.HasImage" aria-hidden="false">
<img class="onboard-logo" ng-src="/apiimage/organizations/f1544944fac34442998a05890c400338-0" src="/apiimage/organizations/f1544944fac34442998a05890c400338-0">
</div>
<!---->
<div class="image-wrapper ng-hide" ng-show="!Org.HasImage" aria-hidden="true">
<div class="image-placeholder">
<div class="center-icon gicon-panorama"></div>
</div>
</div>
<div class="name-wrapper">
<div>Breaking Things</div>
Here is what I'm doing with the driver:
chromeDriver.findElement(By.xpath("//div[#class='name wrapper']//[text()='Breaking Things']")).click();
However it never clicks, what am I missing? I've also tried implicit waits etc with no results.
You should specify exact node name div or wild-card for "any node" - * in this part
//[text()='Breaking Things']
like below:
"//div[#class='name-wrapper']//div[text()='Breaking Things']"
or
"//div[#class='name-wrapper']//*[text()='Breaking Things']"
The class name is name-wrapper. The - is important
chromeDriver.findElement(By.xpath("//div[#class='name-wrapper']//[text()='Breaking Things']")).click();
In #class='name wrapper' you are actually telling the driver to look for an WebElement with two classes, name and wrapper.

xpath not finding text inside <div><span>

.//*[contains(text(), "Apply")]
<input type="hidden" value="false" name="needsValidation"/>
<input type="hidden" value="false" name="fullValidationPerformed"/>
<div class="loadingBox hidden">
<div class="paneContent">
<div class="topButtons">
<div class="rightSide">
<div id="saveChangesButton" class="majorButton">
<div>
<div>
<div>
<span class="hidden"/>
Apply Changes
<span class="down"/>
</div>
</div>
</div>
</div>
</div>
Why is it that the xpath string I created doesn't find "Apply" here? It appears that my xpath statement only fails when the text I want to find is inside a "span" tag inside a "div" tag like this.
Can someone help me understand what I'm missing here please?
The reason that contains(text(), 'Apply') does not work is that the element has several text nodes, and the contains function in XPath 1.0 ignores all but the first. (XPath 2.0 would give you an error if there is more than one).
If you want to get an element whose string value contains 'Apply' without also returning its ancestors, the simplest way is to get the last element containing this string:
(//*[contains(., 'Apply')])[last()]

Dijit: Why am I getting an "Uncaught Error: Invalid Template"?

I have a dijit that looks fine as far as I can tell, but it is raising Uncaught Error: Invalid template every time. I have not been able to figure out why. All variables (e.g. ${variableName} are defined in the widget correctly.
Here is the widget:
<div class="${classPrefix}-wrapper">
<div class="${classPrefix} flair" dojoAttachPoint="flairNode"></div>
<div class="${classPrefix}-count hidden" dojoAttachPoint="countWrapperNode">
<div class="count" dojoAttachPoint="countNode">0</div>
</div>
<div class="${classPrefix} ${secondaryClass} action hidden" dojoAttachPoint="secondaryClickNode" dojoAttachEvent="onclick:_onSecondaryClick">
<div class="${classPrefix}-inner"></div>
<div class="${classPrefix}-icon"></div>
</div>
<div class="${classPrefix} ${primaryClass} action" dojoAttachPoint="primaryClickNode" dojoAttachEvent="onclick:_onPrimaryClick">
<div class="${classPrefix}-inner"></div>
<div class="${classPrefix}-icon"></div>
</div>
<div class="${classPrefix}-message hidden" dojoAttachPoint="messageNode"></div>
</div>
<div class="${actionPromptNodeClass}" dojoAttachPoint="actionPromptMessageNode">
<span dojoAttachPoint="actionPromptMessage">${actionPromptText}</span>
<span dojoAttachPoint="actionCompletedMessage" class="hidden">${actionCompletedText</span>
</div>
Found the answer to my question. It turns out that you can only have one root node in a Dijit. I missed this in the docs, but it is at the bottom of this tutorial:
Common Pitfalls
Be sure to only have one root node in your template
Don’t start or end your template with a comment because that means you technically have two nodes
Avoid a trailing </div> at the end of your template
There may be only one root element in the template. Wrap your template into <div></div> and it should work.