Angular 4 单元测试中未调用 ngOnChanges detectChanges()

Posted

技术标签:

【中文标题】Angular 4 单元测试中未调用 ngOnChanges detectChanges()【英文标题】:ngOnChanges not called in Angular 4 unit test detectChanges() 【发布时间】:2018-06-13 15:27:51 【问题描述】:

问题

我有一个按钮组件,它接受一个承诺并禁用按钮,直到承诺解决,我想为此功能编写一个单元测试。

我的代码

我的按钮组件有一个承诺的输入

  /**
   * A single promise that triggers the busy state until it resolves
   */
  @Input()
  public promise: Promise<any>;

在 ngOnChanges 中我聆听承诺

/**
 * Enable button busy state until promise resolves
 */
if (changes && changes.promise && changes.promise.currentValue) 
  this.busyUntilPromiseResolves(changes.promise.currentValue);

然后我存储了一个活跃的 promise 数组,因此可以传入多个 promise

  /**
   * Add a promise that will keep the button in a busy state until it resolves
   * @param activityProimise
   */
  private busyUntilPromiseResolves(activityProimise) 
    this.activityPromises.push(activityProimise);
    activityProimise.then(() => 
      this.activityPromises.splice(this.activityPromises.indexOf(activityProimise), 1);
    );
  

最后在我的模板中,如果数组中有任何承诺,我将禁用该按钮。

[disabled]="activityPromises.length > 0"

帮我欧比旺

我一直在涉足并尝试不同的方法来完成这项工作,这是我当前不起作用的测试代码。基本上,我需要在承诺解决之前检查按钮是否被禁用,然后我会想做另一个测试,检查它在承诺解决后是否重新启用。

  it('should be disabled when passed a single promise', async((done) => 
    let promise;

    return promise = new Promise(resolve => 
      component.promise = promise;
      fixture.detectChanges();
      expect(buttonElement.disabled).toBe(true);
      return resolve();
    );
  ));

一如既往,我们将不胜感激,谢谢。

【问题讨论】:

【参考方案1】:

这个问题的简短回答是 ngOnChanges 在单元测试期间不会自动触发,所以我不得不手动调用它。

it('should be disabled when passed a single promise', async () => 
    let promise;
    let resolve;

    // should not be disabled here
    expect(buttonElement.disabled).toBe(false);

    // Pass a promise to the component to disable it
    promise = new Promise((r) => (resolve = r));
    component.ngOnChanges(
        promise: new SimpleChange(null, promise, null),
    );

    fixture.detectChanges();
    expect(buttonElement.disabled).toBe(true);

    // now resolve the promise and make sure it's enabled again.
    promise.then(() => 
        fixture.detectChanges();
        expect(buttonElement.disabled).toBe(false);
    );

    resolve();
);

【讨论】:

【参考方案2】:

您是否尝试过在添加该承诺之前进行断言?

it('should be disabled when passed a single promise', async(() => 
  let promise;
  // should not be disabledhere
  expect(buttonElement.disabled).toBe(false);
  let resolve;
  const promise = new Promise(r => resolve = r);
  component.promise = promise;
  component.ngOnChanges(); // Call this here, TestBed doesn't know it needs to.
  fixture.detectChanges();
  expect(buttonElement.disabled).toBe(true);

  // now resolve the promise and make sure it's disabled again.
  resolve();
  fixture.detectChanges();
  expect(buttonElement.disabled).toBe(false);
));

编辑: 如 cmets 所述,您设置 promise 属性的方式不适用于 TestBed,因此它永远不会调用您的 ngOnChanges() 方法。您可以直接调用它,就像我在上面所做的那样。

或者,将您的测试组件包装在主机组件中:

@Component(
  selector: 'test-component',
  template: `<my-component [promise]="promise"></my-component>`
)
class TestComponent 
  promise;


// then use that in your test instead:
const wrapperCmp = TestBed.createComponent(TestComponent);
wrapperCmp.promise = promise; // and check for the button state before and after all the changes.

【讨论】:

嘿!谢谢你的建议。不幸的是,这给了我“预期错误为真的”。 for "expect(buttonElement.disabled).toBe(true);" 这是由于您的组件的工作方式,可能是一个单独的问题。我在这里手动添加了对ngOnChanges() 的调用(当您像这样直接更改属性时,TestBed 不会调用 ngOnChanges),或者更好的解决方案是将组件包装在主机组件中。

以上是关于Angular 4 单元测试中未调用 ngOnChanges detectChanges()的主要内容,如果未能解决你的问题,请参考以下文章

else 单元测试中未采用的路径

Angular 2/4/6/7 - 使用路由器进行单元测试

Angular - 单元测试间谍无法识别该函数已被调用

Angular 4 单元测试(TestBed)非常慢

如何在Angular 8中未调用的组件之间传递数据[重复]

AG-Grid gridReady 未在使用 Angular 和 Jest 的测试中调用