When I write my Cypress e2e tests for my Angular application, I often use the visit() command like this:
.visit('/foo/bar')
This get's the job done, i.e. Cypress navigates to /foo/bar
, but the entire application reloads. This is very slow, and does not mimic actual user behaviour.
Is it possible to navigate/visit the Angular application, without full page reloads?
I did try:
cy.window().then((win) => {
win.history.pushState({}, '', '/foo/bar')
})
But angular does not react to this.
Install Cypress in Angular Project The above command will help open a chrome browser to check the cypress test cases like the below screen. Click on the spec. ts file, and it will run the cypress test cases for that file. It will run in a terminal and share the spec success and failure report.
cy. reload() can time out waiting for the page to fire its load event. cy. reload() can time out waiting for assertions you've added to pass.
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.
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);
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With