DEV Community

Samuel Rouse
Samuel Rouse

Posted on

⚑️ Supercharged Debugging 🐞 with Conditional Breakpoints

You might be accustomed to setting breakpoints to troubleshoot or debug your code, but you can supercharge your debugging and testing process with conditional breakpoints. Let's dive in.

Conditional Breakpoints

Conditional breakpoints execute an expression in the context where the breakpoint is set. If the outcome is true (truthy, actually), the breakpoint will pause execution. Otherwise, the code continues to run. These were introduced in Safari's WebKit engine way back in 2009 and Chrome shortly thereafter, as well as Firefox 19 a few years later as they replaced the FireBug extension. I've found reference to support in Internet Explorer Developer Tools as well, but I didn't find a timeline on that.

Basic Usage

The appearance and interaction for conditional breakpoints varies somewhat by browser platform.

Chromium – Chrome, Edge, Opera, Arc…

If you left-click the line number in the Sources panel – or the dash where a line number would be if the code is prettified – you get a regular breakpoint. If, instead, you right-click, you are presented with options, one of which is a "Add conditional breakpoint…"

Selecting

Selecting this will present you with the ability to enter an expression.

Entering a breakpoint condition in Chrome

Once completed, a conditional breakpoint will appear orange.

A conditional breakpoint displayed in Chrome

To change this, you can right-click on the conditional breakpoint and choose "Edit breakpoint..."

The context menu of a breakpoint in Chrome

You can also edit other breakpoint types and convert them to a conditional breakpoint.

The breakpoint type menu in Chrome

Gecko – Firefox, IceCat, K-Meleon

If you right-click on a line number in the Debugger panel, you can choose "Add condition".

Right-click a line in the Firefox Debugger

Once selected, you are presented with a temporary inline field below the selected line to enter your condition.

Conditional breakpoint entry in Firefox

When complete, it turns into an orange conditional breakpoint.

Appearance of a conditional breakpoint in Firefox

These can be edited by right-clicking and choosing "Edit condition".

Image description

WebKit – Safari

Safari is a bit different. Any breakpoint may have conditions, so start by left-clicking to create a breakpoint, and then right-click it to bring up the context menu and choose "Edit Breakpoint..."

Breakpoint context menu in Safari

You can then enter a condition used to trigger the breakpoint.

Edit Breakpoint screen in Safari Developer Tools

Editing a condition is the same as the first edit.

Breakpoint context menu in Safari

Breakpoint Position

It's important to remember that breakpoints stop at the specific location in that line. With a standard breakpoint at a line, it stops before that code is run. Knowing the line you are on hasn't run can be important when trying to debug. Stopping one line too early may mean variables or data you need aren't available, yet. You may need to adjust the position of a breakpoint to ensure

Inline Breakpoints

Chrome and Firefox both support even more specific inline breakpoint. Once the line's breakpoint is set, you can select a more specific point for breaking. This can be very helpful when dealing with callbacks or inline arrow functions.

Inline breakpoint in Chrome

Inline breakpoint in Firefox

When you create the inline breakpoint, do not remove the full-size breakpoint or all breakpoints within that line will be removed. You can remove the smaller breakpoint earlier in the line.

Individual inline breakpoint markers in Chrome

In both Chrome and Firefox these inline breakpoints can be made conditional.

At this time Firefox will not properly display an inline conditional breakpoint – it will remain blue – but it will function correctly. You will not be able to edit the condition, but can replace it each time.

Supercharging

Now that we know how to create conditional breakpoints, let's look at how we can use them to improve development and troubleshooting.

The Revelation

When it comes down to it, conditional breakpoints are blobs of code executed in the context where they are set. This means they have access to the variables and functions in that context. It also means conditional breakpoints can change data.

Image description

In this case .add() returns no value, so not only does this conditional breakpoint change something, the result is falsy, so it doesn't stop execution.

We just performed a live code injection!

What's more, it doesn't stop execution, so it allows us to make changes without worrying about significantly changing execution times or experiencing new race conditions caused by completing network requests or events while the browser is paused.

We get most of the benefit of directly changing source code, without a build or deploy step.

Complex Operations

What if we want to perform an action that returns a truthy value? Or we want to perform multiple actions? You can use semi-colons to make separate statements, or use commas to chain statements together.

t.classList.add("submitting"); console.log("It's a breakpoint!"); false;
Enter fullscreen mode Exit fullscreen mode
t.classList.add("submitting"), console.log("It's a breakpoint!"), false
Enter fullscreen mode Exit fullscreen mode

This gives us the ability to do virtually anything in a condition. We can:

  • call functions
  • update values
  • iterate over objects
  • replace properties or methods
  • make network requests
  • define new variables to be accessed by later conditional breakpoints!

All of this from inside a breakpoint which doesn't even have to stop the code.

Complex conditions

Because we have complete control, we can even use conditional statements inside our conditional breakpoint to make specific changes.

Dynamic data

One of the most convenient uses is modifying a network response. By injecting changes as the data is returned, we can test updates or configuration changes without having to modify the application source, affect other consumers of the API, or restart services after changes.

// Change a configuration flag
response.data.config.someConfigurationFlag = true;
false;

// Change data formats
response.data.rows = response.data.rows.map(row => ({
  ...row,
  value: row.type === 'date'
    ? moment(row.value, 'MM/DD/YYYY').format('YYYY-MM-DD')
    : row.value,
});
false;
Enter fullscreen mode Exit fullscreen mode

If you need, you can even completely replace the response object to test different response scenarios without the effort to create a scenario. This can be useful for replaying known responses and errors which would normally require a time-consuming setup process.

This can be a very powerful tool, but be sure we don't exclude proper validation. Static changes can become stale and incorrectly represent the proper server response.

Trace It

A standard breakpoint provides a wealth of information, but it comes at the risk of disrupting the normal execution flow. When this becomes a concern, I like to fall back to console.trace(). While you can insert this directly into your code, tossing console.trace() into a conditional breakpoint will log the stack trace out and keep running.

Complex loggers

One of my favorite uses of complex conditional breakpoints is creating complex loggers. The console.trace() can be really useful, but it makes finding information in the console difficult. Wrapping them in a console.groupCollapsed() gives a great balance, where you can locate the title and expand the group to see the detail.

I use this trick inside state management where the function calls that might not end up triggering updates can be logged to get a more complete picture of what's happening.

console.groupCollapsed('Update:', key, oldValue, newValue);
console.trace();
console.groupEnd();
Enter fullscreen mode Exit fullscreen mode

Conclusion

Conditional Breakpoints are a great addition to your developer toolkit. They open up a huge range of possibilities, from making it convenient to pause in often-executed loops to my favorite way to live-patch code for testing, troubleshooting, or tinkering.

Top comments (0)