最近、複数のコンポーネントとサービスを備えた ng2 (2.0.1 を使用) アプリを作成しました。UserService (拡張された Http クラスを使用する)を含むHeaderComponentのテスト (Karma Jasmine) の最中です。
Angular.io Docsから簡単なテストを複製してサービスをスパイし、コンポーネントの初期化後にサービス関数が起動されたかどうかとその内容を確認しました。header.component の currentUser 変数の内容をチェックする fakeAsync (および async) を使用して最後のテストを実行するたびに、次のエラーが表示されます...
Error: Uncaught (in promise): Error: Template parse errors:
'header-section' is not a known element:
1. If 'header-section' is an Angular component, then verify that it is part of this module.
2. If 'header-section' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("
[ERROR ->]<header-section></header-section>
<router-outlet></router-outlet>
<footer-section></footer-sectio"): AppComponent@1:2
'router-outlet' is not a known element:
1. If 'router-outlet' is an Angular component, then verify that it is part of this module.
2. If 'router-outlet' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("
<header-section></header-section>
[ERROR ->]<router-outlet></router-outlet>
<footer-section></footer-section>"): AppComponent@2:2
'footer-section' is not a known element:
1. If 'footer-section' is an Angular component, then verify that it is part of this module.
2. If 'footer-section' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("
<header-section></header-section>
<router-outlet></router-outlet>
[ERROR ->]<footer-section></footer-section>"): AppComponent@3:2
これらのセレクターは私のAppComponentからのものです...
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'my-app',
moduleId: module.id,
template: `
<header-section></header-section>
<router-outlet></router-outlet>
<footer-section></footer-section>`
})
export class AppComponent {
constructor() {}
test(): string {
return 'this is a test';
}
}
私のheader.component.spec ...
import { Http, Request, RequestOptionsArgs, Response, XHRBackend, RequestOptions, ConnectionBackend, Headers } from '@angular/http';
import { HttpIntercept } from '../../services/auth/auth.service';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule, JsonpModule } from '@angular/http';
import { FormsModule } from '@angular/forms';
import { RouterTestingModule } from "@angular/router/testing";
import { appRoutes } from '../../routes';
import { Cookie } from 'ng2-cookies/ng2-cookies';
import { AppComponent } from '../app/app.component';
import { HeaderComponent } from './header.component';
import { FooterComponent } from '../footer/footer.component';
import { HomeComponent } from '../home/home.component';
import { Four0FourComponent } from '../404/four0four.component';
import { UserProfileComponent } from '../user-profile/user-profile.component';
import { UserService } from '../../services/user/user.service';
import { ClockService } from '../../services/clock/clock.service';
import { Observable } from 'rxjs/Observable';
import { TestBed, async, fakeAsync, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { User } from '../../models/user/user.model';
class MockRouter { public navigate() { }; }
describe('HeaderComponent Test', () => {
let fixture;
let comp;
let userService;
let spy;
let user = new User({
_id: 123456,
userName: 'testName',
firstName: 'testFirst',
lastName: 'testLast',
email: 'test@email.com',
create: 'now',
role: 'user'
});
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
BrowserModule,
HttpModule,
FormsModule,
JsonpModule,
RouterTestingModule.withRoutes(appRoutes)
],
declarations: [
HomeComponent,
UserProfileComponent,
Four0FourComponent,
FooterComponent,
HeaderComponent,
AppComponent
],
providers: [
{
provide: Http,
useFactory: (
backend: XHRBackend,
defaultOptions: RequestOptions) =>
new HttpIntercept(backend, defaultOptions),
deps: [XHRBackend, RequestOptions]
},
Cookie
]
});
fixture = TestBed.createComponent(HeaderComponent);
comp = fixture.componentInstance;
userService = fixture.debugElement.injector.get(UserService);
spy = spyOn(userService, 'getMe')
.and.returnValue(Observable.of(user));
});
it('should instantiate component', () => {
expect(fixture.componentInstance instanceof HeaderComponent).toBe(true);
});
it('should not show currentUser before OnInit', () => {
expect(spy.calls.any()).toBe(false, 'getMe not yet called');
});
it('should still not show currentUser after component initialized', () => {
// Set cookie token, for the getMe to call
Cookie.set('token', 'test_token_alpha');
fixture.detectChanges();
expect(spy.calls.any()).toBe(true, 'getMe called');
});
//The problem test is bellow
it('should show currentUser after getMe promise', fakeAsync(() => {
fixture.detectChanges();
tick();
fixture.detectChanges();
expect(comp.currentUser).toEqual(user);
}));
});
これが私のheader.componentです...
import { Component } from '@angular/core';
import { Cookie } from 'ng2-cookies/ng2-cookies';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/interval';
import { UserService } from '../../services/user/user.service';
import { ClockService } from '../../services/clock/clock.service';
import { User } from '../../models/user/user.model';
@Component({
selector: 'header-section',
providers: [
UserService,
ClockService
],
moduleId: module.id,
template: `
<style>
header{
background: rgb(55, 129, 215);
position: relative;
}
.user-sign{
position: absolute;
top:0;
right:0;
margin: 23px 5%;
}
.app-title{
font-family: cursive;
padding: 15px;
text-align: center;
font-size: 36px;
color: white;
}
.user-sign button:hover{
cursor: pointer;
}
.active{
color: orange;
}
</style>
<header>
<a routerLink='/' routerLinkActive='active'>Home</a>
<a routerLink='/profile' routerLinkActive='active'>Profile</a>
<a routerLink='/yoloswaq69420blazeitfgt' routerLinkActive='active'>404</a>
<div class='user-sign'>
<h3 *ngIf='currentUser'>Welcome, {{currentUser.userName}}</h3>
<button *ngIf='!currentUser' type='button' (click)='testRegisterUser()'>Sign up</button>
<button *ngIf='!currentUser' type='button' (click)='testUser()'>Sign in</button>
<button type='button' (click)='logout()'>Sign out</button>
</div>
<h1 class='app-title'>MEA2N Fullstack</h1>
</header>`
})
export class HeaderComponent {
errorMessage: string;
public currentUser: User;
clock = this.clockService.currentTime;
constructor(private userService: UserService, private clockService: ClockService) { }
ngOnInit() {
let token = Cookie.get('token');
if (token)
this.userService.getMe().subscribe(user => this.currentUser = user);
}
login(email: string, password: string) {
this.userService.login(email, password)
.subscribe(() => {
return this.userService.getMe()
.subscribe(user => {
this.currentUser = user;
})
});
}
logout() {
this.userService.logout();
this.currentUser = null;
}
registerUser(username: string, email: string, password: string) {
this.userService.signup(username, email, password)
.subscribe(() => {
return this.userService.getMe()
.subscribe(user => {
this.currentUser = user;
})
});
}
testUser() {
this.login('jc.thomas4214@gmail.com', 'flight1855');
}
testRegisterUser() {
this.registerUser('Jason', 'jc.thomas4214@gmail.com', 'flight1855');
}
}
TestBed.configureTestingModule() の初期化方法が原因で、このエラーが発生しているのではないかと疑っています。
私はもう試した...
- app.module と TestBed モジュール宣言の両方の並べ替え
- schema: [CUSTOM_ELEMENTS_SCHEMA] を両方のモジュールに追加