2016-09-30 5 views
5

У меня есть LogComponent в моем приложении. Внутри ngOnInit Я извлекаю журналы с сервера через LogService и отображает их в сетке.угловой 2 тест компонента с forkJoin

Вот 2 способа, как это сделать:

1-й:

import { Component, OnInit } from '@angular/core'; 
import { Router } from '@angular/router'; 
import { Observable } from 'rxjs/Observable'; 

import { Log } from './log'; 
import { LogService } from './log.service'; 
import * as globals from '../../globals'; 
import { DataTransformService, HttpHandlerService, StateManagerService } from '../../shared'; 

@Component({ 
    selector: 'app-log', 
    templateUrl: 'log.component.html', 
    styleUrls: ['log.component.css'], 
    providers: [ DataTransformService, HttpHandlerService, LogService, StateManagerService] 
}) 
export class LogComponent implements OnInit { 

    localGlobals: any = globals; 

    logs: Log[]; 

    currentPage: number; 
    totalRecords: number = 0; 
    firstRowIndex: number = 0; 

    constructor(
    private stateManagerService: StateManagerService, 
    private httpHandlerService: HttpHandlerService, 
    private logService: LogService, 
    private dataTransformService: DataTransformService, 
    private router: Router 
) {} 

    ngOnInit() { 

    //get page number from local storage 
    this.currentPage = this.stateManagerService.getParamFromState(this.router.url, 'page'); 
    this.firstRowIndex = this.currentPage * this.localGlobals.ROWS_PER_PAGE - this.localGlobals.ROWS_PER_PAGE; 

    //get total count 
    let respHandler = (res: any) => { 
     this.totalRecords = res.headers.get('X-Pagination-Total-Count'); 
     return this.httpHandlerService.extractData(res); 
    }; 

    this.logService.search(this.currentPage, respHandler).subscribe(
     logs => { 
     this.logs = logs; 
     }, 
     err => console.error(err) 
    ); 

    } 

} 

1-ый подход использует эту функцию, чтобы получить журналы:

this.logService.search(this.currentPage, respHandler).subscribe(
    logs => { 
    this.logs = logs; 
    }, 
    err => console.error(err) 
); 

2-й способ, чтобы получить регистрируется через Observable.forkJoin:

import { Component, OnInit } from '@angular/core'; 
import { Router } from '@angular/router'; 
import { Observable } from 'rxjs/Observable'; 

import { Log } from './log'; 
import { LogService } from './log.service'; 
import * as globals from '../../globals'; 
import { DataTransformService, HttpHandlerService, StateManagerService } from '../../shared'; 

@Component({ 
    selector: 'app-log', 
    templateUrl: 'log.component.html', 
    styleUrls: ['log.component.css'], 
    providers: [ DataTransformService, HttpHandlerService, LogService, StateManagerService] 
}) 
export class LogComponent implements OnInit { 

    localGlobals: any = globals; 

    logs: Log[]; 

    currentPage: number; 
    totalRecords: number = 0; 
    firstRowIndex: number = 0; 

    constructor(
    private stateManagerService: StateManagerService, 
    private httpHandlerService: HttpHandlerService, 
    private logService: LogService, 
    private dataTransformService: DataTransformService, 
    private router: Router 
) {} 

    ngOnInit() { 

    //get page number from local storage 
    this.currentPage = this.stateManagerService.getParamFromState(this.router.url, 'page'); 
    this.firstRowIndex = this.currentPage * this.localGlobals.ROWS_PER_PAGE - this.localGlobals.ROWS_PER_PAGE; 

    //get total count 
    let respHandler = (res: any) => { 
     this.totalRecords = res.headers.get('X-Pagination-Total-Count'); 
     return this.httpHandlerService.extractData(res); 
    }; 

    Observable.forkJoin(
     this.logService.search(this.currentPage, respHandler) 
    ).subscribe(
     data => { 
     this.logs = data[0]; 
     }, 
     err => console.error(err) 
    ); 

    } 

} 

2-й подход использует эту функцию, чтобы получить журналы:

Observable.forkJoin(
     this.logService.search(this.currentPage, respHandler) 
    ).subscribe(
     data => { 
     this.logs = data[0]; 
     }, 
     err => console.error(err) 
    ); 

У меня есть тест для этого компонента, который проверяет, что свойства инициализируются после запуска:

import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; 
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 
import { FormsModule } from '@angular/forms'; 
import { By } from '@angular/platform-browser'; 
import { Router } from '@angular/router'; 
import { ReplaySubject } from 'rxjs/Rx'; 

import { Log } from './log'; 
import { LogComponent } from './log.component'; 
import { LogService } from './log.service'; 
import { DataTransformService, HttpHandlerService, LocalStorageService, StateManagerService } from '../../shared'; 

let comp: LogComponent; 
let fixture: ComponentFixture<LogComponent>; 
let de:  DebugElement; 

describe('LogComponent',() => { 

    // async compile html and css 
    beforeEach(async(() => { 

    let project = new ReplaySubject(1); 
    let logServiceStub = { 
     search: (pageNum: number, respHandler: any) => { 
      let logs = [ 
       { id: 1, ip: '127.0.0.1', user_id: 1, notification_event_id: 1, created_at: 1 }, 
       { id: 2, ip: '127.0.0.2', user_id: 2, notification_event_id: 2, created_at: 2 } 
      ]; 
      project.next(logs); 
      return project; 
     } 
    }; 

    let routerStub = { 
     url: 'log_url' 
    }; 

    TestBed.configureTestingModule({ 
     declarations: [ LogComponent ], 
     imports: [ FormsModule ], 
     providers: [ 
      DataTransformService, 
      HttpHandlerService, 
      LocalStorageService, 
      { provide: Router, useValue: routerStub }, 
      StateManagerService 
     ], 
     schemas: [ NO_ERRORS_SCHEMA ] 
    }) 
    .overrideComponent(LogComponent, { 
     set: { 
     providers: [ 
      { provide: LogService, useValue: logServiceStub } 
     ] 
     } 
    }) 
    .compileComponents(); 

    })); 

    // synchronous 
    beforeEach(() => { 

    fixture = TestBed.createComponent(LogComponent); 

    // LogComponent test instance 
    comp = fixture.componentInstance; 

    de = fixture.debugElement; 

    }); 

    it('initial variables are set after init',() => { 

     fixture.detectChanges(); 

     console.log(comp.logs); 

     //TODO: test not working when requests are in forkJoin 
     expect(comp.currentPage).toBe(1); 
     expect(comp.firstRowIndex).toBe(0); 
     expect(comp.logs).not.toBeUndefined(); 
     expect(comp.logs.length).toBe(2); 

    }); 

}); 

Проблема: когда я (без Observable.forkJoin), он отлично работает. НО когда я запускаю тест с использованием 2-й подход (с Observable.forkJoin) он терпит неудачу с ошибкой:

Expected undefined not to be undefined.

Так журналы не инициализируется после fixture.detectChanges(). Похоже, если запрос находится внутри Observable.forkJoin(), тогда инициализация не выполняется. Я понимаю, что в Observable.forkJoin() есть только 1 запрос, и я могу пойти с 1-м подходом, но у меня есть другие компоненты в системе, которые используют более одного запроса, поэтому мне нужна эта проблема для решения.

Надеюсь, вы поняли, что я имею в виду.

Заранее спасибо.

+0

Я также сталкиваюсь с этой проблемой. Вы нашли решение для этого? @ryzhak –

+0

Я также ищу ответ на этот вопрос –

+0

. То же самое и здесь.:/ Возможно ли найти решение? – kriskodzi

ответ

2

Хорошо, ребята, после некоторых боев я обнаружил, что наблюдаемые должны быть завершены за forkJoin, чтобы поймать его.
Так что, если вы позвоните
project.next(something)
не достаточно.
Вы также должны позвонить:
project.complete()
, чтобы заставить его работать!

Смежные вопросы