hungryhippos
hungryhippos

Reputation: 637

Find a way to interact with the list generated by scriptAll() with filter

Scenario: I have a table where I am trying to iteratively go through each row that matches my expected text and grab a particular column value for that row.

The html looks something like this:

<table class="table">
    <tbody>
        <tr xpath="1">
            <td>
                <a href="link">Write</a> &nbsp;
            </td>
            <td>
                123
            </td>
            <td>
                1.0.1.8
            </td>
            <td>
                TargetProduct1
            </td>
            <td>
                
            </td>
            <td>
                P1
            </td>
            <td>
                10.0
            </td>
            <td>
                en-US
            </td>
            <td>
        </tr>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
</tbody>
</table>

On that table, my goal is to go through each row and pick any row that has the value of "TargetProduct" and get the fifth column value of that row.

I am using the following Karate command:

* def getProduct = scriptAll('//table//tbody//tr', '_.innerText', function(x){ return x.contains('TargetProduct') })

However, when I do a karate.log on getProduct, I get something like the following:

Write  123 1.0.1.8 TargetProduct1       P1 10.0 en-US
Write  4586 1.0.1.3 TargetProduct5      Test2 10.1  en-US
Write  134 1.0.1.1 TargetProduct0       Four2 10.3  en-US
Write  3 1.0.1.2 TargetProduct2     Boo3 10.1   en-US

Along with many more like it under it (due to each row that matches the criteria).

It looks like primitive data structure, but I am not well versed in JS to know that. However, my goal is to grab the 5th index of each sets of results like above (basically generate a list with just these values: (P1, Test2, Four2, Boo3). What is one way to do that? Historically I have been able to get values using keys (i.e targetJson.result). However, there are no keys in this case to call to.

I have looked over JSON Transforms section of the documentation and I have tried some potential solutions like mapWithKey, however, they have not worked due to the strange data structure.

Please advise.

Upvotes: 1

Views: 165

Answers (2)

don_aman
don_aman

Reputation: 327

You could return an array from the JavaScript expression, containing a first value for filtering and a second string containing the text from your fifth column.

* def filter = function(x){ return x[0].contains('TargetProduct') }
* def rows = scriptAll('//table//tbody//tr', 'function(e){ return [e.innerText, e.cells[4].innerText] }', filter)
* def fifthCols = map(rows, function(x){ return x[1] })

Upvotes: 1

Peter Thomas
Peter Thomas

Reputation: 58088

First, read up on innerText to see what it does: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText - it just returns a single string, concatenating all child elements.

Suggestion: try to do this in multiple steps:

* def rows = locateAll('//table//tbody//tr')
* def filtered = rows.filter(x => x.text.includes('TargetProduct'))
* def temp = filtered.map(x => x.locateAll('td'))

What I have above is a guess, sorry I don't have time to dig into the details.

Upvotes: 1

Related Questions