23

I am writing some unit tests for my component and i am getting this cryptic error message. I found a similar question at Angular 2 unit testing - getting error Failed to load 'ng:///DynamicTestModule/module.ngfactory.js' but the answers did not help me solve my issue. I am angular 4.3.2

Here's the component i am writing the test for:

import {Component} from '@angular/core';
import {Router} from '@angular/router';

import {NotificationService} from '../common/notification/notification.service';
import {SessionService} from '../common/session/session.service';
import {Login} from './login.model';

@Component({
             selector: 'cc-login-form',
             templateUrl: './login.component.html',
             styleUrls: ['./login.component.scss'],
           })
export class LoginComponent {
  model: Login = new Login('', '');

  constructor(private sessionService: SessionService,
              private router: Router,
              private notificationService: NotificationService) {
  }

  onSubmit() {
    this.sessionService
        .login(this.model.email, this.model.password)
        .subscribe(
          sessionInfo => {
            this.notificationService.showSuccess('notification.successfully.logged.in');
            this.router.navigate([`/cc/list`]);
          },
          error => this.notificationService.showError('notification.invalid.login')
        );
  }
}

And here is the test file:

import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {FormsModule} from '@angular/forms';
import {Router} from '@angular/router';
import {TranslateModule, TranslateService} from '@ngx-translate/core';
import {NotificationService} from '../common/notification/notification.service';
import {NotificationServiceStub} from '../common/notification/tests/NotificationServiceStub';
import {SessionService} from '../common/session/session.service';
import {SessionServiceStub} from '../common/session/tests/SessionServiceStub';
import {RouterStub} from '../common/tests/RouterStub';
import {TranslateServiceStub} from '../common/translate/tests/TranslateServiceStub';

import {LoginComponent} from './login.component';

describe('LoginComponent', () => {
  let component: LoginComponent;
  let fixture: ComponentFixture<LoginComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
                                     imports: [
                                       FormsModule,
                                       TranslateModule
                                     ],
                                     declarations: [LoginComponent],
                                     providers: [
                                       {provide: SessionService, useClass: SessionServiceStub},
                                       {provide: Router, useClass: RouterStub},
                                       {provide: NotificationService, useClass: NotificationServiceStub},
                                       {provide: TranslateService, useClass: TranslateServiceStub},
                                     ]
                                   })
           .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(LoginComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should be created', () => {
    expect(component).toBeTruthy();
  });
});

When running the test i get the following on chrome console:

zone.js:2642 XMLHttpRequest cannot load ng:///DynamicTestModule/LoginComponent.ngfactory.js. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
(anonymous) @ zone.js:2642
zone.js:195 Uncaught DOMException: Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'ng:///DynamicTestModule/LoginComponent.ngfactory.js'.
    at http://localhost:9876/_karma_webpack_/webpack:/Users/pedrompg/Documents/quandoo/fe/chains-center/~/zone.js/dist/zone.js:2642:1
    at XMLHttpRequest.proto.(anonymous function) [as send] (

Any can help me with that?

EDIT - 1 Here's the services/stubs implementation

SessionServiceStub

export class SessionServiceStub implements ISessionService {
  login(login: string, password: string): Observable<any> {
    return Observable.of({merchantId: 123});
  }

  logout(): Observable<any> {
    throw new Error('Method not implemented.');
  }

  validateSessionToken(): Observable<any> {
    throw new Error('Method not implemented.');
  }
}

SessionService

@Injectable()
export class SessionService implements ISessionService {

  constructor(private http: CcHttpClient, private router: Router, private localSessionService: LocalSessionService) {
  }

  login(login: string, password: string): Observable<any> {
    return this.http.post(`api/sessions`, {login: login, password: password}).map((res: Object) => {
      this.localSessionService.createSession(res);
      return res;
    });
  }
}

RouterStub

export class RouterStub {
  navigate(commands: any[], extras?: NavigationExtras): Promise<boolean> {
    return Promise.resolve(true);
  };
}

TranslationServiceStub

export class TranslateServiceStub {
  instant(key: string | Array<string>, interpolateParams?: Object): string | any {
    return 'translation';
  };
}

NotificationServiceStub

export class NotificationServiceStub implements INotificationService {
  showToast(type, text, title, defaultTitle): Promise<Toast> {
    return Promise.resolve(null);
  }

  showSuccess(msg, title?): Promise<Toast> {
    return Promise.resolve(null);
  }

  showError(msg, title?): Promise<Toast> {
    return Promise.resolve(null);
  }
}

EDIT 2 Changing my TestBed config to the following removed the error but brought a new one:

beforeEach(async(() => {
    TestBed.configureTestingModule({
                                     imports: [
                                       FormsModule,
                                       HttpClientModule,
                                       TranslateModule.forRoot({
                                                                 loader: {
                                                                   provide: TranslateLoader,
                                                                   useFactory: HttpTranslateLoaderFactory,
                                                                   deps: [HttpClient]
                                                                 }
                                                               })
                                     ],
                                     declarations: [LoginComponent],
                                     providers: [
                                       {provide: SessionService, useClass: SessionServiceStub},
                                       {provide: Router, useClass: RouterStub},
                                       {provide: NotificationService, useClass: NotificationServiceStub},
                                     ]
                                   })
           .compileComponents();
  }));

Now the error message is

TypeError: Cannot read property 'assertPresent' of undefined
        at resetFakeAsyncZone home/pedrompg/Documents/quandoo/fe/chains-center/~/@angular/core/@angular/core/testing.es5.js:304:1)
        at Object.<anonymous> home/pedrompg/Documents/quandoo/fe/chains-center/~/@angular/core/@angular/core/testing.es5.js:1001:1)
        at ZoneQueueRunner.webpackJsonp.../../../../zone.js/dist/jasmine-patch.js.jasmine.QueueRunner.ZoneQueueRunner.execute home/pedrompg/Documents/quandoo/fe/chains-center/~/zone.js/dist/jasmine-patch.js:132:1)

Which happens at this function:

function resetFakeAsyncZone() {
    _fakeAsyncTestZoneSpec = null;
    ProxyZoneSpec.assertPresent().resetDelegate(); //ProxyZoneSpec is undefined here for whatever reason
}
Pedro Garcia Mota
  • 928
  • 2
  • 10
  • 20

4 Answers4

30

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.

In Angular 4-5

  • ng test --sourcemaps=false
    
    or
  • ng test -sm=false
    

In Angular 6+

  • ng test --source-map=false
    

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

snwflk
  • 3,341
  • 4
  • 25
  • 37
yugantar kumar
  • 1,982
  • 1
  • 23
  • 33
7

I just ran into this error and the problem was my mocks. In the component.ngOnInit i used this.route.paramMap.subscribe(...) where route is an ActivatedRoute instance

In my test i provided a mock service like this :

providers: [
    { provide: ActivatedRoute, useValue: { snapshot: { params: { id: 1 } } } }
]

And in fact i missed to mock the paramMap method

Then i fix it adding a paramMap properties like this

providers: [
    { provide: ActivatedRoute, useValue: { snapshot: { params: { id: 1 } }, paramMap: Observable.of({get: () => 1}) } }
]

Then i don't have anymore this stupid error.

So for you, i expect the class SessionServiceStub to be incomplete or erroneous. Does it get a login method that return an Observable ?

If it's not the problem you can check the NotificationServiceStub

You should use a debugger (with Webstorm it's easy to debug step-by-step) to help you.

Rebolon
  • 1,257
  • 11
  • 29
  • i've added the stubs on the question – Pedro Garcia Mota Aug 10 '17 at 10:05
  • all required methods from the comp are stubbed... but could you comment the 2 lines inside your subscribe and replace it with a console.log(sessionInfo) ? – Rebolon Aug 10 '17 at 13:15
  • OK i narrowed it down a bit....commenting all usages of the translate pipe on my template changed the error from that cryptic one to this other not very helpful message: TypeError: Cannot read property 'assertPresent' of undefined at resetFakeAsyncZone home/pedrompg/Documents/quandoo/fe/chains-center/.... – Pedro Garcia Mota Aug 12 '17 at 10:26
  • Same issue here: I subscribed to `ActivatedRoute.queryParams` but forgot to add a mock `queryParams Observable` getter to my mock `ActivatedRoute` object. This answer helped me realize I forgot that. Once I added it, this error about failed XHR went away. – erewok Sep 13 '17 at 22:50
4

I encountered the same issue using angular-cli 6, so to get the right error message one should use the following:

ng test --source-map=false

Maybe it will help someone :) .

Tanmoy Bhattacharjee
  • 1,040
  • 11
  • 21
1

Been chasing this for hours. Finally discovered that the problem was simply that I had imported HttpClientModule, but not HttpClient:

import { HttpClient, HttpClientModule } from '@angular/common/http';

All those CORS errors, and '[Script Loader]', DOMException{stack: 'Error: Failed to execute 'send' on 'XMLHttpRequest' stuff, and it came down to just not having HttpClient!

redOctober13
  • 3,662
  • 6
  • 34
  • 61
  • Well, I partially take it back. That let my unit tests run, but my integration tests (wherein I call `fixture.detectChanges()`) still has all the errors. – redOctober13 Mar 22 '18 at 17:24