Protractor script doesn't work properly

2019-03-04 04:13发布

问题:

Here is exactly what I'm trying to do

I open a page with a table that contains information about users

I getText() of element that indicates a number of user in the table (f.e. "11 Users in list")

I remove " Users in list" part and convert a string into integer to use later in for loop

I need to find certain user by username (9th column) and get j number which is a number of a row this user's information is in (this is where I got stuck)

I go to first column of j row (its going to be edit button for this particular user) and click it to verify type of the user

One example of a code I tried

it("Validation of ND account", function() {
    //login
    element(by.id("j_username")).sendKeys($usernameND);
    element(by.id("j_password")).sendKeys($passwordND);
    element(by.buttonText("Login")).click();
    //navigate to a page with list of users displayed in a table
    element(by.xpath('//a[@short-title="Users"]')).click();
    //narrow the search result by typing 'testuser'
    element(by.model("userList.searchBox.options.query")).sendKeys($usernameND);
    //the table has 11 results such as 'testuser', 'testuser1', 'testuser2'
    //I get text of element with text '11 users in list' to get just the number out of it
    element(by.xpath('//div[@viewid="userList"]//div[@class="results-count ng-binding"]')).getText().then(function(numberOfUsers) {
        numberOfUsers = Number(numberOfUsers.replace(" Users in list",""));
        // declare a variable which will be responsible for accessing to j row in a table
        var j=1
        //I search through 11 rows from the table for my username
        for (i=1; i<numberOfUsers; i++) {

            element(by.xpath("(//td[@data-field='username'])["+j+"]")).getText().then(function(username){   

                if (username===$usernameND){
                    console.log("true");
                    console.log(j);
                    j++
                } else {
                    console.log("false");
                    j++
                }   
            }); 
        }   
    });     
});

this is what I get

true
1
true
2
true
3
true
4
true
5
true
6
true
7
true
8
true
9
true
10

So it does count but always returns true even though username are different (seem to check first row everytime). I try another approach

element(by.xpath('//div[@viewid="userList"]//div[@class="results-count ng-binding"]')).getText().then(function(numberOfUsers) {
    numberOfUsers = Number(numberOfUsers.replace(" Users in list",""));

    for (i=1; i<numberOfUsers; i++) {   
        element(by.xpath("(//td[@data-field='username'])["+i+"]")).getText().then(function(username){   

            if (username===$usernameND){
                console.log("true");
                console.log(i);
            } else {
                console.log("false");
            }       
        });     
    }       
});

I get

true
11
false
false
false
false
false
false
false
false
false

Now it accesses each row and seem to be fine, but on the first row it returns number 11. What's wrong? How to fix it?

P.S. I will give an example what I'm doing screenshot of the page I want to find my user and to click 'edit' button associated with it. I can just simply click on a cell in first column 6th row. But I want to make it reliable in case if more users will be added. To do this I need to search through username column, document the number of the row this user is located in the table, and then navigate to a cell in the first column on the row number I found.

回答1:

To be honest I didn't what are you checking.

First of all you should consider using

element.all(by.xpath("(//td[@data-field='username'])")) instead of element(by.xpath("(//td[@data-field='username'])["+j+"]"))

It returns elementArrayFinder. Assign it to a variable (eg. tableRows) and then you can handle with those data.

If you are trying to check whether the number in a string "11 Users in list" is correct, yuu can use tableRows.count()

You can also filter elements: http://www.protractortest.org/#/api?view=ElementArrayFinder.prototype.filter

use map: http://www.protractortest.org/#/api?view=ElementArrayFinder.prototype.map

Drop me a line what exactly test should do.

Edit:

Ok. Here you have code sample. It clicks EDIT link of defined user (TESTUSER26 in this case): The only change you have to make is change defineSelectorForUsernameCell into real value.

var tableRows = element.all(by.css('td'));
var searchedUsername = 'TESTUSER26';

return tableRows.filter((eachRow) => {
    return eachRow.element(by.css('defineSelectorForUsernameCell')).getText((usernameCellText) => {
        if (usernameCellText === searchedUsername) {
            return eachRow.element(by.linkText('EDIT')).click();
            }
    });
});


回答2:

Easy way for me was accessing tr of the user I was looking for in the table and then clicking the button edit in this row. Two examples

$username26="testuser26"
element.all(by.xpath('//trLocator')).first().element(by.xpath("//tr[.//td[@data-field='username' and text()="+$username26+"]]")).element(by.xpath(".//a[text()='Edit']")).click()

element(by.xpath("//td[@data-field='username' and text()='"+$username26+"']/..")).element(by.xpath(".//a[text()='Edit']")).click();

The important part to understand is a dot in the second xpath which means the current node. Without this dot "//" literally mean anywhere on the page vs ".//" which means starting from the element I've already selected

Now this is the long way, but this was the logic I was looking for

var tableRows = element.all(by.xpath('xpathTableRowsLocator')); //returns 11 rows
var mentricsLogo =  element(by.css('a.logo'));
var searchedUsername = "TESTUSER26";

//somehow the code didn't work by itself so I had to place it inside of random function whuch I didn't care about
mentricsLogo.isPresent().then(function(result) {
        return tableRows.filter(function(eachRow, index) {
//get text of the whole row and separate it by columns
            return eachRow.getText().then(function(text){
                text=text.split(" ")
// I get third element is username
                if (text[2]===searchedUsername){
                    var xpathIndex = Number(index)+1
                    element(by.xpath("//*[@id='user-list-content']/div[2]/div[2]/div[1]/div[2]/div[1]/table/tbody/tr["+xpathIndex+"]/td[1]/a")).click()
                }
            })
        });
});

I know it may look not rationally, but nothing else worked for me.