关于Protractor在Angular同步和非Angular应用页面的测试

这是关于Angular同步相关内容的一篇名为“不可怕的角度计”的文章。

与Angular的同步

Protractor是作为Angular项目的一部分开发的,因此具有针对Angular专门优化的功能。其中之一就是与Angular同步。

在这里所说的”同步”是指具体等待”$digest loop”、”$timeout”和”$http”等待AJAX请求完成。这样一来,我们就不需要像其他的E2E测试框架那样进行休眠或者轮询等待获取到期望值。我们可以编写更快速、减少不确定性的测试。

需要直接执行,则需要调用browser.waitForAngular()。简单来说,这是通过在浏览器中调用Angular内置的$$testability.whenStable(callback)方法来实现的。

我认为通常情况下没有必要直接执行browser.waitForAngular()。如果使用element()或element.all()等方法,当执行click()等命令时,它会自动调用它,并选择元素执行命令。

在非 Angular 应用的页面上进行测试。

使用Angular非常方便,在Angular应用程序以外的页面上使用Protractor,需要将此行为设置为关闭。

browser.ignoreSynchronization = true;

通过这一方法,将能够在非Angular应用程序的页面上进行测试。

在非Angular应用的页面上等待。

在非 Angular 应用程序页面中需要等待 AJAX 请求等的情况下,您需要自己编写代码来进行等待。WebDriverJS 提供了两种方法。

一种方法是使用sleep()函数,它可以等待一段特定的时间。虽然简单,但在某些情况下可能会导致处理时间过长而失败,或者为了避免这种情况而过长地等待,从而延长测试执行时间,所以不太推荐使用。

browser.sleep(1000);

还有一种方法,就是等待满足某个条件。这个条件可以用函数来表示,函数中会返回一个解决为布尔值的Promise。这确实有点麻烦。

var message = element(by.css('.message'));
browser.wait(function() {
  return message.getText().then(function(text) {
    return text === 'Hello, World!'
  });
}, 3000);

您还可以传递 WebDriverJS 提供的条件对象作为函数的替代。请查看 WebDriverJs 的 until 命名空间以获取更多详细信息。

var message = element(by.css('.message'));
browser.wait(protractor.until.elementTextIs(message, 'Hello, World!'), 3000);

嗯,對於使用Protractor測試這樣的頁面是否必要存在這個問題……。

Angular应用程序与非Angular页面的混合

通过切换 browser.ignoreSynchronization 标志,您可以在 Angular 应用程序和非 Angular 页面之间进行测试。这个标志的评估不是在实际操作浏览器之前,而是在调用 click() 等方法之后,所以基本上在命令和命令之间切换标志也会按预期工作。

例如,假设我们要编写一个测试来检查系统是否能够在登录页面不是使用Angular应用程序而是在登录后转到Angular应用程序的情况下正常工作。基于上述原因,以下代码将能够正常运行。

var loginIdField = element(by.name('login_id'));
var passwordField = element(by.name('password'));
var loginButton = element(by.buttonText('ログイン'));
var usernameDisplay = element(by.binding('username'));

browser.ignoreSynchronization = true;
// Angular と同期しない。
browser.get('index.html');

loginIdField.sendKeys('protractaro');
passwordField.sendKeys('P@ssw0rd');
loginButton.click();

browser.ignoreSynchronization = false;
// ここから Angular と同期する。
expect(usernameDisplay.getText()).toEqual('プロトラク太郎');

如果在then()中有命令发出的情况下

在调用then()方法时,需要注意发出命令的顺序。以下是一个不自然的例子,它会导致失败。这是因为在browser.ignoreSynchronization = false;之后,passwordField.sendKeys(‘P@ssw0rd’);行被执行,而在非Angular应用页面等待Angular。

browser.ignoreSynchronization = true;
browser.get('index.html');

// Angular と同期しない。
loginIdField.sendKeys('protractaro')
  .then(function() {
    // Angular と同期しようとする!
    passwordField.sendKeys('P@ssw0rd');
  });
// Angular と同期しない。
loginButton.click();

browser.ignoreSynchronization = false;
// Angular と同期する。
expect(usernameDisplay.getText()).toEqual('プロトラク太郎');

我认为这种情况并不常见,但如果有必要的话,我认为最好将测试用例(it())分开。这是因为需要等待所有命令执行完毕后才能进入下一个测试用例。

it('should login', function() {
  browser.ignoreSynchronization = true;
  browser.get('index.html');

  // Angular と同期しない。
  loginIdField.sendKeys('protractaro')
    .then(function() {
      // Angular と同期しない。
      passwordField.sendKeys('P@ssw0rd');
    });
  // Angular と同期しない。
  loginButton.click();
});

it('should show username', function() {
  browser.ignoreSynchronization = false;
  // Angular と同期する。
  expect(usernameDisplay.getText()).toEqual('プロトラク太郎');
});

整理一下

    • Protractor は Angular アプリには向いている(当たり前)。

 

    • Angular じゃないページで非同期な何かを待つ必要がある場合、つらいけどできなくはない。

 

    • Angular アプリとそうでないページを混在させたシステムもテスト可能。

 

    そういう時は、Angular アプリとそうでないページでテストケースを分けると安心。
广告
将在 10 秒后关闭
bannerAds