Has this ever happened to you? You're working on the code for your Angular app. And since you're an amazing developer, you're also writing test specs using Jasmine. You want to run your tests so you pop down to the terminal and type ng test
to execute your tests.
You expect to have everything run and pass but instead you get a half-zillion test failures and lots of them have a weird and completely unhelpful error message:
Uncaught NetworkError: Failed to execute 'send' on 'XMLHttpRequest'
WHAT -- IS -- GOING -- ON?!?!?!?!
It's Not the Real Error
The problem here is that the real error message is hidden. I don't remember where I learned this trick but it's helped me out a bunch of times in my Jasmine tests for Angular.
Instead of running your tests with the ng test
command, use ng test --source-map=false
.
The Real Error Revealed
Ok. So this time, you head to the command prompt (shell, terminal, etc) and you run ng test --source-map=false
.
This time you'll get a much better error. In this case, the error message is "NullInjectorError: R3InjectorError(DynamicTestModule)[FormBuilder -> FormBuilder]: NullInjectorError: No provider for FormBuilder!
"
It's Almost Always a Dependency Problem
The underlying problem is almost always some kind of missing dependency that's causing the Angular dependency injection / IoC framework to panic.
So when our typescript or javascript code gets executed, it goes through something like a compilation process that take the human-readable code and turns it into something that can be executed efficiently. In the case of typescript, there's an extra step and the code gets 'transpiled' into javascript before execution. The source map is supposed to help us to debug our code by connecting the instructions that are being executed to the source code that inspired those instructions. If we didn't have that, it would be a whole lot harder to debug our apps.
My theory on why ng test --source-map=false helps in these weirdo error cases is that because of the type of problem (dependency injection problems), the source map thinks that the problem is in the dependency injection framework rather than in your code that configures the dependencies.
So. By turning off the source map generation, you get the real error.
(Disclaimer: that theory could be wildly wrong...but it makes sense to me.)
A Little More About My Error
So this blog post is about how to get at the real error message but while I'm here, I figure I might as well tell you how I fixed the real error, too. Like I said, it's almost always a dependency problem. Lately, I've been working on converting a bunch of template-driven angular forms over to reactive forms. This means that in my Jasmine specs, that I need to update the imports
directive to reference ReactiveFormsModule
instead of FormsModule
.
To fix this, I need to get to the call to TestBed.configureTestingModule
and find the FormsModule import. Change this over to be ReactiveFormsModule
and voila! -- the problem is fixed.
Summary
In short, there's something about dependency import problems in Jasmine tests for Angular that sometimes causes the real errors to be eaten. So if you find yourself wondering about why you're getting that strange XMLHttpRequest error, try running your test suite without source maps. The command to do that is ng test --source-map=false
.
I hope this helps.
-Ben
-- Looking for help with Angular and/or Angular testing? We can help. Drop us a line at info@benday.com.