Test fails find(selector).count - testing

I would like to test the filter functionality of items in list-table. On the list, there are 5 elements. After typing stringing eg. "a" into input "Search", there are 2 elements.
And this case the DOM looks following (there are visible only 2 'li' not 5):
<ul _ngcontent-nin-c20="" class="list-group">
<!---->
<!---->
<!---->
<li _ngcontent-nin-c20="" class="ng-star-inserted">...</li>
<!---->
<!---->
<!---->
<li _ngcontent-nin-c20="" class="ng-star-inserted">...</li>
<!---->
<!---->
<!---->
<!---->
</ul>
I defined selectors following way in editPage.js:
this.chosenListGroup = Selector('[class="list-group"]');
this.listGroup = Selector('.form-check-input');
My code where I want to check the number of chosen items looks:
await t
.typeText(editPage.searchField, 'Drama')
.expect(editPage.chosenListGroup.find(editPage.listGroup)
.count)
.eql(1);
I received the following error:
" TypeError: Cannot read property 'find' of undefined"
I do not understand why 'find' is undefined. Where is a bug?
Is my logic to test the filter ok?
Could you answer my question, please?

Related

Greasemonkey Click Button without ID or Name

I'm trying to autoclick this button with greasemonkey. I tried to find a reference to this button with document.getElementsBy[ClassName/Name/TagName] with ClassName i find buttons but not the one i need. Any ideas how i can automate his click-event?
<button type="button" class="ml-2 mt-2 v-btn v-btn--depressed theme--light v-size--default amber darken-1 white--text ">
::before
<span class="v-btn__content">
<!---->
Überspringen
<i aria-hidden="true" class="v-icon notranslate v-icon--right material-icons theme--light">
redo
::after
</i>
<!---->
</span>
</button>
Screenshot from Firefox Inspector with Click Function
Thanks in Advance!
Just use xpath for element searching:
document.evaluate(XPATH, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
You can use class parameter instead id or name:
xpath: //button[#class='ml-2 mt-2 v-btn v-btn--depressed theme....']
If you do not need to use all value, you can use contains keyword:
xpath:
//button[contains(#class, 'ml-2 m2-2')]
css:
button[class*='ml-2 m2-2']
Of course, this value must be unique.
You can search child element and return back to the parent:
//button/span[#class='v-btn__content']/i/../..
You can use text for searching (bad practics if location possible to change)
//button/span[text()='Überspringen']/..

Vue to render tr array recursively

I have to create collapsible tree with table data using bootstrap. This look the following way
<tr><td>Parent node1</td><td>...</td><td>...</td></tr>
<tr><td>Subparent node1.1</td><td>...</td><td>...</td></tr>
<tr><td>Subsupparent node1.1.1</td><td>...</td><td>...</td></tr>
<tr><td>Subsupparent node1.1.2</td><td>...</td><td>...</td></tr>
<tr><td>Subparent node1.2</td><td>...</td><td>...</td></tr>
<tr><td>Subsupparent node2.1.1</td><td>...</td><td>...</td></tr>
<tr><td>Subsupparent node2.1.2</td><td>...</td><td>...</td></tr>
I decided to create Vue component rendering on each level html with own data and collection of children via recursion:
<template id="tree-item">
<tr :key="currentNode.id">
<span #click="setExpanded(currentNode)">
<div style="display: inline-block;">
<span class="treegrid-indent" :style="{width: 15 * level + 'px'}"></span>
<span class="treegrid-expander fa" :class="currentNode.isExpanded ?'fa-chevron-down':'fa-chevron-right'">
</span>
</div>
{{level}} {{currentNode.id}}
</span>
</tr>
<tree-item v-for="item in currentNode.items" :currentNode="item" :level="level+1"> </tree-item>
</template>
But i get Vue error:Component template should contain exactly one root element.
Are there any ways to solve the task?
If you can relax your requirements to use a list instead of table then you can try something like this:
<div class="folder_container">
<ul class="no_list no_space">
<FolderTree :folder="folders" :level="0"/>
</ul>
</div>
And the FolderTree component's template looks like this:
<template>
<li>
<div>
<div class="folder_name">{{ folder.name }}</div>
</div>
<ul v-if="folder.child && folder.child.length > 0" class="no_list no_space">
<FolderTree
v-for="(fold,idx) in folder.child"
:key="fold.id"
:folder="fold"
:level="level + 1"
:last="1 + idx === folder.child.length"
/>
</ul>
</li>
</template>
If you need to use a table - then you will have to somehow transform your nested objects into a linear list/array of items. Otherwise you won't be able to overcome the limitation for only 1 root element in templates (unless you use render functions).

Validate array of inputs with Vee-Validate (Vuejs)

The following works:
<li :key="index" v-for="(...) in items">
<input type="text" name="itemFields[]" v-validate="required">
</li>
// ...
<div class="vv-errors">
<ul>
// shows only for last active input
<li v-for="error in errors.collect('itemFields[]')">{{ error }}</li>
</ul>
</div>
If I make some input empty, it shows an error message. But if I then fill some other empty input with text, the error message disappears completely. That should not be the case, because the other input is still empty. To summarize, the error messages only consider the last active input.
How to achieve that the error message shows up if at least one of the inputs is empty?
Actually the issue you are facing is because the name field is same for all your inputs and that should be unique.
Hence while using v-for you could do something as below :
<div v-for="i in 5" >
<input type="text" :name="'email'+i" placeholder="Email" v-validate="'required|email'">
<span class="error" v-if="errors.has('email'+i)">{{errors.first('email'+i)}}
</span>
</div>
Here is a basic example to solve your problem.

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();
});

Font Awesome not updating properly with vue

I'm trying to make a clickable "star" icon using font-awesome with bulma, switching between regular and solid styles (fas and far) in Vue, to achieve this I have the following component:
<template>
<span v-if="isStarred" class="icon starred config-icon clickable-text" #click="unstar">
<i class="far fa-star" title="Unstar Ranking"/>
</span>
<span v-else class="icon unstarred config-icon clickable-text" #click="star">
<i class="fas fa-star" title="Star Ranking"/>
</span>
</template>
The value isStarred is being updated properly and the span elements are updating accordingly. However the i element with the icon doesn't update until I fully reload the page.
I was able to make this work with v-show instead of v-if but I don't understand why this wouldn't work.
Vue tries to render elements as efficiently as possible, often re-using them instead of rendering from scratch. This isn’t always desirable though, so Vue offers a way for you to say, “These two elements are completely separate - don’t re-use them.” Add a key attribute with unique values:
<i class="far fa-star" title="Unstar Ranking" key="unstared"/>
...
<i class="fas fa-star" title="Star Ranking" key="stared"/>
Now those i elements will be rendered from scratch each time you toggle.
You can also update your classes with class binding:
<span v-if="isStarred" v-bind:class="{starred: isStarred, unstarred: !isStarred}" class="icon config-icon clickable-text" #click="toggleStar">
<i v-bind:class="{far: isStarred, fas: !isStarred}" class="fa-star" v-bind:title="title"/>
</span>
I switched the [fontawesome/js/all.js] to [fontawesome/css/all.css], and it solved the problem. I guess the fontawesome js is rendered after the vue.