Angularjs E2E Testing with Angular-UI Select2 Element
Asked Answered
I

5

6

I have a partial with a select2 element utilizing Angular UI http://angular-ui.github.io/

The issue I am running into is that the element is required and although i have successfully set the field through the following code, the required attribute is not removed as Angular's model must not be updating due to the outside change and I am not sure how to either provide a $scope.apply() or utilize another function of Angular to continue the test.

First to allow for direct jQuery functions to run: (taken from How to execute jQuery from Angular e2e test scope?)

angular.scenario.dsl('jQueryFunction', function() {
return function(selector, functionName /*, args */) {
    var args = Array.prototype.slice.call(arguments, 2);
    return this.addFutureAction(functionName, function($window, $document, done) {
        var $ = $window.$; // jQuery inside the iframe
        var elem = $(selector);
        if (!elem.length) {
            return done('Selector ' + selector + ' did not match any elements.');
        }
        done(null, elem[functionName].apply(elem, args));
    });
};
});

Then to change the field value:

jQueryFunction('#s2id_autogen1', 'select2', 'open');
    jQueryFunction('#s2id_autogen1', 'select2', "val", "US");
    jQueryFunction('#s2id_autogen1', 'select2', 'data', {id: "US", text: "United States"});
    jQueryFunction('.select2-results li:eq(3)', 'click');
    jQueryFunction('#s2id_autogen1', 'trigger', 'change');
    jQueryFunction('#s2id_autogen1', 'select2', 'close');
    input('request._countrySelection').enter('US');

Note that not all of those functions are needed to reflect the changes to the ui, merely all that I have utilized to try and get this working...

Ilsa answered 20/8, 2013 at 16:49 Comment(0)
I
2

I was unable to get this to work within the Karma test runner, however this became significantly easier within the protractor test suite.

To accomplish this within the protractor test suite I used the following to select the first select2 box on the page and select the first option within that box:

var select2 = element(by.css('div#s2id_autogen1'));
select2.click();
var lis = element.all(by.css('li.select2-results-dept-0'));
lis.then(function(li) {
    li[0].click();
});

The next select2 on the page has an id of s2id_autogen3

Ilsa answered 31/1, 2014 at 16:11 Comment(1)
if the element has id attribute then the div created by select2 will be s2id_<id>Toowoomba
N
5

To get this to work I consulted both Brian's answer and sinelaw, but it still failed in my case for two reasons:

  1. clicking on 'div#s2id_autogen1' does not open the select2 input for me, the selector I used was 'div#s2id_autogen1 a'
  2. getting the select2 element I would get the ElementNotVisibleError, probably because my select2 is inside a bootstrap modal, so I explicitly wait for the element to be visible before clicking it (you can read the original hint I read to use this here).

The resulting code is:

function select2ClickFirstItem(select2Id) {
        var select2Input;

        // Wait for select2 element to be visible
        browser.driver.wait(function() {
            select2Input =  element(by.css('#s2id_' + select2Id + ' a'));
            return select2Input;
        }).then(function() {
            select2Input.click();

            var items = element.all(by.css('.select2-results-dept-0'));
            browser.driver.wait(function () {
                return items.count().then(function (count) {
                    return 0 < count;
                });
            });
            items.get(0).click();
        });
    }

Hope it helps.

Nelson answered 14/5, 2014 at 13:32 Comment(0)
I
2

I was unable to get this to work within the Karma test runner, however this became significantly easier within the protractor test suite.

To accomplish this within the protractor test suite I used the following to select the first select2 box on the page and select the first option within that box:

var select2 = element(by.css('div#s2id_autogen1'));
select2.click();
var lis = element.all(by.css('li.select2-results-dept-0'));
lis.then(function(li) {
    li[0].click();
});

The next select2 on the page has an id of s2id_autogen3

Ilsa answered 31/1, 2014 at 16:11 Comment(1)
if the element has id attribute then the div created by select2 will be s2id_<id>Toowoomba
K
2

I'll second what @Brian said if you use protractor and the new karma this has worked for me:

function uiSelect(model, hasText) {
    var selector = element(by.model('query.cohort')),
        toggle = selector.element(by.css('.ui-select-toggle'));

    toggle.click();

    browser.driver.wait(function(){
        return selector.all(by.css('.ui-select-choices-row')).count().then(function(count){
            return count > 0;
        });
    }, 2000);

    var choice = selector.element(by.cssContainingText('.ui-select-choices-row',hasText));
    choice.click();
};

use it like:

if the value of the item you want to select is "Q3 2013" you can provide it the model of the selector and an exact or partial text match of the item you want to select.

uiSelect('query.cohort','Q3 2013');

or

uiSelect('query.cohort','Q3');

will both work

Klondike answered 24/8, 2015 at 21:41 Comment(0)
W
0

I made it work under Karma with following changes.

Add following DSL to the top of your e2e test file:

angular.scenario.dsl('jQueryFunction', function() {
  return function(selector, functionName /*, args */) {
    var args = Array.prototype.slice.call(arguments, 2);
    return this.addFutureAction(functionName, function($window, $document, done) {
      var $ = $window.$; // jQuery inside the iframe
      var elem = $(selector);
      if (!elem.length) {
        return done('Selector ' + selector + ' did not match any elements.');
      }
      done(null, elem[functionName].apply(elem, args));
    });
  };
});

Then to change select2 value in your scenario use

it('should narrow down organizations by likeness of name entered', function() {
  jQueryFunction('#s2id_physicianOrganization', 'select2', 'open');
  jQueryFunction('#s2id_physicianOrganization', 'select2', 'search', 'usa');
  expect(element('div.select2-result-label').count()).toBe(2);
});
Wite answered 14/3, 2014 at 10:43 Comment(0)
F
0

Sometimes the select2 may take time to load, especially when working with ajax-loaded data. So when using protractor, and expanding on Brian's answer, here's a method I've found to be reliable:

function select2ClickFirstItem(select2Id) {
    var select2 = element(by.css('div#s2id_' + select2Id));
    select2.click();
    var items = element.all(by.css('.select2-results-dept-0'));
    browser.driver.wait(function () {
        return items.count().then(function (count) {
            return 0 < count;
        })
    });
    items.get(0).click();
}

This uses the fact that driver.wait can take a promise as a result.

Falchion answered 21/3, 2014 at 16:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.