get element attribute value in Protractor

33,058

Solution 1

I would not combine the wait and the getting attribute parts - logically these are two separate things, keep them separate:

browser.wait(function() {
    return element(by.id('element-id')).getAttribute("attribute").then(function(value) {
        item = value;
        // console.log(item);
        return value !== '';
    });
});

element(by.id('element-id')).getAttribute("attribute").then(function (value) {
    console.log(value);
});

Note that, you may simplify the wait condition this way:

var EC = protractor.ExpectedConditions;
var elm = $('#element-id[attribute="expected value"]');

browser.wait(EC.presenceOf(elm), 5000);
elm.getAttribute("attribute").then(function (value) {
    console.log(value);
});

Just FYI, you may have solved your current problem with the deferred:

function test() {
    getItem().then(function (value) {
        console.log(value);
    });
}

function getItem() {
    var item = protractor.promise.defer();
    browser.wait(function() {
        return element(by.id('element-id')).getAttribute('attribute').then(function(value) {
            var result = value !== '';
            if (result) {
                item.fulfill(value);
            }
            return result;
        });
    });
    return item.promise;
}

Solution 2

After doing some more reading about how protractor works with promises and schedules/registers them with the control flow, I found an easier work-around close to the first solution @alecxe provided. Here it goes:

function test() {
  var item = getItem().then(function(item) {
    console.log(item);
  });
}

function getItem() {
  return browser.wait(function() {
    return element(by.id('element-id')).getAttribute('attribute-name').then(function(value) {
      return value;
    });
  });
}

Since browser.wait() returns a promise itself, it can be chained with another then() inside the caller and this way the right order of execution is guaranteed.

Share:
33,058
exbuddha
Author by

exbuddha

Computer Science Consultant It is Null-safety check as a subject matter that will lead a developer to see that the requirement for languages as intensive as Kotlin to have to perform deep analysis of the code lies in the fact that compiled code can only be as optimized as possible when predictability becomes regularized. Designing with consistency is now truly within the grasp of developers. One of the many perks that follows the language's new approach to writing expressions and to invoking code blocks across different threads, is redefining what a logical context really is and how it can be formulated in code. Starting on the logical axis where your application is continuously diverging into states, each state representing a place in time where the user and the system are in an agreeing form of relationship, the only reason to denormalize them would be to preserve program memory at the cost of formulaic computation (runtime). This is a law that constitutes all angles revolving the subject of performance optimization for every computer program. A coroutine scope is an equivalent of a call-site (a logical enclosure, or the scope of execution). A coroutine context is a line of thought and execution. A coroutine (job) is a divergence from a line of thought, and a parent job is the reduction determinant inside its own context (a folding operation upon all or some of its elements). A determinant can stay alive by a join call, or die and promote all its children that are able to survive cancellation, or are non-cooperative, to parent jobs. Everything else in a Kotlin runtime environment is resolvable by the aid of concurrent models. Extended functions in general are a good design choice specially when your code is internal. Extended inline functions are always appropriate and will give your application an edge when it comes to writing code that scales across many hardware or device types. Chain-calling run, with, and let properly is your best starting option to providing and mixing call-sites at the current thread. The latter will not cause the penalty of a cast operation while the others may. Cover Letter and Resume Experience: Senior Android Developer Senior Unix Developer Test Automation Engineer Test Lead Sound Engineer Musician Projects: Consolator 1 - Android Work Engine - https://github.com/exbuddha/Consolator Log.kt - Kotlin Logger - https://github.com/exbuddha/Log.kt pond 1.0 - Bash Script Runner - https://github.com/exbuddha/pond Solar 0.0.0 - Paper on Music Analysis and Performance - https://github.com/exbuddha/Solar

Updated on July 09, 2022

Comments

  • exbuddha
    exbuddha almost 2 years

    I'm writing a Protractor test that has to wait for an element attribute to have a non-empty value and then I want to return that value to the caller function. This has proven to be more difficult to write than I expected!

    I am able to correctly schedule a browser.wait() command to wait for the element attribute to have a non-empty value and I have verified that this value is in fact what I am expecting to get inside the callback function, but for some reason, I am not able to return that value outside of the callback function and onto the rest of the test code.

    Here is how my code looks like:

    function test() {
        var item = getItem();
        console.log(item);
    }
    
    function getItem() {
        var item;
        browser.wait(function() {
            return element(by.id('element-id')).getAttribute('attribute-name').then(function(value) {
                item = value;
                // console.log(item);
                return value !== '';
            });
        });
        return item;
    }
    

    I can tell that the order of execution is not as I expect it to be, because when I uncomment the console.log() call inside the callback function, I see the expected value printed out. However, the same call in the test() function prints 'undefined'.

    What is going on here? What am I missing? How can I get the attribute value out of the callback function properly?

    I appreciate your help.

  • exbuddha
    exbuddha over 8 years
    Thanks! With some minor corrections, the last approach works in my case. I was hoping to be able to return the item value straight to the caller function but apparently this is not the right way of thinking when it comes to promises in asynchronous calls. The last line should be return item.promise;.