Как сделать 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');