An Ember Debugging Flowchart

By Chris Westra on 11 08 2016

My standard workflow for debugging

I'll admit that I have a lot of experience with things not going well in Ember.
Over time I've started to get a general workflow in place that I'd like to share.
When I have to debug it's commonly performed from two points of view. Either the page didn't render at all due to a javascript error,
or the page rendered, just not in the way that I was expecting. From there I find myself following the flow in the chart below.


<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="2462" inkscape:window-height="1328" id="namedview4244" showgrid="false" inkscape:zoom="1.1972936" inkscape:cx="387.8658" inkscape:cy="1045.9024" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="0" inkscape:current-layer="g3832" inkscape:snap-global="true" inkscape:snap-midpoints="true" inkscape:snap-bbox="true" inkscape:object-nodes="true" inkscape:bbox-nodes="true"/>
Produced by OmniGraffle 6.5.2 <dc:date>2016-07-29 19:32:49 +0000</dc:date>
<rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF>




















Canvas 1

Layer 1

<xlink:use xlink:href="#id1_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id168_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id19_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id23_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id163_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id47_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id59_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id3_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id25_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id31_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id68_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id34_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id96_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id98_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id110_Graphic" filter="url(#Shadow)"/>
<xlink:use xlink:href="#id173_Graphic" filter="url(#Shadow)"/>


I don’t see
what I was
expecting



There was a
javascript
error






Maybe the routes aren’t running
correctly
.
LOG_TRANSITIONS_INTERNAL: true






Check the rendered state of the
template using the inspector



W
as there a javascript
error?






Not really






Y
es



Did the page render
at all?






- Reload and see if the transition to the
page fi
nished successfully.
If a
transition failed go debug from there
- Make sure any ajax requests
completed successfully



Are the values in the template/
components what you expected?






Obvs No



How is that particular value
supposed to be set?





- Check dependent keys
- Set a breakpoint and check if the observer
is fi
ring as intended
- Make sure you’ve added .on(‘init’) if
needed




Observer




- Check dependent keys
- Make sure the property isn’t getting
overwritten




Computed Property




- Set a breakpoint and make sure the
helper is recomputing as needed




Helper




- Make sure the value isn’t getting set from
somewhere else
-
T
emporarily add an observer that watches
the value and set a breakpoint there




Binding




- Set a breakpoint and check that the action
is fi
ring as intended
- For closure actions make sure params are
curried correctly




Action




- Make sure the hook is fi
ring, especially if the
problem is occurring after a value change or re-
render
- If the rerender is from a route transition, ember
might reuse an instance of a given component and
not call the Init() hook every time.
- Make sure to call this._super(…arguments)




Component Lifecycle Hook





Does the CP
depend on something async?
- DS.hasMany(‘foo’, {async: true})
- PromiseProxy
, PromiseArray
, etc.






Make sure the CP
is still valid when the async
dependency is in an unfulfi
lled state






-If there’
s a consistent problem in a runloop use

Ember.run.backburner.DEBUG = true






- If using chrome make sure the ‘async’

check box on the inspector is enabled
- If the browser stack trace isn’t useful
take a look the error

s ‘stack’
property




- Check server responses
- Set a breakpoint and check if the observer
is fi
ring as intended
- Make sure you’ve added .on(‘init’) if
needed




Ember Data Model


A small companion guide

  • Start at the template. The template is the source of truth for what goes on the screen, and Ember's handy inspector makes it
    quick to confirm the state of all those bound values. If the page rendered incorrectly it means a bound value somewhere isn't what I was expecting.
    From there I go to each incorrect value and try to determine how it was set, essentially recursing back through the flowchart.

  • Blank screens and no error? Start logging. In some apps the way I've (poorly) set up my routes and their error handling will lead to a route swallowing
    an error during a transition. If I come across a blank page with no error I'll normally set LOG_TRANSITIONS_INTERNAL: true like the debugging guide
    demonstrates. Then tracking down the failed route hook is a snap.

  • Check computed property dependent keys I've shot myself in the foot countless times from typos or plain mistakes in computed property keys. If I write a property whose keys don't
    correspond to the get() calls inside, I try to write a comment saying why.

  • I <3 developer tools I couldn't get through my working day if I didn't have the Chrome developer tools. Half of the items on my flowchart involve setting a breakpoint somewhere
    in my app's source code or in the ember source code. I often find myself setting a breakpoint at an obvious place, then navigating up the stack and setting more breakpoints closer to
    what I think is the source of the problem.

  • Use error.stack When the browser pauses on an Ember error, there are many cases where the browser stack trace at that moment won't be very useful. In that case, I check the thrown
    error's stack property. It often has a more informative list of places for me to check.

  • Debug two-way bindings with observers Sometimes I get plain stuck trying to figure out how a value is being changed in a component. Observers to the rescue! Here's a quick example:

Ember.Component.extend({
heisenValue: "foo",

  // If heisenValue changes for any reason, the observer will fire synchronously
  // and show me where the change is coming from.
  forDebug: Ember.observer('heisenValue', function() {
    debugger;
  })
});

  • Check the server response If my Ember Data models aren't showing the right information I'll always take a quick look at the network response
    to make sure the data is what I'd expect before diving in further on the client side. It's saved me a ton of time, especially when working on a new feature.

Take heart!

Debugging can be frustrating, but I've found having a consistent set of steps has made finding run of the mill problems much less taxing.