How to click element using Cucumber without using xpath? - angularjs

My application requires to test favorite feature for any product.Products List & UI
When a user click on the heart icon shown in the snippet, it will add that product into Favorites list. I would like to know about the Capybara/Cucumber method to click on the heart icon.
I have tried using XPATH but it seems not working. The code that I tried is as follow.
When(/^I click on the favourite icon on the first product$/) do
find(:xpath,'/html/body/div[1]/div[2]/div/div/div/span/div/div/div/div[3]/div[1]/span[1]/div/div/div/div/div[4]/div[2]/div/favorite/a').click
end
I have also tried following capybara method using XPATH. It is also not working.
When(/^I click on the favourite icon on the first product$/) do
find(:xpath,'//a[contains(., "#heart")]).click
end
Also, I tried following code which is throwing out an error.
When(/^I click on the favourite icon on the first product$/) do
within("div.search-results-wrapper") do
find(first('a.ng-scope')).trigger(:mouseover)
end
end
Error:
The given selector #<Capybara::Node::Element:0x007fd18d841690> is either invalid or does not result in a WebElement. The following error occurred:
InvalidSelectorError: An invalid or illegal selector was specified (Selenium::WebDriver::Error::InvalidSelectorError)
The HTML code for the Favorite icon is as follow:
<favorite product="result" ng-if="!ui.showIpsaProductCell()" class="product-action ng-scope ng-isolate-scope"><a ng-mousedown="product.favoriting = true" ng-mouseenter="product.showList = true" active="::product.favoriting" ng-click="toggle(true)" class="ng-scope active">
<i ng-class="::{
'icon-heart-filled':
product.hasFavorite || !showCount || newProductPage,
'icon-heart-outline':
!product.hasFavorite && showCount && !newProductPage
}" class="heart icon-heart-filled"></i>
<!-- ngIf: ::showCount --><span class="count ng-scope" ng-if="::showCount">
1
</span><!-- end ngIf: ::showCount -->
<!-- ngIf: ::addToList && product.hasFavorite --><div component="add-to-list" ng-if="::addToList && product.hasFavorite" class="ng-scope">
<!-- ngInclude: '/modules/components/add-to-list/add-to-list.tpl.html' --><span ng-include="'/modules/components/add-to-list/add-to-list.tpl.html'" ng-controller="AddToListCtrl" class="ng-scope"><div ng-mouseleave="product.showList = false" class="add-to-list-desktop ng-scope">
<!-- ngIf: product.showList -->
<!-- ngIf: product.showListMenu && product.showList -->
</div>
</span></div><!-- end ngIf: ::addToList && product.hasFavorite -->
</a></favorite>

Since you have multiple "favourite" icons you would need to find your icon within a given parent container, not being able to see the full html page it would go something like:
within(".myParentContainer") do
find(".icon-heart-filled").click
end

Related

md-autocomplete md-require-match on lose focus

I have an autocomplete control (Angular Material version 1.1.2) with md-require-match=true and a validation message
<md-autocomplete required
md-no-cache="true"
md-select-on-match = "true"
md-selected-item="vm.selectedItem"
md-search-text="vm.searchText"
md-items="country in vm.querySearch(vm.searchText)"
md-item-text="country.nm"
md-min-length="2"
md-selected-item-change="vm.updateOrgCountry(country.cd)"
md-require-match = "true"
md-input-name="countryField"
md-match-case-insensitive = "true"
md-floating-label="Country">
<md-item-template>
<span md-highlight-text="vm.searchText" md-highlight-flags="^i">{{country.nm}}</span>
</md-item-template>
<md-not-found>
No Countries matching "{{vm.searchText}}" were found.
</md-not-found>
<div ng-messages="orgForm.countryField.$error">
<div ng-message="required"></div>
<div ng-message="md-require-match">Country not found.</div>
</div>
</md-autocomplete>
When I first enter the control and start typing everything works as expected. If I don't select an item from the list and then move away from the control I get the "Country not found" error message.
However if I go back to the control and start typing again I get the "Country not found" error message after every key press until I select something from the list. I don't want this behaviour as the user should be seeing an error while still entering data.
Is there a way to configure the autocomplete control to only validate for a match as the control loses focus?

angular dir-paginate paginate-id error

i have a list and within that list i have a new list that needs to be paginated. To make sure that each inner list know which list they belong to i use: pagination-id:
<div class="list-group bg-white m-none b-t">
<span dir-paginate="module in category.organization_has_modules | itemsPerPage:10 | filter:search"
pagination-id="category.id">
<a ui-sref="app.library_assign({module_id:module.module.id})"
class="list-group-item"
ng-if="module.is_active != 0">
<i class="fa fa-fw {{module.module.module_type.icon}}"></i>
{{module.module.name}}
<span class="pull-right">
<i class="fa fa-sign-in"></i>
</span>
<div class="clear"></div>
</a>
</span>
<dir-pagination-controls class="pull-right" pagination-id="category.id"></dir-pagination-controls>
When i run this i sadly get the following error message:
error: [$parse:syntax] Syntax Error: Token '__currentPage' is an unexpected token at column 4 of the expression [103__currentPage] starting at [__currentPage].
if i run it without the pagination-id it runs fine however it is unable to differ the different lists which means all the pages change when i change it in one of the lists.
Does anyone have any idea of what im doing wrong?
The problem was apprently a bug with the id being a number. The parser in dirPagination.js line 206 does not accept numbers and the regex created to replace any numbers is apprently not working. So instead of using a number i used a string.

Strange issue with AngularJS template

I'm getting a very very strange issue with Angularjs, I'm using a directive where I defined an inline template on page like this:
<script type="text/ng-template" id="breadcrumb.html"> {[ state.current.displayName ]} </script>
However, I'm getting this weird error:
> Error: JSON.parse: expected property name or '}'
> fromJson#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:1035
> #http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:6926
> transformData/<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:6901
> forEach#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:302
> transformData#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:6900
> transformResponse#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:7570
> qFactory/defer/deferred.promise.then/wrappedCallback#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:10905
> qFactory/ref/<.then/<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:10991
> Scope.prototype.$eval#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:11906
> Scope.prototype.$digest#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:11734
> Scope.prototype.$apply#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:12012
> bootstrap/doBootstrap/<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:1299
> invoke#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:3697
> bootstrap/doBootstrap#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:1298
> bootstrap#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:1311
> angularInit#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:1260
> #http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js:20534
> x.Callbacks/c#http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js:4
> x.Callbacks/p.fireWith#http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js:4
> .ready#http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js:4
> q#http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js:4
Now, if I actually add something into the template, for example any random character like this:
<script type="text/ng-template" id="breadcrumb.html"> a{[ state.current.displayName ]} </script>
Then the error goes away, everything renders fine.
PS: Note that I changed from {{}} to {[]} to avoid syntax conflict with Twig
Edit:
In respond to the interpolate issue, I already use:
angular.module('myapp', []).config(function($interpolateProvider){
$interpolateProvider.startSymbol('{[').endSymbol(']}');
}
);
Shouldn't this be enough. And if that doesn't work, the why does putting a random character 'a' to it helps?
Edit 2:
Plunker added:
Please check this link for working code:
http://plnkr.co/edit/OQiJovrNzOraJdsSXeSY?p=preview
Please check this link for non-working code:
http://plnkr.co/edit/IzGpTdnqmO5MxtldnKec?p=preview
Angular expects {{}} for interpolation.
To avoid conflicts you can use ng-bind:
<script type="text/ng-template" id="breadcrumb.html" ng-bind="state.current.displayName"></script>
But, I've never tried it with a <script> tag though.
This is a confirmed issue of the current version of Angular JS (1.2.x)
I have submitted a ticket here:
https://github.com/angular/angular.js/issues/5756

I cannot get ng-class working when the class I am adding has a hyphen in it .

I am trying to add a class to my element in Angular. Here's my code:
<button class="medium"
data-ng-disabled="!gridForm.$pristine || fetching.length != 0"
data-ng-click="getQuestions()">
Retrieve<span class="fa fa-spinner fa-fw mlr75" data-ng-class="{fa-spin: fetching.length > 0}"> </span>
</button>
However it's giving me a strange error:
Syntax Error
error in component $parse
Syntax Error: Token '-' is at column {2} of the expression [{3}] starting at [{4}].
Does anyone have any ideas as to what might be wrong? Note that it works when I use the class faspin without the hyphen !!
Surround class name with singe quotation.
data-ng-class="{'fa-spin': fetching.length > 0}"
Otherwise angular search your scope for fa-spin which is not a valid name for variables.

angularjs + yeoman + ng-switch + build:minify -> assertion

I am using an ng-switch in angularjs to have dynamic content in my page, dependent on the url. And I am managing my project with yeoman. Here is the code of the dynamic content generation:
html:
<div class="div-content bgcontent" id="content">
<span ng-switch on="renderPath[0]">
<div ng-switch-when="home" ng-include="'partials/home.html'"></div>
<div ng-switch-when="gallery" ng-include="'partials/gallery.html'"></div>
</span>
</div>
controller:
$scope.renderPath = $location.path().split('/');
// remove first entry because it's empty string
$scope.renderPath.shift();
This works perfectly well when running the stuff with 'yeoman server'. But if I build with 'yeoman build:minify', it doesn't work anymore afterwards. It hits an assertion:
at assertArg (http://host:8888/scripts/vendor/d10639ae.angular.js:973:11)
at Object.ngDirective.compile (http://host:8888/scripts/vendor/d10639ae.angular.js:13474:5)
at applyDirectivesToNode (http://host:8888/scripts/vendor/d10639ae.angular.js:4047:32)
at compileNodes (http://host:8888/scripts/vendor/d10639ae.angular.js:3794:14)
at compileNodes (http://host:8888/scripts/vendor/d10639ae.angular.js:3799:14)
at compile (http://host:8888/scripts/vendor/d10639ae.angular.js:3739:29)
at update (http://host:8888/scripts/vendor/d10639ae.angular.js:13685:22)
at $get.Scope.$broadcast.next (http://host:8888/scripts/vendor/d10639ae.angular.js:8002:24)
at Array.forEach (native)
at forEach (http://host:8888/scripts/vendor/d10639ae.angular.js:110:11) <!-- ngSwitchWhen: home -->
Does someone know how to fix this? Or where I need to look to debug it?
If you are using dependency-injection within your scripts, make sure to use the minify-proof syntax as described here: http://docs.angularjs.org/guide/di

Resources