我到了
Failed: Uncaught (in promise): Error: Cannot find primary outlet to load 'UserList'
错误。
当我使用组件中的admin/userlist
对我的登录组件进行单元测试重定向到this._router.navigate(['admin/userlist']);
时,会发生这种情况。
的login.html:
<div class="row registration">
<div id="login-form-control" class="col-xs-12 form-area">
<h2 class="registration-header">Login</h2>
<form (ngSubmit)="login()" [formGroup]="form">
<input id="login-username-textbox" type="text" class="form-control" placeholder="Username" [formControl]="username" required>
<input id="login-password-textbox" type="password" class="form-control" placeholder="Password" [formControl]="password" required>
<div *ngIf="errorMessage">
<span class="help-block error">{{errorMessage}}</span>
</div>
<div *ngIf="successMessage">
<span class="help-block success">{{successMessage}}</span>
</div>
<button id="login-submit" type="submit" class="go-btn btn btn-lg btn-success btn-block">Login</button>
</form>
<div class="row">
<a [routerLink]="['../register']">Register</a>
</div>
</div>
</div>
login.ts:
import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { RegistrationService } from '../shared/services/registration';
@Component({
selector: 'rg-login',
templateUrl: './login.html'
})
export class Login {
form: FormGroup;
username = new FormControl('', Validators.required);
password = new FormControl('', Validators.required);
errorMessage = '';
successMessage = '';
constructor(private _registrationService: RegistrationService, private _formBuilder: FormBuilder, private _router: Router) {
this._createForm();
}
ngOnInit() {
}
login() {
this._registrationService.loginUser(this.form.value)
.subscribe(data => {
if (data) {
this.errorMessage = '';
this.successMessage = 'Login successful';
this._router.navigate(['admin/userlist']);
} else {
this.errorMessage = 'Error';
this.successMessage = '';
}
}, error => {
this.errorMessage = error;
this.successMessage = '';
});
}
_createForm() {
this.form = this._formBuilder.group({
username: this.username,
password: this.password
});
}
}
login.spec.ts:
import { Component } from '@angular/core';
import { async, inject, TestBed } from '@angular/core/testing';
import { BaseRequestOptions, ConnectionBackend, Http } from '@angular/http';
import { MockBackend } from '@angular/http/testing';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';
import { Observable } from 'rxjs/Rx';
import { RegistrationService } from '../shared/services/registration';
import { Login } from './login';
@Component({
template: ''
})
class Register { }
@Component({
template: ''
})
class UserList { }
class MockRegistrationService {
loginUser(user) {
return Observable.of({
username: 'TestUser1',
password: 'TestPassword1'
});
}
}
describe('Login', () => {
let mockRegistrationService = new MockRegistrationService();
beforeEach(() => TestBed.configureTestingModule({
declarations: [
Login,
Register,
UserList
],
providers: [
Login,
{ provide: RegistrationService, useValue: mockRegistrationService }
],
imports: [
ReactiveFormsModule,
RouterTestingModule.withRoutes([
{ path: 'register', component: Register },
{ path: 'admin/userlist', component: UserList }
])
]
}));
it('should successfully login', async(() => {
let fixture = TestBed.createComponent(Login);
let loginComponent = fixture.componentInstance;
fixture.detectChanges();
loginComponent.login({
username: 'TestUser1',
password: 'TestPassword1'
});
expect(loginComponent.successMessage).toEqual('Login successful');
expect(loginComponent.errorMessage).toEqual('');
}));
});
完整错误:
FAILED TESTS:
Login
✖ should successfully login
PhantomJS 2.1.1 (Mac OS X 0.0.0)
Failed: Uncaught (in promise): Error: Cannot find primary outlet to load 'UserList'
resolvePromise@webpack:///~/zone.js/dist/zone.js:429:0 <- config/spec-bundle.js:53943:75
webpack:///~/zone.js/dist/zone.js:406:0 <- config/spec-bundle.js:53920:27
invoke@webpack:///~/zone.js/dist/zone.js:203:0 <- config/spec-bundle.js:53717:33
onInvoke@webpack:///~/zone.js/dist/async-test.js:42:0 <- config/spec-bundle.js:52757:45
onInvoke@webpack:///~/zone.js/dist/proxy.js:69:0 <- config/spec-bundle.js:53414:47
invoke@webpack:///~/zone.js/dist/zone.js:202:0 <- config/spec-bundle.js:53716:42
run@webpack:///~/zone.js/dist/zone.js:96:0 <- config/spec-bundle.js:53610:49
webpack:///~/zone.js/dist/zone.js:462:0 <- config/spec-bundle.js:53976:60
invokeTask@webpack:///~/zone.js/dist/zone.js:236:0 <- config/spec-bundle.js:53750:42
onInvokeTask@webpack:///~/zone.js/dist/proxy.js:96:0 <- config/spec-bundle.js:53441:49
invokeTask@webpack:///~/zone.js/dist/zone.js:235:0 <- config/spec-bundle.js:53749:54
runTask@webpack:///~/zone.js/dist/zone.js:136:0 <- config/spec-bundle.js:53650:57
drainMicroTaskQueue@webpack:///~/zone.js/dist/zone.js:368:0 <- config/spec-bundle.js:53882:42
invoke@webpack:///~/zone.js/dist/zone.js:308:0 <- config/spec-bundle.js:53822:44
答案 0 :(得分:2)
您能解释一下如何正确创建路由器存根
只做
let routerStub;
beforeEach(() => {
routerStub = {
navigate: jasmine.createSpy("navigate")
};
TestBed.configureTestingModule({
providers: [
// add router provider
{ provide: Router, useValue: routerStub },
{ provide: RegistrationService, useValue: mockRegistrationService }
],
imports: [
ReactiveFormsModule,
// Remove Router Module
]
})
});
然后在测试中,检查是否使用正确的参数调用navigate
方法
expect(routerStub.navigate).toHaveBeenCalledWith(['someurl'])
这更像是单元测试应该是什么样子。您只想测试组件的行为。所以你只需检查它是否在路由器上调用了导航方法。