0

I am using Nightwatch.js to test a website. On this website there is a table which looks like this:

<tr>
    <td class="sorting_1">...</td>
    <td class="sorting_2">...</td>
    <td class="sorting_3">...</td>
    <td class="sorting_3">...</td>
</tr>

Now I want to check if this table contains the correct words. I found out that it is possible to select an element this way:

'td[class="sorting_2"]'

I can get the text with this command:

.getText('td[class="sorting_2"]', function(result){
    this.assert.equal(result.value, 'Testbenutzer');
})

But what do I have to do if I want to select one of two equally defined elements like in the list above. The last two elements both have the class sorting_3. How can I get the nth element of the table with a special class. I already tried this:

'td:nth-of-type(1)[class="sorting_3"]'
'td:nth-child(1)[class="sorting_3"]'
'td[class="sorting_3"]:nth-child(1)'
'td:nth-child(3)'

Nothing of this worked. How can I do it?

Garrarufa
  • 1,145
  • 1
  • 12
  • 29

3 Answers3

1

You could use the [<n>] notation to select the first, or second, etc.

//td[@class="sorting_3"][1]
//td[@class="sorting_3"][2]

The values of 1 and 2 correspond to the first and second, respectively.

function find_nodes(selector, callback)
{
  var result = document.evaluate(selector, document);

  var node = result.iterateNext();
  while (node) {
    callback(node);
    node = result.iterateNext();
  }
}

find_nodes('//td[@class="sorting_3"][1]', function(node) {
  node.style.backgroundColor = 'lightgreen';
});

find_nodes('//td[@class="sorting_3"][2]', function(node) {
  node.style.backgroundColor = 'lightblue';
});
<table>
<tr>
    <td class="sorting_1">foo</td>
    <td class="sorting_2">bar</td>
    <td class="sorting_3">baz</td>
    <td class="sorting_3">qux</td>
</tr>
</table>
Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
  • unfortunately this leads to an error message. this seems not to be supported by nightwatch.js – Garrarufa Jun 15 '15 at 08:12
  • @Garrarufa what's the error message? if it supports xpath selectors, it should be able to handle this. – Ja͢ck Jun 15 '15 at 08:14
  • ReferenceError: document is not defined – Garrarufa Jun 15 '15 at 08:20
  • @Garrarufa I didn't even mention `document` in my answer; the code snippet is just there to demonstrate it works in a browser that supports it. The important part is the selector path itself. – Ja͢ck Jun 15 '15 at 08:21
  • ok, but when i use the selector it gives me this error message: `ERROR: Unable to locate element: "td[class="sorting_3"][2]" using: css selector ` – Garrarufa Jun 15 '15 at 08:43
  • @Garrarufa Hmm, could you try with `//td` instead? – Ja͢ck Jun 15 '15 at 08:44
  • this is the same: `ERROR: Unable to locate element: "//td[class="sorting_3"][2]" using: css selector ` – Garrarufa Jun 15 '15 at 08:49
  • @Garrarufa Perhaps you should check [this thread](https://github.com/beatfactor/nightwatch/issues/33) out regarding XPath selector support. – Ja͢ck Jun 15 '15 at 08:51
1

The only way I can think of accessing multiple .sorting_3 elements, without knowledge of how Nightwatch.js actually works, is to pass it siblings ~ combinator selector.

i.e.: when you want to select the first element out of .sorting_3 elements, you would do this:

.getText('td[class="sorting_3"]', function(result){
    this.assert.equal(result.value, 'Testbenutzer');
})

And for second element:

.getText('td[class="sorting_3"] ~ td[class="sorting_3"]', function(result){
    this.assert.equal(result.value, 'Testbenutzer');
})

And so on ...

Problem is, this approach is not scalable. You will need to know ahead of time how many elements are you expecting in the .sorting_3 selector.

Hope this helps.

Tahir Ahmed
  • 5,687
  • 2
  • 17
  • 28
  • Glad it helped. While I am at it, you could also shorten the selectors by using `$` symbol to select class names ending at `_3`. So your selector would become `td[class$="_3"]`. I think this is a nice feature to know too wouldn't you agree? – Tahir Ahmed Jun 15 '15 at 08:59
  • i tried this for a mac address input, but it only works for the first three elements. is there a limit? – Garrarufa Jun 29 '15 at 08:35
  • as I mentioned, this approach doesn't *scale* well. Tell me more about what you are trying to do now? May be we can find a way to solve it too. – Tahir Ahmed Jun 29 '15 at 10:08
  • thank you for your answer. i noticed that i don't need to access every single field explicitly – Garrarufa Jun 29 '15 at 10:44
  • We are still talking about Nightwatch.js right? Since it is built on top of Selenium, there must be a way to directly call & utilise Selenium API. I believe Selenium exposes handful of very useful methods: [[Link](http://nightwatchjs.org/api#protocol)]. – Tahir Ahmed Jun 29 '15 at 15:05
  • now i face a similar problem again. i have a table and want to get the 6th column of the thead tag. How can i do this? – Garrarufa Jul 06 '15 at 08:28
  • can't you form the selector in similar way like: `'td[class="sorting_3"] ~ td[class="sorting_3"] ~ td[class="sorting_3"] ~ td[class="sorting_3"] ~ td[class="sorting_3"] ~ td[class="sorting_3"]'`? – Tahir Ahmed Jul 06 '15 at 08:36
1

You can use the solution that Jack proposed(//td[@class="sorting_3"][1]), but you have to set Nightwatch to use xPath as the locateStrategy. From the errors you were getting, your default locateStrategy appears to be CSS. See this command in the API reference

suntruth
  • 341
  • 1
  • 3