javascript 量角器中的自定义浏览器操作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32789460/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 15:46:10  来源:igfitidea点击:

Custom browser actions in Protractor

javascriptseleniumselenium-webdriverprotractor

提问by alecxe

The problem:

问题:

In one of our tests we have a "long click"/"click and hold" functionalitythat we solve by using:

在我们的一项测试中,我们使用以下方法解决了“长按”/“单击并按住”功能

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

Which we would like to ideally solve in one line by having sleep()a part of the action chain:

我们希望通过拥有sleep()动作链的一部分在一行中理想地解决:

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

Clearly, this would not work since there is no "sleep" action.

显然,这行不通,因为没有“睡眠”操作

Another practical example could be the "human-like typing". For instance:

另一个实际例子可能是“类人打字”。例如:

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

Note that these are just examples, the question is meant to be generic.

请注意,这些只是示例,问题是通用的。

The Question:

问题:

Is it possible to extend browser.actions()action sequences and introduce custom actions?

是否可以扩展browser.actions()动作序列并引入自定义动作?



采纳答案by Louis

Yes, you can extend the actions framework.But, strictly speaking, getting something like:

是的,您可以扩展操作框架。但是,严格来说,得到类似的东西:

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

means messing with Selenium's guts. So, YMMV.

意味着搞乱 Selenium 的胆量。所以,YMMV。

Note that the Protractor documentationrefers to webdriver.WebDriver.prototype.actionswhen explaining actions, which I take to mean that it does not modify or add to what Selenium provides.

注意,量角器文件指的是webdriver.WebDriver.prototype.actions解释的行为,这是我采取意味着它不会修改或补充硒什么时提供。

The class of object returned by webdriver.WebDriver.prototype.actionsis webdriver.ActionSequence. The method that actually causes the sequence to do anything is webdriver.ActionSequence.prototype.perform. In the default implementation, this function takes the commands that were recorded when you called .sendKeys()or .mouseDown()and has the driver to which the ActionSequenceis associated schedule them in order. So adding a .sleepmethod CANNOT be done this way:

返回的对象类webdriver.WebDriver.prototype.actionswebdriver.ActionSequence。实际上使序列做任何事情的方法是webdriver.ActionSequence.prototype.perform. 在默认实现中,此函数采用您调用.sendKeys()或时记录的命令,并让关联.mouseDown()的驱动程序ActionSequence按顺序安排它们。所以添加一个.sleep方法不能这样完成

webdriver.ActionSequence.prototype.sleep = function (delay) {
    var driver = this.driver_;
    driver.sleep(delay);
    return this;
};

Otherwise, the sleep would happen out of order. What you have to do is recordthe effect you want so that it is executed later.

否则,睡眠会发生的顺序进行。你要做的就是记录你想要的效果,以便稍后执行。

Now, the other thing to consider is that the default .perform()only expects to execute webdriver.Command, which are commands to be sent to the browser. Sleeping is not one such command. So .perform()has to be modified to handle what we are going to record with .sleep(). In the code below I've opted to have .sleep()record a function and modified .perform()to handle functions in addition to webdriver.Command.

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

Here is what the whole thing looks like, once put together. I've first given an example using stock Selenium and then added the patches and an example using the modified code.

这是整个事情的样子,一旦放在一起。我首先给出了一个使用股票 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();

In my implementation of .perform()I've replaced the goog...functions that Selenium's code uses with stock JavaScript.

在我的实现中,.perform()我已将goog...Selenium 代码使用的函数替换为常用 JavaScript。

回答by alecxe

Here is what I did (based on the perfect @Louis's answer).

这是我所做的(基于完美的@Louis 的回答)。

Put the following into onPrepare()in the protractor config:

将以下内容放入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);
};

Now you'll have sleep()and clickAndHold()browser actions available. Example usage:

现在你要sleep()clickAndHold()可用的浏览器操作。用法示例:

browser.actions().clickAndHold(element).perform();

回答by John Stennett

I think it is possible to extend the browser.actions()function but that is currently above my skill level so I'll lay out the route that I would take to solve this issue. I would recommend setting up a "HelperFunctions.js" Page Object that will contain all of these Global Helper Functions. In that file you can list your browserfunctions and reference it in multiple tests with all of the code in one location.

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

This is the code for the "HelperFunctions.js" file that I would recommend setting up:

这是我建议设置的“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();


Then in your Test you can reference the Helper file like this:

然后在您的测试中,您可以像这样引用 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);
    });
});


In my Test Suite I have a few Helper files setup and they are referenced through out all of my Tests.

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

回答by QBM5

I have very little knowledge of selenium or protractor, but I'll give it a shot.

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

This assumes that

这假设

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

is valid syntax for your issue, if so then this would likely do the trick

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

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