Как сделать Promise API синхронным способом?

Я использую selenium-webdriver для тестирования с NodeJS. Я хочу сделать API-интерфейс Selen-Webdriver синхронным, чтобы мои тесты были очень краткими.

getTitle () Запланирует команду для получения заголовка текущей страницы. Этот API возвращает webdriver.promise.Promise

например с селен-вебдрайвером я делаю

driver.getTitle().then(function(title) {
   .....
 });

driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');

Как я могу сделать полностью синхронный API (сделать API Promise синхронным?), Вот так

var titleElement = driver.getTitle();
var qElement= driver.findElement(webdriver.By.name('q'));
qElement.sendKeys('webdriver');

Обновление (с ответом Бенджамина Грюнбаума):

Используйте yield с Promise.coroutine из API bluebird

function myBrowser() {

}

myBrowser.prototype.getTitle = Promise.coroutine(function* (driver) {
    var title = yield driver.getTitle(); // yield makes it wait
    console.log('prototype.getTitle: ' + title)
    return title;
});

var driver = createDriver();

driver.get('https://www.google.fr/')
driver.getTitle().then(function(title) {
    console.log('getTitle: ' + title)
 });

// Use bluebird API
var mb = new myBrowser();
var title = mb.getTitle(driver)
// KO, It' an object Promise, not string title
console.log('main Process: ' + title)

Выход

[INFO:CONSOLE(0)] main Process: [object Promise] 
[INFO:CONSOLE(0)] getTitle: Google
[INFO:CONSOLE(0)] prototype.getTitle: Google

2 ответа

Решение

Если вы используете новую версию NodeJS (например, io.js (узел 3.0) или выше), вы можете использовать yield вместе с Promise.coroutine от bluebird (это можно активировать в старых версиях, запустив --harmony-generators флаг):

Promise.coroutine(function*(){
    var title = yield driver.getTitle(); // yield makes it wait
    yield driver.findElement(By.name("q")).sendKeys("webdriver");
})();

Если вы используете babel, как подсказывает TJ, вы также можете использовать асинхронные функции:

(async function(){
    let title = await driver.getTitle();
    // ...
})();

Вы не можете, если API не делает это возможным каким-либо образом (см. Ниже). Если используемый вами Selenium API предназначен для асинхронной работы, вы не можете заставить его работать синхронно. Я не могу найти документацию для getTitle используемый вами вызов, но так как он возвращает обещание, а значение обещания доступно только через then обратные вызовы (и обещание, возможно, еще не выполнено, когда вы его получите), и, поскольку эти обратные вызовы всегда вызываются асинхронно (если они соответствуют Promises/A+), вам придется писать код, ожидающий асинхронность.

Вы можете сделать этот обратный вызов более кратким, если это ваша цель, используя функции стрелок ES6:

driver.getTitle().then((title) => {
   // .....
});
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');

Сейчас я думаю, что для использования функций стрелок с Node, вы должны использовать транспортер, такой как Babel.


Обратитесь к вашему обновлению, ссылаясь на документацию: API может предоставлять функцию, которая позволяет вам делать это: вы можете использовать wait, но трудно сказать, потому что документация не работает: пример показывает wait возвращение ожидаемой вещи (кнопка):

var button = driver.wait(until.elementLocated(By.id('foo'), 10000);
button.click();

... но в документации четко сказано wait возвращает обещание:

Возвращает

webdriver.promise.Promise<T>

Обещание, которое будет выполнено с первым истинным значением, возвращенным функцией условия, или отклонено, если условие истекло.

Если последнее неверно (что кажется вероятным), то

var title = driver.wait(driver.getTitle(), 10000);

... будет ждать до 10 секунд для названия. Или, если ваша цель на самом деле не получить заголовок, а получить элемент с именем q тогда это почти так же, как пример для wait выше:

driver.wait(until.elementLocated(By.name('q'), 10000).sendKeys('webdriver');
Другие вопросы по тегам