My protractor script is working fine until a page where reveal.js package is used. I am not sure if that is the reason it causes the scripts to fail, but otherwise the code base is same as the other pages where my scripts works fine.
Note: I tried most of the protractor actions (click, highlight, waitForElement, toContain, etc), none of them worked. I could only click the links by inserting jQuery in my script.
CODE:
let HighlightElement = function (el) {
return browser.executeScript("arguments[0].setAttribute('style', arguments[1]);", el.getWebElement(), "color: Red; border: 1px solid red;").
then(function (resp) {
browser.sleep(2000);
return el;
}, function (err) { });
}
let waitUntilElementPresent = function (visibilityOfObject, maxWaitTime) {
var EC = protractor.ExpectedConditions;
browser.manage().timeouts().implicitlyWait(2);
browser.wait(function () {
browser.manage().timeouts().implicitlyWait(3);
return visibilityOfObject.isDisplayed()
.then(
function (isDisplayed) {
browser.wait(EC.visibilityOf(visibilityOfObject), maxWaitTime, "Element taking more time to load");
browser.manage().timeouts().implicitlyWait(3);
return isDisplayed;
},
function (error) {
return false;
});
}, 100000);
}
ACTUAL CODE:
var homepage = new homePageObj();
utilities.waitUntilElementPresent(homepage.waitScreenText); //here the script is failing. It is just a simple script and it used to work in other pages but it doesn’t work only in some of the pages
utilities.HighlightElement(homepage.waitScreenText);
utilities.HighlightElement(homepage.startButton);
homepage.startButton.click();
Error:
Failed: Wait timed out after 120062ms
Using below jQuery I am able to click, but we need to give wait time explicitly for each and every java script that we use, which is time consuming. I am beginner in automation, Kindly help me with a solution.
browser.executeScript("document.getElementsByClassName('cc-button')[0].click()");
My code started running after proving "browser.waitForAngularEnabled(false)" at the start of the script.
I have code like this:
element(by.model("roleSelection.role")).element(by.cssContainingText('option', newRole)).click();//.then(function() {console.log('role click')})//;
where the options is loaded via a call to the server.
I can wait for the first element by doing this
browser.wait(function() {
return browser.isElementPresent(by.model("roleSelection.role")).then(function(present){
return present;
});}, 8000);
and it seems to work. But how can I wait until the "sub-element" is clickable.
I have tried this
browser.wait(function() {
return browser.isElementPresent(by.model("roleSelection.role")).then(function(present){
if (present) {
var elm = element(by.model("roleSelection.role"));
return elm.isElementPresent(by.cssContainingText('option', newRole)).then(function(subpresent) {
return subpresent;
});
}
}); }, 8000);
Have you tried clickable? Something along these lines
var EC = protractor.ExpectedConditions;
var select = element(by.model("roleSelection.role"))
var isClickable = EC.elementToBeClickable(select);
browser.wait(isClickable,5000); //now options should have been loaded by now
Well, try to this: https://angular.github.io/protractor/#/api?view=ExpectedConditions.prototype.elementToBeClickable
But, Please keep in mind, Protractor is suitable for angular webpages and interactions, and animations. For example ng-animate. So, it is not sure to working for example jquery, or other animates.
In this way:
onPrepare: function () {
// disable animations when testing to speed things up
var disableNgAnimate = function () {
angular.module('disableNgAnimate', []).run(function ($animate) {
$animate.enabled(false);
});
};
browser.addMockModule('disableNgAnimate', disableNgAnimate);
}
Or you can switch in script way in browser.executeScript().
Please see this link. It works only jquery animations.
If you not have animate problems. Use setTimeout() JS function.
I am a UI person and very new to ionic framework.. I wanted to add search feature in my android app built using Ionic framework. After a research i found that I will need to use this plugin https://github.com/djett41/ionic-filter-bar. but there is no detail documentation available. Can anyone please guide how to use this plugin working. I have made all setup but stuck with actual code.
First of all you must install the plugin. You can use bower for that:
bower install ionic-filter-bar --save
and it will copy all the javascript and css needed in the lib folder inside www.
Then you must add the references to the css to your index.html:
<link href="lib/ionic-filter-bar/dist/ionic.filter.bar.css" rel="stylesheet">
same thing for the javascript:
<script src="lib/ionic-filter-bar/dist/ionic.filter.bar.js"></script>
You have to inject the module jett.ionic.filter.bar you your main module:
var app = angular.module('app', [
'ionic',
'jett.ionic.filter.bar'
]);
and you must reference the service $ionicFilterBar in your controller:
angular.module('app')
.controller('home', function($scope, $ionicFilterBar){
});
Now you can start using it.
In my sample I want to trigger the search-box when the user clicks/taps on a icon in the header. I would add this HTML to the view:
<ion-nav-buttons side="secondary">
<button class="button button-icon icon ion-ios-search-strong" ng-click="showFilterBar()">
</button>
</ion-nav-buttons>
The action trigger an event in my controller showFilterBar:
$scope.showFilterBar = function () {
var filterBarInstance = $ionicFilterBar.show({
cancelText: "<i class='ion-ios-close-outline'></i>",
items: $scope.places,
update: function (filteredItems, filterText) {
$scope.places = filteredItems;
}
});
};
which creates the $ionicFilterBar and shows it.
As you can see here I am using an array of objects $scope.places
$scope.places = [{name:'New York'}, {name: 'London'}, {name: 'Milan'}, {name:'Paris'}];
which I have linked to the items member of my $ionicFilterBar. The update method will give me in filteredItems the items (places) filtered.
You can play with this plunker.
Another option is to use the plugin to actually fetch some data remotely through $http.
If we want to achieve this we can use the update function again.
Now we don't need to bind the items to our array of objects cause we won't need the filtered elements.
We will use the filterText to perform some action:
$scope.showFilterBar = function () {
var filterBarInstance = $ionicFilterBar.show({
cancelText: "<i class='ion-ios-close-outline'></i>",
// items: $scope.places,
update: function (filteredItems, filterText) {
if (filterText) {
console.log(filterText);
$scope.fetchPlaces(filterText);
}
}
});
};
We will call another function which will, maybe, call $http and return some data which we can bind to our array of objects:
$scope.fetchPlaces = function(searchText)
{
$scope.places = <result of $http call>;
}
Another plunker here.
PS:
If you want to configure it using some sort of customization you must do it in your configuration using the provider $ionicFilterBarConfigProvider:
angular.module('app')
.config(function($ionicFilterBarConfigProvider){
$ionicFilterBarConfigProvider.clear('ion-ios-close-empty');
})
PPS:
In my plunker I've included the css and the script directly copying it from the source.
UPDATE:
Someone asked not to replace the list with the updated one.
My cheap and dirty solution is to check if the filterText contains some values. If it's empty (no searches) we go throught each element an set a property found = false otherwise we compare the places array we the filteredItems array.
Matching elements will be marked as found.
function allNotFound(filteredItems) {
angular.forEach($scope.places, function(item){
item.found = false;
});
}
function matchingItems(filteredItems) {
angular.forEach($scope.places, function(item){
var found = $filter('filter')(filteredItems, {name: item.name});
if (found && found.length > 0) {
console.log('found', item.name);
item.found = true;
} else {
item.found = false;
console.log('not found', item.name);
}
});
and now we can integrate the filter bar this way:
$scope.showFilterBar = function () {
var filterBarInstance = $ionicFilterBar.show({
cancelText: "<i class='ion-ios-close-outline'></i>",
items: $scope.places,
update: function (filteredItems, filterText) {
if (!filterText) {
allNotFound();
} else {
matchingItems(filteredItems);
}
}
});
};
We can use the found attribute of the object to change the style of the element.
As always, a Plunker to show how it works.
Ionic uses Angular, and Angular include an atributte filter very useful. Look this: https://docs.angularjs.org/api/ng/filter/filter and the example there. Regards
I have saved data in the appAPI.db.async database. And now I want to display it in the popup page.
Here's what I have in the popup page:
function crossriderMain($) {
var db_keys = appAPI.db.async.getKeys();
db_keys.forEach(
function(key)
{
$("ul#id").append("<li>" + appAPI.db.async.get(key).url + "</li>");
});
}
</script>
</head>
<body>
<ul id="history">History</ul>
</body>
</html>
which doesn't give the intended result.
What I want to know is what's available for me when inside a popup page?.
Also, as an aside question: how do I open a browser tab from an HTML page in my resources directory, instead of a popup that won't take the whole screen space, in the browserAction.onClick handler?
Something like that in background.js:
appAPI.browserAction.onClick(
function()
{
appAPI.tabs.create("/Resources/templates/history.html");
}
);
Thanks (:->)
Answer to question 1
appAPI.db.async is asynchronous by design and hence you must use a callback to receive and use the values from the database. Additionally, it is not necessary to get the keys first and then their associated data; you can simply achieve your goal in one step using appAPI.db.async.getList.
Hence, using your example the code should be:
function crossriderMain($) {
appAPI.db.async.getList(function(arrayOfItems) {
for (var i=0; i<arrayOfItems.length; i++) {
$("ul#id").append("<li>" + arrayOfItems[i].value + "</li>");
}
});
}
Answer to question 2
To create a new tab that opens a resource page, use the appAPI.openURL method.
Hence, using your example the code should be:
appAPI.ready(function($) {
// When using a button, first set the icon!
appAPI.browserAction.setResourceIcon('images/icon.png');
appAPI.browserAction.onClick(function() {
appAPI.openURL({
resourcePath: "templates/history.html",
where: "tab",
});
});
});
[Disclaimer: I am a Crossrider employee]
I have problem with web after adding icon to Home Screen. If the web is launched from Home Screen, all links will open in new window in Safari (and lose full screen functionality). How can I prevent it? I couldn't find any help, only the same unanswered question.
I found JavaScript solution in iWebKit framework:
var a=document.getElementsByTagName("a");
for(var i=0;i<a.length;i++)
{
a[i].onclick=function()
{
window.location=this.getAttribute("href");
return false
}
}
The other solutions here either don't account for external links (that you probably want to open externally in Safari) or don't account for relative links (without the domain in them).
The html5 mobile-boilerplate project links to this gist which has a good discussion on the topic: https://gist.github.com/1042026
Here's the final code they came up with:
<script>(function(a,b,c){if(c in b&&b[c]){var d,e=a.location,f=/^(a|html)$/i;a.addEventListener("click",function(a){d=a.target;while(!f.test(d.nodeName))d=d.parentNode;"href"in d&&(d.href.indexOf("http")||~d.href.indexOf(e.host))&&(a.preventDefault(),e.href=d.href)},!1)}})(document,window.navigator,"standalone")</script>
If you are using jQuery, you can do:
$("a").click(function (event) {
event.preventDefault();
window.location = $(this).attr("href");
});
This is working for me on iOS 6.1 and with Bootstrap JS links (i.e dropdown menus etc)
$(document).ready(function(){
if (("standalone" in window.navigator) && window.navigator.standalone) {
// For iOS Apps
$('a').on('click', function(e){
e.preventDefault();
var new_location = $(this).attr('href');
if (new_location != undefined && new_location.substr(0, 1) != '#' && $(this).attr('data-method') == undefined){
window.location = new_location;
}
});
}
});
This is an old question and many of the solutions here are using javascript. Since then, iOS 11.3 has been released and you can now use the scope member. The scope member is a URL like "/" where all paths under that scope will not open a new page.
The scope member is a string that represents the navigation scope of
this web application's application context.
Here is my example:
{
"name": "Test",
"short_name": "Test",
"lang": "en-US",
"start_url": "/",
"scope": "/",
...
}
You can also read more about it here. I also recommend using the generator which will provide this functionality.
If you specify the scope, everything works as expected similar to
Android, destinations out of the scope will open in Safari — with a
back button (the small one in the status bar) to your PWA.
Based on Davids answer and Richards comment, you should perform a domain check. Otherwise links to other websites will also opened in your web app.
$('a').live('click', function (event)
{
var href = $(this).attr("href");
if (href.indexOf(location.hostname) > -1)
{
event.preventDefault();
window.location = href;
}
});
If using jQuery Mobile you will experience the new window when using the data-ajax='false' attribute. In fact, this will happen whenever ajaxEnabled is turned off, being by and external link, by a $.mobile.ajaxEnabled setting or by having a target='' attribute.
You may fix it using this:
$("a[data-ajax='false']").live("click", function(event){
if (this.href) {
event.preventDefault();
location.href=this.href;
return false;
}
});
(Thanks to Richard Poole for the live() method - wasn't working with bind())
If you've turned ajaxEnabled off globally, you will need to drop the [data-ajax='false'].
This took me rather long to figure out as I was expecting it to be a jQuery Mobile specific problem where in fact it was the Ajax linking that actually prohibited the new window.
This code works for iOS 5 (it worked for me):
In the head tag:
<script type="text/javascript">
function OpenLink(theLink){
window.location.href = theLink.href;
}
</script>
In the link that you want to be opened in the same window:
Link
I got this code from this comment: iphone web app meta tags
Maybe you should allow to open links in new window when target is explicitly set to "_blank" as well :
$('a').live('click', function (event)
{
var href = $(this).attr("href");
// prevent internal links (href.indexOf...) to open in safari if target
// is not explicitly set_blank, doesn't break href="#" links
if (href.indexOf(location.hostname) > -1 && href != "#" && $(this).attr("target") != "_blank")
{
event.preventDefault();
window.location = href;
}
});
I've found one that is very complete and efficient because it checks to be running only under standalone WebApp, works without jQuery and is also straightforward, just tested under iOS 8.2 :
Stay Standalone: Prevent links in standalone web apps opening Mobile Safari
You can also do linking almost normally:
TEXT OF THE LINK
And you can remove the hash tag and href, everything it does it affects appearance..
This is what worked for me on iOS 6 (very slight adaptation of rmarscher's answer):
<script>
(function(document,navigator,standalone) {
if (standalone in navigator && navigator[standalone]) {
var curnode,location=document.location,stop=/^(a|html)$/i;
document.addEventListener("click", function(e) {
curnode=e.target;
while (!stop.test(curnode.nodeName)) {
curnode=curnode.parentNode;
}
if ("href" in curnode && (curnode.href.indexOf("http") || ~curnode.href.indexOf(location.host)) && curnode.target == false) {
e.preventDefault();
location.href=curnode.href
}
},false);
}
})(document,window.navigator,"standalone")
</script>
This is slightly adapted version of Sean's which was preventing back button
// this function makes anchor tags work properly on an iphone
$(document).ready(function(){
if (("standalone" in window.navigator) && window.navigator.standalone) {
// For iOS Apps
$("a").on("click", function(e){
var new_location = $(this).attr("href");
if (new_location != undefined && new_location.substr(0, 1) != "#" && new_location!='' && $(this).attr("data-method") == undefined){
e.preventDefault();
window.location = new_location;
}
});
}
});
For those with Twitter Bootstrap and Rails 3
$('a').live('click', function (event) {
if(!($(this).attr('data-method')=='delete')){
var href = $(this).attr("href");
event.preventDefault();
window.location = href;
}
});
Delete links are still working this way.
I prefer to open all links inside the standalone web app mode except ones that have target="_blank". Using jQuery, of course.
$(document).on('click', 'a', function(e) {
if ($(this).attr('target') !== '_blank') {
e.preventDefault();
window.location = $(this).attr('href');
}
});
One workaround i used for an iOS web app was that I made all links (which were buttons by CSS) form submit buttons. So I opened a form which posted to the destination link, then input type="submit"
Not the best way, but it's what I figured out before I found this page.
I created a bower installable package out of #rmarscher's answer which can be found here:
http://github.com/stylr/iosweblinks
You can easily install the snippet with bower using bower install --save iosweblinks
For those using JQuery Mobile, the above solutions break popup dialog. This will keep links within webapp and allow for popups.
$(document).on('click','a', function (event) {
if($(this).attr('href').indexOf('#') == 0) {
return true;
}
event.preventDefault();
window.location = $(this).attr('href');
});
Could also do it by:
$(document).on('click','a', function (event){
if($(this).attr('data-rel') == 'popup'){
return true;
}
event.preventDefault();
window.location = $(this).attr('href');
});
Here is what I'd use for all links on a page...
document.body.addEventListener(function(event) {
if (event.target.href && event.target.target != "_blank") {
event.preventDefault();
window.location = this.href;
}
});
If you're using jQuery or Zepto...
$("body").on("click", "a", function(event) {
event.target.target != "_blank" && (window.location = event.target.href);
});
You can simply remove this meta tag.
<meta name="apple-mobile-web-app-capable" content="yes">