Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protractor Find and Click Element

Tags:

protractor

I have a pretty simple setup. I need to be able to find a link and click it. But whenever I find it and click() it i get

StaleElementReferenceError: stale element reference: element is not attached to the page document

Can someone explain to me what I am doing wrong? If I target it via css it works fine. Its only when I used the protractor extensions that it fails. Nothing is changing on the page and I have tried doing a "waitForAngular" as well as a long timeout. Same result.

<li ng-click="getLocation(l)" class="" ng-repeat="l in location"  >
   <div class="location_name">{{ l.LocationID }} - {{l.LocationName}}</div>
</li>

var locations= element.all(
    by.binding('{{l.LocationName}}'))
    .each(function(item){
        item.getText().then(function(text){
            if(text == name){
                console.log("found", item);
                item.click()
                console.log("clicked")
                found = true;
            }
        });
    });

An added plus would be to explain to me how to get the debugger working. I'm using the latest version of protractor(0.20.1)

Failed to open socket on port 5858, waiting 1000 ms before retrying

Ex Dump

StaleElementReferenceError: stale element reference: element is not attached to the page document
  (Session info: chrome=33.0.1750.146)
  (Driver info: chromedriver=2.9.248307,platform=Mac OS X 10.9.1 x86_64) (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 5 milliseconds
For documentation on this error, please visit: http://seleniumhq.org/exceptions/stale_element_reference.html
Build info: version: '2.40.0', revision: 'fbe29a9', time: '2014-02-19 20:54:28'
System info: host: '.home', ip: '192.168.1.2', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.9.1', java.version: '1.6.0_65'
Session ID: 935f7630f50d9b1b4c8da73261e54153
Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities [{platform=MAC, acceptSslCerts=true, javascriptEnabled=true, browserName=chrome, chrome={userDataDir=/var/folders/qj/xvhg6hv5245cryry73wygbkw0000gn/T/.org.chromium.Chromium.b5z7Xe}, rotatable=false, locationContextEnabled=true, version=33.0.1750.146, takesHeapSnapshot=true, cssSelectorsEnabled=true, databaseEnabled=false, handlesAlerts=true, browserConnectionEnabled=false, nativeEvents=true, webStorageEnabled=true, applicationCacheEnabled=false, takesScreenshot=true}]
   Stacktrace:
     Error
    at null.<anonymous> (/Users//work////selenium/spec/locationsSpec.js:21:3)
    at Object.<anonymous> (/Users//work////selenium/spec/locationsSpec.js:7:1)
At async task:
      StaleElementReferenceError: stale element reference: element is not attached to the page document
  (Session info: chrome=33.0.1750.146)
  (Driver info: chromedriver=2.9.248307,platform=Mac OS X 10.9.1 x86_64) (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 5 milliseconds
For documentation on this error, please visit: http://seleniumhq.org/exceptions/stale_element_reference.html
Build info: version: '2.40.0', revision: 'fbe29a9', time: '2014-02-19 20:54:28'
System info: host: '.home', ip: '192.168.1.2', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.9.1', java.version: '1.6.0_65'
Session ID: 935f7630f50d9b1b4c8da73261e54153
Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities [{platform=MAC, acceptSslCerts=true, javascriptEnabled=true, browserName=chrome, chrome={userDataDir=/var/folders/qj/xvhg6hv5245cryry73wygbkw0000gn/T/.org.chromium.Chromium.b5z7Xe}, rotatable=false, locationContextEnabled=true, version=33.0.1750.146, takesHeapSnapshot=true, cssSelectorsEnabled=true, databaseEnabled=false, handlesAlerts=true, browserConnectionEnabled=false, nativeEvents=true, webStorageEnabled=true, applicationCacheEnabled=false, takesScreenshot=true}]
==== async task ====
WebElement.getText()
    at element.(anonymous function) [as getText] (/Users//work////selenium/node_modules/protractor/lib/protractor.js:599:32)
    at /Users//work////selenium/helpers/locations.js:10:18
    at /Users//work////selenium/node_modules/protractor/lib/protractor.js:367:11
    at Array.forEach (native)
    at /Users//work////selenium/node_modules/protractor/lib/protractor.js:366:13
==== async task ====
asynchronous test function
like image 499
Nix Avatar asked Jun 05 '26 15:06

Nix


1 Answers

I believe the underlying issue was I was navigating away while the getText was being called. The below block of code accomplishes what I needed

LocationsPage.prototype.goTo = function(name) {
    var locations  = element.all(by.repeater('l in location'));
    expect(locations.count()).toNotBe(0);
    return locations.map(
            function(locationElement, index) {
              return {
                index: index,
                text: locationElement.getText()
              };
            }
    ).then(function(items) {
      _.each(items, function(item) {
        if (item.text == name) {
            console.log("clicking ", name)
            locations.get(item.index).click();
        };
      });
    });
}

* Leaving the below here just in case someone wants an example of how to do a more complicated/custom promise flow*

I found a solution but its way to complicated. Hoping someone can help me simplify this..

I believe the underlying issue was I was navigating away while the getText was being called.

LocationsPage.prototype.goTo = function(name){
    var locations  = element.all(by.repeater('l in location'));
    expect(locations.count()).toNotBe(0);
    return protractor.promise.createFlow(function(flow){
        var found;
        var locations  = element.all(by.repeater('l in location'));
        var searchPromise = protractor.promise.defer();
        flow.execute(function(){
            var idx = 0, found = -1;
            locations.each(function(item){
                var _idx = idx;
                if(found >= 0){
                    console.log("skipping")
                    return;
                }
                item.getText().then(function(text){
                    if(text == name){
                        console.log("setting found.")
                        found = _idx;
                    }
                    if(found >= 0 || _idx === locations.count()-1){
                         searchPromise.fulfill(found);
                    }
                });
                idx++;
            });
            return searchPromise.promise;
        })
        flow.execute(function(){
            var promise = protractor.promise.defer();
            searchPromise.then(function(idx){
                locations.get(idx).click().then(function(){
                    promise.fulfill(true);
                });

            })

            return promise.promise;
        });
    });

}

You will notice some other stuff in there protractor.promise.createFlow I had to use that because my expects where not being correctly resolved when I used just protractor.promise.defer()

like image 178
Nix Avatar answered Jun 07 '26 23:06

Nix