0

In my angular protractor e2e tests, I want to do assertions on a html fragment like this:

<table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Age</th>
            <th>Gender</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Joe</td>
            <td>23</td>
            <td>M</td>
        </tr>
        <tr>
            <td>Mary</td>
            <td>26</td>
            <td>W</td>
        </tr>
        ...
    </tbody>
</table>

How can I convert that into a JavaScript object like this?

[
    {Name: 'Joe', Age: 23, Gender: 'M'},
    {Name: 'Mary', Age: 25, Gender: 'W'},
    ...
]

I tried this, but it gives me one dimensional array:

const row = element.all(by.css('tr'));
const cells = row.all(by.tagName('td'));
return cells.map(function (elm) {
  return elm.getText();
});
3
  • stackoverflow.com/questions/29501976/… seems not to work for me, because I did not create the table using ng-repeater. Commented Mar 2, 2018 at 12:34
  • you don't need a repeater for that, you can get lists of elements based on other selectors too.. Commented Mar 2, 2018 at 12:52
  • what you had is correct, you just need to create objects instead of just mapping on the columns Commented Mar 2, 2018 at 12:53

1 Answer 1

3

For your specific example, you can convert the HTML into a simple array of objects that match your needs:

function isHTMLTableElement(elem: HTMLTableElement | HTMLElement) : elem is HTMLTableElement {
    return elem.tagName === 'TABLE';
}

const table = document.getElementById('test');
const result: {name: string, age: number, gender: string}[] = [];

if (isHTMLTableElement(table)) {
    const rows: HTMLElement[] = [].slice.call(table.querySelectorAll('tbody tr'));
    for (const row of rows) {
        const cells: HTMLElement[] = [].slice.call(row.querySelectorAll('td'));
        const [name, age, gender] = cells.map(c => c.innerText);
        result.push({
            name: name,
            age: +age,
            gender: gender
        });
    }

    console.log(JSON.stringify(result));
}

You could collapse this further by replacing for loops with array methods, but I left it like this as it is probably more understandable.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks a lot! However, currently protractor complains: Failed: document is not defined
If possible, I would prefer a solution, that uses the th elements to produce the names. However, I can give it a try to figure it out by myself. The type safety (age as number) is not a priority for me.
You can do a similar trick on the thead > tr > th elements to get the names.
Indeed it helped me, But How can we make it dynamic, like the name,age,gender etc. columns should come dynamically

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.