Angular 量角器 - 验证页面重定向

Angular Protractor - Verifying page redirect

我正在 Angular 应用程序中编写一些 E2E 测试。我遇到的一个问题是,每当我重定向到新路由时,我都想验证是否显示了正确的组件。由于某种原因,这总是导致失败并出现以下错误:

- Failed: script timeout

我一直在网上搜索以尝试找到解决方案,但我找到的所有解决方案都不适合我。

例子

browser.waitForAngular();

Reference

browser.driver.wait(() => {
    browser.driver.getCurrentUrl().then((url) => {
        return /expected-url/.test(url);
    });
}, 10000);


代码示例

以下是测试登录功能的代码示例。

登录页面对象Class

import { browser, element, by } from 'protractor';

export class LoginPage {
    private credentials: { username: string, password: string } = {
        username: 'admin',
        password: 'admin'
    };

    navigateTo() {
        return browser.get(browser.baseUrl) as Promise<any>;
    }

    getLoginComponent() {
        return element(by.css('ra-login'));
    }

    getUsernameTextbox() {
        return element(by.css('ra-login [data-test-id="username"]'));
    }

    getPasswordTextbox() {
        return element(by.css('ra-login [data-test-id="password"]'));
    }

    getLoginButton() {
        return element(by.css('ra-login [data-test-id="login-btn"]'));
    }

    getSecurePage() {
        return element(by.css('ra-secure-content'));
    }

    login(credentials: { username: string, password: string } = this.credentials) {
        this.getUsernameTextbox().sendKeys(credentials.username);
        this.getPasswordTextbox().sendKeys(credentials.password);
        this.getLoginButton().click();
    }

    getErrorMessage() {
        return element(by.css('ra-login [data-test-id="login-error"]'));
    }
}

登录 E2E 规范文件

describe('Login Functionality', () => {
    let loginPage: LoginPage;

    beforeEach(() => {
        loginPage = new LoginPage();
    });

    // Test runs successfully
    it('should display login', () => {
        loginPage.navigateTo();
        expect(loginPage.getLoginComponent().isPresent()).toBeTruthy();
    });

    // Test runs successfully
    it('should have the login button disabled', () => {
        loginPage.navigateTo();
        expect(loginPage.getLoginButton().isEnabled()).toBe(false);
    });

    // Test runs fails
    it('should redirect to a secure page', () => {
        loginPage.navigateTo();
        loginPage.login();

        expect(loginPage.getSecurePage().isPresent()).toBeTruthy();
    });

    afterEach(async () => {
        // Assert that there are no errors emitted from the browser
        const logs = await browser.manage().logs().get(logging.Type.BROWSER);
        expect(logs).not.toContain(jasmine.objectContaining({
            level: logging.Level.SEVERE,
        } as logging.Entry));
    });
});

使用上面的代码,测试 'should redirect to a secure page' 失败了。此测试试图验证在成功登录后,显示 "secure content" 组件。此组件是一个包装器组件,用于托管只有在用户登录后才能显示的页面。

页面重定向总是成功的,并且正在显示正确的页面。我怀疑测试以某种方式试图在实际重定向之前获取元素?

我是 E2E 的新手,所以我不确定这是否是问题所在。


以防万一这里是重要包的版本号:

我建议您使用 async/await 语句结构。您的怀疑似乎是正确的,您面临的问题是由于承诺处理不当。

您可以尝试将规范写成:

it('should redirect to a secure page', async() => {
        await loginPage.navigateTo();
        await loginPage.login();

        expect(await(await loginPage.getSecurePage()).isPresent()).toBeTruthy();
    });

并将导航和登录功能更改为:

async navigateTo() {
        return await browser.get(browser.baseUrl);
    }

您可以在有浏览器交互时添加 await,如果有任何 await 语句则使函数异步。

参考:[1]:https://hackernoon.com/should-i-use-promises-or-async-await-126ab5c98789

你必须对运算符使用 promise then 这个解决方案对我有用 如果你知道回复时间,你可以使用

browser.driver.sleep(1000)

但这是一种不好的做法

注意:如果应用程序速度很慢,则需要报告性能问题。

在我的例子中,除了等待某些 Promise 对象外,还有其他原因导致了错误。长话短说,我有一个时间间隔负责向用户显示当前时间。由于间隔是一个异步函数,Protractor 将假设 Angular 仍然是 运行 一些函数,因此继续等待 Angular 成为 "responsive".

在 Angular 2+ 中,为了满足这种情况,setInterval() 函数需要 运行 在 Angular 区域之外。

例子

ngOnInit() {
    this.now = new Date();

    setInterval(() => {
        this.now = new Date();
    }, 1000);
}

只要页面上存在具有间隔的组件,以上代码将导致 Protractor 超时。

要解决此问题,我们可以使用 NgZone

例子

import { NgZone } from '@angular/core';

constructor(private ngZone: NgZone) { }

ngOnInit() {
    this.now = new Date();

    // running setInterval() function outside angular
    // this sets the asynchronous call to not run within the angular zone
    this.ngZone.runOutsideAngular(() => {
        setInterval(() => {
            // update the date within angular, so that change detection is triggered
            this.ngZone.runTask(() => {
                this.now = new Date();
            });
        }, 1000);
    });
}

参考资料


在我的测试中,我还添加了一个实用函数,它有助于等待元素显示在屏幕上。

import { ElementFinder, ExpectedConditions, browser } from 'protractor';

const until = ExpectedConditions;

export const waitForElement = (elementToFind: ElementFinder, timeout = 10000) => {
    return browser.wait(until.presenceOf(elementToFind), timeout, 'Element not found');
};

然后在测试中使用如下:

it('should redirect to a secure page', async () => {
    loginPage.navigateTo();
    loginPage.login();

    const secureContent = loginPage.getSecureContentComponent();
    waitForElement(secureContent);

    expect(secureContent.isPresent()).toBe(true);
});

参考资料