在Angular 2中测试OnPush组件

时间:2016-11-30 18:42:15

标签: angular testing angular-cli

我在使用OnPush更改检测策略测试组件时遇到问题。

测试就像这样

it('should show edit button for featured only for owners', () => {
    let selector = '.edit-button';

    component.isOwner = false;
    fixture.detectChanges();

    expect(fixture.debugElement.query(By.css(selector))).toBeFalsy();

    component.isOwner = true;
    fixture.detectChanges();

    expect(fixture.debugElement.query(By.css(selector))).toBeTruthy();
});

如果我使用Default策略,它会按预期工作,但使用OnPush时,isOwner的调用不会被detectChanges调用。我错过了什么吗?

5 个答案:

答案 0 :(得分:3)

你需要告诉angular你改变了组件的输入属性。在理想的世界中,您将替换

component.isOwner = false;
fixture.detectChanges();

component.isOwner = false;
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();

不幸的是,由于角度(https://github.com/angular/angular/issues/12313)存在错误,因此不起作用。您可以使用其中描述的解决方法之一。

答案 1 :(得分:1)

如果你查看了这个伟大的@Günter的答案angular 2 change detection and ChangeDetectionStrategy.OnPush,那么你可以使用以下事件处理程序解决它:

location.href

这是 Plunker Example

答案 2 :(得分:1)

类似于@michaelbromley确实公开ChangeDetectionRef的变通方法,但是由于这仅用于测试,因此我刚刚从v2.6中关闭了TypeScript errors for the next line using // @ts-ignore标志,因此我可以离开ref private。

这可能如何工作的示例:

import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { WidgetComponent } from './widget.component';

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `<my-widget *ngIf="widgetEnabled"></my-widget>`,
});
export class PushyComponent {
  @Input() widgetEnabled = true;

  constructor(private cdr: ChangeDetectorRef) {}

  // methods that actually use this.cdr here...
}

TestBed.configureTestingModule({
  declarations: [ PushyComponent, WidgetComponent ],
}).compileComponents();

const fixture = TestBed.createComponent(PushyComponent);
const component = fixture.componentInstance;
fixture.detectChanges();

expect(component.widgetEnabled).toBe(true);
let el = fixture.debugElement.query(By.directive(WidgetComponent));
expect(el).toBeTruthy();

component.widgetEnabled = false;
// @ts-ignore: for testing we need to access the private cdr to detect changes
component.cdr.detectChanges();
el = fixture.debugElement.query(By.directive(WidgetComponent));
expect(el).toBeFalsy();

答案 3 :(得分:0)

这个问题很容易解决... https://github.com/angular/angular/issues/12313#issuecomment-298697327

{{1}}

请记住,这种方法可能掩盖了一些变更检测问题

积分:marchitos

答案 4 :(得分:0)

有几种解决方案,但就您而言,我认为最简单的方法是将您的测试拆分为两个单独的测试。如果在每个测试中您调用 CompletableFuture<List<ResponseModels.A>> list1 = api.getListOfObjects(); CompletableFuture<List<ResponseModels.A>> list2 = api.getListOfOtherObjects(); CompletableFuture<ResponseModels.B> l = list1.thenApply(list1Objects -> list2.thenApply(list2Objects -> { List<String> list1OfStrings = fop.stream().map(otcPaymentResultDTO -> JsonUtils.gsonFullBody.toJson(ResponseModels.B.builder() .payload(JsonUtils.gsonFullBody.toJson(list1Objects)) )).collect(Collectors.toList()); List<String> list2OfStrings = dvp.stream().map(otcDvPDTO -> JsonUtils.gsonFullBody.toJson(ResponseModels.B.builder() .payload(JsonUtils.gsonFullBody.toJson(list2Objects)))).collect(Collectors.toList()); List<String> combinedList = Stream.concat(list1OfStrings.stream(), list2OfStrings.stream()) .collect(Collectors.toList()); return combinedList; }))); return Flux.just(l); 函数只调用一次,一切都应该正常。

示例:

fixture.detectChanges()