AngularのE2Eテスト Protractorで遅延実行
(150213追記)書いてしばらくしてから思ったんですが、けっこう微妙なこと言ってます。もう少しスマートなwaitの方法がありそう。この記事は記録として残します。
こんにちは、@armorik83です。
今回ProtractorでE2Eテストの実施中、svg周りの描画の遅れと要素取得に関してどうも安定感がなく、実行するたびに通るか落ちるか変わるテストというものが生まれました。これではテストの意味がありません。
specの書き方が悪いのではなく取得で落ちていることはログからも明白だったため、どうにかして処理に遅延を挟めないかと調べ続けていたところ、素晴らしいテクニックを見つけたので紹介します。
Protractorとは何かという説明は割愛します。
Can protractor be made to run slowly?
http://stackoverflow.com/questions/24960290/can-protractor-be-made-to-run-slowly
ドンピシャな質問文で嬉しいなか、回答に凄まじくGeekなものがありました。
var origFn = browser.driver.controlFlow().execute;
browser.driver.controlFlow().execute = function() {
var args = arguments;
// queue 100ms wait
origFn.call(browser.driver.controlFlow(), function() {
return protractor.promise.delayed(100);
});
return origFn.apply(browser.driver.controlFlow(), args);
};
死んだ頭でこれは再帰なのかフックなのかと色々考えたものの、とにかく動作したので考えるのやめました。たぶん何か細工してます。すいません。
ちょっと使いやすく
残念なことに、これを一度実行すると全てのテストが100msの遅延となるようでした。これではテストが遅すぎます。
そのため一度ラップして、(TypeScriptやES6のアロー関数式はarguments
の挙動が狂ったので止めた)
function delay(msec) {
var controlFlowExec = browser.driver.controlFlow().execute;
// do not use arrow for using arguments
browser.driver.controlFlow().execute = function () {
var args = arguments;
controlFlowExec.call(browser.driver.controlFlow(), function () {
return protractor.promise.delayed(msec);
});
return controlFlowExec.apply(browser.driver.controlFlow(), args);
};
}
使います。原文によるとdescribe
の外に書けということでした。
delay(100);
describe('', function() {
// ...
});
分割実行
specファイルを分けても一度に実行するProtractor全てが遅延してしまうため、どうしても結果が不安定なものだけ別ディレクトリに移し、protractor.conf.js
を複製してprotractor-delay.conf.js
とし、grunt-protractor-runner
#で2回に分けて実行します。
protractor: {
options: {
keepAlive: true,
noColor: false
},
fast: {
options: {
configFile: "./protractor.conf.js"
}
},
needDelay: {
options: {
configFile: "./protractor-delay.conf.js"
}
}
},
// ...
grunt.registerTask('e2e', [
'protractor' // :以降を書かないと全て実行する
]);
こうすれば高速で済む分と泣く泣く遅延が必要な分を一連で短時間に実行できます。美しくはない。
こういった小細工なしに短時間で済むのが理想ですが、そうもいかない状況などに。
ではまた。
Discussion