【问题标题】:How to prevent full page reload when testing Angular with Cypress?使用 Cypress 测试 Angular 时如何防止整页重新加载?
【发布时间】:2019-03-21 15:00:49
【问题描述】:

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

.visit('/foo/bar')

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

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

我试过了:

cy.window().then((win) => {
   win.history.pushState({}, '', '/foo/bar')
})

但 Angular 对此没有反应。

【问题讨论】:

  • 有一篇博客文章解释了如何与 Cypress 的 AngularJS 进行交互:cypress.io/blog/2017/11/15/… 适用于 1.x,但可能有些概念仍然相关。
  • 一种解决方法是实际单击菜单中的导航按钮。
  • 嗨@totymedli - 确保单击按钮是一种解决方法,但对我的团队用例来说不是很好。我用我们现在使用的解决方案添加了一个答案。

标签: angular angular-routing cypress


【解决方案1】:

我通过添加一个自定义 cypress 命令来解决这个问题,该命令调用 Angular 应用程序 app.component.ts 上的方法。解决方案如下所示已更新到 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;
    };
}

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

【讨论】:

  • 嗨@DauleDK,CI/CD 管道中的这种方法有问题吗?
  • 这里的“问题”是运行CI时不同的spec文件是隔离的。所以这种方法并不能真正加快速度。实际上,我们放弃了上述方法,只是承认赛普拉斯是为“大”它的规格而构建的,因此导航无论如何只会发生一次(每个规格)。
【解决方案2】:

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

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);
    });
});

【讨论】:

  • 嗨@Diego - 这是一个很棒的提示。谢谢。
【解决方案3】:

如果您使用的是基于哈希的路由,您可以手动操作 URL:

cy.window().then(win => win.location.hash = "/foo/bar")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-30
    • 1970-01-01
    • 2015-06-17
    • 2011-12-14
    • 2019-06-24
    • 2019-10-21
    相关资源
    最近更新 更多