Renvoie la valeur en fonction d’un bloc de promesse

J’essaie d’écrire une fonction (à l’aide de WebdriverJS lib) qui itère dans une liste d’éléments, vérifie les noms et crée un localisateur xpath correspondant à ce nom. J’ai simplifié les localisateurs xpath ici, alors ne faites pas attention.

Les problèmes auxquels je suis confronté sont les suivants: 1) L’appel de cette fonction renvoie non défini. Autant que je sache, cela est dû au fait que l’instruction return n’est pas à sa place, mais: 2) si elle est placée au bon endroit où un code synchrone fonctionnerait normalement, cela ne fonctionne pas pour les promesses asynchrones; l’appel de cette fonction retournera donc le même indéfini, mais parce que l’instruction return est déclenchée avant l’instruction “driver.findElement”.

Comment utiliser l’instruction return ici si je souhaite obtenir la variable createdTask à la suite de l’appel de cette fonction?

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

Vous pouvez d’abord obtenir tous les textes avec promise.map puis la position avec 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 + "]"; }); } 

Voilà, je l’ai un peu nettoyé. Cela retournera en fait une erreur si on en a une dans les promesses nestedes:

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

Vous l'appelez en utilisant

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

Vous ne pourrez pas renvoyer la valeur que vous souhaitez de cette fonction car, lorsque cette fonction est renvoyée, la valeur n’est pas encore définie.

Ce n’est pas un problème que vous essayez de renvoyer la valeur au mauvais endroit, mais que vous essayez d’y accéder au mauvais moment.

Vous avez deux options: vous pouvez soit renvoyer une promesse à partir de cette fonction, soit prendre un rappel qui serait appelé lorsque la valeur est disponible.

Exemples

Ceci n’a pas été testé mais devrait vous donner une idée de la façon d’y réfléchir.

Promettre

Version avec promesse:

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

et ensuite vous l'appelez avec:

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

Rappeler

Version avec rappel:

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

et ensuite vous l'appelez avec:

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

Plus d'informations

Vous pouvez lire d'autres réponses expliquant le fonctionnement des promesses et des rappels si vous souhaitez en savoir plus à ce sujet:

  • Une explication détaillée sur l'utilisation des rappels et des promesses
  • Explication sur l'utilisation des promesses dans les gestionnaires de demandes complexes
  • Une explication de ce qu'est une promesse, à l'exemple des demandes AJAX
  • Une explication des rappels, des promesses et de la manière d'accéder aux données renvoyées de manière asynchrone