Protractor - count elements in repeater and print it - angularjs

I'm trying to count the elements in repeater and to print it to console.
This is the markup:
<div class="col-md-3 ng-scope" ng-repeat="app in userApps" >...< /div>
currently I'm counting and comparing:
expect(element.all(by.repeater('app in userApps')).count()).toEqual(4);
it works, but I want to be able to print it also.
I've tried this:
var rows = element.all(by.repeater("app in userApps"));
var sum = rows.count();
console.log(sum.getText());
but I'm getting:
TypeError: Object [object Object] has no method 'getText'
there are two question actually-
1. am I doing it the correct way?
2. how do I print it to console?

If I understand your problem correctly, you actually want to print the count and not the entire content, right?
element.all(by.repeater('app in userApps')).count().then(function(count) {
console.log(count);
});

the more 'modern' way of doing this is using async/await
it('test case', async () => {
let count = await element.all(by.repeater('app in userApps')).count();
console.log(count);
});

Related

Loop Object and Array when Array is inside of an Object

I am using a query to receive a JSON response. I would like to loop each object (VGF, SSR, BCV, etc..) and output them to premade divs, then the arrays within those objects will loop and create divs within that matching object container.
This is a shortened down version of what I have, and it works mostly. (hopefully, I haven't screwed it up here).
The problem is I have to repeat the searchresult function by copying and pasting the entire function for each object (VGF, SSR, BCV, etc). I would really like to learn how to loop this and not have the same code pasted more than a dozen times.
If I have messed up or left something out of this question, please let me know and I will take care of it.
Here is my ajax request and javascript. I know my problem lies within this loop. I have tried to do a loop inside of a loop, etc. But, when I do that I get no results at all. I am baffled and ready to learn.
$(function getData() {
$("#searchbtn").click(function () {
$.ajax({
url: "action.php",
type: "POST",
data: {},
dataType: "json",
success: function (response) {
console.log(response);
searchresult(response);
}
});
});
});
let searchresult = function(response) {
let container = document.getElementById('VGFresults');
let output = "";
for (let j = 0; j < response.length; j++) {
if (response[j].rcode == "VGF") {
output +=
`<div id="person${response[j].code}">
<p>${response[j].firstname} ${response[j].lastname}</p>
</div>`
}
$(container).html(output);
}
};
Here is my response (Same layout as I am currently receiving but shortened the objects in the arrays).
response =
{"VGF":
[{"code":"TU","rcode":"VGF","firstname":"Tom","lastname":"Riddle"},
{"code":"AZ","rcode":"VGF","firstname":"Harry","lastname":"Potter"},
{"code":"FR","rcode":"VGF","firstname":"Hermoine","lastname":"Granger"}],
"SSR":
[{"code":"HG","rcode":"SSR","firstname":"Walt","lastname":"Disney"},
{"code":"TR","rcode":"SSR","firstname":"H.R.","lastname":"Pickins"},
{"code":"ED","rcode":"SSR","firstname":"Tom","lastname":"Ford"}],
"BCV":
[{"code":"YH","rcode":"BCV","firstname":"Tom","lastname":"Clancy"},
{"code":"RS","rcode":"BCV","firstname":"Robin","lastname":"Williams"},
{"code":"AB","rcode":"BCV","firstname":"Brett","lastname":"Favre"}]}
Here is the HTML that the searchresult function is working with. Currently, it works fine.
To clarify, I would like each object to insert its arrays within the corresponding div. Example:
SSR arrays will go into <div id="SSRresults">
BCV arrays will go into <div id="BCVresults">
From there, each array will create a div within that *results div for each array.
<div id="VGFresults">
<div id="VGFheader">This is the VGF Header</div>
<div id="VGFresults">The Javascript Creates Divs for each array here.</div>
</div>
<div id="SSRresults">
<div id="SSRheader">This is the SSR Header</div>
<div id="SSRresults">The Javascript Creates Divs for each array here.</div>
</div>
<div id="BCVresults">
<div id="BCVheader">This is the BCV Header</div>
<div id="BCVresults">The Javascript Creates Divs for each array here.</div>
</div>
Thanks, any help is much appreciated.
I would do like this:
I declare the response as variable (but sure it will work with your ajax response.
var response =
{"VGF":
[{"code":"TU","rcode":"VGF","firstname":"Tom","lastname":"Riddle"},
{"code":"AZ","rcode":"VGF","firstname":"Harry","lastname":"Potter"},
{"code":"FR","rcode":"VGF","firstname":"Hermoine","lastname":"Granger"}],
"SSR":
[{"code":"HG","rcode":"SSR","firstname":"Walt","lastname":"Disney"},
{"code":"TR","rcode":"SSR","firstname":"H.R.","lastname":"Pickins"},
{"code":"ED","rcode":"SSR","firstname":"Tom","lastname":"Ford"}],
"BCV":
[{"code":"YH","rcode":"BCV","firstname":"Tom","lastname":"Clancy"},
{"code":"RS","rcode":"BCV","firstname":"Robin","lastname":"Williams"},
{"code":"AB","rcode":"BCV","firstname":"Brett","lastname":"Favre"}]}
let searchresult = function(response) {
// let container = document.getElementById('VGFresults');
let output = "";
for (var key in response) {
// skip loop if the property is from prototype
if (!response.hasOwnProperty(key)) continue;
var obj = response[key];
let container = document.getElementById(key+'results');
for (var prop in obj) {
// skip loop if the property is from prototype
if (!obj.hasOwnProperty(prop)) continue;
// your code
//alert(prop + " = " + obj[prop]);
console.log(obj[prop])
output += "<div id="+prop+"><p>"+obj[prop].firstname+" "+ obj[prop].lastname+"</p></div>"
}
}
container.innerText = output;
console.log(output);
};
<div id="VGFresults"></div>
each property VGF, SSR, BCV and so on can be handled now.
EDIT: based on users request, I guess you can edit the selector like this:
let container = document.getElementById(key+'results');

In Cypress to test getting total number of elements from listbox and then according to the data run in loop and as per each data perform an if

In Cyress Test writing an test of react application when I click on a Listbox in the drop down it get list of data.
eg : 123a, 1233, 111c etc suppose have count 50
then select each 1 by 1 however need to compare each that if its certain account perform certain checks
in details:
have searched and clicked the listbox but the issue i am facing how can i find the total number of elements in that listbox and need to traverse each item/value 1 by 1 and when select verify certain asserts.
so 3 challenges where i am stuck
1) How to get total number of elements have tried initial count=cy.get('#alias').length seems not working.
2) after we get how can I iterate through the loop 1 at a time as after selecting 1 item as have to certain assertions.
Thanks
Varun Awasthi
First:
cy.get("alias").length can never work because of the async structure of cypress. The get() returns never the wrapped element but a chainable. Thus you would have to write something like get(..).then(obj => ...)
Second:
Given this HTML structure:
<div>
<div class="item">
...many other html code
</div>
<div class="item">
...many other html code
</div>
<div class="item">
...many other html code
</div>
</div>
You can get the length ( = the mount of item elements) like this:
it("test", () => {
cy.get(".item").should($items => {
cy.log(`amount: ${$items.length}`)
})
})
Third:
Please try something like this:
it("test", () => {
cy.get(".item").each($item => {
cy.wrap($item).should($e => {
expect($e.text()).to.eq("test")
})
})
})
But you must not use cypress commands here. Something like this should also work:
cy.get(".item").should($items => {
for(var i = 0; i < $items.length; i++) {
expect($items[i].text()).to.eq(...)
}
})
So you can also work with a combination of cypress commands and jQuery.
Let me know if you need furhter assistance
I am new to this, but to get the count of elements returned I would use something like this:
cy.get('.item').its('length')
Then, if you want to work with specific elements from that array:
.then(size => {
for(i= 0; i < size: i++) {
cy.get('.item').eq(size).should('have.value', 'list item')
}
})

How to get values from ng-repeat in protractor?

<div ng-repeat="obj in list">
</div>
This obj is having 6 properties like name, country, state, city, street, and contact. I have written following code for this but it is giving me undefined as the value if i try to fetch the stored value in obj.
var elm = element.all(by.repeater('obj in list'));
elm.then(function(obj){
console.log("Number of Rows : "+ rows.length);
for(var i=0; i< rows.length; i++){
console.log("App name : " + rows[i].name);
}
});
This is printing "App name : undefined" only.
Keep in mind that you are using promises so you can't log a unresolved promise. All executions in Protractor are promises.
Secondly, you are using the rows, but you never defined it. Is rows the same as obj?
Third, try to avoid the a for loop with Promises. It's better to use for example the each from protractor. If you do that your code looks like this
var elm = element.all(by.repeater('obj in list'));
elm.each(function(obj, index) {
// Will print 0 First, 1 Second, 2 Third.
obj.getText().then(function (text) {
console.log(index, text);
});
});
firstly, the ng-repeat does not contain an object, it contains a list. in your case, an array.
if you have nested lists (ng-repeat in ng-repeat) please specify that in your question. otherwise, the following code should work for you.
let elm = element.all(by.repeater('obj in list'));
elm.getText().then(function(text){
console.log(text);
});

AngularJS Filter throws infdig error when it creates new array

i am about to bang my head to walls. i thought i had an understanding of how angular works (filters too). but i just cant find the problem about my filter. it causes infdig. and i even dont change source array in filter.
(function () {
angular.module('project.filters').filter('splitListFilter', function () {
return function (data, chunk) {
if(!data || data.length === 0){
return data;
}
var resultArray = [];
for (var i = 0, j = data.length; i < j; i += chunk) {
resultArray.push(data.slice(i, i + chunk));
}
return resultArray;
};
});
})();
i have lists where i need to split data to x columns. it is complicated to solve with limitTo.
(limitTo: $index*x | limitTo: $last ? -z : -x)
it causes a dirty template file. so i decided to create a filter which splits an array to groups.
[1,2,3,4,5,6,7,8] -> [[1,2,3],[4,5,6],[7,8]]
so i can easily use it in my template.
Can u help me about what causes infdig in this filter?
Edit: the error message itself looks strange with some numbers in that don't appear anywhere in the code, which can be seen at http://plnkr.co/edit/pV1gkp0o5KeimwPlEMlF
10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [[{"msg":"fn: regularInterceptedExpression","newVal":23,"oldVal":20}],[{"msg":"fn: regularInterceptedExpression","newVal":26,"oldVal":23}],[{"msg":"fn: regularInterceptedExpression","newVal":29,"oldVal":26}],[{"msg":"fn: regularInterceptedExpression","newVal":32,"oldVal":29}],[{"msg":"fn: regularInterceptedExpression","newVal":35,"oldVal":32}]]
HTML Template
<div class="row" ng-repeat="chunk in docProfile.SysMedicalInterests | splitListFilter: 3">
<div class="col-md-4" ng-repeat="medInterest in chunk">
<label style="font-weight:normal;">
<input type="checkbox" value="{{medInterest.ID}}" ng-click="docProfile.saveInterest(medInterest.ID)" ng-checked="docProfile.isMedChecked(medInterest.ID)"> {{medInterest.Name}}
</label>
</div>
</div>
Controller Code
var me = this;
me['SysMedicalInterests'] = null;
var loadMedicalInterests = function(){
var postData = { 'Data': me['data']['subData'] };
return docService.loadMedicalInterests(postData).then(function(resp) {
me['SysMedicalInterests'] = resp['data'];
}, function(){});
};
loadMedicalInterests();
so array starts with a null reference and loads data from server. which changes array causes a second filter run. but it doesnt stop after that
Edit: here is plunkr http://plnkr.co/edit/OmHQ62VgiCXeVzKa5qjz?p=preview
Edit: related answer on so https://stackoverflow.com/a/21653981/1666060 but this still doesn't explain angular built in filters.
here is angularjs limitTo filter source code
https://github.com/angular/angular.js/blob/master/src/ng/filter/limitTo.js#L3
About what exactly causes it, I suspect is something to do with the fact that every time you run the filter a new array reference is created and returned. However, Angular's built-in filter filter does the same thing, so I'm not sure what is going wrong. It could be something to do with the fact that it's an array of arrays that is being returned.
The best I have come up with is a workaround/hack, to cache the array reference manually as an added property, which I've called $$splitListFilter on the array, and only change it if it fails a test on angular.equals with the correct results calculated in the filter:
app.filter('splitListFilter', function () {
return function (data, chunk) {
if(!data || data.length === 0){
return data;
}
var results = [];
for (var i = 0, j = data.length; i < j; i += chunk) {
results.push(data.slice(i, i + chunk));
}
if (!data.$$splitListFilter || !angular.equals(data.$$splitListFilter, results)) {
data.$$splitListFilter = results;
}
return data.$$splitListFilter;
};
});
You can see this working at http://plnkr.co/edit/vvVJcyDxsp8uoFOinX3V
The answer uses Angular 1.3.15
The JS fiddle works fine: http://jsfiddle.net/3tzapfhh/1/
Maybe you use the filter wrongly.
<body ng-app='app'>
<div ng-controller='ctrl'>
{{arr | splitListFilter:3}}
</div>
</body>

Angular: How to populate a dynamic array for select using ngOptions?

Ideally, I want to populate the array via computed property. For example,
Object.defineProperty(MyObj.prototype, 'linkedList', {
get: function () {
var list = [];
this.dataList.forEach(function (cs) {
if (cs !== this) {
list.push(cs.name);
}
});
return list;
}
});
However, if I used this computed property as select options like
<select data-ng-model="name" data-ng-options="g for g in myObj.linkedList"></select>
I will get this error:
Error: 10 $digest() iterations reached. Aborting!
In fact, I still get this error even if I return a fixed list like:
Object.defineProperty(MyObj.prototype, 'linkedList', {
get: function () {
return ['test1', 'test2'];
}
});
However, it is okay if I return a static array:
MyObj._linkedList = ['test1', 'test2'];
Object.defineProperty(MyObj.prototype, 'linkedList', {
get: function () {
return MyObj._linkedList;
}
});
I also tried to use a filter in the ngOptions and the same error is thrown. Why and How?
UPDATE:
As it turns out, my original question above doesn't truly reflect the problem, because the problem happens only if I use a directive. To simplify the question, I removed the directive part.
Anyway, in my directive, I have
scope: {
name: '=',
isEditing: '=',
isHidden: '=',
options: '='
}
<div>
<div data-ng-hide="!isHidden" style="background-color: lightgrey"> </div>
<div data-ng-show="!isEditing && !isHidden">{{name}}</div>
<select class="select-input" data-ng-show="isEditing && !isHidden" data-ng-model="name" data-ng-options="g for g in {{options}}"><option value=""></option></select>
</div>
Here is how to use it:
<td><ms-table-select-cell name="myObj.link" is-editing="myObj.isEditing" options="myObj.linkedList" /></td>
This is how the error occurs. If I directly use the select tag with ngOptions, it's not a problem.
I think the problem is that your 'get' property is called at each loop.
You can try to assign the variable value once and then loop on it.
<select data-ng-model="name" data-ng-options="g for g in myArray = myObj.linkedList"></select>
In your first case every time angular calls myObj.linkedList it gets a new object, so angular repeatedly begin new digest cycle and does it untill the number of iterations exceeds 10 - than it throw an error "10 $digest() iterations reached".
To avoid this you must construct your code so that every call to the myObj.linkedList returns the same object.
Try to move the var list = []; expression out of the Object.defineProperty call.
I prepared 2 fiddles:
fiddle 1 - with the Error
fiddle 2 - without the Error and with tiny modification.
Compare them.
Hope it will help you

Resources