webdriverIO tips: using $$(selector) vs browser.elements(selector)

Last week, I started working on integrating a test suite previously built using Nightwatch, and making it work with webdriverIO. While I love all of webdriverIO's features like synchronous code when using their test runner and a REPL, there were a few things that I'd like to share which were a little hard to find in the docs or on a quick search.

Each day this week, I'll be posting one thing I've learned while getting started with webdriverIO. Here's the tip for today

Using $$.selector vs browser.elements(selector)

One of the first use cases I tackled in my test was finding all elements with a particular CSS class and then doing something to them. The docs seem to indicate that browser.$$(selector) is a shorthand for browser.elements(selector) and they seem to be synonymous except for a small difference:

$$(selector) will return items that you can take an action like .click() on
.elements(selector) returns a WebElement JSON object (see more info about it on the github issue) - but its basically a JSON object that contains an ID (looks like a decimal number).

If you try to click on the first element in a group using something like browser.elements(selector)[0].click(), you might get an error like Can't call click on undefined because it does not return an array, but an object containing a key called value which has Ids for those elements.

Here's an example of the value of $$(selector)

> browser.$$(".link-gray-dark")
[ { ELEMENT: '0.15821111822631395-1',
    'element-6066-11e4-a52e-4f735466cecf': '0.15821111822631395-1',
    value: { ELEMENT: '0.15821111822631395-1' },
    selector: '.link-gray-dark',
    index: 0 },
  { ELEMENT: '0.15821111822631395-2',
    'element-6066-11e4-a52e-4f735466cecf': '0.15821111822631395-2',
    value: { ELEMENT: '0.15821111822631395-2' },
    selector: '.link-gray-dark',
    index: 1 },
    ....

and now compare that to browser.elements(selector)

> browser.elements(".link-gray-dark")
{ sessionId: '651d1e513eb87326a67969d65bbd597c',
  value:
   [ { ELEMENT: '0.15821111822631395-1',
       'element-6066-11e4-a52e-4f735466cecf': '0.15821111822631395-1',
       selector: '.link-gray-dark',
       value: [Object],
       index: 0 },
     { ELEMENT: '0.15821111822631395-2',
       'element-6066-11e4-a52e-4f735466cecf': '0.15821111822631395-2',
       selector: '.link-gray-dark',
       value: [Object],
       index: 1 },

For the most part, I can do everything I want to do with $$(selector) since I'll usually try to find a group of elements and either click on them or input text on some of them.

One reason you might want to use browser.elements(selector) instead would be if you needed to use one of the webdriver Protocol methods like elementIdClick(id) or elementIdName(id), and elementIdScreenshot(id) (which will take a screenshot of ONLY the element you want and not the whole page, neat!). Webdriver gives you a nice API so that you generally don't need to use these methods, but there are some nice features there if you do need to use them.

Recap

Prefer to use $$(selector) since it should be enough for the majority of your use cases.

If you need access to some of the elementId* methods like elementIdClick(id) that show up under the Protocol section in the docs, then use browser.elements(selector).

You might be interested in…

Menu