使用赛普拉斯测试 Angular 时如何防止整页重新加载?

Dau*_*eDK 9 angular-routing angular cypress

当我为 Angular 应用程序编写 Cypress e2e 测试时,我经常使用这样的visit()命令:

.visit('/foo/bar')

这样就完成了工作,即 Cypress 导航到/foo/bar,但整个应用程序会重新加载。这非常慢,并且不会模仿实际的用户行为。

是否可以在不重新加载整页的情况下导航/访问 Angular 应用程序?

我确实尝试过:

cy.window().then((win) => {
   win.history.pushState({}, '', '/foo/bar')
})
Run Code Online (Sandbox Code Playgroud)

但是 angular 对此没有反应。

Dau*_*eDK 6

我通过添加一个调用 Angular 应用程序方法的自定义 cypress 命令解决了这个问题app.component.ts。解决方案看起来像这样更新到常春藤

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);
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

柏树/支持/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);
Run Code Online (Sandbox Code Playgroud)

柏树/支持/index.d.ts

interface Window {
    ng: {
        getComponent: (element: any) => any;
    };
}
Run Code Online (Sandbox Code Playgroud)

我们已经使用它 2 个月了,它在本地开发中效果很好,可以加快 x3 的测试执行速度。但在 CI 中则是另一回事。


Die*_*cca 6

你可以让它在 CI 环境中工作,注册一个全局函数,而不是角度组件的调用:

应用程序组件.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);
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

赛普拉斯/支持/commands.ts

Cypress.Commands.add('visitAngular', (url) => {
    cy.window().then((win) => {
        win.cypressNavigateByUrl(url);
    });
});
Run Code Online (Sandbox Code Playgroud)