Automation script is not working? - javascript

This is the first time I get my hands on with automation instruments in xcode The script works well for all button taps but the one making server connection. I don't know the reason
Here is the script I tried so far
var target = UIATarget.localTarget();
target.pushTimeout(4);
target.popTimeout();
var window=target.frontMostApp().mainWindow()
var appScroll=window.scrollViews()[0];
appScroll.logElementTree();
UIATarget.localTarget().delay(2);
appScroll.buttons()[1].tap();
The above script works up to showing the UIActivityIndicator instead of moving to next controller after success
I know There must be a very simple point I am missing. So help me out

UIAutomation attempts to make things "easy" for the developer, but in doing so it can make things very confusing. It sounds like you're getting a reference to window, waiting for a button to appear, then executing .tap() on that button.
I see that you've already considered messing with target.pushTimeout(), which is related to your issue. The timeout system lets you do something that would be impossible in any sane system: get a reference to an element before it exists. I suspect that behind-the-scenes, UIAutomation repeatedly attempts to get the reference you want -- as long as the timeout will allow.
So, in the example you've posted, it's possible for this "feature" to actually hurt you.
var window=target.frontMostApp().mainWindow()
var appScroll=window.scrollViews()[0];
UIATarget.localTarget().delay(2);
appScroll.buttons()[1].tap();
What if the view changes during the 2-second delay? Your reference to target.frontMostApp().mainWindow.scrollViews()[0] may be invalid, or it may not point to the object you think you're pointing at.
We got around this in our Illuminator framework by forgetting about the timeout system altogether, and just manually re-evaluating a given reference until it actually returns something. We called it waitForChildExistence, but the functionality is basically as follows:
var myTimeout = 3; // how long we want to wait
// this function selects an element
// relative to a parent element (target) that we will pass in
var selectorFn = function (myTarget) {
var ret = myTarget.frontMostApp().mainWindow.scrollViews()[0];
// assert that ret exists, is visible, etc
return ret;
}
// re-evaluate our selector until we get something
var element = null;
var later = get_current_time() + myTimeout;
while (element === null && get_current_time() < later) {
try {
element = selectorFn(target);
} catch (e) {
// must not have worked
}
}
// check whether element is still null
// do something with element
For cases where there is a temporary progress dialog, this code will simply wait for it to disappear before successfully returning the element you want.

Related

Chrome Extension JavaScript Program Not Working

I am learning chrome extension programming from the tutorial here .
You can find the full code for the chrome extension here.
The code snippet where I tried to remove few links:
var clean_twitter = function(){
var ugly = [];
ugly.push('.Trends module trends');
ugly.push('.flex-module');
ugly.push('.MomentMakerHomeModule-header');
ugly.push('.Footer module roaming-module');
ugly.push('.flex-module-header');
$('.promoted-tweet').hide(); // oops! :P
for(var i=0;i<ugly.length;i++) {
var u = $(ugly[i]).find('a'); // also 'b'
u.text('');
}
}
The code tries to remove some buttons and div from the twitter website.
Now, when I put it on my pc nothing happens. I tried to remove the change link inside the trends box and it isn't removed.
Please help if I am doing something wrong here. Thanks.
At the beginning of the process_new_tweets function there's a comment explaining how the presence or absence of .mini-profile in the DOM is used as a flag.
In summary, the absence of the .mini-profile element in the DOM means that the function returns and won't proceed any further. Since the tutorial was written it would appear that Twitter no longer has a .mini-profile element anywhere in its DOM, so the function is always returning and script execution is not proceeding any further.
Remove the following lines from the beginning of the process_new_tweets function:
var mp = document.getElementsByClassName('mini-profile');
if(mp.length === 0) { return; }
And the elements that you've selected in your clean_twitter function will be removed from the DOM as expected.

document.getElementById always returns "null" for ribbons

I need to set the background color of one of the buttons in the form's ribbon. This isn't supported through Ribbon Workbench, so I have written following javascripts to achieve the same:
function setOpportunityRibbonsAppearance() {
var submitToForeCastButton = parent.document.getElementById("opportunity|NoRelationship|Form|sfw.opportunity.Button1.Button");
if (submitToForeCastButton != null) {
submitToForeCastButton.style.backgroundColor = "lightyellow";
}
}
I have registered this scripts in Form Load event. However the issue is that, I always get parent.document.getElementById as null only.
Surprisingly, I am able to see the control while running the parent.document.getElementById statement in the browser's console, and can also change the styling attributes.
Can anyone please suggest what could be wrong here?
P.S. - I understand document.getElementById is not recommended to use in CRM, however, I am left with no other choice while trying to change the appearance of some of the buttons.
Any help on this, will be much appreciated.
You could upload an icon with a yellow background, to keep everything supported. You won't see text on yellow but it might work for you. Easy and standard.
To keep it unsupported and ugly, you could just keep on trying until you make it, setInterval allows for a function to be repeated:
function setOpportunityRibbonsAppearance() {
var submitToForeCastButton = null;
var interval = setInterval(function(){
submitToForeCastButton = parent.document.getElementById("opportunity|NoRelationship|Form|sfw.opportunity.Button1.Button");
if(submitToForeCastButton != null) {
submitToForeCastButton.style.backgroundColor = "lightyellow";
clearInterval(interval);
}
}, 500); // Every 500ms. Adjust as needed, not too fast or browser will choke.
}
Its probably because your script is running before the page is fully loaded.
Try adding a delay to the to the function Put a Delay in Javascript

Why does waitForKeyElements() only trigger once despite later changes?

For several years I've used the waitForKeyElements() function to track changes in webpages from a userscript. However, sometimes I've found it doesn't trigger as expected and have worked around out. I've run into another example of this problem, and so am now trying to figure out what the problem is. The following is the barest example I can create.
Given a simple HTML page that looks like this:
<span class="e1">blah</span>
And some Javascript:
// function defined here https://gist.github.com/BrockA/2625891
waitForKeyElements('.e1', handle_e1, false);
function handle_e1(node) {
console.log(node.text());
alert(node.text());
}
setInterval(function() {
$('.e1').text("updated: "+Math.random());
}, 5000);
I would expect this code to trigger an alert() and a console.log() every 5 seconds. However, it only triggers once. Any ideas?
Here's a codepen that demonstrates this.
By design and default, waitForKeyElements processes a node just once. To tell it to keep checking, return true from the callback function.
You'll also want to compare the string (or whatever) to see if it has changed.
So, in this case, handle_e1() would be something like:
function handle_e1 (jNode) {
var newTxt = jNode.text ();
if (typeof this.lastTxt === "undefined" || this.lastTxt !== newTxt) {
console.log (newTxt);
this.lastTxt = newTxt;
}
return true; // Allow repeat firings for this node.
}
With the constant string comparisons though, performance might be an issue if you have a lot of this on one page. In that scenario, switching to a MutationObserver approach might be best.

How to resolve StaleElementReference in Mocha.js + Selenium + wd.js

I'm writing automation tests for a website using Mocha + SeleniumServer + wd.js + chai-as-promised.
The website uses JavaScript for the front-end which seems to refresh the elements on the page when certain action is performed. i.e. Upon selecting an element in a grid, the "next" button is enabled to allow user to move on to the next page. It seems that this changes the reference to the button element resulting in the StaleElementReference error.
describe('1st step', function () {
it('should select an element is grid', function () {
return browser
.waitForElementByCss('#grid', wd.asserters.isDisplayed, 20000)
.elementByCss('#grid .elementToBeSelected')
.click()
.sleep(1000)
.hasElementByCss('#grid elementToBeSelected.active')
.should.eventually.be.true;
});
it('should proceed next step', function () {
return browser
.waitForElementByCss('.btnGrid .btn.nextBtn:not(.disabled)', wd.asserters.isDisplayed, 20000)
.elementByCss('.btnGrid .btn.nextBtn:not(.disabled)')
.click()//Error thrown here
.sleep(2000)
.url()
.should.eventually.become('http://www.somewebsite.com/nextpage');
});
});
With my limited experience with JavaScript, I have tried all that i could think off, but to no avail. So is there anyway I can avoid this StaleElementReference error? Also, the error is only sometimes thrown during execution.
You might want to read some more on the Stale Element Reference exception. From what you are describing, it sounds like you get a reference to an element, do something on the page which then changes/removes the referenced element. When you do something with the variable reference you get this error. The solution really depends on the code you are using to do your tests and your framework for accessing elements. In general, you need to be aware of when you perform an action that changes the page and refetch the element before you access it. You could always refetch an element before you access it, you could refetch all elements that are affected by a page change, and so on...
You code probably looks something like this
WebElement e = driver.findElement(...); // get the element
// do something that changes the page which, in turn, changes e above
e.click(); // throws the StaleElementReference exception
What you probably want is something more like one of these...
Don't fetch the element until you need it
// do something that changes the page which, in turn, changes e above
WebElement e = driver.findElement(...); // get the element
e.click(); // throws the StaleElementReference exception
...or fetch it again right before you need it...
WebElement e = driver.findElement(...); // get the element
// do something that changes the page which, in turn, changes e above
e = driver.findElement(...); // get the element
e.click(); // throws the StaleElementReference exception
I would prefer the first fix... just fetch what you need when you need it. That should be the most efficient way to solve this problem. The second fix might have performance issues because you might be refetching a bunch of elements over and over and either never using them or refetching them 10 times only to reference the element once at the end.

document.getElementById does not return null, but also does not do what I want. No error in javascript console

In this instance, I load a single paypal page, in which I am prompted to login. Once I login, the page changes, through the use of other javascripts on paypal's end. The address does not change on this transition, nor does the source code in any material way. I am trying to find a way to have my script wait long enough after the first click to be able to get the element that loads after. I thought I could do this fairly simple using the following:
document.getElementById("submitLogin").click();
window.onload = function() {
document.getElementById("continue").click();
};
When the script is executed, the first button is clicked, the page transitions, but it won't click the second button that loads. My javascript console does not report any errors, suggesting that it is able to "get" the element. Not sure why it won't click it though.
If nothing else, you could always poll for the existence of the "continue" element at some interval:
function clickContinue() {
var button = document.getElementById("continue");
return button ? button.click() : setTimeout(clickContinue, 100);
}
document.getElementById("submitLogin").click();
clickContinue();
If you go this route, you'll probably want to include a failsafe so it doesn't run too long, in case something unexpected happens. Something like this should work:
clickContinue.interval = 100; // Look for "continue" button every 0.1 second
clickContinue.ttl = 10000; // Approximate time to live: 10 seconds ~ 10,000 ms
clickContinue.tries = clickContinue.ttl / clickContinue.interval | 0;
function clickContinue() {
var button = document.getElementById("continue"),
interval = clickContinue.interval;
return button ? button.click() :
clickContinue.tries-- && setTimeout(clickContinue, interval);
}
// ...
Take a look at PayPal's API docs and see if they provide a way to set up a callback to handle this, though. This polling technique should probably only be used as a last resort.

Categories