Can't scroll when testing using intern.js - javascript

I use moveMouseTo but it doesn't seem to work. This is my code. Does anyone able to see what is wrong with it? The assert should work and not return error, because if you try to scroll down the page at www.keylocation.sg, it will shows a navigation bar.
Thanks before.
define([
'intern!object',
'intern/chai!assert',
'./util',
'intern/dojo/node!fs'
], function(registerSuite, assert, util, fs) {
var suite = {
name: 'home-navbar',
afterEach: util.checkJSErrors,
// testing the visibility of navigation bar in the home page
'Home page navigation bar: navigation bar visibility': function() {
var remote = this.remote
.setWindowSize(1024, 768)
.get('about:blank')
.get('https://www.keylocation.sg');
this.timeout = 300000;
return remote
// check: Home page loads, navbar is not visible
.findById('header-menu').isDisplayed().then(assert.isFalse).end()
// check: Scroll down to next page, navbar becomes visible
.moveMouseTo(0,1000).end()
.findById('header-menu').isDisplayed().then(assert.isTrue).end();
}
};
registerSuite(suite);
});

Your test is probably failing because of how the WebDriver server you're using determines element visibility. The header menu on that page is initially not visible because it has a negative top margin, which moves it outside of the viewport. However, according to the WebDriver spec, an element that's outside the viewport because of a negative margin isn't necessarily considered invisible. Chrome's and Firefox's WebDriver servers, at least, say it's visible. This is a WebDriver issue rather than an Intern issue; Intern is basically just asking the WebDriver server "is this element visible" and telling you the answer.
Since isDisplayed doesn't seem like it will work in this case, you could instead check whether the element has the disabled class, which is what causes it to have the negative margin.
Unfortunately, trying to simply move the mouse 1000 pixels outside of an element context doesn't scroll the page. When you don't give moveMouseTo an element, it moves within the current context element (the last thing that was found). When there's no context, it's moving within the outermost element, which in this case is only 632px high. You'll need to set the context to an element that's tall enough to contain your movement offset, or you can find an element at the bottom of the page, like the footer, and move the mouse to that:
.findByCssSelector('.wrapper')
.moveMouseTo(0, 1500) // 1000 pixels is too small to show the scrollbar
.end()
or
.findByTagName('footer')
.then(function (footer) {
return this.parent.moveMouseTo(footer);
})
.end()
Your test has a few other issues you may want to correct as well. The initial get('about:blank') isn't necessary. There's no reason to split the two halves of your command chain; the timeout applies to the whole chain whether it's split or whole. You don't need an end after the moveMouseTo; end is for popping elements off the command chain's context, and moveMouseTo doesn't add anything to the context.

Related

Scroll to top of a bubble in botframework webchat

Some answers of our chatbot are very long. The webchat scrolls automatically to the bottom so users have to scroll up to get to the top of the bubble and start reading.
I've implemented a custom renderer (react) to wrap the answers into a custom component which simply wraps the answer into a div-tag. I also implemented a simple piece of code to scroll to the top of the bubble.
const MyCustomActivityContainer = ({ children }) => {
const triggerScrollTo = () => {
if (scrollRef && scrollRef.current) {
(scrollRef.current as any).scrollIntoView({
behavior: 'smooth',
block: 'start',
})
}
}
const scrollRef: React.RefObject<HTMLDivElement> = React.createRef()
return (
<div ref={ scrollRef } onClick={ triggerScrollTo }>
{ children }
</div>
)
}
export const activityMiddleware = () => next => card => {
if (/* some conditions */) {
return (
<MyCustomActivityContainer>
{ next(card) }
</MyCustomActivityContainer>
);
} else {
return (
{ next(card) }
)
}
};
But this only works if the scrollbar slider is not at its lowest position (there is at least 1 pixel left to scroll down, see here). The problem is the useScrollToBottom hook which always scrolls to bottom automatically if the scrollbar is completely scrolled down.
Is there any way to overwrite the scroll behavior or to temporarily disable the scrollToBottom feature?
As there is no reproducible example I can only guess.
And I'll have to make some guesses on the question too.
Because it's not clear what exactly in not working:
Do you mean that click on the <div> of MyCustomActivityContainer and subsequent call to triggerScrollTo doesn't result into a scroll?
That would be strange, but who knows. In this case I doubt anyone will help you without reproducible example.
Or do you mean that you can scroll the message into view, but if it is already in the view then new messages can result into a scroll while user is still reading a message.
That's so, but it contradicts with you statement that your messages are very long, because that would be the problem with short messages, not with the long ones.
But anyway, you should be able to fix that.
If it works fine with 1 pixel off the lowest position, then just scroll that 1 pixel. You'll need to find the scrollable element. And do scrollable_element.scrollTop -= 1. I tested this approach here. And it worked (there the scrollable element is the grandparent of <p>'s)
Or do you try to scroll automatically at the moment the message arrives? Аnd that is the real issue, but you forgot to mention it, and didn't posted the code that tries to auto-scroll?
In that case you can try to use setTimeout() and defer the scroll by, let's say, 200ms.
This number in based on what I gathered from the source:
BotFramework-WebChat uses react-scroll-to-bottom
In react-scroll-to-bottom there are some timeouts 100ms and 34ms
BotFramework-WebChat doesn't redefine them
There are some heuristics in react-scroll-to-bottom that probably coursing the trouble
https://github.com/compulim/react-scroll-to-bottom/blob/3eb21bc469ee5f5095a431ac584be29a0d2da950/packages/component/src/ScrollToBottom/Composer.js
Currently, there are no reliable way to check if the "scroll" event is trigger due to user gesture, programmatic scrolling, or Chrome-synthesized "scroll" event to compensate size change. Thus, we use our best-effort to guess if it is triggered by user gesture, and disable sticky if it is heading towards the start direction.
And
https://github.com/compulim/react-scroll-to-bottom/blob/f19b14d6db63dcb07ffa45b4433e72284a9d53b6/packages/component/src/ScrollToBottom/Composer.js#L91
For what we observed, #1 is fired about 20ms before #2. There is a chance that this stickyCheckTimeout is being scheduled between 1 and 2. That means, if we just look at #1 to decide if we should scroll, we will always scroll, in oppose to the user's intention.
That's why I think you should use setTimeout()
Since there isn't a reproducible code for me tweak and show you. My suggestion is tweak your code slightly. Chatbot requires constant streaming of data when a new message arrives calculate the height of the div element created for the message. If the div element is greater than the widget height scroll to the top else you can choose to leave it as it is.

Get element position relative to screen. (Or alternative solution)

I am aware this had been asked before, but no answer actually did the trick as far as I tested them.
Basically what I need is to change some element styles as soon as it "hits" the top border of the screen while scrolling down. This element is a 'Back to Top' button that will be sitting in a section and start following the user when they scroll pass said section.
I am not asking about CSS properties, I am asking about some JS property or method that allow me to know this. IE:
$('#back').distanceFromTopOfTheScreen() // This value will decrease as I scroll down
I know there are other soultions, but the client has asked for this behavior.
Any idea?
You can :
distance = $('#eleId')[0].getBoundingClientRect().top;
For more about getBoundingClientRect() look at the MDN Documentation
Note: This value change when you're scrolling, it gives you the distance between the top border of the element and the top of the Page
Sometimes JQuery make's everything more confusing than Native Javascript, even forgothing the very basics functions:
window.onscroll = function() { fixPosition()};
function fixPosition() {
var Yplus = 4; //number of lines in every scroll
document.getElementById('element').style.top = document.body.scrollTop + Yplus ;
}
This will allows you to move an "element" static on the window following the scroll.

window scroll method flickers in IE

This may come as a huge surprise to some people but I am having an issue with the IE browser when I am using the $(window).scroll method.
My goal:
I would like to have the menu located on the left retain it's position until the scroll reaches > y value. It will then fix itself to the top of the page until the scroll returns to a < y value.
My error:
Everything seems just fine in Chrome and Firefox but when I go to Internet Explorer it would seem the browser is moving #scroller every time the scroll value changes, this is causing a moving/flickering event.
If someone could point me to a resource or give me a workaround for this I would be very grateful!
Here is a fiddle:
http://jsfiddle.net/CampbeII/nLK7j/
Here is a link to the site in dev:
http://squ4reone.com/domains/ottawakaraoke/Squ4reone/responsive/index.php
My script:
$(window).scroll(function () {
var navigation = $(window).scrollTop();
if (navigation > 400) {
$('#scroller').css('top',navigation - 220);
} else {
$('#scroller').css('top',183);
$('#scroller').css('position','relative');
}
});
You might want to take a look at the jQuery Waypoints plugin, it lets you do sticky elements like this and a lot more.
If you want to stick with your current method, like the other answers have indicated you should toggle fixed positioning instead of updating the .top attribute in every scroll event. However, I would also introduce a flag to track whether or not it is currently stuck, this way you are only updating the position and top attributes when it actually make the transition instead of every scroll event. Interacting with the DOM is computationally expensive, this will take a lot of load off of the layout engine and should make things even smoother.
http://jsfiddle.net/WYNcj/6/
$(function () {
var stuck = false,
stickAt = $('#scroller').offset().top;
$(window).scroll(function () {
var scrollTop = $(window).scrollTop();
if (!stuck && scrollTop > stickAt) {
$('#scroller').css('top', 0);
$('#scroller').css('position','fixed');
stuck = true;
} else if (stuck && scrollTop < stickAt) {
$('#scroller').css('top', stickAt);
$('#scroller').css('position','absolute');
stuck = false;
}
});
});
Update
Switching the #scroller from relative to fixed removes it from the normal flow of the page, this can have unintended consequences for the layout as it re-flows without the missing block. If you change #scroller to use an absolute position it will be removed from the normal flow and will no longer cause these side-effects. I've updated the above example and the linked jsfiddle to reflect the changes to the JS/CSS.
I also changed the way that stickAt is calculated as well, it uses .offset() to find the exact position of the top of #scoller instead of relying on the CSS top value.
Instead of setting the top distance at each scroll event, please consider only switching between a fixed position and an absolute or relative position.All browsers will appreciate and Especially IE.
So you still listen to scroll but you now keep a state flag out of the scroll handler and simply evaluate if it has to switch between display types.
That is so much more optimized and IE likes it.
I can get flickers in Chrome as well if I scroll very quickly. Instead of updating the top position on scroll, instead used the fixed position for your element once the page has scrolled below the threshold. Take a look at the updated fiddle: http://jsfiddle.net/nLK7j/2/

How to create a dynamic navigation bar which follows you when you reach certain location

I want to create a navigation bar similar to this site's:
http://www.mysupermarket.co.uk/#/shelves/top_offers_in_asda.html
Can anyone tell me how to create that navigation bar, which follows you as you scroll the page down, but not following you at the initial loading of page?
When you access to the given website, try to scrolling down and you will understand what I am talking about. The navigation bar that consists of MY SHOP, OFFERS, IDEAS & LIFESTYLE, BAKERY and so-on...
I have really no idea what it's called. At least tell me what it's called, so I'll be able to search.
Here is the solution I've done
window.onscroll = function(){
if(getScrollTop()>140) {
document.getElementById("menu").style.position="fixed";
} else {
document.getElementById("menu").style.position="";
}
}
function getScrollTop() {
if (window.onscroll) {
// Most browsers
return window.pageYOffset;
}
var d = document.documentElement;
if (d.clientHeight) {
// IE in standards mode
return d.scrollTop;
}
// IE in quirks mode
return document.body.scrollTop;
}
Holding an element on same position can be achieved by fixed position styling.
If you want your navigation bar to stay on exact same location, position:fixed; is enough. (At least non IE6)
You can find a working example and some details here
However, if you want your navigation bar to move from it's initial location to the top border of page as you scroll the page down, you must implement some JavaScript to catch page scroll event and move the <div> accordingly.
See this question for an example on how to do that.
Note: this won't work with the Android 2.3 browser; position:fixed will not behave as expected - it kinda of temporarily attaches its position to the scrolling element before jumping back to the top.
if you want you could just set the z-index to be a specific No. and that should work.
example
z-index:100;

How to control the jump to a bookmark inside a page

I'm trying to achieve a page with a certain number of divs, each of which has a bookmark (a name). The problem is, when I jump to one of the bookmarks, part of the text is gone, caused by the design. I'd like to know if there's a way to change the behaviour of the bookmark, so it won't set the start of it at the top of the page, but a set number of pixels below.
The page can be accessed here: Not longer online, sorry.
The behaviour occurs when you go to any of the bookmarks (except #6, because the document ends there), like on here: Not longer online, sorry.
Can this be solved by a css property or any other way? (update) I'd prefer this over a javascript solution because I'm planning to use javascript to tab them, and keep the bookmarks in case of disabled javascript
You can do it with JavaScript using scrollBy. Put this in a load listener or onload handler:
if(window.location.hash.length > 1) {
window.scrollBy(0, -60); // Adjust to suit your needs.
}
window.onhashchange = window.onload = function () {
if( window.location.hash.length && window.scrollY > window.pageYOffset ) {
window.scrollBy( 0, -100 ); // Scroll up 100 pixels on hash change
};
};
I got the answer myself, so this is basically for references.
To ignore the 100px offset that is caused by the header, I added a padding-top of 100px to each single div element, and then I changed the links to go to the div's instead of the a elements I added. This padding-top basically makes the text appear where it should and thus solved my problem.

Categories

Resources