問題:
私たちのテストの1つには、 "ロングクリック"/"クリックアンドホールド"機能 があり、これを使用して解決します。
_browser.actions().mouseDown(element).perform();
browser.sleep(5000);
browser.actions().mouseUp(element).perform();
_
アクションチェーンの一部にsleep()
を含めることで、1行で理想的に解決したいものはどれですか。
_browser.actions().mouseDown(element).sleep(5000).mouseUp(element).perform();
_
「スリープ」アクションなし があるため、明らかにこれは機能しません。
別の実用的な例は、「人間のようなタイピング」でしょう。例えば:
_browser.actions().mouseMove(element).click()
.sendKeys("t").sleep(50) // we should randomize the delays, strictly speaking
.sendKeys("e").sleep(10)
.sendKeys("s").sleep(20)
.sendKeys("t")
.perform();
_
これらは単なる例であり、質問は一般的なものであることに注意してください。
質問:
browser.actions()
アクションシーケンスを拡張してカスタムアクションを導入することは可能ですか?
はい、アクションフレームワークを拡張できます。しかし、厳密に言えば、次のようなものを取得します。
_browser.actions().mouseDown(element).sleep(5000).mouseUp(element).perform();
_
セレンの腸をいじることを意味します。だから、YMMV。
Protractor documentation は、アクションを説明するときに_webdriver.WebDriver.prototype.actions
_を参照していることに注意してください。これは、Seleniumが提供するものを変更または追加しないことを意味します。
_webdriver.WebDriver.prototype.actions
_によって返されるオブジェクトのクラスは_webdriver.ActionSequence
_です。実際にシーケンスに何かをさせるメソッドは_webdriver.ActionSequence.prototype.perform
_です。デフォルトの実装では、この関数は.sendKeys()
または.mouseDown()
を呼び出したときに記録されたコマンドを取得し、ActionSequence
が関連付けられているドライバーを使用してそれらを順番にスケジュールします。したがって、_.sleep
_メソッドを追加することは、この方法では実行できません:
_webdriver.ActionSequence.prototype.sleep = function (delay) {
var driver = this.driver_;
driver.sleep(delay);
return this;
};
_
そうしないと、スリープが発生します順不同。あなたがしなければならないのは、それが後で実行されるようにしたい効果をrecordすることです。
ここで考慮すべきもう1つのことは、デフォルトの.perform()
は、ブラウザに送信されるコマンドである_webdriver.Command
_の実行のみを想定していることです。睡眠はそのようなコマンドの1つではありません。したがって、.perform()
は、.sleep()
で記録する内容を処理するように変更する必要があります。以下のコードでは、.sleep()
に関数を記録させ、_webdriver.Command
_に加えて関数を処理するように.perform()
を変更することを選択しました。
まとめると、全体が次のようになります。最初にストックSeleniumを使用した例を示し、次にパッチを追加し、変更されたコードを使用した例を追加しました。
_var webdriver = require('Selenium-webdriver');
var By = webdriver.By;
var until = webdriver.until;
var chrome = require('Selenium-webdriver/chrome');
// Do it using what Selenium inherently provides.
var browser = new chrome.Driver();
browser.get("http://www.google.com");
browser.findElement(By.name("q")).click();
browser.actions().sendKeys("foo").perform();
browser.sleep(2000);
browser.actions().sendKeys("bar").perform();
browser.sleep(2000);
// Do it with an extended ActionSequence.
webdriver.ActionSequence.prototype.sleep = function (delay) {
var driver = this.driver_;
// This just records the action in an array. this.schedule_ is part of
// the "stock" code.
this.schedule_("sleep", function () { driver.sleep(delay); });
return this;
};
webdriver.ActionSequence.prototype.perform = function () {
var actions = this.actions_.slice();
var driver = this.driver_;
return driver.controlFlow().execute(function() {
actions.forEach(function(action) {
var command = action.command;
// This is a new test to distinguish functions, which
// require handling one way and the usual commands which
// require a different handling.
if (typeof command === "function")
// This puts the command in its proper place within
// the control flow that was created above
// (driver.controlFlow()).
driver.flow_.execute(command);
else
driver.schedule(command, action.description);
});
}, 'ActionSequence.perform');
};
browser.get("http://www.google.com");
browser.findElement(By.name("q")).click();
browser.actions().sendKeys("foo")
.sleep(2000)
.sendKeys("bar")
.sleep(2000)
.perform();
browser.quit();
_
.perform()
の実装では、Seleniumのコードが使用する_goog...
_関数を標準のJavaScriptに置き換えました。
これが私がやったことです(完璧な@Louisの答えに基づいています)。
分度器設定のonPrepare()
に以下を入力します:
_// extending action sequences
protractor.ActionSequence.prototype.sleep = function (delay) {
var driver = this.driver_;
this.schedule_("sleep", function () { driver.sleep(delay); });
return this;
};
protractor.ActionSequence.prototype.perform = function () {
var actions = this.actions_.slice();
var driver = this.driver_;
return driver.controlFlow().execute(function() {
actions.forEach(function(action) {
var command = action.command;
if (typeof command === "function")
driver.flow_.execute(command);
else
driver.schedule(command, action.description);
});
}, 'ActionSequence.perform');
};
protractor.ActionSequence.prototype.clickAndHold = function (Elm) {
return this.mouseDown(Elm).sleep(3000).mouseUp(Elm);
};
_
これで、sleep()
およびclickAndHold()
ブラウザーアクションを使用できるようになります。使用例:
_browser.actions().clickAndHold(element).perform();
_
browser.actions()
関数を拡張することは可能だと思いますが、それは現在私のスキルレベルを上回っています。そのため、この問題を解決するためのルートを示します。これらのグローバルヘルパー関数をすべて含む "HelperFunctions.js" Page Objectを設定することをお勧めします。そのファイルでは、browser
関数をリストし、すべてのコードを1つの場所に置いて、複数のテストでそれを参照できます。
これは、セットアップを推奨する "HelperFunctions.js"ファイルのコードです。
var HelperFunctions = function() {
this.longClick = function(targetElement) {
browser.actions().mouseDown(targetElement).perform();
browser.sleep(5000);
browser.actions().mouseUp(targetElement).perform();
};
};
module.exports = new HelperFunctions();
次に、テストで次のようにヘルパーファイルを参照できます。
var HelperFunctions = require('../File_Path_To/HelperFunctions.js');
describe('Example Test', function() {
beforeEach(function() {
this.helperFunctions = HelperFunctions;
browser.get('http://www.example.com/');
});
it('Should test something.', function() {
var Element = element(by.className('targetedClassName'));
this.helperFunctions.longClick(Element);
});
});
私のテストスイートでは、いくつかのヘルパーファイルをセットアップしており、それらはすべてのテストで参照されています。
セレンや分度器についてはほとんど知識がありませんが、試してみます。
これは
browser.actions().mouseDown(element).mouseUp(element).perform();
問題の有効な構文です。そうであれば、これでうまくいくでしょう
browser.action().sleep = function(){
browser.sleep.apply(this, arguments);
return browser.action()
}