Parameterizing options dropdown lists in Protractor E2E tests - angularjs

I'm trying to get my protractor E2E tests to interact with a drop down menu.
In the page that I'm testing, we have a drop down for countries. The dropdown contains 4 selectable options "?" which is blank, and then US, UK, and Canada.
I'm obviously not calling the element correctly within my PO file, as the parameterization is not working. The tests "pass", however when you watch what is being driven, the country that is selected, is the "?" one(which is default). So the test is navigating to the page, selecting the element and not actually clicking on the option that I'd like.
From what I can tell, I need to somehow get the parameterized option that is inputed from the spec file to the element however i'm not really sure if this is possible.
What am I missing/doing wrong?
Spec file:
campaignPO.clickCountryLocation('US');
PageObject file:
this.countryType = by.css('select[ng-model="country"]');
this.clickCountryLocation = function(button) {
element(this.countryType).click(button);
};
Here is the element were working with:
<select class="form-control input-sm ng-pristine ng-invalid ng-invalid-required"
ng-size="11"
ng-model="country"
name="country"
ng-options="opt.value as opt.label for opt in countries"
ng-change="updateCountry()"
required="">
<option value="?" selected="selected" label=""></option>
<option value="0" label="US">US</option>
<option value="1" label="UK">UK</option>
<option value="2" label="Canada">Canada</option>
</select>

I'd use a select-option abstraction suggested here:
Select -> option abstraction
Example usage:
var SelectWrapper = require('select-wrapper');
var mySelect = new SelectWrapper(by.name('country'));
mySelect.selectByText('US');

First of all, you can simplify your select locator by using
var selectEl = element(by.model('country'));
I am not sure the attribute css works very well. To select options:
var optionEl = selectEl.element(by.cssContainingText('option', 'US'));
optionEl.click();
If you are just trying to open the select without selecting a value, don't. Selects are HTML components and you don't want to test them in this way. Even working with them in javascript is cumbersome. If you want to see what values are in there, list the option elements.

Related

How to select a value from dropdown using serenity screen play

I have a web page and from where I am trying to to select xpath from a drop down box which don't have any value by default.
<select id="country" class="multi ng-pristine ng-valid ng-empty ng-touched" ng-options="country as country.description for country in vm.countries" ng-change="vm.getDestinations()" ng-model="vm.country" style="">
<option value="?" selected="selected"></option>
<option label="Germany" value="object:589">Germany</option>
<option label="Austria" value="object:590">Austria</option>
<option label="Belgium" value="object:591">Belgium</option>
I have tried using Select.selectByVisibleText() but still not getting. I can find the country field but not able to select a particular country:
public Target selectCountry = Target.the("select country").located(By.xpath("//*[#id=\"app-container\"]/div[1]/span[3]/select[1]"));
Please suggest.
I am able to select the country now. It was not a serenity issue. I was getting to this page after doing some actions on the previous page. Actualy I had 2 separate "When" steps for actions on the previous page and current page. When I merged them in single "When" step then it has started selecting the country from the dropdown on the current page. I don't know why it has not worked with separate steps.
You can inherit (extends) PageObject class to utilize pre defined select class methods such as selectByVisibleText, selectByValue and selectByIndex.
#FindBy(id="country")
WebElementFacade dropDown_Country
public void selectDropDownValues(){
dropDown_Country.selectByVisibleText("Germany");
}
This can be called using Task like
actor.attemptsTo(Click.on(selectDropDownValues()));

How to pre-select option from <select> tag in Angular with options from a different controller?

I'm using two controllers here. One, productComponentsController, handles a call to our database that pulls back an array of productComponent objects. The other, AddEditArticleController, controls the 'Create New / Edit Existing Article' page.
On my Add/Edit Article page, I want a <select> to populate with productComponents, and, if I am editing an existing Article, to be pre-selected with that Article's current productComponent.
Simple as this seems, I cannot make the field pre-select with the existing productComponent, though it does populate the <select> with them correctly. I've tried ngRepeat and ngOptions and both work for populating the dropdown, but neither works for pre-selecting the existing productComponentID from the array returned by the server.
My HTML, using ngOptions:
<!-- productComponentsController as pvm, AddEditArticleController as vm -->
<select id="componentBox"
ng-model="vm.selectedComponent"
placeholder="Select a Product Component"
ng-change="vm.changeProductID()"
class="form-control input-md"
ng-options="component.name for component in pvm.productComponents track by component.id"></select>
My HTML, using ngRepeat:
<!-- productComponentsController as pvm, AddEditArticleController as vm -->
<select id="componentBox"
ng-model="vm.selectedComponent"
placeholder="Select a Product Component"
ng-change="vm.changeProductID()"
class="form-control input-md">
<option value="{{component.id}}"
ng-repeat="component in pvm.productComponents"
ng-selected="vm.selectOption(component.id)"
ng-bind-html="component.name"></option>
</select>
<!-- vm.selectOption() returns true if the current option's ID equals the productComponentID of the current Article. Therefore this option would be selected. -->
In my AddEditArticleController, I set vm.selectedComponent equal to the productComponentID of the Article that was returned by the database, in the promise.then() of my call. While vm.selectedComponent does change, this doesn't do anything to the dropdown.
Also, in my generated HTML, I get the option: <option value="? number:47 ?"></option> (for an Article where the productComponentID is = 47). Apparently this happens as a result of the model being set to an unknown value but I don't know why the model would be set to anything other than an integer id.
Is this because my select is accessing multiple controllers, or am I missing something obvious here? Any help is greatly appreciated, let me know if more info is needed.
I believe you're looking for ng-init...
<!-- productComponentsController as pvm, AddEditArticleController as vm -->
<select id="componentBox"
class="form-control input-md"
placeholder="Select a Product Component"
ng-change="vm.changeProductID()"
ng-model="vm.selectedComponent"
ng-init="vm.selectedComponent=productComponentID"
ng-options="component as component.name for component in pvm.productComponents track by component.id"></select>
So it turns out that because the model has to be a string, I have to cast the vm.selectedOption to a string whenever it's changed (in this case, in the vm.selectOption function) using String(). This is using ngRepeat. ngInit seems to have no bearing on how my code works.
Boom, that's it, and my code works.

why display:none for "Select a option" in select in angular js?

This is code for showing "select a option" in dropdown(select).
<select ng-model="form.type" required="required"
ng-options="option.value as option.name for option in typeOptions" >
<option style="display:none" value="">select a option</option>
</select>
can anybody explain me what is going on behind this code and what is use of display : none in that?
The ng-options directive is like repeater and it will generate options and it will place them after the one with the disply:none which will be selected initially. Check the documentation for more info.
The idea behind the display:none option is to be hidden when the select is expanded so that you end up with valid selection.
With style="display:none" you wont be able to select 'select a option' from the dropdown list. Other than that your selection will be the value of option option.value but the text too choose from will be the name of option as option.name and each option comes from typeOptions.
I found this fiddle, try and remove the style="display:none" and see what happends, also try and remove the whole <option style="display:none" value="">select a option</option> line
The Angular select directive does this because of a wrinkle and how the select control works in the browser. If the select control initially has a value of "X", but there is no option element with value "X", the browser will automatically choose the first option from the list; without the user actually doing so. This is quite unhelpful, as it both generates a spurious change which Angular would then detect, and defeat the likely intention of the "required" setting, which is to require that the human (not the browser, automatically) make a choice.
In your example above, the value is the empty string "", but the same idea applies.
In the "bad old days" of programming the browser DOM by hand, this was also necessary for the same reasons.

Angular set error for required although option is selected

I have this code (there is $index because select's are inside ng repeater, I have more than one dynimally generated)
<select name="udaljenosti_{{$index}}" ng-model="attribute.Choices.Id" class="form-control" required>
<option value="" >--Choose--</option>
<option ng-repeat="choice in attribute.Choices" value="{{choice.Id}}" ng-selected="choice.IsSelected==true">
{{choice.Name}} </option>
</select>
There is IsSelected property on choice as you can see. If all choices have IsSelected==false, on submit I get error that some option is required because of required property on select, and when I choose some option on select and hit submit there is no error. Very good, so far. But, when some option is prepopulated from the database there is some strange behaviour. Everything seems good but when I click submit angular says there is error on select field. It says select is required but some option is already selected!!
EDIT: it seems name ang ng-model should much. How to accomplish this because I get error if I put uudaljenosti_{{$index}} inside ng-model?

protractor test failing because ElementNotVisibleError after adding ng-if directive

I have a web element which the test was able to find until we intruduce ng-if directive to the same. Now my test is not able to find the web element:
ElementNotVisibleError: element not visible
<select ng-if="tasktypepermission" id="elementType" ng-model="task.elementType" ng-options="key as value for (key, value) in elementTypeoptions" name="elementType" class="span3 ng-scope ng-pristine ng-valid errorForInput" data-trigger="blur focusout" tasknumber-validator="" ng-disabled="task.id">
<option class="blank" value="">Select</option>
<option value="1">Val1</option>
<option value="2">Val2</option>
<option value="3">Val3</option>
</select>
The way I am accessing the element is:
var taskType = function(){ return element(by.id('elementType'));};
What should I do to make it work? I am very new to protractor or even front end testing, so please bear with me.
I suggest to try using elementExplorer. you can try to find the requested element in multiple ways (by class,name, ng-model).
it could make things clearer - especially if you are new to protractor.
please let me know if you don't know how to use it.

Resources