Selecting the active .ion-page

With ion-router-outlet it would seem you get multiple instances of your page classes decorated with various combinations of css classes bound to them, e.g.: .ion-page, .ion-page-hidden, .can-go-back, etc.

I’m currently using Ionic 5.1.1 / Angular 9.1.9 and I’m using the Cypress front-end testing framework at 5.4.0. The trouble is I’m in need of a CSS selector prefix that ensures that I find elements that (from my point of view) are singular on the page, but it occur in multiples in the DOM because of these “hidden” ion-router-outlet children that are outside the scope of what I care about testing and sometimes Cypress finds these instead which is super annoying.

The selector I most recently though was good enough to find .my-selector of interest, was: :not(ion-app).ion-page:not(.ion-page-hidden) .my-selector, but then I came accross a failing test case where I looked at the DOM at failure-time and it looked like this:


Where you can see there are two children with .ion-page, and one has .can-go-back. In this case, I’m pretty sure the one I wanted to select was the parent .can-go-back but I don’t think the element I want always has that class.

Please can someone help me identify a CSS selector that consistently / always selects the item currently in the foreground? Can I always count on the foreground .ion-page to appear last in the DOM? Without such a selector writing non-flaky automated tests is an absolute nightmare.

1 Like

While you wait for better answers, I would suggest rolling your own solution here, because I don’t think it makes sense to put arbitrary restrictions on how the framework (or browser, or whatever hosting environment is going to exist in two years that I haven’t even heard of yet) manages such a crucial concept as resource lifecycle management just to placate a single testing harness.

So, how about this? Use Angular’s [class.foobar] syntax (or the related NgClass directive) to attach and remove a class on your <ion-content> (or <ion-header> or whereever) based on the status of an inForeground boolean that sits in your controller and is toggled in the ionViewWillEnter and ionViewDidLeave lifecycle handlers.

Yea, I am “wrapping” the concept in my tests for exactly this reason. That’s an interesting idea about dynamically binding my own classes based on ionViewWillEnter / ionViewWillLeave events… however it will be a lot of work to instrument every one of my pages to get that effect for what would otherwise be an “aspect” of my application. But it’s the best idea I’ve heard so far so good thinking! Bonus points if there is a way to abstract that idea.

I would investigate making a class decorator if you want to go down that road. You could perhaps adapt the way that ngneat/until-destroy works, because I figure it does something similar patching ngOnDestroy.

Wouldn’t these cached doppleganger pages cause problems in every E2E test framework, since the task of identifying a particular button or input using a css selector is a fundamental requirement? I must be missing something.

I guess that depends on how you structure your tests. I’ve only used Protractor much, but it has several predicates revolving around the notion of visibility (visibilityOf, isDisplayed, etc), and in my (admittedly limited) experience I have not encountered false positives caused by hidden cached DOM elements.