Debugging complex values with Jest
Let’s have a look at how to debug complex values with Jest and what steps I had to take to find the source of the problem.
The thing is, we have a bug in the function which operates very complex strings. We can't analyze the whole content, but, fortunately, we can find the problem in a few minutes. It's all thanks to Jest.
Attaching parameters to URLs: Identifying the problem
We are saving a large string containing URLs in the API, and we want to save the URLs with extra query parameters. But we want to display the URLs to the user without them.
So, we want to remove custom variables from a query string but still display everything else. If a user pastes a URL with an existing query string, we want to keep it.
But there’s a bug and a URL becomes a mess on saving. It’s way longer than the original one.
Challenges
- We have two functions modifying URLs (one adds to, and the other one removes something from a query string). Nothing extremely complex but they’re not basic either.
- The input value for the operations is very complicated. It’s not possible to browse all GET variables and analyze them step by step.
- We want to be sure that this bug won’t repeat in the future.
Debugging complex values: Solution
I’ll start with writing unit tests. As a reminder, unit tests are small chunks of code that can be run independently and analyzed step by step. I can commit the tests after I create them, so they stay there forever. Even if a different developer wants to make some changes in the future, they should run those tests and make sure the problem doesn’t repeat.
Debugging complex values: tools used
Before you start, make sure you have Jest set up in the project.
Another tool that could be useful is Jest Test Explorer which is a VSCode extension:
It adds a menu that lets you browse all tests in a tree, run them individually or in groups with one click, and debug them.
Testing the first function
Now, let’s add a test.js
file:
This test will check adding parameters to a URL. How should this function work? Well, it should fetch a URL and attach some variables to it. I typed in the desired behavior - that is, I copied the URL I got from the support and added the expected attributes at the end:
Remember that I can’t tell for sure what exactly happens in this URL, what are these GET parameters and so on. The one thing that is clear it’s that the function should add a predefined chunk at the end of the URL.
I run the test in the test runner:
The test fails:
What’s going on? Let’s see what happened. The extension is kind enough to highlight the tests that failed.
To see the details, just hover over it:
Thanks to that, I can see the value we got from the function and what is the expected value. The only thing I’m missing in VSCode is to see the diff, even though Jest handles it very well. When run from the console, it is able to handle diffs, but the vscode extension does not display them. Luckily, you can see the diff in an online tool like Text Compare.
As you can see, there are no differences except getting &
instead of &
, which means that the function encodes a string. I forgot to consider it when writing the test because I created the function some time ago. I only remembered it after seeing the result. Hence, I’m fixing the test to take it into account (expected value - what’s inside toBe
).
The effect of the test:
Test for the second function
Adding parameters to URLs work. Now that we know that the first of the tested functions isn’t causing any problems, we can move on. Let’s move to the second function: removing parameters from URLs.
Let’s make another test:
Again, I won’t even attempt to understand what’s going on inside these complicated values. For now, I’ll just copy them as they are. This time though, I’ll be doing it the other way round - I’m calling a function on a string with values added at the end. In toBe
, I set an expected result - the same string, only without the variables.
Let’s run the test:
That’s to be expected. Let’s check the result:
It might not be clear from the screenshot, but if I scroll down in the editor, you’d notice that Received is way bigger than Expected. Take a look at the diff in Text Compare:
Now you can clearly see that the function adds useless stuff at the end.
Why does that happen? The function has 80 lines and executes lots of operations, so analyzing it step by step would take a while (and my aim is to show that you can debug it in a simple way by copying + pasting, and running Jest). The extension has a built-in debugger that is super simple to use - just click the icon and you’re done. It will run your test in the debugger but it doesn’t need any extra setup. Let’s use it to see what’s going on.
Finding the problem with the debugger
Let’s set a breakpoint. It will make the JS code stop being executed and we’ll be able to look at the values of all variables. This way, you won’t have to insert console log every other line.
You will only be able to browse the values from the part of the code that already has been executed (that is, before the breakpoint), so let’s place it somewhere near the end.
Breakpoints can be added by clicking on an empty space of the left side of the line number (where the red dot is).
The operation at the end is looking fine. It’s the last operation of generating URL, so if there’s an error, it has to be before this operation. Click the debugger icon in the extension.
This is how it looks when the debugger stops on a given line:
Now, you can hover over the variables to see their values. Let’s start at the end.
I’m able to see a full generated value there. I’m not yet sure if it’s correct at this point but I assume it isn’t. I can’t be bothered analyzing it character by character, especially that the value is too long to even see it all.
Closer and closer to debug complex values with Jest
Let’s try to build this variable a few lines above (221
). Why? We set the breakpoint at the end, so all operations begin to load earlier. Let’s check, step by step, what is being assigned to newHref
:
Okay, there’s a query string here. This variable is at the very beginning of generating the final URL and is taken from the browser’s ‘URL.searchParams’ instead of my code. Let’s assume for now that it’s correct and the error is somewhere between here and the end of the function. It’s not necessarily true but checking it character by character makes no sense. Let’s move on.
Above (in the previous screenshot) we attached a query string (everything after ?
, from url.search
) to the URL we are building. In this code we are taking the value of searchParams
(which is the entire query string), and attaching it to our URL - the second time. The entire query string will show up with the resulting link twice!
In this situation, I’ll just remove the duplicate and run the tests again.
Now, it’s time to commit and push. Good job, your work is done!
Thank you for reading this article about debugging complex values with Jest.