For debugging, I want to be able to print messages, and have the line number prepended.
No, I don't want to get involved with a full-fledged debugger.
I have defined a global constant ln="thisline = new Error().lineNumber";
I have defined a
function println(msg) {
document.write("<br>at " + thisline + ":" + msg);
}
Then at the lines I want to debug I put a line saying:
eval(ln);
println("msg");
The problem is that thisline often doesn't get updated before the print, so I get long stretches with an unchanging line number. I never get more than 3 unique line numbers printed.
Is it just that the eval is too slow? Is there some way to wait till it finishes?
I tried a timeout:
const ln="setTimeout(function() {
thisline = new Error().lineNumber
}, 1000);"
but the global thisline never got set.
Or is it that there is some system limit on the number of errors I can raise?
If you are running the application in IE, then press F12 key(Developer tools) and another popup will open.
click on the Script Tab and click on Start Debugging button.
the page will refresh and you can start performing actions.
on any error, the debugger will automatically take you to the error line number. you can also place break points.
else you can look at the below following post:
How can I get a Javascript stack trace when I throw an exception?
Related
Running in IE is a legacy app built with frames that makes alot of references cross-frame like parent.header.blah.blah and parent.sidebar.so.and.so. Worked fine in old IE compatibility mode. Works in chrome and edge (chromium).
But in regular IE without compatibility mode on, it's throwing a permission denied error on line 43. Thing is, it throws the error in the console NO MATTER WHAT IS ON LINE 43!!! I added superfluous lines of code to push other code down, took out code to move other code up. Doesn't matter, the console ALWAYS says it's on line 43.
I put breakpoints in and noticed the error doesn't actually add to the console until AFTER the javascript has finished running. The page is very large with ALOT of javascript, and it's dificult to comment a section out without breaking the page to experiment with what might be causing the permission denied.
Permission Denied is supposed to indicate a same-origin violation as I understand it, but all frames and files are coming through the same servlet on the same URL with only parameters changing. I printed out the document.domain of every frame, they all are identical.
So..I'm not even sure what to do at this point to narrow it down. How can I figure out what is really the offending piece of code...or even section?
UPDATE - So it seems that the error is actually coming from a function in another frame being called from this frame (nowhere near line 43 by the way). That function is managing the options in a select list. The actual error comes here:
for (var k=0; k < assetListz.options.length; k++) {
if (assetListz.options[k].value == currentAsset) { //permission denied!
inList = true;
assetListz.options[k].selected = true;
break;
}
}
assetListz didn't have a 'z' on it until I just did that to make sure I wasn't accidentally getting scope to some OTHER assetList. I can test the length of the assetList, but as soon as I check the value on that second line, kaboom. Ideas?
Update 2 -
I changed the code to get the assetlist in each reference. No storing it. Blows up in the same place.
for (var k=0; k < document.getElementById('assetList').options.length; k++) {
if (document.getElementById('assetList').options[k].value == currentAsset) {
inList = true;
document.getElementById('assetList').options[k].selected = true;
break;
}
}
Okay, I got this fixed. I'm not sure exactly WHY this fix works, though I can guess. It seems that by rewriting the method so that it avoids use of the options array on the select object, everything works fine. I reference it just once to get the length...which it allows. but if i try to get a specific option by assetList.options[i].anything, then I get permission denied.
I still think this is a bug in IE11's same-origin code, but lucky for me, it seems like MS didn't re-use code so the same bug didn't 'protect' all means of accessing the select options. Just via the array property. Or maybe something else is goin on. I just know this worked for me.
//By changing the value attribute, we change the current selection.
assetList.value = currentAsset.toUpperCase();
if(assetList.selectedIndex == -1) {
//this means the current asset wasn't in the list.
if(assetList.options.length >= 1000) {
//not allowed to add more than 1000. And if so, set the selectedIndex back
alert("The Active Asset List contains the maximum of 1000 entries. \n" +
"The current Asset ID '" + currentAsset + "' was not added to the Active Asset List.");
assetList.selectedIndex = currentSelectedIndex;
return;
} else {
var option = document.createElement("OPTION");
option.value = currentAsset;
option.text = currentAsset;
assetList.add(option, 0);
assetList.selectedIndex = 0;
}
}
What I'm doing
I've been experimenting with Selenium and making a simple program to make my Selenium testing life easier. Part of this is testing webelements and figuring out what methods (clicking submitting ect) make them reload the page, remain static, or become stale without reloading the page. In this question I'm particularly interested in the third case as the first two are already implemented by me.
The problem I'm having
The problem I have is finding a Webelement that goes stale and doesn't cause a page reload. I can't think of a good way to search for one, I don't have the HTML and javascript skills to make one (yet anyways) and I can't verify my code works unless I actually test it.
What I've done/tried
The first thing I thought to look for was a popup but those aren't actually part of the webpage and they're also quite unreliable. I want something thats going to behave consistently because otherwise the test won't work. I think dynamic Webelements, those that change their locators when acted upon will suit my needs but I have no good way of finding them. Any google results for "Self deleting webelement exmaple" or "Webelement goes stale doesn't cause page reload example" or similar, will only give me questions on stackoverflow like this one rather than what I want - concrete examples. The code I'm running simply waits for a staleReferenceException and for an onload event in javascript. If the staleReferenceException occurs but the onload event does not, then I know I've found a self-deleting / dynamic webelement (at least thats what I think is the proper way to detect this). Here is the code I'm running:
try {
//wait until the element goes stale
wait.until(ExpectedConditions.stalenessOf(webElement));
//init the async javascript callback script
String script = "var callback = arguments[arguments.length - 1];" +
"var classToCall = 'SeleniumTest.isPageReloaded';" +
"window.addEventListener('onload'," + "callback(classToCall));";
//execute the script and wait till it returns (unless timeout exceeded)
JavascriptExecutor js = (JavascriptExecutor) driver;
//execute the script and return the java classname to call
//if/when the callback function returns normally
String classToCall = (String) js.executeAsyncScript(script);
clazz = Class.forName(classToCall);
callbackMethod = clazz.getMethod("JavascriptWorking");
callbackMethod.invoke(null,null);
//page reloaded
threadcase = 1;
}
//waiting until webElement becomes stale exceeded timeoutSeconds
catch (TimeoutException e) {
//page was static
threadcase = 2;
}
//waiting until webElement Reloaded the page exceeded timeoutSeconds
catch (ScriptTimeoutException e) {
//the webElement became stale BUT didn't cause a page reload.
threadcase = 3;
As you can notice above there is an int variable named threadcase in this code. The three 'cases' starting from 1 (0 was the starting value which represented a program flow error) represent the three (non-error) possible results of this test:
the page reloads
the page remains static, webelement doesn't change
the page remains static, webelement changes
And I need a good example with which to test the third case.
Solutions I've considered
I've done some basic research into removing webelements in javascript but I A: don't even know if I can act on the page in Selenium like that and B: I'd rather get a test case that just uses the Webpage as is since introducing my edits makes the validity of my testcase reliant on more of my code (which is bad!). So what I need is a good way of finding a webelement that matches my criteria without having to scour the internet with the f12 window open hoping to find that one button that does what I need.
Edit 1
I just tried doing this test more manually, it was suggested in an answer that I manually delete a webelement at the right time and then test my program that way. What I tested was the Google homepage. I tried using the google apps button because when clicked it doesn't cause the whole page to reload. So my thinking was, I'll click it, halt program execution, manually delete it, run the rest of my code, and since no onload events will occur, my program will pass the test. To my suprise thats not what happened.
The exact code I ran is the below. I had my debug stop on the first line:
1 Method callbackMethod = null;
2 try {
3 //wait until the element goes stale
4 wait.until(ExpectedConditions.stalenessOf(webElement));
5 //init the async javascript callback script
6 String script = "var callback = arguments[arguments.length - 1];" +
7 "var classToCall = 'SeleniumTest.isPageReloaded';" +
8 "window.addEventListener('onload', callback(classToCall));";
9 //execute the script and wait till it returns (unless timeout
10 //exceeded)
11 JavascriptExecutor js = (JavascriptExecutor) driver;
12 //execute the script and return the java classname to call if/when
13 //the callback function returns normally
14 String classToCall = (String) js.executeAsyncScript(script);
15 clazz = Class.forName(classToCall);
16 callbackMethod = clazz.getMethod("JavascriptWorking");
17 callbackMethod.invoke(null,null);
18 //page reloaded
19 threadcase = 1;
20 }
21 //waiting until webElement becomes stale exceeded timeoutSeconds
22 catch (TimeoutException e) {
23 //page was static
24 threadcase = 2;
25 }
26 //waiting until webElement Reloaded the page exceeded
27 //timeoutSeconds
28 catch (ScriptTimeoutException e) {
29 //the webElement became stale BUT didn't cause a page reload.
30 threadcase = 3;
31 //trying to get the class from javascript callback failed.
32 }
whats supposed to happen is that a Stale webelement causes the program to stop waiting on line 4, the program progresses, initializes the Javascript callback in lines 6-11 and then on line 14 the call to executeAsyncScript is SUPPOSED to wait untill an 'onload' event which should only occur if the page reloads. Right now its not doing that or I'm blind. I must be confusing the program flow because I'm 99% certain that there are no page reloads happening when I manipulate the DOM to delete the webelement I'm clicking on.
This is the URL I'm trying:
https://www.google.com/webhp?gws_rd=ssl
Simple google homepage, the button I'm deleting is the google apps button (the black 9-grid in the top right)
some info on that element:
class="gb_8 gb_9c gb_R gb_g"
id="gbwa"
Its the general container element for the button itself and the dropdown it creates. I'm deleting this when my program hits the STOP on line 1. Then I go through my program in the debugger. Note (you may have to click inspect element on the button more than once to focus in on it). I'm going to try deleting lower level elements rather than the whole container and see if that changes anything but still this behavior baffles me. The goal here is to get the program flow to threadcase 3 because thats the one we are testing for. There should be no page reloads BUT the webelement should become stale after I manually delete it. I don't have any clue why the javascript callback is running when I can't see a page reload. Let me know if you need more info on what exactly I'm deleting on the google homepage and I'll try sending a picture (with optional freehand circles of course).
I would think that you could debug through a test, place a breakpoint at a suitable point, then use the browsers dev tools to manually update the HTML.
Obviously, if you want this to be a repeatable process it is not an option, but if you are just investigating, then a manual intervention could be suitable
I'd like to execute a sequence of javascript code on a website which involves a lot of loading of new pages, still continuing the execution at every freshly loaded page. This is an excerpt:
document.location.href = "https://www.somehost.com"
document.getElementById("userfield").value = "<username>"
document.getElementById("passfield").value = "<password>"
document.getElementById("loginbtn").click();
document.evaluate(".//a[.='Messages']",document,null,XPathResult.ANY_UNORDERED_NODE_TYPE,null).singleNodeValue.click();
document.evaluate(".//a[.='Inbox']",document,null,XPathResult.ANY_UNORDERED_NODE_TYPE,null).singleNodeValue.click();
If I paste this line by line into Firefox' console (starting at about:blank), everything works fine and I get to my Inbox. However, if I paste the whole sequence, or encapsulate it into a function, I only get past the first step of loading the page where it tells me that getElementByID returns null. I also tried to do the same with a new window:
var new_window = window.open("https://www.somehost.com","_blank");
new_window.document.getElementById("userfield").value = "<username>"
new_window.document.getElementById("passfield").value = "<password>"
new_window.document.getElementById("loginbtn").click();
new_window.document.evaluate(".//a[.='Messages']",new_window.document,null,XPathResult.ANY_UNORDERED_NODE_TYPE,null).singleNodeValue.click();
new_window.document.evaluate(".//a[.='Inbox']",new_window.document,null,XPathResult.ANY_UNORDERED_NODE_TYPE,null).singleNodeValue.click();
Still no luck.
How can I execute this sequence as if I just pasted every single line one by one?
Does it have to do something with the javascript execution being faster than the website's loading process?
I am trying to delete a database for unit testing:
var DeleteDb = indexedDB.deleteDatabase(dbName);
this piece of code gets directly called in the first beforeEach in jasmine.
with chrome devTools i can see that DeleteDb.error has the following value:
error: [Exception: DOMException: Failed to read the 'error' property from 'IDBRequest': The request has not finished.]
DeleteDb.onsuccess or DeleteDb.onerror are never fired. Also i am never trying to read an 'error' property in the code.
Does somebody know what this error means, where it is coming from or how i can solve it?
UPDATE:
This code still sometimes fails for me. it gives me the same error as above.
<html>
<head>
<script>
var deleteDb = window.indexedDB.deleteDatabase('fakeNonExistentDatabase');
deleteDb.onsuccess = function() {
console.log('complete');
};
</script>
</head>
</html>
I am still not sure why this is happening. sometimes opening a new tab or closing another one works.
Also it never gives an error when removing the onsuccess callback
UPDATE 2
Well it seems that the code is actualy working, but the onsuccess event is never getting fired because no events are getting fired anymore when pressing F8 in chrome devtools. The error i;m getting now is:
Uncaught InvalidStateError: Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing.
I thought the above error message was a result of the first error message in this post but actualy it was the other way around. There are a few pages i can find about this topic on the internet but there isn't really provided a answer.
Any thoughts?
Also check onblocked. There might be another db connection that keeps your delete request from neither succeeding nor failing.
It is possible to avoid this behaviour by listening to onversionchange on your opened connections and make sure to close the connection when that event is triggered.
Okay as it turns out all of my code was good but deleting a database a second time takes somwhere between 10 seconds and several minutes.
you can test this for yourself: the code in this post shows it
what was happening is that jasmine times out after 5 seconds by default (i changed this to a higher number but who would think i takes THAT long)
browser: Chrome 39.0.2171.71 m
Make sure when deleting
the RESULT from DB creation is not empty
close the RESULT before deleting
delete through the same connection you created
var init=function(){
var request = this.connection.open(name,version);
request.onupgradeneeded=function(e){
var version=e.target.result;
};
request.onsuccess=function(e){
db.result=e.target.result;
};
request.onerror=function(e){
};
};
var remove=function(){
if (typeof db.result !== 'undefined') {
db.result.close();
return this.connection.deleteDatabase(version);
}
}
This is 5 years late, but just in case there are more guys like me...
close the connection to the database before deleting it...
I work with some very large and confusing JavaScript files that I did not write. Sometimes an alert will come up but I don't know where it's coming from.
You could search all files for the text contained in the alert but if that text is dynamic it won't work.
Is there a way to set a breakpoint in order to intercept an alert?
At the very top of your HTML:
window.alert = function() {
debugger;
}
debugger is a statement that invokes any debugging functionality available. With developer tools open, you'll automatically hit a breakpoint whenever alert is called. You can then inspect the call stack to see exactly what called the custom alert function.
It may or may not be helpful to you, but you can overwrite the alert function to do whatever you want with it. For example, instead of alert boxes, you could have it log the message to the console.
window.alert = function(msg) {
console.log(msg);
}
alert('test');
I agree with Brian Glaz, but in order to get more details (line number) you might try to throw an error when alerting something and outputting the error on the console. this way, the console will point you to the right line number where the alert function was called.
Put this snippet at the top of your document and give it a try :
var originalAlert = window.alert;
window.alert = function(){
try{
throw new Error('alert was called');
} catch(e){
console.warn(e);
}
return originalAlert.apply(window, arguments);
}
Open Chrome push F12 key and go to Sources.
Then choose a script file Ctrl+F and search for alert.
You can put breakpoint on any line you wish