mindparse mindparse - 5 months ago 68
AngularJS Question

Protractor - testing an Angular form with dynamically populated inputs

I am trying to write an e2e test for my angular application, and in particular a form that has 3 select inputs on. The test will need to involve picking random options from these selects. The first select is already populated with data, but the other 2 selects asynchronously populate when the one before has been selected, so they are dependant on each other.

The select inputs also use ng-disabled and only enable when there are options available as per their ng-repeat expressions.

I am using the page object approach with my tests, and so am trying to make some utility functions to achieve the random selection behaviour I need in my tests:

Page Object:

this.selectRandomCustomer = function() {
var option,
randomIndex;
this.customerSelect.click();
this.customerSelectOptions.count().then(function(count) {
randomIndex = Math.floor(Math.random() * count);
option = element(by.repeater('customer in vm.customers').row(randomIndex));
option.click();
});
};

this.selectRandomOrder = function() {
if(this.orderSelect.isEnabled()===true) {
var option,
randomIndex;
this.orderSelect.click();
this.orderSelectOptions.count().then(function(count) {
randomIndex = Math.floor(Math.random() * count);
option = element(by.repeater('order in vm.orders').row(randomIndex));
option.click();
});
}
};


Given that the
orderSelect
can only be selected once populated with options after choosing an option from the
customerSelect
, I wondered about hooking into the promise returned when calling
this.customerSelectOptions.count()
, so calling
this.selectRandomOrder
, but it seems this is undefined as I get an error from protractor saying it cannot find the
selectRandomOrder
function.

Right now I can only get the first select to pick an option since it's always populated on the initial page load.

Also, I'm unsure whether using
isEnabled()
is actually working for me, as I am certain this should be returning true for my second input, but if I console log this out, I see false. Does this not work with
ng-disabled
?

What are the best practices for dealing with inputs on a form that wont initially be populated with data and waiting for angular to fetch and populate any available options?

Thanks

UPDATE:

I have got this to working using a call to
getAttribute()
checking for the presence of the
disabled
property instead.

So from my spec file in an
it
block I can call

page.customerSelect.getAttribute('disabled').then(function(result){
if(!result) {
page.selectRandomCustomer();
}
});

page.orderSelect.getAttribute('disabled').then(function(result){
if(!result) {
page.selectRandomOrder();
}
});


Ideally what I'd like to be able to do is to call the selectRandomOrder after clicking the option in the selectRandomCustomer:

this.selectRandomCustomer = function() {
var option,
randomIndex;
this.customerSelect.click();
this.customerSelectOptions.count().then(function(count) {
randomIndex = Math.floor(Math.random() * count);
option = element(by.repeater('customer in vm.customer').row(randomIndex));
option.click();
//Like to be able to call selectRandomOrder but only after angular has finished performing AJAX request for data and received response
});
};

this.selectRandomOrder = function() {
var option,
randomIndex;
this.orderSelect.click();
this.orderSelectOptions.count().then(function(count) {
randomIndex = Math.floor(Math.random() * count);
option = element(by.repeater('order in vm.orders').row(randomIndex));
option.click();
});
};


I did try calling
this.selectRandomOrder
immediately after the
option.click()
but I get an error saying no such function, it seems
this
is not accessible from inside the returned promise function callback.

Answer

There is at least one major problem in the posted code:

if(this.orderSelect.isEnabled()===true) {

Here isEnabled() returns a promise. You have to resolve it to check it's value:

var self = this;  // saving the page object reference
this.orderSelect.isEnabled().then(function (isEnabled) {
    if (isEnabled) {
        var option,
            randomIndex;
        self.orderSelect.click();
        self.orderSelectOptions.count().then(function(count) {
            randomIndex = Math.floor(Math.random() * count);
            option = element(by.repeater('order in vm.orders').row(randomIndex));
            option.click();
        });
    }
});