Angular 4 unit test - Cannot read property 'root' of undefined

谁说胖子不能爱 提交于 2019-12-11 05:44:43

问题


I've got a problem with my unit test. I don't know what's wrong with this test. I've searched a soulations but nothing works for me. When I want to mock Router I have an error TypeError: Cannot read property 'root' of undefined. Thanks in advace for any help.

Error:

 TypeError: Cannot read property 'root' of undefined
        at rootRoute (webpack:///~/@angular/router/@angular/router.es5.js:5880:0 <- src/test.ts:53760:30)
        at DynamicTestModuleInjector.get (ng:///DynamicTestModule/module.ngfactory.js:401:75)
        at DynamicTestModuleInjector.getInternal (ng:///DynamicTestModule/module.ngfactory.js:919:55)
        at DynamicTestModuleInjector.NgModuleInjector.get (webpack:///~/@angular/core/@angular/core.es5.js:3556:25 <- src/test.ts:3909:44)
        at resolveDep (webpack:///~/@angular/core/@angular/core.es5.js:11017:0 <- src/test.ts:11370:45)
        at createClass (webpack:///~/@angular/core/@angular/core.es5.js:10881:0 <- src/test.ts:11234:32)
        at createDirectiveInstance (webpack:///~/@angular/core/@angular/core.es5.js:10701:21 <- src/test.ts:11054:37)
        at createViewNodes (webpack:///~/@angular/core/@angular/core.es5.js:12064:33 <- src/test.ts:12417:49)
        at createRootView (webpack:///~/@angular/core/@angular/core.es5.js:11969:0 <- src/test.ts:12322:5)
        at callWithDebugContext (webpack:///~/@angular/core/@angular/core.es5.js:13184:25 <- src/test.ts:13537:42)
        at Object.debugCreateRootView [as createRootView] (webpack:///~/@angular/core/@angular/core.es5.js:12644:0 <- src/test.ts:12997:12)
        at ComponentFactory_.create (webpack:///~/@angular/core/@angular/core.es5.js:9890:25 <- src/test.ts:10243:46)
        at initComponent (webpack:///~/@angular/core/@angular/core/testing.es5.js:800:0 <- src/test.ts:55130:49)
        at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:365:0 <- src/test.ts:151874:26)
        at ProxyZoneSpec.onInvoke (webpack:///~/zone.js/dist/proxy.js:79:0 <- src/test.ts:118466:39)
        at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:364:0 <- src/test.ts:151873:32)
    TypeError: Cannot read property 'form' of undefined
        at updateForm (webpack:///src/app/auth/login/login.component.spec.ts:62:14 <- src/test.ts:64296:18)
        at Object.<anonymous> (webpack:///src/app/auth/login/login.component.spec.ts:88:4 <- src/test.ts:64316:9)
        at Object.<anonymous> (webpack:///~/@angular/core/@angular/core/testing.es5.js:336:0 <- src/test.ts:54666:26)
        at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:365:0 <- src/test.ts:151874:26)
        at ProxyZoneSpec.onInvoke (webpack:///~/zone.js/dist/proxy.js:79:0 <- src/test.ts:118466:39)
        at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:364:0 <- src/test.ts:151873:32)
        at Zone.run (webpack:///~/zone.js/dist/zone.js:125:0 <- src/test.ts:151634:43)
        at Object.<anonymous> (webpack:///~/zone.js/dist/jasmine-patch.js:104:0 <- src/test.ts:118180:34)
        at webpack:///~/@angular/core/@angular/core/testing.es5.js:96:0 <- src/test.ts:54426:17
        at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:365:0 <- src/test.ts:151874:26)
        at AsyncTestZoneSpec.onInvoke (webpack:///~/zone.js/dist/async-test.js:49:0 <- src/test.ts:117775:39)

Testing method:

onSubmit(): void {
const payload = this.form.value;
this.form.reset();
this.form.disable();

this.authService.login(payload)
  .finally(() => {
    this.form.enable();
  })
  .subscribe(
    ({ res }) => {
      if (typeof res.cmp === 'undefined' || typeof res.rel === 'undefined') {
        this.router.navigate(['test']);
      } else {
        this.router.navigate([this.returnUrl]);
      }
    },
    ({ sts }) => {
      this.dialogService.alert({
        title: 'Error',
        message: `${backendMessage(sts, false)}`
      });
    }
  );

}

Unit test:

const mockUser = {
  email: 'test@test.test',
  password: 'Test1235',
  remember: true
};

const mockInvalidUser = {
  email: null,
  password: null,
  remember: true
};

@Injectable()
class AuthServiceMock {

  login(payload: any): Observable<BackendResponse<Auth>> {
    let sessionObj: BackendResponse<Auth> = { sts: null, res: { cmp: null, rel: null, prs: null } };
    return Observable.of(sessionObj);
  }
}

const router = {
  navigate: jasmine.createSpy('navigate')
};

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [AuthModule, AppModule],
      providers: [
        ExtendedFormBuilder,
        { provide: AuthService, useClass: AuthServiceMock },
        { provide: Router, useValue: router }
      ],
    }).compileComponents();
  }));

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

  function updateForm(userEmail: string, userPassword: string): void {
    component.form.controls['prs.email'].setValue(userEmail);
    component.form.controls['prs.passwd'].setValue(userPassword);
  }

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

  it('return url should have a default value', () => {
    expect(component.returnUrl).toBeTruthy();
  });

  it('check form controls values after update', fakeAsync(() => {
    updateForm(mockUser.email, mockUser.password);
    expect(component.form.controls['prs.email'].value).toEqual(mockUser.email);
    expect(component.form.controls['prs.passwd'].value).toEqual(mockUser.password);
  }));

  it('check if the form is valid after set incorrect values', fakeAsync(() => {
    updateForm(mockInvalidUser.email, mockInvalidUser.password);
    expect(component.form.valid).toBeFalsy();
  }));

  fit('should update model on submit', fakeAsync(() => {
    updateForm(mockUser.email, mockUser.password);
    component.onSubmit();
    expect(router.navigate).toHaveBeenCalledWith(['./']);
  }));
});

回答1:


I could be mistaken, but it doesn't look like you're doing anything with the actual template itself. So the easiest way to get this going would be to just import the NO_ERROR_SCHEMA from '@angular/core', and provide it in your testbed configuration as

providers: [...],
schemas: [NO_ERROR_SCHEMA]

Now if/when you get to a point that you also want to test the template, then you have a few more options. You can provide some router stubs, as shown in the angular test project. They're under the testing folder. Use those and put them in the testbed declarations, and that should resolve at least the routing issue. You could also just create your own stubs. Or, you could configure the RouterTestingModule.withRoutes([]).

Hope this helps.



来源:https://stackoverflow.com/questions/44237786/angular-4-unit-test-cannot-read-property-root-of-undefined

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!