Protractor sendKeys returns NoSuchElementError - angularjs

I am learning Protractor and am trying to sendKeys in an input field in the angularjs.org page but I am getting this error:
NoSuchElementError: No element found using locator:
By.model("projectList.search")
Here is my code:
describe ("Search list", function() {
it ("should search for jQuery and display 1 result", function() {
browser.get("https://angularjs.org/");
element(by.model("projectList.search")).sendKeys("jQuery");
});
});
I tried using by.id and got the same error. I am assuming that this is caused because element is not visible yet. When I add browser.pause() and go step by step (slowly), the test passes. What is the best way to solve this?
Related HTML from angularjs.org
<input type="text" ng-model="projectList.search" class="search-query" id="projects_search"
placeholder="Search">
<table>
<thead>
<tr>
<th>Project</th>
<th>Description</th>
<th><i class="icon-plus-sign"></i></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="project in projectList.projects | filter:projectList.search | orderBy:'name'">
<td><a ng-href="{{project.site}}" target="_blank">{{project.name}}</a></td>
<td>{{project.description}}</td>
<td>
<a ng-href="#/edit/{{project.$id}}"><i class="icon-pencil"></i></a>
</td>
</tr>
</tbody>
</table>

I managed to find a small library called waitReady.js and it has solved my problem. Here is my final code,
require './waitReady.js')
var searchBtnElm = element(by.model('projectList.search'));
searchBtnElm.waitReady().then(function() {
searchBtnElm.sendKeys("myText");
});

You can try something like that :
var elementSelector = by.model("projectList.search");
browser.driver.isElementPresent(elementSelector).then(function(isPresent){
element(elementSelector).sendKeys("jQuery");
});
See protractor docs for more usefull functions

Is waitReady.js really works for you ?
Have tried to use it to click on stale elements but sometimes anyway exceptions occurs.
Have written function to click on element:
function clickWait(element) {
(element).waitReady().then(function () {
return element.click();
});
};
And invoke it like that:
clickWait(element);
framework: jasmine2

Related

Getting undefined when using target '_blank' with ui-router

Hi I'm having the below issue.
Below is my html page
<div class="content" ng-controller="DataController">
<table class="table table-striped" id="show" ng-if="datalist.length>0">
<thead>
<th>State</th>
<th>District</th>
<th>Non-DND's</th>
</thead>
<tbody>
<tr dir-paginate="data in datalist| filter:search|orderBy:sortKey:reverse|itemsPerPage:10" style="cursor:pointer;">
<td>{{data.state}}</td>
<td>{{data.district}}</td>
<td><a ng-click="getnre(data.nondnd,data.dnd,data.land,data.email)" ui-sref="numsemailsdata" target="_blank">{{data.nondnd.length}}</a></td>
</tr>
</tbody>
</table>
<dir-pagination-controls max-size="10" direction-links="true" boundary-links="true" style="float:right" ng-if="datalist.length>0">
</dir-pagination-controls>
</div>
Below is the code in my controller.js
app.controller("DataController", function($scope, DataService) {
$scope.datalist=DataService.getData();
$scope.getnre=function(ndnd,dnd,land,email) {
$scope.numsem = {
ndnds : ndnd,
dnds : dnd,
lands : land,
emails : email
}
}
});
Below is the numsdetails.html
<div class="content" ng-controller="DataController">
<table class="table table-striped">
<thead>
<th>Non-DND's</th>
</thead>
<tbody>
<tr ng-repeat="ndnd in numsems.ndnds">
<td>{{ndnd}}</td>
</tr>
</tbody>
</table>
</div>
Here I'm displaying the non-dnd's count in my first html page and I need to display the non-dnd's in new tab which is numsemails.html
When I'm trying to bind the data to numsemails.html, I'm getting the data as undefined even I'm binding the data from same controller.
Please help me with a solution.
The reason you are getting undefined for numsems is because when you open a new page (blank) you create an entire new instance of your app. It is like loading the page for the first time. Think of it as a totally different browser instance, because that is what it is. You can pass a parameter using stateparams, this gets passed in the url, however you are trying to pass an entire object so it becomes a bit more difficult.
There are multiple solutions to your problem. You can pass some data in the url, or you can use localstorage, $window, or cookies to store the data. I'm sure there are also other solutions. Choose one of these methods to hand your data properly and we can help you with it.
This issue has been discussed in other threads.
ui-router: open state in new tab with target=“_blank” with object params
Your controller code is wrong, you're missing brackets and braces:
app.controller("DataController", function($scope) {
$scope.datalist = DataService.getData();
$scope.getnre = function(ndnd,dnd,land,email) {
$scope.numsem = {
ndnds : ndnd,
dnds : dnd,
lands : land,
emails : email
};
}
});

ngTable updates ngClass result in error

I'm using esvit' ngTable. to display a big collectiong of data.
But when I try to add a ng-class(fn). First rendering it works (displays info class), but when I manipulate the data (as when i change the attribute winner on user (from the ng-click="(toggleWinner(user))"), it throws an error instead of updating the class.
ngTable:
<div ng-show="(answers).length > 0">
<table ng-table="tableParams" template-pagination="custom/pager" class="table table-striped table-bordered table-hover" style="margin-top: 12px;">
<tr style="cursor:pointer;" ng-click="toggleWinner(user);" ng-repeat="user in $data" ng-class="getClass(user)">
<td data-title="'Bruger'" sortable="'name'">{{user.name}}</td>
<td data-title="'Email'" sortable="'email'">{{user.email}}</td>
<td data-title="'Firma'" sortable="'company'">{{user.company}}</td>
<td data-title="'Mobil'" sortable="'mobile'">{{user.mobile}}</td>
<td data-title="'Vundet dato'" >{{getPreviousWinnings(user.email)}}</td>
<td data-title="'Udvælg Vinder'" >
<span ng-show="user.winner == true" class="glyphicon glyphicon-ok" style="color:darkgreen"></span>
</td>
</tr>
</table>
</div>
getClass(user):
$scope.getClass = function(user) {
if (user.winner) {
return "success";
} else if ($scope.getPreviousWinnings(user.email).length > 0) {
return "info";
} else {
return "";
}
};
I hope you can help, and thanks for taking a look
Error description:
TypeError: undefined is not a function
at Object.k [as fn] (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js:136:370)
at h.$digest (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js:106:311)
at h.$apply (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js:109:287)
at HTMLTableRowElement.<anonymous> (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js:189:372)
at HTMLTableRowElement.m.event.dispatch (local/js/libs/jquery-1.11.1.min.js:3:8436)
at HTMLTableRowElement.r.handle (local/js/libs/jquery-1.11.1.min.js:3:5146)
Most important thing first (solution):
Check your versions of libs to make sure they are the same
I was using angularjs 1.2.16 and angular-animate 1.2.10.
This resulted in angularjs calling it's own (it thought) $animate.setClass().
But in angular-animate 1.2.10 it is not there, and since I import the animate, it overwrites the $animate then there was no method to be called. Hard to see when using minified versions.
Anyways, thanks Kostia for making me make plunker so I could see it functioning.

AngularJs - Bindonce force refresh using refreshOn attribute

I am trying to force refresh my bindonce table after editing few records but I dont know how to use bindonce refreshOn attribute.
HTML Code:
<tbody bindonce="filteredItems" refresh-on="refreshTaskList" ng-repeat="task in filteredItems | orderBy:sortingOrder:reverse">
<tr>
<td><span bo-bind="task.serviceTypeName | isEmpty : 'None'"></span></td>
<td ><span bo-bind="task.percentageCompleted | isEmpty : 'Not Started'"></span></td>
</tr>
</tbody>
I am calling this line in my Controller:
$scope.refreshTaskList();
Also, I tried calling this as well but nothing works:
$scope.$broadcast('refreshTaskList');
Can you anyone please help me how to use this in a proper manner?
Change it to: refresh-on="'refreshTaskList'"
Example:
<button ng-click="refresh()">Refresh table</button>
$scope.refresh = function () {
$scope.$broadcast('refreshTaskList');
};
If it still doesn't work you might have a version that doesn't contain the refresh-on attribute.
Demo: http://plnkr.co/edit/nYPDMRG4b1OtkMolEEDQ?p=preview

Selector [ng\:model="test"] did not match any elements

I want to run an e2e-test using angular.
This is my html file:
<html>
<div>
<table class="table table-bordered">
<thread>
<tr>
.
.
.
<th class="icon">
<i ng-click="test" ng-show="isQuestionEditable()" class="icon-plus"></i>
</th>
</tr>
</thread>
</div>
</html>
How do I call ng-click properly?
I tried:
it('test', function(){
element('test').click();
});
But I get the error message: Selector [ng\:model="test"] did not match any elements.
I am accessing the right page for sure. I wrote:
beforeEach(function() {
browser().navigateTo('/');
});
'/' being proxied as http://localhost:8080/test
One work around would be to give the button an id="button" and then your selector would be element('#button').
Also check the caveat at the bottom of http://docs.angularjs.org/guide/dev_guide.e2e-testing
Its hard to tell from your example if you are manually bootstrapping angular or using ng-app.

turn off re-sorting in angularJS while editing

I have an AngularJS app that lists a bunch of items in a table. Like this:
<table class='unstyled tmain'>
<tr>
<td ng-click='setSort($event)'>X</td>
<td ng-click='setSort($event)'>Desc</td>
<td ng-click='setSort($event)'>created</td>
<td> </td>
</tr>
<tr ng-repeat="item in items | orderBy:itemNormalizationFunction:sortReverse">
<td><input type='checkbox' ng-model='item.done'
ng-click='onCheckedChanged(item)'/></td>
<td><div edit-in-place="item.text"
on-save="updateItemText(value,previousValue,item)"></div></td>
<td><span class='foo'>{{item.created | dateFormatter}}</span></td>
</tr>
</table>
The table headers are clickable to set the sort order. The cell in the 2nd column in each data row is editable "in place" - if you click on the text it gets replaced with an input textbox, and the user can edit the text. I have a little directive enabling that. This all works.
The problem comes in while editing. Suppose I have it set to sort by "description" (the 2nd column). Then if I edit the description (via the edit-in-place directive), as I am typing in the input box, the sort order changes. If I change the first few characters, then angular re-sorts and the item is no longer under my cursor. Nor is it even focused. I have to go hunting through the list to find out where it got re-sorted to, then I can re-focus, and resume typing.
This is kinda lame.
What I'd like to do is tell angular to (a) stop re-sorting while I am keying in the input box, or (b) sort on a separate (not-displayed) index value that preserves the ordering before the edit began. But I don't know how to do either of those. Can anyone give me a hint?
I know this is sort of complicated so I'll try to put together a plunkr to show what's happening.
This is the plunkr that shows how I solved the problem.
http://embed.plnkr.co/eBbjOqNly2QFKkmz9EIh/preview
You can create custom filter and call that only when necessary. Example when you click on 'Grid header' for sorting or after dynamically adding/removing values to array, or simply click of a button(Refresh Grid)
You need to dependency Inject Angular filter and sort filter
angular
.module('MyModule')
.controller('MyController', ['filterFilter', '$filter', MyContFunc])
function ExpenseSubmitter(funcAngularFilter, funcAngularFilterOrderBy) {
oCont = this;
oCont.ArrayOfData = [{
name: 'RackBar',
age: 24
}, {
name: 'BamaO',
age: 48
}];
oCont.sortOnColumn = 'age';
oCont.orderBy = false;
var SearchObj = {
name: 'Bama'
};
oCont.RefreshGrid = function() {
oCont.ArrayOfData = funcAngularFilter(oCont.ArrayOfData, SearchObj);
oCont.ArrayOfData = funcAngularFilterOrderBy('orderBy')(oCont.ArrayOfData, oCont.sortOnColumn, oCont.orderBy);
}
}
and call in HTML something like:
<table>
<thead>
<tr>
<th ng-click="oCont.sortOnColumn = 'age'; oCont.RefreshGrid()">Age</th>
<th ng-click="oCont.sortOnColumn = 'name'; oCont.RefreshGrid()">Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="val in oCont.ArrayOfData">
<td>{{val.age}}</td>
<td>{{val.name}}</td>
</tr>
</tbody>
</table>

Resources