Every test starts by going somewhere. That sounds trivial, and there is one habit here that catches real bugs.
cy.visit loads a page:
cy.visit('/login');
If baseUrl is set in your config, that path is added to it. Cypress waits for the page to load before moving on, so you do not need to wait yourself.
Most navigation in a test is not cy.visit, though. It is the user clicking something:
cy.get('[data-testid="cart-link"]').click();
Now, the habit. After navigation, check where you landed.
cy.get('[data-testid="login-button"]').click();
cy.url().should('include', '/dashboard');
This looks like a formality. It is one of the most useful assertions you can write, for a specific reason: it catches the failure where login silently does nothing.
Think about what happens without it. You click login, the app rejects the credentials and stays on the login page, and your next line looks for a welcome message. That fails with "element not found", which tells you nothing about the cause. With the URL check, the test fails one line earlier saying it expected to be on /dashboard and was on /login. Now you know exactly what happened.
Two more commands you will want.
cy.go('back'); // the browser back button
cy.reload(); // reload the current page
cy.reload() is more useful than it looks. It is how you prove something was really saved rather than just drawn on screen. Create a contact, reload, and check the row is still there. Without the reload, you have only proved the app updated its own display, which it would also do if the save request failed silently.
One thing that surprises people coming from Selenium. In most modern apps, clicking a link does not reload the page. JavaScript swaps the content and updates the address bar. Cypress handles both cases, but it matters for your mental model: the URL changing does not mean a fresh page load, and state you set earlier may still be there.
Remember this: after any navigation, assert the URL. It turns a confusing failure into an obvious one.
Reference: cy.visit.