ngOnChanges не вызывается в модульном тесте Angular 4 detectChanges()

Вопрос

У меня есть компонент кнопки, который принимает обещание и отключает кнопку до тех пор, пока обещание не будет разрешено, и я хочу написать модульный тест для этой функции.

Мой код

Мой компонент кнопки имеет вход для обещания

  /**
   * 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);
}

Затем я сохраняю массив активных обещаний, чтобы можно было передать несколько обещаний в

  /**
   * 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();
    });
  }));

Как всегда, любая помощь будет оценена, спасибо.

2 ответа

Решение

Короткий ответ на этот вопрос заключается в том, что 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();

  }));

Вы пытались утверждать, прежде чем добавить это обещание?

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);
}));

Изменить: как отмечено в комментариях, способ, которым вы устанавливаете это 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.
Другие вопросы по тегам