1

I'm trying to create a program to google search using selenium
based on this answer, so far the code looks like this

const { Builder, By, Key, until } = require('selenium-webdriver');

const driver = new Builder().forBrowser("firefox").build();

(async () => {
    await driver.get(`https://www.google.com`);

     var el = await driver.findElement(By.name('q'));
     await driver.wait(until.elementIsVisible(el),1000);
     await el.sendKeys('selenium');

     var el = await driver.findElement(By.name(`btnK`));
     await driver.wait(until.elementIsVisible(el),1000);
     await el.click();

    console.log('...Task Complete!')
})();

but writing

var el = await driver.findElement(By.something('...'));
     await driver.wait(until.elementIsVisible(el),1000);
     await el.do_something();

everytime becomes difficult so I tried to make a function like this:

const { Builder, By, Key, until } = require('selenium-webdriver');

const driver = new Builder().forBrowser("firefox").build();

async function whenElement(by_identity,timeout=1000){
  var el = await driver.findElement(by_identity);
  await driver.wait(until.elementIsVisible(el),timeout);
  return el;
}

(async () => {
    await driver.get(`https://www.google.com`);

     await whenElement(By.name('q')).sendKeys('selenium');

     await whenElement(By.name('btnK')).click();

    console.log('...Task Complete!')
})();

but it gives this ERROR:

UnhandledPromiseRejectionWarning: TypeError: whenElement(...).sendKeys is not a function

My aim is to reduce the number of variables and make it as simple as possible
so what exactly am I doing wrong here?

1 Answers1

0

There seems to be an error with the promises. You can only invoke a function on the actual element returned by the Promise and not the promise itself. You must first wait for the promise that waits for the element whenElement to resolve and then you can use the element and wait for the promise returned by sendKeys to resolve.

const el = await whenElement(By.name('q'));
await el.sendKeys('selenium');

or

await (await whenElement(By.name('q'))).sendKeys('selenium');

or

await whenElement(By.name('q')).then(el => el.sendKeys('selenium'));
doberkofler
  • 9,511
  • 18
  • 74
  • 126
  • Thanks this works ! but is there way to reduce the await keywords? I'm going to be using this function a lot in bigger projects so it's really inefficient to write await every single time –  Jun 12 '21 at 19:34
  • If you just want to reduce the number of await you could use `then` as I show in my updated answer but generally speaking you will still have to wait for almost every call to the browser when using the selenium driver for JavaScript. Alternatively you could clearly create special functions like for example a `whenElementSendKey` that combines the lookup and the sendKeys functionality. This reduces the complexity of the individual calls, but leaves you with a large number of very specific functions. – doberkofler Jun 12 '21 at 20:04
  • You could also use a "higher order" function that executes the promises sequentially as for example discussed here: https://stackoverflow.com/questions/43082934/how-to-execute-promises-sequentially-passing-the-parameters-from-an-array – doberkofler Jun 12 '21 at 20:04