Monday, October 1, 2012

Ember.js Debugging 1 — Firefox

Note: Debugging was going to part 5 of the "Tools & Resources" series, but when I started outlining it and doing additional research, it became apparent that it's simply too big a topic for that. I've instead spun it out into a separate series.

This post is about the tools built-in to Firefox which are relevant to debugging Ember.js apps. I'll be using the latest version, which is 15 as of this post.

Mozilla Development Network

The MDN site is incredible — a wealth of information about everything a web developer could want to know about the browser platform:


However, the most important section (for us) isn't linked from here — or anywhere else on the site that I could find. I had to stumble across it a different way, but now I can save you the trouble:

https://developer.mozilla.org/en-US/docs/Tools

I'll be covering the Page Inspector and Web Console below. I didn't find the Scratchpad useful, and while the Debugger is important, it behaves like most debuggers. If you want the details, click through to the docs page, it's short.

All of the tools can be found via the Tools -> Web Developer menu. While the Error Console is still listed, it's use has been deprecated in favor of the Web Console since v4.

Page Inspector

It's listed on the menu as "Inspect", but it's full name is the Page Inspector to differentiate it from the Object Inspector (more on that soon). You can active it from the menu, or via the shortcut (Shift+Ctrl+I), or by right-clicking on an element in the page and selecting "Inspect Element".

This pops up a gray bar along the bottom of the window that shows you the path to the element in breadcrumb-style. You can get information about the HTML attributes and CSS styles, navigate the DOM from that point using arrow keys, or pop up a larger pane with the whole DOM tree.

I prefer Firebug's inspector, but it's still handy to have this, and the form factor is more elegant. There are two more features I'd like to call attention to. First of all, if an element is selected, you can reference that element using the $0 variable in the Web Console. Secondly, it has a 3D View button:


It's fun to play with, but it's also useful for visualizing the DOM and seeing how your elements are nesting.

Web Console

You can active it from the menu or via the shortcut (Shift+Ctrl+K). This pops up a pane along the top of the window which displays the log of console output, followed by an input box which you can type JavaScript into to to try things out, examine variable state, etc. This is invaluable. Do it now so you see what it looks like before I get into more detail about the pane. (You can detach the pane to leave more room for reading this post by clicking on Position.)

No, seriously. Do it now. (Shift+Ctrl+K)

The Output Pane

The four categories of console messages are Net, which show all HTTP activity (like fetching documents or POSTing to a server); CSS, which is for reporting CSS errors; JavaScript, which is for reporting JavaScript errors (syntax/API errors, not application exceptions); and Logging, which is for messages generated via the console.error/info/log/warn methods.

The four buttons on the top left correspond to those four categories, and you can click on them to control which messages get filtered out. Note the color keys (black, blue, yellow, light gray). There's a vertical bar just to the right of timestamp at the start of each line. The section of of that bar on each line is color-coded to indicate which of the four categories that line's message comes from.


Some tips:
  • The URL in Net messages is a link which pops open a window that let's you see the all details, including headers, cookies, status code — but first...
  • Right-click on the pane and select "Log Request and Response Bodies". Now you'll be able to see the actual content of the request and response in addition to the headers, which is critical when debugging REST API calls. (It's capped at 1mb of data.)
  • Console messages that repeat multiple times (like an error generated in a loop) are grouped into a single line with a red counter near the right end.
The Input Box

This is essentially an interactive JavaScript shell, like irb for Ruby. Type in an expression, then hit enter to execute. The semicolon is optional, and the return value of the expression is output to the console. Notice that the resulting lines in the log are color-coded dark gray, as opposed to the light gray for output from the console.* methods mentioned above.

It has the usual shell niceties you'd expect, like command history (up/down arrows), and autocomplete for known variable/property names. You can expand the input box with Shift+Enter if you want to type multiple lines before submitting. If you evaluate an object (type it's name and hit enter), the object's contents will be output to the log — and the output is a link which pops open a window that let's you inspect the object's contents in a saner (more readable) fashion. This is the Object Inspector (as opposed to the Page Inspector covered earlier).

The Scope (What's this?)

The this object in the console is not the window object, as it normally is for JavaScript code run in the browser the conventional way. It's a proxy that let's you access properties of the window object, but any new variables you create while playing around will not pollute the real namespace. If you want to stick things in the window namespace, you can use the window property of the this object to access it.

For example, I created a test page that contains the following code:
<script type="text/javascript">
var foo = 23;
</script>
<button onclick="alert(bar);"></button>

After loading it, I opened the console and did the following:
  1. Evaluated foo; it returned 23, because you can access already-defined variables.
  2. Evaluated bar; it returned undefined because it doesn't exist.
  3. Set bar to 42; it returned 42.
  4. Clicked on the "bar" button; it generated an error because bar is still not defined in it's scope!
  5. Set window.bar to 42; it returned 42.
  6. Click on the "bar" button again; this time it worked.


Note: Things don't seem to work the way I expect them to when using the Web Console to interact with variables in my fiddle. Not sure how jsFiddle is implemented, so I can't point to a cause or solution. Just be aware.

JavaScript Helpers

The console also provides a set of helper functions that aren't already built-in to JavaScript:
  • $('CSS selector') — This behaves like the jQuery object, which is handy if jQuery isn't loaded; if jQuery is loaded, the jQuery object will overwrite this one.
  • keys(obj) — Returns the list of keys in an object.
  • values(obj) — Returns the list of values in an object.
  • clear() — Clears the console output pane (like clicking the Clear button).
  • inspect(obj) — Pops up the Object Inspector for that object.
  • pprint(obj) — Dumps object's contents to console, but formatted nicely-er.

The console Object

The console object allows you to write output to the console in your JavaScript code, which is critical for debugging.

The four logging methods are .error(), .info(), .log(), and .warn(). They all take the same input — one or more args of any type. The args are stringified and joined with spaces between them before being output to the console. The only difference is in how they are output. You can click on the Logging button to control which message types are filtered. Also, each of the types (except .log(), the most commonly used one) will have a tiny icon displayed to the left of each line indicating it's type:


The above output is the result of executing the following code:
console.time('testTimer');
console.error('This is a console.error() msg');
console.info('This is a console.info() msg');
console.log('This is a console.log() msg');
console.warn('This is a pair of console.warn() msgs');
console.warn('This is a pair of console.warn() msgs');
function outerFunc() { console.trace(); }
outerFunc();
console.timeEnd('testTimer');
Additional methods showcased here:
  • .time() Starts a named timer.
  • .timeEnd() Ends the timer and outputs the elapsed time between.
  • .trace() Outputs a stack trace.
The console object is available in most browsers, though there are differences in the API and implementation. This wonderfully comprehensive post has more details.

Also of potential interest is window.dump(), which you can use to log output to the native OS console the browser was run from (if you started it from the command line) — which means you can redirect it to a file. Useful if you have large amounts of output for some reason.

Note: I haven't played much with Chrome yet, and I don't have access to Safari. Since the point of this blog is to share my personal insight rather than google links for you (which you can do just as well), I won't be writing analogs of this post for either right now. If you know any relevant resources that deserve mention, please add a comment about them. Lastly, if you want to write it for me, I'll post it on this blog with appropriate creditation.

Next up: Firebug

2 comments:

  1. The reason that you can't interact with your output in jsFiddle is because its intentionally sandboxed for security (it uses fiddle.jshell.net instead of just jsfiddle.net). However, there is a pretty simple work-around for this. Just open the output iframe in a new window/tab instead of having it as an iframe. So, if your URL is http://jsfiddle.net/xyz/ then try http://fiddle.jshell.net/xyz/show/ (see also http://doc.jsfiddle.net/use/embedding.html)

    ReplyDelete
  2. Great tip! I just tried it, and since I'm using a public fiddle under my account (one with a title), the url includes my username, so it ended up being http://fiddle.jshell.net/odigity/whhpN/show/.

    But then I tried just adding 'show/' to the original URL, and that worked, too: http://jsfiddle.net/odigity/whhpN/show/

    I just learned about another alternative last night while re-watching Tom Dale's Debugging Ember presentation to prepare for my next debugging post (http://vimeo.com/37539737). If you're using Chrome's Web Developer Tools, there's a select box at the bottom that lets you pick with frame in the current page to use as your console context, so you can pick the show frame that way.

    ReplyDelete