When I run tests in Cypress, it always scrolls down to the element, so it is in the very top of the screen. But I'm writing tests for a WordPress system, where the fixed bar always is in the top of the screen taking up 75px (ish). So I can never see what's going on, when my test run.
Are there a way, where I can define all elements, for all tests, to so when they're in focus, that they are 200px from the top? Like a global constant?
Code
cy.get( 'tr[data-slug="cmb2"]' ).should( 'have.class', 'active' );
See the problem here:
Solution attempt 1: Set it in the .env configuration-file
It would be smart if I could set it in the cypress.json-file. I read the docs on Cypress Configuration, but couldn't find it in there.
Solution attempt 2: Hiding the admin-bar with CSS
I could also try and add a stylesheet to always load, when running Cypress-tests in the backend. But is this a normal way to get around it?
And even if I did this, I wouldn't know how to do this.
Solution attempt 3: Use scrollIntoView
I tried adding scrollIntoView with some options:
cy.get( 'tr[data-slug="cmb2"]' ).scrollIntoView({ offset: { top: 150, left: 0 } }).should( 'have.class', 'active' );
But I'm still unable to see the title of my div, when hovering it. I also tried the solution suggested here that looks a bit like it.
Solution attempt 4: Add scrollBehavior to my .env-file
I add that to my .env-file:
{
"env": {
"name": "staging",
...
},
"viewportWidth": 1100,
"viewportHeight": 1800,
"watchForFileChanges": false,
"chromeWebSecurity": true,
"scrollBehavior": "bottom" <---- My attempt!
}
But no cigar:
Related questions
Cypress scrolling behaviour on get and relative positionning
I'm not sure about your Wordpress site, but the following worked for the Material-UI site referenced in Cypress scrolling behaviour on get and relative positionning
.scrollIntoView() offset should be negative
it('make Elvis appear', () => {
cy.viewport(750,480)
cy.visit('https://mui.com/getting-started/templates/dashboard/');
cy.contains('Elvis Presley').scrollIntoView({offset:{top: -100}})
})
use native scrollIntoView
it('make Elvis appear', () => {
cy.viewport(750,480)
cy.visit('https://mui.com/getting-started/templates/dashboard/');
// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
cy.contains('Elvis Presley')
.then($el => $el[0].scrollIntoView(false)) // scrolls $el to bottom
})
make header transparent
it('make Elvis appear', () => {
cy.viewport(750,480)
cy.visit('https://mui.com/getting-started/templates/dashboard/');
cy.get('header').invoke('css', 'opacity', '0')
cy.contains('Elvis Presley').scrollIntoView()
})
using .scrollTo()
This command applies to the scroll container, not the element you target, so the positioning may not come out correctly every time.
function getScrollParent(node) {
if (node == null) return null;
if (node.scrollHeight > node.clientHeight) {
return node;
} else {
return getScrollParent(node.parentNode);
}
}
it('make Elvis appear', () => {
cy.viewport(750,480)
cy.visit('https://mui.com/getting-started/templates/dashboard/');
cy.contains('Elvis Presley')
.then($el => {
const scrollParent = getScrollParent($el[0])
cy.wrap(scrollParent).scrollTo('center')
})
})
Actually, there is a bug on this already reported here. Cypress peeps fixed this here. It needs to be merged though.
Solution for element being hidden by website top menu on get(), contains(), click().
Add following to Cypress global config or test config.
From my cypress.config.ts (reduced to focus):
import { defineConfig } from 'cypress'
export default defineConfig({
e2e: {
scrollBehavior: false
}
})
Then scroll "manually" using cy.scrollTo(), cy.scrollIntoView(), dynamically, ...
references:
Cypress configuration: Actionability
StackOverflow: Disable Cypress from automatic scrolling
Related
I'm working on an Ionic 6 Webapp based on Angular 13. The client's QA-department want's to perform regression-testing via Selenium test-automatization. For other project's they used window.scrollBy(0, window.innerHeight) to systematically scroll over the page and take screenshots to find regression issues. But this is not possible on Ionic pages, since the HTML body is not scrollable, only the content of the ion-content element. Is there any way to trigger scrolling within the ion-content element via simple JavaScript? I created a Stackblitz where you can see the basic structure of my ionic-page.
So far I tried different things but none worked:
document.getElementsByTagName("ion-content")[0].scrollTo(0, 300);
document.getElementsByTagName("ion-content")[0].scrollToBottom();
document.getElementsByTagName("ion-content")[0].shadowRoot.childNodes[1].scrollTo(0, 300); //tried to access the inner-scroll div
document.getElementsByTagName("ion-content")[0].shadowRoot.childNodes[1].scrollToBottom(); //tried to access the inner-scroll div
why do you want JavaScript to scroll when ionic and angular have a better way to scroll. please check the stackblitz link I have done some code in it.
HTML
<ion-app>
<ion-header>Demo Header</ion-header>
<ion-content>
<div class="large-content-div"></div>
<p id="scrollMe">Scroll to find me</p>
</ion-content>
<ion-footer>Demo footer</ion-footer>
</ion-app>
TS File
export class AppComponent {
name = 'Ionic 6 Angular ' + VERSION.major;
constructor() {
setTimeout(() => {
this.scrollToBottom();
}, 5000);
}
scrollToBottom(): void {
try {
document.querySelector('#scrollMe').scrollIntoView({
behavior: 'smooth',
});
} catch (err) {}
}
}
Here, I have given both the solution if you want to scroll to the bottom scrollToBottom() method or you want to scrollTo some division points scrollTo() method, use it as per the requirement.
This is the best way to call scroll Event in Ionic/Angular
I am trying to create a page redirection to a particular section, i.e. I want to go to a particular anchor div on a page without scrolling behavior. However, I have a query string in the URL for pagination so the #id method failed for me. I tried "scrollIntoView()" but it contains the page scrolling behavior, which is undesired. May I ask if there is any alternative solution to this problem?
I am using Vue for the frontend & Codeigniter for the backend. Here is my code:
mounted() {
// anchorPageToProductList
if (this.isOnQuery) {
console.log('isOnQuery');
this.scrollToProductList();
} else {
console.log('isNotOnQuery');
}
},
methods: {
scrollToProductList(){
window.addEventListener('DOMContentLoaded', () => {
// scroll animation
document.getElementById('product-list-anchor').scrollIntoView(true);
});
},
Example of my URL case:
http://www.example.com/Product/list?search=&sort=3&type=-1&event%5B%5D=11&pagination=1
Thank you!!
I've tried to unset the scrolling behavior, allow the the page to jump to the desired section, then set back the smooth-scroll behavior. So It now works without the scrolling behavior. Thanks for all the comments:)
My code:
scrollToProductList(){
window.addEventListener('DOMContentLoaded', () => {
// select the whole html & disable smooth-scroll behavior in css
let htmlElement = document.querySelector('html');
htmlElement.style.scrollBehavior = 'auto';
// go to the anchor point
document.getElementById('product-list-anchor').scrollIntoView(true);
// enable smooth-scroll behavior again
htmlElement.style.scrollBehavior = 'smooth';
});
}
i have this really annoying problem in my Ionic 4 application that when I change page the screen reader focus is at the bottom of the page which means that my users will have to reverse through the content to get to my main content section.
i did some research and this seems to be a problem with Angular Angular accessibility documentation
Here they suggest that you should set focus on the main content.
However when I attempt this using:
ionViewDidEnter() {
const mainHeader = document.querySelector('#mainContent');
if (mainHeader) {
(mainHeader as HTMLElement)?.focus();
}
}
it doesn't really do anything.
Has anyone had a similar issue and know how I might fix it?
Edit
I have also tried with the viewChild:
#ViewChild('mainPage') mainContent: ElementRef;
ngOnInit() {
this.router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(() => {
this.mainContent.nativeElement.focus();
});
}
And setting the mainPage element's tabIndex=0:
<div #mainPage tabindex="0"><ion-router-outlet main></ion-router-outlet></div>
Yet still no focus.
So I have been using ScrollIntoView() to jump to anchors in a react component as part of a web app. For small pages, it works fine, goes to the right spot and behaves as one would expect. I have one larger page where the behavior is strange. On loading, the jump to anchor is below where it should be by half a page or more. The first time one clicks on a link to any anchor, including the same anchor, the anchor ends up above where it should be by a similar amount. Every subsequent click after that works perfectly as long as the page is not reloaded. Here is my code for the function. It has a setTimeout because I thought that the problem had something to do with the page loading, but there is no effect. Here is my function:
scrollToAnchor: function () {
let anchorName = this.props.location.hash || window.location.hash;
if (anchorName) {
anchorName = anchorName.replace("#", "");
let anchorElement = document.getElementById(anchorName);
if (anchorElement) {
window.setTimeout(anchorElement.scrollIntoView(true), 0);
}
} else {
window.scrollTo(0, 0);
}
},
In my case, I had to add the default params manually in order for it to work in some browsers. The block and inline params have an associated default value, but I had to put them in manually like this:
my_element.scrollIntoView(
{ behavior: 'smooth' , block: 'start', inline: 'nearest'}
);
Once I defined them in the scrollIntoViewOptions, it worked fine across all browsers.
PS: don't forget the polyfill for smooth scrolling.
I want to scroll my ListView on a specific item automatically. The ListView must auto-scroll to an item from his index.
listView.ensureVisible(itemIndex);
But it's not working. Another alternative:
yourListView.currentItem = { index: 8, hasFocus: true, showFocus: true }
And it's failed also.
How can this be solved?
Generally you have to wrap your call to ensureVisible(index) in a call to msSetImmediate. Not sure exactly why this is the case, probably a bug, but works for me. Example:
msSetImmediate(function (){ listView.ensureVisible(4);} );
If you look at the documentation for setImmediate (msSetImmediate being a Microsoft specific implentation), the function is described as:
Requests that a function be called when current or pending tasks are complete, such as events or screen updates.
This does make a bit of sense as it sounds like it ensures that all list view animating etc is completed before making your call to ensure an item is visible.
See this thread for a related post: http://social.msdn.microsoft.com/Forums/en-US/winappswithhtml5/thread/2f11e46f-9421-4e31-93d3-fca06563ec41/
I might have an answer for you. You can't set the scroll position of a ListView immediately because the layout for the ListView has not been done yet and so attempting to scroll it to a position is futile. So you have to wait until the ListView gets to that state where its layout has been calculated. Here's how...
myListView.onloadingstatechanged = function () {
if (app.sessionState.homeScrollPosition && myListView.loadingState == "viewPortLoaded") {
myListView.scrollPosition = app.sessionState.homeScrollPosition;
app.sessionState.homeScrollPosition = null;
}
};
You can see this in context by looking at the /pages/home/home.js file in my open source codeSHOW project.
Hope that helps.