64

I have angular 2 webpack application, all webpack,karma configuration created as per angular.io webpack guide. I am not using aot. I am writing jasmine unit test spec to test my components. First I tried without async block, in that case , unit test just get execute only till fixture.detectChanges() call, code after that doesn't get executed. Seems like fixture.detectChanges call getting blocked infinitely.

I tried by including code in async block. Then I get following error. Error:Failed to execute 'send' on 'XMLHttpRequest' : Failed to load 'ng:///DynamicTestModule​/module.ngfactory.js'


Code without async

beforeeach(()=> {
TestBed.configureTestingModule({
imports:[],
declaration :[Mycomp],
providers:[{ provide:MyService, useclass:MyMockService}]
});
 fixture=TestBed.createComponent(Mycomp);
 console.log(' before detect changes'):
 fixture.detectChanges():
 console.log('after detect changes');// this is not getting   
    logged .. karma shows 0 of 1 executed successfully

 });

With async

  beforeeach(async(()=> {
 TestBed.configureTestingModule({
  imports:[],
  declaration :[Mycomp],
  providers:[{ provide:MyService,       useclass:MyMockService}]
  });
   fixture=TestBed.createComponent(Mycomp);
    fixture.detectChanges():
  }));

getting error Failed to load dynamictestmodule/module.ngfactory.js

Amit Gaikwad
  • 923
  • 1
  • 9
  • 15

10 Answers10

104

I ran into this issue myself yesterday. The problem was that I had an Input() property on my component class that I wasn't setting in the test. So for example, in my-component.ts:

@Component({
  selector: 'my-component'
})
export class MyComponent {
  @Input() title: string;
}

and my-component.spec.ts:

beforeEach(() => {
  fixture = TestBed.createComponent(MyComponent);
  component = fixture.componentInstance;
  component.title = 'Hello there!' // <-- this is required!
  fixture.detectChanges();
});

Or you could provide a default value in the component somewhere. Either way, the test will crash if any inputs are not set and you'll get that unintuitive error.

Note: Running ng test -sm=false will give the actual error message causing the problem. Credit: https://stackoverflow.com/a/45802115/61311

Peter Morris
  • 20,174
  • 9
  • 81
  • 146
newclearwinter
  • 1,073
  • 1
  • 8
  • 7
  • 2
    This is true, but I also get the same error sometimes when I have a service that is not properly mocked or if my component is trying to access a null value returned by one of those services. Still a valid answer, but beware that this might not always fix the issue. – blo0p3r Aug 10 '17 at 14:58
  • 26
    Just figured out, you can get a better error message by setting the `sourcemap` option to false : `ng test --sourcemap=false` – blo0p3r Aug 10 '17 at 15:20
  • @blo0p3r That's a good catch! setting sourcemap to false turns the useless XMLHttpRequest error into the actual root error. – newclearwinter Aug 15 '17 at 14:48
  • 1
    In my case `--sourcemap=false` removed the error entirely ^^ – siebmanb Aug 23 '17 at 07:59
  • Using a custom script in package.json does not work with -sm=false and karma. ie "scripts": { "custom-test": "karma start --single-run=false -sm=false" } You must use ng test -sm=false. – Esaith Nov 15 '17 at 20:59
  • yes, this might be one of the sources, but in my case component didn't have any properties, but I did incorrect mocking. – s-f Mar 27 '18 at 12:40
  • when I use `--sm=false` all cases are passed, not getting any error message – SPnL May 03 '18 at 07:21
77

To find out what's really causing the error, disable source maps:

For angular-cli >= v6.x:

ng test --source-map=false

For angular-cli v1.x:

ng test -sm=false

You will then see a better error, e.g. "Cannot read property 'x' of undefined" in the actual source file that's causing the error. For some reason, there's a bug with sourcemaps right now in testing, and you just get this cryptic error.

André Werlang
  • 5,839
  • 1
  • 35
  • 49
Dan Field
  • 20,885
  • 5
  • 55
  • 71
18

running tests with --sourcemaps=false will not fail Karma silently but give you some detail about the error instead.

user776686
  • 7,933
  • 14
  • 71
  • 124
6

Adding on to Dan Field's answer

This is a problem with the Angular Cli version 1.2.2 or newer. Run your test with --sourcemaps=false and you will get the right error messages.

ng test --sourcemaps=false

shorthand for this is:

ng test -sm=false

See details here: https://github.com/angular/angular-cli/issues/7296

yugantar kumar
  • 1,982
  • 1
  • 23
  • 33
5

I also had this issue and it was due to malformed mocked data. In my component I had a service which made a http call.

something like: (service code)

getData() {
   return this.http.get(obj);
}

In the component I called this function and subscribed to it: (component code)

this.service.getData().subscribe((data) => {
  this.componentData = data.things; //**<=== part that broke everything**
}, (error) => {
  console.log(error);
});

Solution:

When I mocked out the service function I failed to return data that had the attribute things. This is what caused the XMLHttpRequest failure, I guess to angular it looked like the error happened as if it was the HTTP request. Making sure that I returned the correct attributes on any mocked HTTP requests fixed the issues.

Hope this clears things up. Below is the code for the implementation of the mock.

(component.specs)

function fakeSubscribe(returnValue,errorValue) {
  return {
    subscribe:function(callback,error){
      callback(returnValue);
      error(errorValue);
    }
  }
}



 class MockService {
      getData() {
        var fakeData = {
          things:[]
        }
        return fakeSubscribe(fakeData,0);
      }
   }
Niles Tanner
  • 3,911
  • 2
  • 17
  • 29
  • 1
    Was trying to figure this out, and similar concept. My mock services were returning types other than Observable, when the component was expecting an Observable. – Z. Bagley Aug 04 '17 at 16:37
3

This is the most deceiving error message that I've ever encountered in Angular.

In my case it had nothing to do with sending, nothing to do with XmlHttpRequest - at least not on the level you'd guess when trying to follow the message.

It was too about mocking a class, namely ngrx/store. I introduced two Observable methods in a container that had not been included in my mock-up class before and I forgot to do so when I started using those. Once added to the mock-up, the error went away.

...leaving Karma happy to be able to execute 'send' from the XmlHttpRequest whatever it means.

user776686
  • 7,933
  • 14
  • 71
  • 124
  • @KevinOrfas, I had the same issue and a similar resolution to my problem. In my case, a component nested inside the component I was testing made an HTTP call. I needed to mock the HTTP service to get past their bizarre error. – tylerjgarland Aug 18 '17 at 22:20
  • @user776686 , How you mocked the class and how you resolved, could you please give some info. – Roy Sep 05 '18 at 18:36
2

I was bitten by the same error next day - this time the problem was buried in the HTML file. Using a simple array length test for *ngIf

<ng-container *ngIf="myArray.length > 0">

had to be refactored into

<ng-container *ngIf="myArrayNotEmpty">

with a getter as in:

get myArrayNotEmpty(){
  return this.myArray && this.myArray.length > 0;
}

I am a bit irritated though that such a variety of causes is covered by one very misleading and unhelpful message.

user776686
  • 7,933
  • 14
  • 71
  • 124
  • You've answered this question twice - and both answers were relevant to me in different sections of my codebase. I am rather irritated by this issue. – Miller Aug 10 '17 at 05:00
  • You could also do ` 0">` instead. Since your code broke because myArray wasn't available at that time and got added afterwards. Adding *?* is lazy checking and does the same as what you have achieved in your external function. – Markus Mar 14 '18 at 14:22
  • @markus You are obviously right, I have learned it as time went by. I even forgot I answered this question ;-) – user776686 Mar 14 '18 at 14:25
1

In my case, my mock service was missing some public variables accessed by the component in the ngOnInit method.

maia
  • 3,910
  • 4
  • 27
  • 34
0

I just had this issue as well. It turned out to be a simple null reference error in my component in one of my *ngIf checks.

I would suggest running ng serve and checking the component is working in the browser without any errors, or simply run ng test --source-map=false to get a more useful error message.

Greg Quinn
  • 1,927
  • 1
  • 23
  • 26
0

I had the same error when I accessed a variable of an undefined object.

Example:

Component:

soemthing = {}

Template:

<demo-something [someinput]="something.anotherthing.data"> ...

So something was defined, anotherthing was undefined and data could therefor not be accessed.

Very annoying error and as far as I could tell not in the list yet :)

Stefan
  • 14,826
  • 17
  • 80
  • 143