Protractor中的自定义浏览器操作

时间:2015-09-25 19:38:14

标签: javascript selenium selenium-webdriver protractor

问题:

在我们的一个测试中,我们使用以下方法解决了"long click"/"click and hold" functionality

gravity_vertical

我们希望通过让browser.actions().mouseDown(element).perform(); browser.sleep(5000); browser.actions().mouseUp(element).perform(); 成为行动链的一部分来理想地解决这一问题:

sleep()

显然,由于存在no "sleep" action,这不起作用。

另一个实际例子可能是"类似人类的打字"。例如:

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(); 操作序列并引入自定义操作?

4 个答案:

答案 0 :(得分:10)

是的,你可以扩展行动框架。但是,严格来说,得到类似的东西:

browser.actions().mouseDown(element).sleep(5000).mouseUp(element).perform();

意味着搞乱Selenium的胆量。所以,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;
};

否则,睡眠会发生乱序。您需要做的是记录您想要的效果,以便以后执行。

现在,要考虑的另一件事是默认.perform()只期望执行webdriver.Command,这是要发送到浏览器的命令。睡觉不是一个这样的命令。因此,必须修改.perform()以处理我们将使用.sleep()记录的内容。在下面的代码中,除了.sleep()之外,我选择.perform()记录一个函数并修改webdriver.Command来处理函数。

这就是整个事情的样子,一旦放在一起。我首先使用库存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。

答案 1 :(得分:4)

这就是我所做的(基于完美的@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();

答案 2 :(得分:3)

我认为可以扩展browser.actions()功能但目前高于我的技能水平,所以我将列出解决此问题的路线。我建议设置一个" HelperFunctions.js "包含所有这些全局助手函数的页面对象。在该文件中,您可以列出您的browser函数,并在多个测试中引用它,并将所有代码放在一个位置。

这是" 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();

然后在您的测试中,您可以像这样引用Helper文件:

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

在我的测试套件中,我设置了一些帮助文件,并在我的所有测试中引用它们。

答案 3 :(得分:2)

我对硒或量角器知之甚少,但我会试一试。

这假定

browser.actions().mouseDown(element).mouseUp(element).perform();

是您的问题的有效语法,如果是这样,那么这可能会成功

browser.action().sleep = function(){
    browser.sleep.apply(this, arguments);
    return browser.action()
}