模板中可观察的最佳测试

时间:2017-07-13 18:46:19

标签: angular unit-testing asynchronous angular-components

这是测试中的组件:

@Component({
  moduleId: module.id,
  selector: 'my-search',
  templateUrl: 'search.component.html',
  styleUrls: ['search.component.css'],
})
export class SearchComponent implements OnInit {

  things: Observable<Thing[]>;

  private searchTerms = new Subject<string>();

  constructor(private searchService: SearchService) { }

  ngOnInit() {
    this.things = this.searchTerms
      .debounceTime(300)
      .distinctUntilChanged()
      .switchMap((term: string) => term
        ? this.searchService.search(term)
        : Observable.of<Thing[]>([]));
  }

  search(term: string) {
    this.searchTerms.next(term);
  }
}

这里是search.component.html:

<form (submit)="search()">
  <input #searchBox (keyup)="search(searchBox.value)" />
  <button type="submit">Search</button>
</form>

<div *ngIf="(things | async)?.length == 0; else searchResults">No things found.</div> 
<ng-template #searchResults>
  <div class="search-results">
    <div *ngFor="let thing of things | async" class="search-result">
      {{thing.id}}
    </div>
  </div>
</ng-template>

这是失败的测试:

it('should exhibit issue', fakeAsync(() => {
    component.ngOnInit();
    fixture.detectChanges();

    component.search('123');
    tick(300);
    fixture.detectChanges();

    component.things.subscribe((things) => {
        // This fails. (I've tried various things, this is just the latest attempt.)
        expect(dom.querySelectorAll('.search-results .search-result').length).toBe(1);
    });
}));

Here's a plunk with what I've got so far.

无论我做什么,我都看不到DOM的变化。 fixture.detectChanges()没有对DOM做任何事情。

如何测试Observables?

2 个答案:

答案 0 :(得分:0)

这对我有用

const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
fixture.detectChanges();
app.search('123');
tick(400);
fixture.detectChanges();
const searchNodes = fixture.debugElement.queryAll(By.css('.search-results .search-result')).map((item) => item.nativeElement);
expect(searchNodes.length).toBe(3);

答案 1 :(得分:0)

终于开始工作了。您可以查看the plunk (version 25),但这是精简解决方案:

it('now works!', async(() => {
    // Initialize the component.
    component.ngOnInit();
    fixture.detectChanges();

    // The Observable is now initialized and we can now subscribe.
    component.things.subscribe((things) => {
        // Now that we've got the data, look for changes.
        fixture.detectChanges();

        // The DOM/view should now be up to date.
        expect(dom.querySelectorAll('.search-results .search-result').length).toBe(1);
    });

    // Initiate stuff happening.
    component.search('123');
}));

亮点:

  • 使用async代替fakeAsync
  • 请务必在订阅中致电detectChanges,以便更新视图。

我要注意的一件事:subscribe是在事件之前还是之后(示例中对search的调用)似乎并不重要案件。我之前已经把它放在了预防措施之前,因为这是一个很热门的事情。 Observable可能会在subscribe寄存器之前处理该事件;然后观察者会错过通知,回调永远不会发射,测试将无效。