webdriverIO tips: using $$(selector) vs browser.elements(selector)
Tags: webdriverio, testing, webdev, javascript
Published: 2018-11-12 21:46:08

---
title: webdriverIO tips: using $$(selector) vs browser.elements(selector)
published: true
description: 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
tags: webdriverIO, testing, webdev, javascript
canonical_url: https://www.intricatecloud.io/2018/11/webdriverio-tips-using-selector-vs-browser-elementsselector/
---

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](http://webdriver.io/api/utility/$$.html) 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](https://github.com/webdriverio/webdriverio/issues/2728)) - 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](http://webdriver.io/api/protocol/elementIdClick.html), then use `browser.elements(selector)`.