findElementWithElement in webdriverio not allowing me to perform action on returned child element - selenium-chromedriver

i am trying to target the div element nested inside parent div to scrollintoview to that element using webdriverio v8. below is the code structure within each parent div (note: parent div with analytics attribute repeated multiple times in DOM. there can be many div with analytics attribute with different values on the page)
<div analytics='analyticsvalue1'.. >
<div class='one'></div>
<div class="two"></div>
<div class="unit-image-wrapper"></div>
</div>
the webdriver io selectors used in my js file:
//getting all div blocks with attribute analytics except that with value 3
const tiles= await $$("div[analytics]:not([analytics='value3'])")
//loop in array of div elements to target div with class .unit-image-wrapper
tiles.forEach(async (tile)=>{
//get the nested .unit-image-wrapper div within each parent analytics div
const elem=await browser.findElementFromElement(tile.elementId,'css selector','.unit-image-wrapper');
//log the result
console.log(`tile is !!!! ${JSON.stringify(elem)}`);
})
but the above gave the output which follows the below format:
tile is !!!! {"element-6066-11e4-a52e-4f735466cecf":"ce58a46f-3709-447b-9148-1f072ede6ff4"}
if i try to do any action on the returned element like elem.getHTML() or elem.getTagName() and log the result to console, i get no output to the console

Related

How can I use getElementsByClassName(<classname>).outerHTML="" to hide a <div> when there are multiple names for the div's class?

I am trying to learn how to hide <div> sections on a webpage, using javascript getElementsByClassName("<classname>").outerHTML="".
It all works great if the element I am hiding e.g. <div class="someclassname">Some content I want to hide</div>. Or, I have success if using getElementByID("<divId>") if working with e.g. <div id="somedivID">.
The problem is, when wanting to hide a <div> that has no id and when there are multiple names listed for the div's class such as below:
<div class="cake forest carousel">Some content I want to hide.</div>
How can I hide such a div that has not id and no single class name?
For classes, you can use document.querySelectorAll() along with css selectors, like this:
document.querySelector('button').addEventListener('click', () => {
document.querySelectorAll('.cake')[0].style.display = 'none';
});
<div class="cake forest carousel">Some content I want to hide.</div>
<button>Hide content</button>
With classNames, remember that you can specify ALL the classNames (sometimes that is useful to pinpoint one element if there are other elements that contain part of the classList:
document.querySelectorAll('.cake.forest.carousel')[0] . . .
Also note that document.querySelectorAll() returns a collection, not a string - which is why it is necessary to use the [0] notation to choose the first element returned in the collection.
Using getElementsByClassName() is much the same idea - again, it returns a collection and one must either use the [0] notation to get the first element (usually if only one is returned), or a forEach() loop to choose the desired element based on other criteria.
document.querySelector('button').addEventListener('click', () => {
document.getElementsByClassName('cake forest')[0].style.display = 'none';
});
<div class="cake forest carousel">This div has classes cake, forest and carousel</div>
<div class="cake">This div only has class cake</div>
<button>Hide divs with classes cake AND forest</button>

Robot Framework: wait for an element to (dis)appear based on a custom HTML property?

I have a div with a property panelname that changes depending on which view in a multi step process I am in (every panel has a Next-button).
It takes a few seconds after each click on Next for the next panel to load and render. This div has the same ID on every step instead panelname changes for each view.
I can read the value for panelname using Get Element Attribute but how do I use this in one of the Wait until page/for element, or similar, keywords?
The following should work, assuming you know each panel's name:
Wait Until Page Contains Element //div[#id='sameId' and #panelname='name2']
This the example HTML for the keyword above:
<div id="sameId" panelname="name2"></div>

outerHTML behavior in a <template>

Given this <template>:
<template id="my-template">
<h1 id="h">Hello!</h1>
</template>
And JS:
var t = document.querySelector("#my-template");
var h = t.content.querySelector("h1");
h.outerHTML = "<h3>AAAAAAAAAAAAAA</h3>";
It's interesting that it works in FireFox and Edge but in Chrome outerHTML requires a parent element, otherwise it throws error in console (https://chromium.googlesource.com/chromium/blink/+/master/Source/core/dom/Element.cpp#2528):
<template id="my-template">
<div>
<h1 id="h">Hello!</h1>
</div>
</template>
See https://jsfiddle.net/q5fmn186/11/
My question is, is Chrome behavior the correct one? Should setting outerHTML not work in <template> on direct children? Why aren't the other web-browser treat it like an error?
The other web browsers won't treat it like an error because they are following the DOM Parsing and Serialization W3C Candidate Recommendation (which is not a standard yet):
On setting [outerHTML], the following steps must be run:
Let parent be the context object's parent.
If parent is null, terminate these steps. There would be no way to obtain a reference to the nodes created even if the remaining steps were run.
If parent is a Document, throw a DOMException with name "NoModificationAllowedError" exception.
If parent is a DocumentFragment, let parent be a new Element with body as its local name, the HTML namespace as its namespace, and the context object's node document as its node document.
Let fragment be the result of invoking the fragment parsing algorithm with the new value as markup, and parent as the context element.
Replace the context object with fragment within the context object's parent.
The <template>'s content is of type DocumentFragment (step 4) but it is treated (in this situation) as a Document (step 3) by Chrome and Safari.

Bind value of html element to ng-model dynamicall angularjs

I have an html element (div)
I append anther html element like (textarea) to to this (div), I want to bind the value of the added element to ng-model which is an area
.html file
<div id="new-view{{$index}}"></div>
.js file
var parent = $('#new-view' + controllerIndex);
var question = angular.element('<textarea data-ng-model="self.array['+Index+'].question"></textarea>');
parent.append(question);
How to I bind what the user will write inside this text area to the array?
You can try another approach with ng-repeat directive. Operate on your data. And angular 2-way binding will update your interface.
Little example: http://jsfiddle.net/joshdmiller/hb7lu/
<div >
<textarea ng-repeat="q in questions" ng-model="q.text"></textarea>
</div>

div equal height animation on document ready

I have a script called equal-heights.js which works together with underscore.js. It equalize the divs to the size of the highest div with an animation (optional). The problem is that when I charge the page nothing happens, it starts to equalize the divs only when I resize the browser.
The initialising code on the HTML:
$(document).ready(function() {
$('.profile-panel').equalHeights({
responsive:true,
animate:true,
animateSpeed:500
});
});
You can see the equal-heights.js here: http://webdesign.igorlaszlo.com/templates/js/blogger-equal-heights-responsive.js
What should I do so that, when the page loads, the animation starts to equalize the divs automatically?
I created my own test and realized the issue is with the way the plugin has been written, namely that it only accepts one value for the class name, otherwise it will break.
This is because of the following line in the script:
className = '.'+$(this).prop('class');
What this does is that it takes the class property of your element and adds a dot (.) in front; a nice but not very scalable way of getting the current selector, because if you have multiple class names, it will only put a dot in front of the first one, so if you have...
<div class="profile-panel profile-panel-1st-row profile-panel1">
...it will transform it into...
$('.profile-panel profile-panel-1st-row profile-panel1')
...so understandably this will not work properly, as the dots are missing from the rest of the classes.
To go around this, until version 1.7, jQuery had a .selector property, that however has now been deprecated. Instead they're now suggesting to add the selector as an argument of your plugin's function as follows (and I tailored it to your situation):
First define an option called selector when calling the function:
$('.profile-panel-1st-row').equalHeights({
selector:'.profile-panel-1st-row',
// ...
});
Then setup the className variable inside the plugin as follows:
var className = options.selector;
Another thing you can do is the place the class you're using to activate the plugin as the first one for each element you want to use it on, so instead of...
<div class="profile-panel profile-panel-1st-row profile-panel1">
...do this...
<div class="profile-panel-1st-row profile-panel profile-panel1">
...then you can setup the className variable inside the plugin as follows:
var className = '.'+ $(this).prop('class').split(" ").slice(0,1);
This basically splits the class names into parts divided by space and takes the first one.
To have the best of both solutions, simply set className to the following:
var className = options.selector || '.'+ $(this).prop('class').split(" ").slice(0,1);
As to the animation, it only works on resize; that is intended, that's how the plugin has been built, you can play around with the original example of the plugin creator that I added to jsfiddle: http://jsfiddle.net/o9rjvq8j/1/
EDIT #2: If you're happy to change the plugin even more, just remove $(window).resize(function() in the if(settings.responsive === true) check and you'll have it working. ;)
if(settings.responsive === true) {
//reset height to auto
$(className).css("height","auto");
//re initialise
reInit();
}