In one of our internal angular applications, there is a license text box displayed. Since there is a lot of text inside, the license box, represented as a div element, has a scroll.
Question: How to test whether an element has a scroll or not in protractor?
Here is an HTML representation of the element:
<div class="login-disclaimer-text-canvas ng-binding" ng-bind-html="disclaimer">
Copyright © Company, 2015. All Rights Reserved.
...
</div>
where login-disclaimer-text-canvas has the following CSS styles defined:
.login-disclaimer-text-canvas {
height: 50px;
width: 100%;
overflow-y: auto;
background-color: #eee;
color: #3E6372;
padding: 4px;
font-size: 10px;
}
The trick (originally proposed here) is to compare height property:
The height CSS property specifies the height of the content area of an
element. The content area is inside the padding, border, and margin of
the element.
with scrollHeight:
The Element.scrollHeight read-only attribute is a measurement of the
height of an element's content, including content not visible on the
screen due to overflow. The scrollHeight value is equal to the minimum
clientHeight the element would require in order to fit all the content
in the viewpoint without using a vertical scrollbar. It includes the
element padding but not its margin.
If scrollHeight is greater than height - then an element has a scrollbar.
In protractor we need to compare the resolved promises of getAttribute('height') and getAttribute('scrollHeight'). Let's make a reusable function and resolve one of two promises via then() letting expect() to resolve the second:
function elementHasScroll(element) {
element.getAttribute('height').then(function (height) {
expect(element.getAttribute('scrollHeight')).toBeGreaterThan(height);
});
};
where toBeGreaterThan() handy matcher is a part of jasmine-matchers third-party.
Related
I had a problem in Safari when the page loaded in Devtools > Network drowser loaded two versions of the same image.
For example:
yNG3yARUuYG2BUZL___media_library_original_1080_1080.jpg
and
yNG3yARUuYG2BUZL___media_library_original_529_529.jpg
I noticed that the first image is loaded (1080) and the image is logically closest to the width of the image.
I use it in vueJS component.
This data i pass into img:
image: {
src: 'https://example.com/media/3276/yNG3yARUuYG2BUZL.jpg',
srcset: 'https://example.com/media/3276/responsive-images/yNG3yARUuYG2BUZL___media_library_original_1080_1080.jpg 1080w, https://example.com/media/3276/responsive-images/yNG3yARUuYG2BUZL___media_library_original_903_903.jpg 903w, https://example.com/media/3276/responsive-images/yNG3yARUuYG2BUZL___media_library_original_755_755.jpg 755w, https://example.com/media/3276/responsive-images/yNG3yARUuYG2BUZL___media_library_original_632_632.jpg 632w, https://example.com/media/3276/responsive-images/yNG3yARUuYG2BUZL___media_library_original_529_529.jpg 529w, data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAb1BMVEX///8AAABLS0vc3Ny7u7vl5eWdnZ2lpaXW1tZVVVXy8vIWFhaWlpbo6Oj39/fR0dE1NTV9fX0fHx+MjIwaGhq3t7cLCwuHh4dpaWk+Pj7MzMxycnJdXV3CwsKtra2QkJAlJSVDQ0NkZGQyMjIkJCQUVGSgAAADzElEQVR4nO3d61raQBCAYeVsMAl4AI+o1fu/xtYGH5NJWLLJLLPR7/1bSPNJnW4OwNkZAAAAAAAAAAAAAAAAAPxa+XpkbZ0H7EsuzmNwkQQLXFq37S1DJcbxCn66CBM4se4qmYQIzK6ss0qusgCF19ZVFdf6gVPrJmGqXjiyThJG2oExjZmC8rCJaswUbnSHzYt1TwPVYTO2rmk0ViyMZzVTpriykWNmk48t5BuxH3rDRm55rrZlP3P5KmpteCu2e6+1YW/3Yk+2OputjZmQh6BuudwVnWHzJLZ6p7LVbu7EvjxpbLS2mgl2hN1CIndGY9jIbVqNmUKAYRPPmCmoD5vaQdODxm728CB3qO9hlFzNWI6ZwqPYo54rm6jGTKE2bG77bK120GQ7Zgpy2PQ6ZyPPzazUdrMPOWx6HEbVxozdaqastrLpPmzkmHlU3M0+1IZNhGOmoLWyyV7FdmIYMwU5bD66DZs4x0xhJfat08omutVMmcqwiXXMFOSw6XCCWI6Z/enJycxaMVWyG7F/3iub7EP+Fm7X/8h/HCY+d2QrfxO9VzYxngJ281zZxHalqQ2/czaxXWlq49UnsDaMB2HnUShn8TC8eRTK9dowbDwK47ta2IrHkcG79b524vMaylOIw+BzmDjE/w49Dw3iunmmHc8TncP7/+LJd2F6Ky+LRq7LCYjFpOK5upqfT06reuJi9Vz9U52j8+paVfNGiDaq12nV74j6j8KwKNRAYVgUaqAwLAo1UBgWhRooDItCDRSGRaGG31yY7ubt7Wo/m+mhp5fPL1kWpn/O/awqt8eNHVdjb77vPzAs7PKeqNKNE0fe9nfd/NecsjDrEFi6yfHoz2fX+MBTFna7AeW+eaMNNolxYe3OnZYWxdPT44/cGRd2fWfi/jJDizffPhoXLjoWzoqn3x5/5N2wC3/+a9jiYrP172HPwtp993XpwAuPTqrmBw6o8Nhv4vrrccMtPMvfDj9q+X2rWiSF77PLQ2bVt6LOShteHHrWc+nmg0gKXffsVC/EzxyPbDSAwhmFbhRqoJBCCt0o1EAhhRS6UaiBQgopdKNQA4UUUuhGoQYKKaTQjUINFFJIoRuFGiikkEI3CjVQSCGFbhRqoJBCCt0o1EAhhRS6UajhtxXmyaes+tU9oyQ9JKl+QvhllvipfnjzKQqXe+fdbJa+Tl5oi0IKKbRHIYXNfD/CJKQwX+HX4tMBTkb5a8e/yK+esfMRJrDzu5r1LQIV1r8h00jA79bKXuy/2+P1pc83OraQTm2lYfMAAAAAAAAAAICdvynTXWdGs+9dAAAAAElFTkSuQmCC 32w',
},
<template>
<img
class="responsive-image"
:srcset="image.srcset"
:src="image.src"
loading="lazy"
onload="window.requestAnimationFrame(function(){if(!(size=getBoundingClientRect().width))return;onload=null;sizes=Math.ceil(size/window.innerWidth*100)+'vw';});"
sizes="1px"
>
</template>
<style scoped>
.responsive-image {
display: block;
box-sizing: border-box;
max-width: 100%;
width: 100%;
height: auto;
padding: 0;
margin: 0;
}
</style>
The function after loading the image sets the value of the size attribute to the relative size of the image to the width of the display.
This is required because the image is used in the gallery grid.
When changing the width of the display, the grid adapts using CSS media queries. Desktop - 3 elements in a line, tablet - 2 elements, phone - 1 element.
I tried to set sizes attribute based on this.$parent.$l.getBoundingClientRect().width not on img.getBoundingClientRect().width in mounted() hook before onload event on img run simmilsr code but it's not fix my problem.
Tested in Chrome, Firefox and Safari (by Lambdatest).
In Chrome and Firefox it works correctly.
I am building an in-app walkthrough with Vuetify. And I need to be able to define the position of many dialogs on the same page. I am able to custom position one dialog with this CSS overriding the default:
>>> .v-dialog {
position: absolute !important;
bottom: 0px !important;
right: 45px !important;
}
And I've tried to use custom classes, with the same css, but they won't work. I'm having to redefine the built in class, and so it will end up placing ALL the dialogs in the same spot which isn't what I want.
I am using Vuetify and Electron to make an app to help me with certain tasks at my job. I have disable the browserWindow frame and made my header the draggable area with a button to close the window. I am using the electron vuetify template
vue init vuetifyjs/electron
My problem is the scrollbar reaches all the way to the top but I would like it below my fixed header.
I have tried playing with overflow properties on the html, body, app div, and content div tags but i have not been successful.
How would I accomplish this?
This is purely a CSS question really as you can see this behaviour in the browser too with similar layouts. The easiest way to fix this is using a flex layout:
HTML:
<div class="container">
<div class="titlebar"></div>
<div class="content">
<h1>So much content we scroll</h1>
<h1>So much content we scroll</h1>
<!-- etc -->
</div>
</div>
CSS:
body {
margin: 0;
padding: 0;
overflow: hidden;
}
.container {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
}
.titlebar {
background-color: blue;
height: 35px;
flex-shrink: 0;
}
.content {
flex-grow: 1;
overflow-x: auto;
}
Check out this out in this CodePen
I'd like to offer a Vuetify specific answer for this question, this should apply whether or not Electron is involved.
Vuetify's default styles make this a bit more difficult than a simple CSS solution can give you, especially when the layout gets more complex.
For this example I'm using the complex layout from Vuetify's pre-defined themes here
Vuetify ships with an overflow-y: scroll on the html element so the first step is adding an override for this.
html {
overflow: hidden;
}
This will get rid of the bar on the right side that spans the whole height of the app.
Next you will want to set your v-content area as the scrollable area. There are a few gotchas to watch out for when you're setting this area:
Display flex is already declared
Vuetify sets padding in the style attribute so you'll need to override depending on your case
You'll need a margin the height of your header(only matters if you're changing header height from 64px)
You'll need to remove the header height from the height of the content container using calc(Same as above)
If you have a nav drawer on the right side you'll need to bind a class to take care of this.
My CSS for v-content looks like this, you will need an important to override the padding since it is set by Vuetify through style binding:
main.v-content {
width: 100vw;
height: calc(100vh - 64px);
flex-direction: column;
overflow: scroll;
margin-top: 64px;
padding-top: 0 !important;
}
I also have a class bound to the state of the temporary right drawer on the v-content tag in the template, this makes sure that the scroll bar doesn't disappear underneath the right nav drawer when it's open:
<v-content :class="{ draweropen: drawerRight }">
And the CSS for that bound class, once again you'll need an important to remove the default right padding Vuetify puts on v-content when the drawer is open:
.draweropen {
width: calc(100vw - 300px) !important;
padding-right: 0 !important;
}
You can optionally set the flex-direction to column-reverse if your content is bottom loaded like a chat which is what I'm doing in this CodePen Example
I built a little component that wraps the v-main and moves the scrollbar to the main container instead of the default (the entire html).
Simply replace v-main with this and you're done.
<template>
<v-main class="my-main">
<div class="my-main__scroll-container">
<slot />
</div>
</v-main>
</template>
<script>
export default {
mounted: function() {
let elHtml = document.getElementsByTagName('html')[0]
elHtml.style.overflowY = 'hidden'
},
destroyed: function() {
let elHtml = document.getElementsByTagName('html')[0]
elHtml.style.overflowY = null
},
}
</script>
<style>
.my-main
height: 100vh
.my-main__scroll-container
height: 100%
overflow: auto
</style>
In HTML/CSS if you want an absolutely positioned element to expand wider than its parent to fit all its text in one line, you can use white-space: no-wrap
.parent {
position: relative;
width: 100px;
}
// text content of this node is wider than 100px
.child {
position: absolute;
white-space: nowrap;
}
The child element will grow just wide enough to fit all the text in one line. There doesn't be a way to do this with Text components in React Native. You have to specify a fixed number width or the Text component will max out at the parent width. Is there a way?
Figured out that the answer is quite simple.
Text wrap can be specified with the <Text> component's built-in interface called numberOfLines, instead of CSS.
<Text numberOfLines={1}>Foobar</Text>
The documentation for this can be found here.
I am working on location picker inside modal popup using Bootstrap3 CSS and JQuery location picker. Normally Bootstrap3's modal body size expands if content needs it.
What I need to do is to force modal to have relative to screen size because initial DOM content is empty and is filled via JQuery (Google maps initialization).
The problem is, that when setting relevant divs to have style= height:100%, body is overlapping its parent with the exact height of its sibling modal headers div.
How to prevent such behaviour and make modal body fill free space and not overlap parent component?
Here is working example
https://jsfiddle.net/qfqjq82r/
Ok after some consulting I have found the workaround/answer.
The trick was to threat divs like table and table rows. After adding some additional styling, dialog looks exactly like it should.
https://jsfiddle.net/qfqjq82r/7/
And the css:
#location-picker .modal-content {
display: table;
width: 100%;
}
#location-picker .modal-dialog{
width: 80%;
height: 85%;
}
#location-picker .modal-body{
height: 100%;
display: table-row;
width: 100%;
}
#location-picker .row{
padding:15px;
}
.full-height{
height: 100%;
}