Devuelve valor en función de un bloque de promesa

Estoy intentando escribir una función (usando WebdriverJS lib) que itera a través de una lista de elementos, verifica los nombres y crea un localizador xpath que corresponda a ese nombre. Simplifique los localizadores xpath aquí, así que no presten atención.

Los problemas que estoy enfrentando aquí son: 1) Llamar a esta función devuelve indefinido. Por lo que yo entiendo, esto se debe a que la statement de retorno no está en su lugar, pero: 2) Colocarlo en el lugar correcto donde normalmente funcionaría un código sincrónico, no funciona para promesas asíncronas, por lo que llamar a esta función volverá lo mismo indefinido, sino porque la statement de devolución se activa antes de la instrucción “driver.findElement”.

¿Cómo debería usar la statement return aquí, si deseo obtener la variable CreateTask como resultado de llamar a esta función?

var findCreatedTask = function() { var createdTask; driver.findElements(By.xpath("//div[@id='Tasks_Tab']")).then(function(tasks) { for (var index = 1; index <= tasks.length; index++) { driver.findElement(By.xpath("//div[@id='Tasks_Tab'][" + index + "]//div[@class='task-title']")).getText().then(function(taskTitle) { if (taskTitle == "testName") { createdTask = "//div[@id='Tasks_Tab'][" + index + "]"; return createdTask; } }); } }); }; 

Primero puede obtener todos los textos con promise.map y luego obtener el puesto con indexOf :

 var map = webdriver.promise.map; var findCreatedTask = function() { var elems = driver.findElements(By.xpath("//div[@id='Tasks_Tab']//div[@class='task-title']")); return map(elems, elem => elem.getText()).then(titles => { var position = titles.indexOf("testName") + 1; return "//div[@id='Tasks_Tab'][" + position + "]"; }); } 

Aquí tienes, lo limpié un poco. Esto realmente devolverá un error si uno tiene experiencia en las promesas anidadas:

 var findCreatedTask = function() { var Promise = require('bluebird'); var createdTask; return driver.findElements(By.xpath("//div[@id='Tasks_Tab']")) .then(function(tasks) { return Promise.map(tasks, function(task){ return driver.findElement(By.xpath("//div[@id='Tasks_Tab'][" + index + "]//div[@class='task-title']")).getText() }).then(function(taskTitles){ for (let i = 0; i < taskTitles.length; i++){ if(taskTitles[i] === 'testName'){ createdTask = "//div[@id='Tasks_Tab'][" + i + "]"; return createdTask; } } }); }); }; 

Lo llamas usando

 findCreatedTask.then(function(res){ //do your thing }).catch(function(err){ console.error(err.stack); }); 

No podrá devolver el valor que desea de esta función porque cuando esta función retorna, el valor aún no está definido.

No es un problema que trate de devolver el valor en el lugar incorrecto, sino que intente acceder a él en el momento equivocado.

Tiene dos opciones: puede devolver una promesa desde esta función, o esta función puede tomar una callback que se llamaría cuando el valor esté disponible.

Ejemplos

Esto no se ha probado, pero debería darle una idea sobre cómo pensarlo.

Promesa

Versión con promesa:

 var findCreatedTask = function (callback) { var createdTask; return new Promise(function (resolve, reject) { driver.findElements(By.xpath("//div[@id='Tasks_Tab']")).then(function(tasks) { for (let index = 1; index < = tasks.length && !createdTask; index++) { driver.findElement(By.xpath("//div[@id='Tasks_Tab'][" + index + "]//div[@class='task-title']")).getText().then(function(taskTitle) { if (taskTitle == "testName") { createdTask = "//div[@id='Tasks_Tab'][" + index + "]"; resolve(createdTask); } }); } }); }); }; 

y luego lo llamas con:

 findCreatedTask().then(function (createdTask) { // you have your createdTask here }); 

Llamar de vuelta

Versión con callback:

 var findCreatedTask = function (callback) { var createdTask; driver.findElements(By.xpath("//div[@id='Tasks_Tab']")).then(function(tasks) { for (let index = 1; index < = tasks.length && !createdTask; index++) { driver.findElement(By.xpath("//div[@id='Tasks_Tab'][" + index + "]//div[@class='task-title']")).getText().then(function(taskTitle) { if (taskTitle == "testName") { createdTask = "//div[@id='Tasks_Tab'][" + index + "]"; callback(null, createdTask); } }); } }); }; 

y luego lo llamas con:

 findCreatedTask(function (err, createdTask) { // you have your createdTask here }); 

Más información

Puede leer algunas otras respuestas que explican cómo funcionan las promesas y devoluciones de llamada si le interesa saber más al respecto:

  • Una explicación detallada sobre cómo usar devoluciones de llamada y promesas
  • Explicación sobre cómo usar promesas en controladores de solicitudes complejos
  • Una explicación de lo que realmente es una promesa, en el ejemplo de las solicitudes AJAX
  • Una explicación de devoluciones de llamadas, promesas y cómo acceder a los datos devueltos de forma asincrónica