【问题标题】:Angular Protractor - Verifying page redirectAngular Protractor - 验证页面重定向
【发布时间】:2020-06-11 08:51:21
【问题描述】:

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

- Failed: script timeout

我一直在网上搜索以试图找到解决方案,但我找到的所有解决方案都对我不起作用。

示例

  • 等待 Angular

browser.waitForAngular();

Reference

  • 检查浏览器当前 URL 并与预期 URL 进行比较:
browser.driver.wait(() => {
    browser.driver.getCurrentUrl().then((url) => {
        return /expected-url/.test(url);
    });
}, 10000);

Reference


代码示例

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

登录页面对象类

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' 失败了。此测试试图验证成功登录后是否显示“安全内容”组件。该组件是一个包装器组件,用于托管只有在用户登录时才能显示的页面。

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

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


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

  • 角度:8.2.14
  • Angular CLI:8.2.2
  • 量角器:5.4.2
  • 茉莉花:2.8.0

【问题讨论】:

    标签: angular protractor angular-e2e


    【解决方案1】:

    我建议您使用 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

    【讨论】:

    • 感谢您的回答,不幸的是它仍然没有工作。我将继续调查.. 老实说,我仍然不确定是否需要 async/await,因为在我读过的一些文章中提到 Protractor 应该在步骤之间自动等待每个 Promise。当然,我可能错了。
    • 当我开始使用量角器时,我正在使用 then() 来解决 Promise。之后阅读几篇文章,了解 await/async 是如何工作的。它确实使执行变得更容易和顺利,消除了对手动承诺解决方案的依赖。但它是一个选择,使用与否。谢谢。
    • 是的,同意,我更喜欢 async/await 模式,因为它使代码更具可读性。我发现使用带有多个嵌套回调的then() 有时难以阅读。当然,这是个人喜好,两种方法都会产生相同的结果:)
    【解决方案2】:

    你必须使用操作员then 的承诺这个解决方案对我有用 如果您知道响应时间,您可以使用

    browser.driver.sleep(1000)
    

    但这是一种不好的做法

    注意:如果应用程序非常慢,是时候报告性能问题了。

    【讨论】:

      【解决方案3】:

      就我而言,除了等待某些 Promise 对象外,我还有其他原因导致错误。长话短说,我有一个区间负责向用户显示当前时间。由于间隔是一个异步函数,量角器会假设 Angular 仍在运行某个函数,因此会一直等待 Angular 做出“响应”。

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

      参考文献

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-28
        相关资源
        最近更新 更多