I have a windbg-issue concerning the execution
of a javascript-function as a breakpoint-command.
This observation was made in windbg Preview 10.0.17030.1002
and also in recent versions of windbg
when debugging a native x86 C++ program on Windows 10.
Test Setup
In my javascript-file dbg_test.js I have the following function:
function test()
{
var ctl = host.namespace.Debugger.Utility.Control;
host.diagnostics.debugLog(">>> Test\n");
ctl.ExecuteCommand("g");
}
In windbg, I load the javascript-provider, load my dbg_test.js script
and define a breakpoint-command to call this javascript-function:
bs 0 "dx #$scriptContents.test()"
Expected Behavior
The string ">>> Test" is shown in the output-pane of the command-window
everytime when breakpoint 0 is hit.
The debugger resumes execution.
Observed Behavior
The output ">>> Test" is shown only the first time
when breakpoint 0 is hit.
Subsequently hitting breakpoint 0 does not
produce any output.
Remarks
1) Doing the analogous test with "old style" windbg-commands works fine:
bs 0 ".printf \">>> Test\\n\\n\";g;"
but only after ending and restarting windbg
2) The same behavior is shown when I move the code of function "test" to the function "invokeScript()" and define the breakpoint-command via
bs 0 ".scriptrun d:\\dbg_scripts\\dbg_test.js"
3) Running the script from the windbg-command-line works.
4) Calling javascript-functions as in the test-scenario above worked in previous versions of windbg.
5) It seems that the statement
ctl.ExecuteCommand("g");
is the crucial one: If I comment out this statement, then the breakpoint
is hit every time and the output from
host.diagnostics.debugLog(">>> Test\n");
is shown on each hit of the breakpoint.
Of course, I have to resume the execution manually by pressing F5 or entering the command "g"
Questions
Can someone reproduce this issue ?
Is it legal to use javascript-functions in this way or am I doing something wrong here ?
Your feedback is greatly appreciated!
Kind/Best regards!
I ran into the same problem as you did. I was able to somewhat bypass the problem by declaring a script global variable
var lines = [];
and pushing log messages to this array rather than debug printing them:
lines.push(">>> Test");
In order to see the lines, I created a function
function print_lines() {
for (var line of lines) {
host.diagnostics.debugLog(line + "\n");
}
lines = [];
}
which I called from the prompt like so
dx #$scriptContents.print_lines();
I know that this is not really answering your question, but it might still be helpful for someone else that faces the same problem.
Related
Is there any automatical way to trace execution in a javascript application (in browser) ?
My need is to know according to the use case :
which functions are called
which functions call which functions
In fact, it's a code coverage by instrumentation (like Istanbul) but for runtime.
------------------------- EDIT -------------------------
I want to generate a map of functions used during execution.
Example :
1 - for use case #1 :
functA1 -> [functB3, functC2 -> [functE5, functD8 ] ]
functA2 -> [functT2]
functA3
With this kind of execution map, i can understand how the appl works
and compare execution between two releases.
on chrome debugging is awesomely done:
ctrl + option + j
click on 'Sources'
and then go to "Event Listener Breakpoints" and choose the event that may call your function and after that where the function call is going just press the F10 on it will move to next statement to execute and so on.
Please refer the screenshot: https://iamlalit.tinytake.com/sf/MTY5MDc1N181NjM1ODA1
You can set breakpoints in the browser's sources tab. On chrome it's ctrl + option + j and click on 'Sources'. From there you set a breakpoint at the function you want and can trace what gets executed line by line.
Hope this helps.
I've been having a hell of a time getting the comment count script to work on my react pages. To start, they recommend putting the script in my index.html file, at the bottom of the <body> tag. I've done this, and seen no result.
<body>
<div id="app">
</div>
<script src="static/index.js"></script>
<script id="dsq-count-scr" src="//mtg-hunter.disqus.com/count.js" async></script>
</body>
I have an index.js file which is loading all my components, including the component (let's call it ResultComponent.js) which I want to have the comment count <span> tags in. The <span> tags themselves look like this:
var commentCount = <span className="disqus-comment-count" onClick={function() {this.setState({currentSelectedTab: 4})}.bind(this)}
data-disqus-identifier={idGoesHere}
style={{fontVariant:"small-caps"}}>0 Comments</span>
So far, so simple. I'm not using any <a> tags so I haven't got #disqus_thread anywhere. When I load my page, I expect my comment count to go up, but no such luck. To test this, I copied the raw script, unaltered, from the raw count.js script (which is located here). I then pasted it straight into Chrome's devtools console, and it worked; all the relevant comment counters went to their appropriate values.
EDIT: a day later, more prodding; I added breakpoints in the actual code in the disqus.com domain. The script in the script tag is running just fine at the right time, except it's missing variables when it enters the displayCount() function. There's several variables that just aren't given values so it can't go in and populate the comment counts, it always fails out. I have no idea why this fails when it's called from within my index.html but not when I paste the raw count.js code into my console and do it there. No idea why.
To clarify, this is the relevant code:
e.displayCount = function(b) {
for (var c, a, d, e = b.counts, b = b.text.comments; c = e.shift(); )
if (a = j[c.id]) {
switch (c.comments) {
case 0:
d = b.zero;
break;
case 1:
d = b.one;
break;
default:
d = b.multiple
}
c = d.replace("{num}", c.comments);
a = a.elements;
for (d = a.length - 1; d >= 0; d--)
a[d].innerHTML = c
}
}
;
When it runs properly, from my pasting the script into the console, the j variable is defined. When it runs called from index.html, j is undefined, so it fails at the first if. The calling url is exactly the same in both situations: http://mtg-hunter.disqus.com/count-data.js?1=19767&1=235597&1=373322&1=382310&1=382841&1=382866&1=383023&1=397543&1=397682&1=398434. That gives the b parameter, and when I run the script locally it defines j so that the assignment operator in the if can work (which is a really weird way of doing it, but ok).
edit again: I should point out I'm doing this on a local test server (localhost:3000), not sure if that makes a difference or not?
edit more: The answer to my above question turns out to be 'no'. I uploaded my code to my server and the production site also showed that the script wasn't running properly. This is absurd... I'm out of ideas by now.
edit again more: Partial breakthrough... I added this code to ResultComponent.js:
componentDidMount() {
DISQUSWIDGETS.getCount();
},
componentDidUpdate() {
DISQUSWIDGETS.getCount();
},
Good news; when I refresh the page, it shows the right comment count! Hooray! Bad news: when I change parts of the page that hide the Result component, and then bring it back (triggering componentDidUpdate), the DISQUSWIDGETS.getCount() call doesn't work. It still gets called, but the displayCount part of the script never does, so the DOM is never updated with the new information. It's yet another example of this horrid script behaving differently despite being called in exactly the same way...
OK, after much back and forth with the support guy at Disqus I finally found an answer; I was close. The solution is:
componentDidMount() {
DISQUSWIDGETS.getCount({reset:true});
},
componentDidUpdate() {
DISQUSWIDGETS.getCount({reset:true});
},
Turns out I had to pass the reset:true param, which enabled a chunk of code in getCount to actually do something. I suppose I could've figured that out from the code, but I blame the intensely minified formatting (even with chrome dev tools helping to prettify it) for me missing that. It was also in their knowledge base article for how to add comment counters, but I missed the context of it (and got absorbed by the 'fact' that 'it obviously had to be the script not working, clearly').
And so ends one of my most frustrating few days of coding. And a useful lesson... step back and look at the big picture every now and again, because the answer can be staring you in the face.
I'm working on a Google Scripts add on for Google Sheets, but I'm trying to get the script working before I actually set it up on the sheet. The code below works fine if I set a breakpoint somewhere in the extractNumbers function. If I just execute the code without breakpoints, I get an error:
TypeError: Cannot call method "replace" of undefined. (line 36, file "")
Here's the code:
var myVar = phoneCheck("a1","a2","o1","o2");
Logger.log(myVar);
function phoneCheck(newCell,newHome,oldCell,oldHome) {
Logger.clear();
var newCell = extractNumbers(newCell);
var oldCell = extractNumbers(oldCell);
var newHome = extractNumbers(newHome);
var oldHome = extractNumbers(oldHome);
if (newCell === oldCell) {
return newCell;
exit;
} else if (newCell === oldHome && newHome === oldCell) {
return oldCell;
exit;
}
if (newCell === '' && oldCell !== '' ) {
return oldCell;
exit;
}
if (newCell !== oldCell && newCell !== oldHome) {
return newCell;
exit;
}
return "No value found";
exit;
}
function extractNumbers(input) {
Logger.log(input);
var str = input;
return str.replace( /\D+/g, '');
}
Now I realize my if/then logic is more than a bit inelegant, but for my purposes, quick and dirty is fine. I just need it to run.
ALSO, I have read of other novice JavaScript programmers having similar issues related to the sequence of code execution. If someone would like to link to a concise source aimed at a non-advanced audience, that would be great too. Thanks!
EDIT: I put my code into a new fiddle and it works fine, but it continues to fail in Google Scripts editor unless running in debug mode with a breakpoint. The problem seems to be that the function parameters aren't available to the function unless there is a breakpoint. Anyone have access to Google Scripts that can try my updated code from https://jsfiddle.net/hrzqg64L/ ?
None of the suggestions got to the root of your problem - and neither did your answer, although you've avoided the problem by putting an enclosure around everything.
There's no AJAX, no asynchronous behavior - it's simpler than that. "Shadowing of parameters" is likewise a red herring. Bad coding practice, yes - but not a factor here.
If someone would like to link to a concise source aimed at a non-advanced audience, that would be great too.
Sorry - no such thing. I can explain what's going on, but can't guarantee it will be accessible to novices.
The exception
Let's just clarify what causes the exception, or thrown error, that you've observed.
As written, extractNumbers() will throw an exception if it has a null parameter (or any non-string parameter) passed to it. If you choose to extractNumbers() then hit "run", you'll get:
TypeError: Cannot call method "replace" of undefined. (line 36, file "")
That is telling you that on line 36, which is return str.replace( /\D+/g, '');, the variable str contains an object that is undefined (...and has no replace() method).
For bullet-proof code, you would check your parameter(s) to ensure they are valid, and handle them appropriately. Sometimes that would be with a valid default, and other times you might return an error or throw an exception that is more explicit about the parameter problems.
Running code in Google's debugger
The only way to run code in Google's Debugger is to select a function, then choose "run" or "debug". Assuming you posted all your code, you had just two functions to choose from:
phoneCheck()
extractNumbers()
Whenever Google Apps Script runs any part of a script, the entire script is loaded and scanned to find all symbols & check syntax. The scope of all symbols is noted as well, and so are any dependencies between functions and global symbols (symbols outside of any closure, or block of code).
That takes some time. To speed things up when asked to execute a specific function, the global symbols are only evaluated if they are a dependency for the requested function or the functions it may call. There is another condition that will trigger evaluation of global symbols, and that is if there is a possibility that the debugger may need to stop and display values.
When this happens, any code that is outside a closure (outside a function, for example) will be executed. This is what you observed when you set breakpoints.
Why did it work when breakpoints were set?
As explained, just having a breakpoint set triggers evaluation of global symbols.
You start this script with a few lines of code that are not in any closure:
var myVar = phoneCheck("a1","a2","o1","o2");
Logger.log(myVar);
It is that code which makes the only proper invocation of phoneCheck() with parameters. Because myVar is evaluated, phoneCheck() gets called with parameters, and in turn calls extractNumbers() with a defined parameter.
Unfortunately, because of the way the debugger works, you cannot choose to run that code yourself. You need to rely on these side-effect behaviors.
How to fix this?
Simple. Don't rely on global code to invoke functions under test. Instead, write an explicit test function, and call that.
function test_phoneCheck() {
var myVar = phoneCheck("a1","a2","o1","o2");
Logger.log(myVar);
}
Finally found the issue, but I don't fully understand it.
This question got me thinking about scope and how it might be different in the Google Script environment. I figured a simple workaround would be to enclose the entire script in its own void function, and it worked! Also, I simplified the script quite a bit with an array:
function init () {
var numberArray = ["a3", "a2", "o3", "o10"];
var myVar = phoneCheck(numberArray);
Logger.log(myVar);
function phoneCheck(myArray) {
var phoneString = '';
Logger.clear();
var arrayLength = myArray.length;
for (i = 0; i < arrayLength; i++) {
phoneString += myArray[i].replace(/\D+/g, '');
}
return phoneString;
}
}
Also, I realize the functionality of this script is different than the original, but I was really just trying to solve this problem. Now that I have, I can finish the script properly.
Thanks for all the suggestions, everyone! I learned a lot of good things, even though they turned out not to be the answer.
I need this because I often work on existing projects, and I'm required to crash right into the middle of somebody else's work. With little time nowadays, I'm looking for whatever tool I can find to do this:
Load a JS application
Start / Pause recording activity
Show me exactly what happened, in the form of what functions were called without requiring me to change the source code.
For example:
<script language="javascript">
var fn1 = function(strvar){ alert('var='+strvar); fn2(strvar); }
var fn2 = function(strvar2){ alert('var='+strvar2); }
</script>
click here
After I click the anchor, (at best) should get something like this:
(click) event on a
(call) fn1("click here")
(call) fn2("click here") from inside fn1 called at pct. 2
Some sort of stack tracing but without having to alter the source because it takes formidable time as it is.
If you write
debugger;
in your innermost function, you can open firebug or the chrome dev tools and their debugger will pause when it hits that line. Then in the section on the right of the tools, you can see the stack trace and other relevant data (locals, etc...).
You only need to add one line to a function you own and it will show you any calls made with anyone's code.
I am trying to customize the behavior of Selenium's click command, (via user-extentions.js), by intercepting calls to doClick(locator). Basically I need to delay click actions whenever our application's "busy indicator" is being displayed.
(Now the standard answer for this kind of thing is to insert a waitFor into the script for those situations. Indeed, we currently have zillions of them throughout our scripts. I'm trying to eliminate those.)
Detecting the page element is the trivial part. The tricky part is getting the script to actually wait. My promising looking, but failed attempt looks like this:
var nativeClick = Selenium.prototype.doClick;
Selenium.prototype.doClick = function(locator) {
this.doWaitForCondition("!selenium.browserbot.findElementOrNull('busy-indicator')", 5000);
return nativeClick.call(this, locator);
}
The doWaitForCondition gets called before every click, but it does not wait when the condition evaluates to false. nativeClick always gets called immediately, and so no delay is introduced. I suspect that the doWaitForCondition function doesn't actually do any waiting per se, but rather establishes the conditions for it within the command execution loop. And in this case the click command is already in play, and I'm trying to run a command within a command.
Can somebody shed some light on how Selenium command execution and waitFor works, or offer suggestions on how this might be done?
I have finally solved this. And with an approach that is much better than trying to intercept click processing in its various forms. My refined goal is: to delay execution of script command completion when our application is "busy".
How Selenium command processing works:
Upon completion, each selenium command returns an ActionResult object, (see ActionHandler.prototype.execute). The terminationCondition attribute on this object is a function that determines when it is okay for selenium to proceed to the next command, (TestLoop.prototype.continueTestWhenConditionIsTrue). Basically, selenium repeatedly executes the condition function until it yields true. The result object it quite trivial:
function ActionResult(terminationCondition) {
this.terminationCondition = terminationCondition;
}
Customizing it:
I want to delay execution any time myAppIsBusy() returns true. Of course all of the standard delays need to remain in place as well, like waiting for page loads, and explicit waitFor conditions as scripted. The solution is to redefine the selenium result object in my user-extensions.js, as follows:
function ActionResult(terminationCondition) {
this.terminationCondition = function() {
// a null terminationCondition means okay to continue
return (!terminationCondition || terminationCondition()) && !myAppIsBusy();
}
}
The great thing is that this is at a low enough level that it works for the IDE, as well as for RC.
Note that this does not affect Accessor or Assert command types, which return different result objects. But that should be fine, because those commands don't effect the state of the application.
Well, a look at the java drivers com.thoughtworks.selenium.Wait class reveals this:
public void wait(String message, long timeoutInMilliseconds, long intervalInMilliseconds) {
long start = System.currentTimeMillis();
long end = start + timeoutInMilliseconds;
while (System.currentTimeMillis() < end) {
if (until()) return;
try {
Thread.sleep(intervalInMilliseconds);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
throw new WaitTimedOutException(message);
}
I am not to deep into selenium but I excpect that every waitXXX Method points to this.
So, Selenium is working with Thread.sleep(). While this might not look like an ideal solution it shows at least that you cant make it worse by using Thread.sleep() on your own if neccessary. ;-)