Opera Dragonfly documentation

JavaScript Debugger

Opera Dragonfly contains a fully-featured JavaScript Debugger. This is accessible from the Scripts panel in the main application toolbar. The JavaScript Debugger enables the state of the webpage or application to be inspected by setting break points to control the flow of the program as the code is stepped through. The debugger supports breaking on user-defined events and tracking of program state, including variable and object values. This makes it easier to identify bugs in the application and understand exactly what is happening at any given stage.

Note: Opera Dragonfly also features a Console, which is fully integrated with the debugger.

Source view

The source view provides a means to view and interact with JavaScript files and inline scripts.

Selecting a script

Any linked, inline and evaled scripts can be selected from the document selector in the Scripts toolbar. These are organized under their parent runtime. If there are multiple documents, such as iframes or linked SVG files, the scripts will be listed under the document in which they are defined. Injected scripts such as Browser.js and User.js are also listed under their respective headings. The list of scripts can be filtered to only show scripts whose filename or path matches a particular string.

If Opera Dragonfly is opened after the page was loaded it will have to be reloaded, either using the browser reload button or the reload button in the center of the Source panel for the scripts to be shown, as for performance reasons debugging information is not collected when Opera Dragonfly is inactive.

The Source panel

Once a script is selected, the syntax highlighted source is shown in the main panel. From this panel, breakpoints can be set to control the flow of the program by clicking on the line number in the gutter. Breakpoints are covered in more detail in the Breakpoints section below.

Search

The JavaScript Debugger provides a search panel that offers a number of advanced methods to search inside scripts. From here it is possible to enter a search term, and navigate between the results with either the forward and backwards buttons or the Enter and Shift+Enter keys. Search results show the line of code where the result is contained, along with its line number; clicking on the line will select it in the Source panel, switching to the correct script if it is not the currently active one.

A number of search options can be found below the search field. These allow for searching inside all JavaScript files, including inline scripts, searching using a regular expression (RegExp), and ignoring case. When searching all files, the results can be cluttered by hits in injected scripts such as Browser JS or extension scripts. disabling the injected checkbox will avoid searching in those scripts.

Searching using short search queries can hinder performance when searching in all files or very long scripts. For this reason the maximum number of hits is limited to 1,000 in the JavaScript search. If this limit is too low it can be adjusted in the Source section of the Scripts tab in the settings.

Go to line

Pressing Ctrl+G (⌘+L) when the Source panel is active will open the Go to line window. Entering a number will scroll to the specified line. It will temporarily highlight to show which is the correct line.

Breakpoints

Breakpoints define where the execution of the program halts. When a breakpoint is reached Opera Dragonfly switches to break mode. When you add breakpoints, you can then manage them using the Breakpoints sub-panel.

Types of breakpoints

Opera Dragonfly supports a number of different kinds of breakpoints:

Line breakpoint

Line breakpoints break the execution when the specified line is reached. A line breakpoint can be set by clicking the line number in the left-hand gutter of the source view.

The breakpoint will show in the Breakpoints sub-panel, identified by the debugging context, the line number, and a snippet of code from that line.

Event breakpoint

An event breakpoint pauses execution when the specified type of event is fired. An event breakpoint can be set by checking the box next to the event name in the Breakpoints sub-panel. The events are organized under expandable headings corresponding to the event type. When an event is checked, the relevant event breakpoint will appear in the Breakpoints sub-panel, identified by the event name.

Custom events

With DOM Level 3 Events it is possible to use the CustomEvent interface to define a custom event in JavaScript. In Opera Dragonfly it is possible to break on a custom event by entering the custom event name in the text field under the Custom Events heading and clicking the Apply button.

Conditional breakpoint

A conditional breakpoint has an expression attached to it that is evaluated when the breakpoint is reached. If the evaluation returns true, the execution breaks; otherwise, it continues.

A regular line or event breakpoint can be changed to a conditional breakpoint by selecting Add condition from the context menu of the appropriate breakpoint in the Breakpoints sub-panel, and entering a valid expression in the condition field. The expression must return a boolean value. The breakpoint symbol in the source view gutter will change to indicate it has a condition attached.

For line breakpoints, it is also possible to right click on the breakpoint in the source view gutter and select Add condition.

To remove a condition, delete the text inside the condition field and press Enter.

Examples of conditions include testing if: a variable equals a specific value (foo == 10), a variable is greater than another variable (foo > bar), a function returns true (foo.bar(baz) === true), or, when an event breakpoint fires, if it is a specific element (event.target.id == "foo").

Break on first statement of a new script

Break on first statement of a new script pauses the execution each time a new script is loaded and the first statement is evaluated. This can be enabled in the Scripts toolbar.

Break on error

It is possible to get Opera Dragonfly to stop execution when a parse error occurs. Enabling the last button in the Scripts toolbar will stop JavaScript execution at the line where the parse error occurred and highlight it in the gutter in a similar manner to breakpoints. The same button will also stop execution when an exception is thrown.

Deleting and disabling breakpoints

An individual breakpoint can be disabled by unchecking the checkbox next to the name of the breakpoint in the Breakpoints sub-panel. The icon in the gutter will change to show it is disabled.

It is often useful to disable all breakpoints when debugging to see how the application runs normally without losing all the breakpoints. This can be achieved by clicking the Disable all breakpoints button in the Breakpoints toolbar or by selecting Disable all from the context menu inside the breakpoints list.

If a breakpoint is not needed anymore it can be deleted by selecting Delete in the context menu of the breakpoint to be deleted in the breakpoint list. For line breakpoints, it is also possible to click on the breakpoint symbol in the gutter.

Deleting all breakpoints can be achieved in a similar way: by pressing the Delete all breakpoints button, or selecting the Delete all context menu item.

Program flow

The program flow is controlled by setting breakpoints. Once the program hits a breakpoint, the execution will halt and will switch to the paused state. A paused execution indicator will be shown on the Scripts application toolbar button to indicate the program is currently at a break point. When Opera Dragonfly is in this state, the call stack and the variable object for the currently selected execution context are shown in the State sub-panel.

The breakpoint will be hit when the code it is defined on is evaluated, and any condition evaluates to true. For example, if a breakpoint is set on the first line of a function for handling what happens when a button is pressed, pressing that button will likely hit that breakpoint and pause execution. The document will have to be reloaded if the breakpoint is set on code that is only evaluated once when loading the page, and it has already been evaluated when the breakpoint is set.

Once a breakpoint is hit, it is possible to continue execution in a number of ways, using the buttons in the Scripts toolbar:

Continue

The Continue button or F8 (F5) continues execution until the next breakpoint or the end of program.

Step Into

The Step Into button or F11 (F7) steps to the next line of code. If the next line is a function call, the function is followed and execution breaks on the first line of code inside that function.

Step Over

The Step Over button or F10 (F6) also steps to the next line of code. However, if the next line is a function call, the function is executed and the program breaks at the next line after the function returns.

Step Out

The Step Out button or Shift+F11 (Shift+F7) continues execution until the end of the current function and breaks at the next line after the function returns.

Viewing variables and state

There are various ways to see and monitor variables and their state in Opera Dragonfly. When in the paused state, a full list of the properties in scope can be found in the Inspection section of the State sub-panel. Properties of interest can be watched in the Watches section of the State sub-panel.

Inspecting properties

When at a breakpoint, it is possible to inspect the variables, objects, and functions in the currently selected execution context. These can be found under the Inspection section of the State sub-panel. The currently active execution context is selected in the Call Stack section. It is possible to step back in the call stack to access previously active execution contexts.

All variables in scope for the execution context are listed along with their current value. Functions and objects can be further examined by clicking the expander icon next to its name. This will show all the properties and functions contained within.

As the number of properties can start to get unwieldy, it is possible to hide variables which have a default value of null or an empty string by deactivating the relevant button on the Inspection toolbar. It is also possible to hide non-enumerable properties.

It is also possible to filter by a search term using the Filter field in the toolbar. This will only match properties that are currently visible.

Dynamic Value Inspection Tooltips

In addition to the State sub-panel, dynamic inspection tooltips offer the ability to observe values of properties, variables, objects and expressions.

Hovering over an object in the Script panel source view will open a filterable tooltip.

Pressing shift while hovering over a function invocation will also evaluate the function and show its return value in the tooltip. For example, pressing Shift while hovering over a call to document.getElementsByClassName('frame') returns the NodeList instance.

Selecting any amount of code and pressing Shift will evaluate it and display the result in the tooltip. This also works across multiple lines.

We have also added a new kind of tooltip for all JavaScript inspections. For properties of type Object we show the according Class. If you now hover over the Class name of any Element, Function, Date, RegExp, Error and Exception, you will get a tooltip with a pretty-printed representation. This even works on top of another tooltip.

Watches

Watches allow JavaScript expressions to be monitored. These can be useful if there is a specific piece of information, such as the value of a variable, that needs to be tracked as the application is executed. Each time the application steps the expression is evaluated. Watches can be found under the Watches section in the State sub-panel.

Examples of watches include individual variables or objects (foo), the return value of a function (foo.bar()), or manipulating variables (bar + baz * superman). If the variables or functions are in scope the result will be returned.

Adding a watch

Click the Add watch button in the Watches section of the State sub-panel, enter a valid JavaScript expression; then, press Enter. The expression will be evaluated and the result shown next to it.

It is also possible to add a watch from the context menu on variables in the Inspection section of the State sub-panel.

Editing a watch

An existing watch can be edited by double clicking on the expression or selecting Edit from the context menu.

Deleting a watch

A watch can be deleted by selecting Delete from the context menu of the watch.

Return values

When debugging a program, it is often useful to know the value that was returned from the last function call. If the value is assigned to a variable, this can be done easily from the Inspection of Watches section. There are situations, though, where return values are not explicitly assigned, particularly if they formed part of a more complex expression.

As an example, let's take the following trivial function call:

mul(add(1, 2), add(3, 4));

If we set a breakpoint in our script at this point, and then "Step over" this call, we can see that the Return values section lists all function calls and their respective return values, in the order in which they were executed (with the oldest call at the bottom, and the most recent call at the top). Clicking on the arrow next to the function name will jump to that particular function's definition, while the arrow next to the return value jumps directly to the return statement inside the function.

Call stack

When a function is called it is pushed onto the top of the call stack, and when it returns it is popped off the stack. The call stack contains a frame for each function that has not yet returned, with global scope at the base. The frames on the stack are listed in the Call Stack section of the State sub-panel.

Clicking on an entry in the stack will switch to that frame. From there it is possible to see all the variables in scope for that frame in the Inspection section, as described above. The source view will also switch to the function that the frame represents. The execution position will be at the line that contains the function call that created the frame above on the call stack.