I've encountered this issue myself and we've tried many different things at work on our app. Even though it's something which needs to be adapted, we're quite happy with our current solution.
But before I get to the solution, let me explain why this is a hard problem to solve without simply having a long wait before we start testing.
First of all, we need to wait for our page to be ready. Luckily for us, Cypress does that for us.
Then, we could wait for Angular to be bootstraped. One way of being aware of that is by checking if getAllAngularRootElements is available on the window object. And yes this function is apparently there even in prod mode!
cy.window()
.its('getAllAngularRootElements' as any)
.should('exist');
But this isn't a perfect solution especially if... You use lazy loading.
Just because Angular bootstraped your app doesn't mean all your lazy modules are loaded! And this is where it gets really unlikely to find an automatic way of waiting for exactly what you want to be ready.
So how do we start testing as soon as we can and in a safe way? In my opinion the best option to do so is to have a check after every cy.visit call and wait for one element around what you're about to test, to exist. Example:
cy.visit(`some-page`);
cy.get(
'.some-class-around-what-I-want-to-test',
{ timeout: 15000 }
).should('exist');
// ... rest of the test goes here
The code above will load the page, wait for the element you're targetting to exist for a maximum of 15 seconds but the important thing to note is that as soon as this element is available, it'll consider that check successful and move on. So if your app takes 2 seconds to display that element, your tests will starts straight after!
If you want to make it less repetitive for all your tests, you can create a function to open a given page and wait for its content to be there before doing something else. Example:
// at the top of the test file
const openProfilePage = () => {
cy.visit('profile');
cy.get(
'.profile',
{ timeout: 15000 }
).should('exist');
}
// in every tests after or in a before each
openProfilePage();
// test something else