javascript selenium selenium-webdriver protractor

javascript - Acciones de navegador personalizadas en Protractor



selenium selenium-webdriver (4)

El problema:

En una de nuestras pruebas tenemos una funcionalidad de "clic largo" / "clic y mantener" que resolvemos mediante el uso de:

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

Lo que nos gustaría resolver idealmente en una línea haciendo que sleep() forme parte de la cadena de acción:

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

Claramente, esto no funcionaría ya que no existe una acción de "suspensión" .

Otro ejemplo práctico podría ser el "tipeo humano". Por ejemplo:

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

Tenga en cuenta que estos son solo ejemplos, la pregunta debe ser genérica.

La pregunta:

¿Es posible extender las secuencias de acción de browser.actions() e introducir acciones personalizadas?


Creo que es posible extender la función browser.actions() , pero actualmente está por encima de mi nivel de habilidad, así que diseñaré la ruta que tomaría para resolver este problema. Recomendaría configurar un objeto de página " HelperFunctions.js " que contendrá todas estas funciones de ayuda global. En ese archivo puede enumerar browser funciones de su browser y hacer referencia a él en múltiples pruebas con todo el código en una ubicación.

Este es el código para el archivo "HelperFunctions.js" que recomendaría configurar:

var HelperFunctions = function() { this.longClick = function(targetElement) { browser.actions().mouseDown(targetElement).perform(); browser.sleep(5000); browser.actions().mouseUp(targetElement).perform(); }; }; module.exports = new HelperFunctions();

Luego, en su prueba, puede hacer referencia al archivo auxiliar de esta manera:

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

En mi Test Suite tengo algunos archivos de configuración de ayuda y se hace referencia a ellos en todas mis pruebas.


Esto es lo que hice (basado en la respuesta perfecta de @ Louis).

Ponga lo siguiente en onPrepare() en la configuración del transportador:

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

Ahora tendrá las acciones del navegador sleep() y clickAndHold() disponibles. Ejemplo de uso:

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


Tengo muy poco conocimiento de selenio o transportador, pero lo intentaré.

Esto supone que

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

es una sintaxis válida para su problema, si es así, esto probablemente funcionaría

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


Sí, puede ampliar el marco de acciones. Pero, estrictamente hablando, obtener algo como:

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

significa jugar con las entrañas de Selenium. Entonces, YMMV.

Tenga en cuenta que la documentación del transportador se refiere a webdriver.WebDriver.prototype.actions al explicar las acciones, lo que considero que no modifica ni agrega a lo que proporciona Selenium.

La clase de objeto devuelta por webdriver.WebDriver.prototype.actions es webdriver.ActionSequence . El método que realmente hace que la secuencia haga algo es webdriver.ActionSequence.prototype.perform . En la implementación predeterminada, esta función toma los comandos que se grabaron cuando llamó a .sendKeys() o .mouseDown() y tiene el controlador al que está asociado ActionSequence programarlos en orden. Por lo .sleep , NO se puede agregar un método .sleep esta manera :

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

De lo contrario, el sueño no funcionaría . Lo que debe hacer es registrar el efecto que desea para que se ejecute más tarde.

Ahora, la otra cosa a considerar es que el .perform() predeterminado solo espera ejecutar webdriver.Command , que son comandos que se enviarán al navegador. Dormir no es uno de esos comandos. Entonces .perform() tiene que ser modificado para manejar lo que vamos a grabar con .sleep() . En el siguiente código, he optado por que .sleep() grabe una función y modifique .perform() para manejar funciones además de webdriver.Command .

Así es como se ve todo, una vez juntos. Primero he dado un ejemplo usando Stock Selenium y luego agregué los parches y un ejemplo usando el código modificado.

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

En mi implementación de .perform() , he reemplazado las funciones goog... que el código de Selenium usa con JavaScript goog... .