Protractor の動作をゆっくりにする

主に Angular 向けの E2E テスト用ツール「Protractor」。コレに関して、書いていたつもりで書いていなかったネタがあったので書いておく。

Protractor の Control Flow

Protractor は Control Flow という独自のキューを持っていて、コイツによって Promise を待って動作してくれたり、比較検証を行ったりしてくれる。

この辺の仕様は以下の文献で詳しく紹介されている。

なんだけど、どうもこの「Promise を待っての処理」が綺麗に行われないタイミングがあって、表面的に聞いただけだと

browser.wait(protractor.ExpectedConditions.visibilityOf(myElement));
myElement.click();

と書いても問題ないように聞こえるのだが、このように書くと時たまテストが失敗したりすることがある。

browser.wait() は Promise を返すので、

browser.wait(protractor.ExpectedConditions.visibilityOf(myElement))
  .then(() => {
    myElement.click();
  });

こんな風に書くと、テストが安定したりする。

Protractor の動作をゆっくりにする

この Control Flow の動作を遅延させて、Protractor のテスト実行をゆっくりにさせる方法が紹介されていた。

E2E テストコードを書いたファイルの先頭の方で、こんな実装をしてやる。

import { browser } from 'protractor';

const origFn = browser.driver.controlFlow().execute;
browser.driver.controlFlow().execute = function() {
  const args = arguments;
  origFn.call(browser.driver.controlFlow(), function() {
    return protractor.promise.delayed(100);  // 100ミリ秒待つ
  });
  return origFn.apply(browser.driver.controlFlow(), args);
};

describe('……', () => {
  // 以降テスト…
});

コレで、Protractor の動作ごとに100ミリ秒待ってくれるようになる。browser.sleep(1000) みたいな不安定なコード書かなくて済むし、E2E テストコードを実装中に上手く動かせているか確認もしやすい。

arguments とか使ってるのでアロー関数への書き換えはしないでおこう。