Using protractor to test infinite scrolling - javascript

I don't think this is strictly infinite scrolling but it was the best i could think of that compares to what i am seeing.
Anyway, we are using ng-grid to show data in a table. We have roughly 170 items (rows) to display. when we use ng-grid it creates a repeater. When i inspect this repeater from the browser its limited to 35 items and, as you scroll down the list, you start to lose the top rows from the dom and new rows are added at the bottom etc (hence why i don't think its strictly infinite scrolling as that usually just adds more rows)
Just so I'm clear there is always 35 'ng-repeat=row in rendered rows' elements in the dom no matter how far you have scrolled down.
This is great until it comes to testing. I need to get the text for every item in the list, but using element.all(by.binding('item.name')) or by.repeater or by.css doesn't help as there is only ever 35 items present on the page.
Now to my question, how can i make it so that i can grab all 170 items as an object that i can then iterate through to grab the text of and store as an array?
on other pages where we have less than 35 items iv just used the binding to create an object, then using async.js to go over each row and get text (see below for an example, it is modified extract i know it probably wouldn't work as it is, its just to give you reference)
//column data contains only 35 rows, i need all 170.
var columnData = element.all(by.binding('row.entity.name'))
, colDataTextArr = []
//prevOrderArray gets created elsewhere
, prevOrderArray = ['item1', 'item2'... 'item 169', 'item 170'];
function(columnData, colDataTextArr, prevOrderArray){
columnData.then(function(colData){
//using async to go over each row
async.eachSeries(colData, function(colDataRow, nRow){
//get the text for the current async row
colDataRow.getText().then(function(colDataText){
//add each rows text to an array
colDataTextArr.push(colDataText);
nRow()
});
}, function(err){
if(err){
console.log('Failed to process a row')
}else{
//perform the expect
return expect(colDataTextArr).toEqual(prevOrderArray);
}
});
});
}
As an aside, I am aware that iterating through 170 rows and storing the text in an array isn't very efficient so if there is a better way of doing that as well I'm open to suggestions.
I am fairly new to JavaScript and web testing so if im not making sense because I'm using wrong terminology or whatever let me know and i'll try and explain more clearly.

I think it is an overkill to test all the rows in the grid. I guess it would be sufficient to test that you get values for the first few rows and then, if you absolutely need to test all the elements, use an evaluate().
http://angular.github.io/protractor/#/api?view=ElementFinder.prototype.evaluate
Unfortunately there is no code snippet in the api page, but it would look something like this:
// Grab an element where you want to evaluate an angular expression
element(by.css('grid-selector')).evaluate('rows').then(function(rows){
// This will give you the value of the rows scope variable bound to the element.
expect(rows[169].name).toEqual('some name');
});
Let me know if it works.

Related

Tabulator.js table elements retrieve the index of the row and serve as a control element to other plots

I am using tabulator package 4.3.0 to work on a webpage. The table generated by the package is going to be the control element of a few other plots. In order to achieve this, I have been adding a dataFiltered function when defining the table variable. But instead of getting the order of the rows in my data object, I want to figure a way to get the index of the rows in the filtered table.
Currently, I searched the manual a little bit and have written the code analogue to this:
dataFiltered: function(filters,rows){
console.log(rows[0]._row.data)
console.log(rows[0].getPosition(true));
}
But the getPosition always returned -1, which refers to that the row is not found in the filtered table. I also generated a demo to show the real situ when running the function. with this link: https://jsfiddle.net/Binny92/3kbn8zet/53/.
I would really appreciate it if someone could help me explain a little bit of how could I get the real index of the row in the filtered data so that I could update the plot accordingly and why I am always getting -1 when running the code written in this way.
In addition, I wonder whether there is a way to retrieve the data also when the user is sorting the table. It's a pity that code using the following strategy is not working in the way I am expecting since it is not reacting to the sort action and will not show the information when loading the page for the first time.
$('#trialTable').on('change',function(x){console.log("Yes")})
Thank you for your help in advance.
The reason this is happening is because the dataFiltered callback is triggered after the rows are filtered but before they have been laid out on the table, so they wont necessarily be ready by the time you call the getPosition function on them.
You might do better to use the renderComplete callback, which will also handle the scenario when the table is sorted, which would change the row positions.
You could then use the getRows function passing in the value "active" as the first augment return only rows that have passed the filter:
renderComplete: function(){
var rows = table.getRows("active");
console.log(rows[0].getPosition(true));
}
On a side note i notice you are trying to access the _row property to access the row data. By convention underscore properties are considered private in JavaScript and should not be accessed as it can result in unstable system behaviour.
Tabulator has an extensive set of functions on the Row Component to allow you to access anything you need. In the case of accessing a rows data, there is the getData function
var data = row.getData();

Apify array results displayed in one row instead of separate rows

I'm testing Apify web scraper and i am able to see the results but it's displayed in one row. I'm iterating contents to grab titles from this page - ... and pushing it to array and finally returning array. I would like to see the titles returned in separate rows. Would really appreciate if someone could point me to right direction.
Here is my page function:
async function pageFunction(context) {
// jQuery is handy for finding DOM elements and extracting data from them.
// To use it, make sure to enable the "Inject jQuery" option.
const $ = context.jQuery;
var results = [];
$('.ms-srch-group-content').each(function(){
results.push({
title: $(this).find('.ms-srch-item-link').text().trim(),
date: $(this).find('.soi-news-attributes').text().trim(),
});
});
return results;
}
Here is the result:
...
As you can see in the result screenshot, all the titles are displayed in one row.
The problem here is that you're trying to iterate over the element itself, while what you're trying to achieve would require to move down by one level.
That said - you would only need to change .ms-srch-group-content to .ms-srch-group-content > div[name=Item] and it would work as expected.
Looks like .ms-srch-group-content is selector for group content, so you receive one record not an array.
I guess you need to move down to the next div - .ms-srch-item
$('.ms-srch-item').each(function(){

Remove all elements within a ng-repeat in Angular

I'm working with Angular and part of my page utilizes ng-repeat to display some bug tracker tickets. As part of the site, I also want to provide the ability to search tickets. I'm able to get that part working as I want, and if I'm just appending new tickets they show up fine.
However I would like to be able to, if a user searches, delete all of the currently visible ticket divs and replace them with the search results.
My initial thinking, since I have the ng-repeat set as item in tickets track by item.id, was to just set $scope.tickets equal to the new data. However, this didn't cause Angular to update the DOM.
So, I tried setting $scope.tickets equal to an empty array and then setting it equal to the new data:
$scope.$apply(function() {
$scope.tickets = [];
$scope.tickets = data;
});
Still no update to the DOM, even though console.log($scope.tickets) shows the correct objects.
I'm aware of the method of
$scope.$apply(function() {
array.splice(index, 1);
});
to remove individual elements, but I'm not sure how I would apply that removing all of the elements.
I'll try and get a Plunkr or JSBin added to the Q soon.
What would be the proper way for me to make Angular replace all of the current elements with the new elements created from the data?
try setting array.length = 0
this deletes all elements, while not removing the reference to the array, which actually seems to be the problem in your case.
but another way would be to have a additional data bag.
for example have $scope.data.tickets then you can reasign tickets as usual. important thing is, you have to reference your items using item in data.tickets
Did you test $watch?
$scope.$watch('tickets', function() {
// update data HERE
});

Tablesorter Custom Filter Function - Full Table Filter

I have a tablesorter, with 2 filter Columns. The first Filter works as a drop down and has no issues right now. The second filter is intended to be a full table search and filter mechanism.
That is to say, even though it is associated with the computer column, it should return results for child rows as well
The Computer Filter should respond to all child rows. For instance, if I searched for z840, , only Computers with Model z840 should appear.
However, I have a custom secondary filter mechanism by request The gauge at the top, works as a filter for workgroup
However, If I am filtered in a workgroup, and use the Computer Filter, it ignores the custom hidden rows, and searches against any row in the table. (Child Row Searching works fine).
My Question is, Is there a way to overwrite the functionality of the filter, to ignore any rows that are already satisfying some condition IE: $(row).hasClass('hide')
I have tried using filter_functions but every result ends up searching on computer name only
I am using Jinja Templating so it was a little hard to get a fiddle up and running but here is a sample.
http://jsfiddle.net/brianz820/856bzzeL/813/
Sort by wg02 (at top, no results), and then use the computer filter to search for say, 3.3. No results show up, but once you delete the search, the original workgroup filter is removed.
On my production copy, even typing 3.3 would have returned results for any workgroup, ignoring the filter.
There may be lots of extraneous code on Fiddle, just wanted to get a working version up
Thanks for reading, Goal to maintain free form child searching and filtering on filter selection, but maintain external hidden rows.
if there is any more required information please let me know
I'm not exactly sure if this is what you meant, but the hideRows function can be simplified by using the filter widget (demo):
function hideRows() {
var $table = $('.tablesorter'),
filters = $.tablesorter.getFilters( $table );
filters[2] = selected === 'All' ? '' : selected;
$.tablesorter.setFilters( $table, filters );
}

Identifying filtered rows with DataTables

I have some issues with a project I inherited that is using DataTables and it's filter functionality.
The issue is that in the main function which populates the table, it has the following code:
var rowPos = mainTable.fnAddData(tableData, false)[0];
var rowData = mainTable.fnSettings().aoData[rowPos];
$(rowData.nTr).attr("id", "UID" + id); // Since the id doesn't always match the row
rowData.ID = id;
Now I know that the 3rd line is pretty much useless unless the 'false' argument of the fnAddData is set to 'true'. This is because the HTML elements don't actually exist in the DOM when set to 'false' so there is no way of setting the 'id' attribute.
I can't use 'true' because it will render the table in about 4 seconds when adding several hundred rows to the table. But when I use 'false' it renders the table almost instantaneously (less than a second). So using the 'true' flag in 'fnAddData()' is not even an option.
I see the last line seems to be doing something, but I've tried to find documentation for that on the DataTables web site but can't seem to find anything of value. I'm assuming it allows someone to bind a UID (unique record ID) to the actual row number, which is essential what is wanted.
The code I have also makes use of the 'fnRowCallback', which tries to set the 'id' attribute at this time, such as:
var id = mainTable.fnSettings().aoData[tablePos].ID;
$(row).attr("id", "UID" + id); // Since the id doesn't always match the row
The main problem is that it does not seem to work! If I apply a table filter and purposely filter out all records except the record which should be 'UID' 3, in the 'fnRowCallback', my 'id' variable is set to 0. So the attribute set is always 'UID0' and causes all sorts of bad references.
Is there a way to properly assign my database record ID to table row's? And then refer them later on, such as in the 'fnRowCallback' function? Or is there some other trick someone has managed to figure out?
Thanks in advance for your time and responses!
Update: 2012.11.01 12:33 - I've added an answer below based on various findings so far!
I've been doing a bit of digging and here are my conclusions so far...
Using a JavaScript object inspection that I found on this SO page (by 'goreSplatter') I was able to dump various DataTables objects.
I realized that my 'rowData' object was a tiny container, as expected. And realized that the 'rowData.ID' property did not originally exist in this data structure. I guess the application developer inserted it himself and it makes sense.
From the 'fnRowCallback()' function, I did the same object inspection to try and find the initial 'rowData' that I initialized my 'ID' on. I found it as follows:
var rowData = mainTable.fnSettings().aoData[tablePos];
And when I dump the value of 'rowData.ID' I realized that my 'ID' value was properly set as expected.
The problem occurs when I do my filter! The 'rowData.ID' seems to always be '0' for some reason. It seems like the DataTables takes a copy of the object but does not set any properties it does not know and thus results in '0'.
So it is definitely a bug (at least, in my opinion)! I will contact the DataTables people to see how they would expect users to bind custom application data to their rows and see if they can also set these properties during a filtering process.
I will report any further findings later on.

Categories