How to check an element is having display block / none style in Protractor? - selenium-webdriver

I'm having two div's which are having same css, only difference is the style is having display:block and none.
<div class="autocomplete-suggestions " style="left: 91px; top: 333px; min-width: 747px; display: none;">
<div>item1</div>
<div>item2</div>
</div>
<div class="autocomplete-suggestions " style="left: 91px; top: 333px; min-width: 747px; display: block;">
<div>item3</div>
<div>item4</div>
</div>
How we could identify the which element is having the style display block or none in Protractor?
I need to click item3 div which is reside with display:block div.
I have tried the below code.
browser.findElements(by.css('.autocomplete-suggestions')).then((autoSuggestions) => {
autoSuggestions.map((item) => {
if (item.isDisplayed()) {
item.getTagName().then((x) => {
console.log('tagname', x);
});
browser.pause();
//item[index].click();
}
})
from the above code i can see both div's.
I'm receiving 'could not find element 'click on undefined' error.
I'm trying end to end testing with Anuglar 7, protractor, jasmine and selenium web driver.

You need to filter your expression to take into consideration the style attribute.
You might find XPath selector easier to write/read/understand, you can use XPath contains() function to select only div which has display: block in the style attribute would be:
//div[contains(#class,'autocomplete-suggestions') and contains(#style, 'display: block')]/div[1]
Demo:
If you would like to stay with CSS selectors the equivalent expression will be:
div[class*="autocomplete-suggestions"][style *= "display: block"] >:nth-child(1)

If you're looking for an option using CSS as locator then you can use this
element(by.cssContainingText(".autocomplete-suggestions[style*='display: block'] div", "item3"))

Related

Add CSS to react created elements like data-reactroot

Under my root div react creates another div "automatically". Is there a way to add a class to that div? I need to add height: 100% to it to prevent the background content to scroll in mobile when an overlay is shown.
This is how it is shown when i inspect the element on the site. I need to add height:100% to the data-reactroot div when a button is clicked. But that div is nowhere in my source code.
<div id="root">
<div data-reactroot data-reactid="1" data-react-checksum="161698...
I could add this code in the container's componentDidMount()
let root = document.querySelectorAll('[data-reactroot]')[0];
if (root) {
root.style.height = '100%';
}
But isnt there a better way to do it? This feels like kind of hacky (in a bad way)
#root > [data-reactroot] { height: 100% } in your CSS should work.
Or just the tag itself:
[data-reactroot] { ... }
If you want to use in-line css, just make your top div position is absolute and left, top, right, bottom is zero.
So if you inspect the element:
<div id="root">
<div data-reactroot>
<div style="position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px>
....
So simple by using the id reference
#root{
/* your css here! */
}

Styling text color in angularjs at runtime

I have a html page with this code
<p id="roonnameDiv" >{{chatRoom}}</p>
and an app.js with the following code . It reflects the value corrrectly but if I try to style it with color at runtime it doesnt not reflect on the html page
$scope.$parent.chatRoom = $stateParams.roomId;
$scope.$parent.chatRoom.style = {"color":"green"};
I even tried using ng-color but in vain . Have head using html-unsafe tags t add html5 code to angular variables at runtime , perhaps I could use that to provide style of element but could not find any examples .
Essentially the requirement is of having various styled ( color ,size and fonts ) in roonnameDiv using angular framework
..................Edit .............................
I used the ngstyle as suggested by answers below
$scope.$parent.chatRoom = $stateParams.roomId;
$scope.myStyle = {color: "green"};
however the output text was just plain grey . On exploring it thorugh chorome inspector , I found it is inheriting some styles through body.
Switching off the body color tag just turns the text black instead of green .
Following is the body
<body ng-app="xyz" ng-controller="AppController" class="ng-scope">
This is the body style
body {
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 14px;
line-height: 1.42857143;
color: #333;
background-color: #fff;
}
I want specific style class to apply for different text components without affetcting the overall body style . Could you suggest how to do so ?
You can use ng-style directive.
In Markup
<p id="roonnameDiv" ng-style="myStyle">{{chatRoom}}</p>
In controller
$scope.myStyle = {color: "green", background: "blue"} // Write all the required styles here.
More on ng-style directive at: https://docs.angularjs.org/api/ng/directive/ngStyle
try this
<p id="roonnameDiv" ng-style="chatRoom.style" >{{chatRoom}}</p>

How to override Foundation's display:inherit property for visibility classes?

I'm using Foundation in a mobile first project where many elements are hidden based on the browser size, and I'm running into some trouble using Foundation's visibility classes like .show-for-small-only as Foundation applies
display: inherit !important;
to any element which uses these visibility classes. (For example, see line 5808)...
.show-for-small-only {
display:inherit !important;
}
This is causing me issues. Say have an element that I want to .show-for-small-only:
<div class="someElem show-for-small-only">
<!-- Content -->
</div>
Yet I want this element, when shown, to be formatted as a display:inline-block element. Due to Foundation's use of !important, the div is forced to assume it's default display state of block.
Is there any workaround to this, short of declaring my styling as !important too? (I don't want to have to do that though)...
I agree, using !important always feels gross.
Precedence in CSS is given to the element furthest down the tree so to override the Foundation !important property, just target an element further down the tree, like so:
<div class="show-for-small-only">
<div class="someElm">
<!-- your content here -->
</div>
</div>
With the following CSS
.someElm {
display: inline-block;
}
Here's a Plunker for kicks (just remember the items wont show up unless the screen is small).
I hope this helps.
To overwrite inportant just declare it again after the first declaration
.show-for-small-only {
display:inherit !important;
}
.show-for-small-only {
display: inline-block!important;
}
<div class="someElem show-for-small-only">
Content
</div>

ui bootstrap tooltip cutoff in iframe

I have an app running in an iframe and it makes use of angular ui boostrap tooltips. Unfortunately if the element with the tooltip is on the edge of the iframe, the tooltip will be cutoff by the iframe. Is there any solution to this? Should I play with its position within the iframe, or the z-index value?
UPDATE
So I'm trying to override the tooltip positions (note that I an using angularjs ui bootstrap). I have 2 tooltips which each require their own positioning. I managed to change the css styles (colours and fonts) globally, but I'm having trouble targeting each one to give them unique positions. I have the following html and css:
<div id="my-div">
<ul>
<li tooltip="Foo">A</li>
<li tooltip="Bar">B</li>
</ul>
</div>
Tooltip "Foo" needs a different position that "Bar". So I'm trying to access the li tags using the following css, but it doesn't work.
#my-div > ul > li:nth-child(1).tooltip.top {
margin-left: 10px;
}
#my-div > ul > li:nth-child(2).tooltip.top {
margin-left: 30px;
}
Note that .tooltip.top is the bootstrap class added via the angularjs tooltip directive. I'm guessing this doesn't work because the directive is actually adding another element somewhere.
So it turns out angular will insert a div element right after the element defined as the tooltip. So in my case, when the tooltip event for A is triggered, angular inserts the new element like so:
<div id="my-div">
<ul>
<li tooltip="Foo">A</li>
<div><!-- tooltip for foo --></div>
<li tooltip="Bar">B</li>
</ul>
</div>
Therefore the solution I came up with was to add id's to each of my li tags:
<li id="foo-tip" tooltip="Foo">A</li>
<li id="bar-tip" tooltip="Bar">B</li>
and then access the css tooltip element like so:
#foo-tip + div {
margin-left: 25px;
}
#bar-tip + div {
margin-left: 15px;
}

How do I ngShow and ngHide two different elements at the same time with AngularJS?

So I have two elements that are exclusive:
<span>foo</span>
<span>bar</span>
And I added ngShow and ngHide to them:
<span ng-show="fooTime">foo</span>
<span ng-hide="fooTime">bar</span>
But now when these render, there is a split second where they both show.
How can I make them show/hide at the same time?
Use a ngSwitch rather than an ngShow/ngHide:
<span ng-switch="fooTime">
<span ng-switch-when="true">foo</span>
<span ng-switch-when="false">bar</span>
</span>
Why?
When using the separate ngShow/ngHides, each element is getting a separate $watch which execute asynchronously leaving the potential for a gap between the events. By using ngSwitch, only one $watch is setup so they must render at the same time.
How I got to ngSwitch?
On my first attempt, I realized the watches were not tied together, so I resorted to letting CSS tie the changes together:
<style>
[first] .fooTime {
display: inline;
}
[second] .fooTime, [first] {
display: none;
}
</style>
<span ng-class="{'fooTime':fooTime}">
<span first>foo</span>
<span second>bar</span>
</span>
But ngSwitch is much more clean.
Edit:
It seems ngSwitch triggers enter and leave animations so if you are using ngAnimate, there is a default of a .2 second transition. I haven't found a way around this yet.
You can solve this problem pretty elegantly with some CSS.
*[ng-switch] *[ng-switch-when] + *[ng-switch-when],
*[ng-switch] *[ng-switch-when] + *[ng-switch-default] {
display: none;
}
This uses the wildcard selector (*) and attribute selector for ng-switch-when to make this a general solution that should work in any instance where ng-switch is used.
Upvoted and commented on #eternalmatt's answer ... here is my solution based on the css part of his solution. In my experience ng-swtich will not solve this problem. I am using scss but you can convert scss to css here http://www.sassmeister.com/. The template of my button directive that toggles button text and ajax spinner based on the value of showSpinner.
template
<button class="fin-button no-outline" ng-class="{disabled: state==='disabled'}" ng-click="action()">
<span ng-class="{'showSpinner': showSpinner}">
<span class="text-first" fin-button-text>{{text}}</span>
<span class="glyphicon glyphicon-repeat spinner" fin-button-spinner></span>
</span>
</button>
scss
.fin-button {
[fin-button-text] {
display: inline;
}
[fin-button-spinner] {
display: none
}
.showSpinner {
[fin-button-text] {
display: none;
}
[fin-button-spinner] {
display: inline;
}
}
}
css .. generated from conversion via the above link
.fin-button [fin-button-text] {
display: inline;
}
.fin-button [fin-button-spinner] {
display: none;
}
.fin-button .showSpinner [fin-button-text] {
display: none;
}
.fin-button .showSpinner [fin-button-spinner] {
display: inline;
}
and is here be dragons comment that I have above the scss in my code
// .... HERE BE DRAGONS ... ///
// The following is used to hide show the spinner or the
// button text. Needs to be done like this because ng-hide, ng-show,
// ng-if, and ng-switch all put seperate watches even if you are conditioning
// on the same vairable ... see this SO // http://stackoverflow.com/questions/20341288/how-do-i-ngshow-and-nghide-two-different-elements-at-the-same-time-with-angularj

Resources