How to prevent full page reload when testing Angular with Cypress?
I solved this by adding a custom cypress command that calls a method on the Angular applications app.component.ts
. The solution look like this Updated to Ivy:
app.component.ts
export class AppComponent {
constructor(
private router: Router,
private ngZone: NgZone,
) {}
// Method Cypress will call
public navigateByUrl(url: string) {
this.ngZone.run(() => {
this.router.navigateByUrl(url);
});
}
}
cypress/support/commands.ts
// add new command to the existing Cypress interface
declare global {
namespace Cypress {
interface Chainable {
visitAngular: (url: string) => Chainable<Window>;
}
}
}
// Custom function
export function visitAngular(url: string) {
cy.get('body').then($body => {
try {
const el = $body.find('app-root')[0];
const win = el.ownerDocument.defaultView;
const componentInstance = win.ng.getComponent(el);
cy.log(`Angular nav to '${url}' `);
componentInstance.navigateByUrl(url);
cy.url().should('contain', url);
} catch (error) {
cy.log(`Cypress nav to '${url}' `);
cy.visit(url);
}
});
}
Cypress.Commands.add('visitAngular', visitAngular);
cypress/support/index.d.ts
interface Window {
ng: {
getComponent: (element: any) => any;
};
}
We have used this for 2 months now, and it works great in local development, speeding up test executions with x3. But in CI it's another story.
If you are using hash-based routing, you could manually manipulate the URL:
cy.window().then(win => win.location.hash = "/foo/bar")
You can make it work in a CI enviroment registering a global function an call that instead of the angular component:
app.component.ts
export class AppComponent {
constructor(
private router: Router,
private ngZone: NgZone,
) {
// Method Cypress will call
if ((window as any).Cypress) {
(window as any).cypressNavigateByUrl = (url: string) => this.cypressNavigateByUrl(url);
}
}
public cypressNavigateByUrl(url: string) {
this.ngZone.run(() => {
this.router.navigateByUrl(url);
});
}
}
cypress/support/commands.ts
Cypress.Commands.add('visitAngular', (url) => {
cy.window().then((win) => {
win.cypressNavigateByUrl(url);
});
});