【问题标题】:Angular - Testing / mocking subscriptions that use rxjs fromEventAngular - 测试/模拟使用 rxjs fromEvent 的订阅
【发布时间】:2020-04-23 09:45:30
【问题描述】:

在我的 Angular 组件中,我有一个公司对象数组,通过 @Input() 提供:当它被加载时(因为它是从 HTTP 请求派生的),我获取该值并将其分配给另一个名为 @987654322 的变量@ 我用于*ngFor

*ngFor 用于选择菜单,我有一个@ViewChild,它是一个 HTML 文本输入,当发生按键事件时,我获取输入的值并过滤过滤列表。我正在使用 rxJS fromEvent

捕获 keyup 事件

为了简化这是我的 HTML

<input id="companiesInput" #companyInput>

<mat-selection-list (selectionChange)="listBoxChange($event)">
  <mat-list-option
  *ngFor="let company of filteredList"
    [value]="company"
    [checkboxPosition]="'before'">
    {{company.displayName}}
  </mat-list-option>
</mat-selection-list>

这是我的一些组件代码...一切正常!!

@Input() companyList: any[] = [];
private tagsSubscription: Subscription;
filteredList: any[] = [];

ngOnChanges(changes: any): void {
  if (changes.companyList.currentValue && changes.companyList.currentValue.length > 0) {
    this.filteredList = this.companyList;
  }
}

ngAfterViewInit(): void {
    const tagsSource = fromEvent(this.companyInput.nativeElement, 'keyup').pipe(
      debounceTime(250),
      distinctUntilChanged(),
      switchMap((ev: any) => {
        return of(ev.target.value);
      })
    );

    this.tagsSubscription = tagsSource.subscribe((res: any) => {
      res = res.trim();
      if (res.length > 0) {
        this.filteredList = this.companyList.filter((company) => company.displayName.indexOf(res) > -1);
      } else {
        this.filteredList = this.companyList;
      }
    });
  }

一切都很好,但我需要测试我的代码,这就是我的不足之处。这是我的测试

describe('tagsSubscription', () => {
    it('should filter the available list of companies returned', () => {
      const dummyArray = [
        { id: 1, displayName: 'saftey io' },
        { id: 2, displayName: 'msa' },
        { id: 3, displayName: 'acme' }
      ];

      component.companyList = dummyArray;

      fixture.detectChanges();
      component.ngOnChanges({ companyList: { currentValue: dummyArray } });

      const fromEventSpy = spyOn(rxjs, 'fromEvent').and.returnValue(() => rxjs.of({}));
      const companiesInput = element.querySelector('#companiesInput');

      element.querySelector('#companiesInput').value = 'ac';
      companiesInput.dispatchEvent(generateKeyUpEvent('a'));
      fixture.detectChanges();

      companiesInput.dispatchEvent(generateKeyUpEvent('c'));
      fixture.detectChanges();

      expect(component.filteredList.length).toEqual(1);
    });
  });

从注销中我可以看到,在我的测试中,fromEvent 从未引发,因此 tagsSource.subscribe 从未运行。我做错了什么,我想在我的测试中通过将以下行添加到我的事件顶部来模拟 fromEvent,就像这样

const fromEventSpy = spyOn(rxjs, 'fromEvent').and.returnValue(() =&gt; rxjs.of('ac'));

这也不起作用。有没有人知道如何使用 Angular 测试 fromEvent Observables,也许可以告诉我如何让我的测试正常工作?

【问题讨论】:

  • 你确定ngAfterViewInit()方法是自动调用的,不用你自己调用吗?
  • 我在ngAfterViewInit() 中放了一个console.log 以检查它是否被调用,所以这不是问题
  • 在你使用spyOn之前还是之后调用它?
  • 使用 spyOn 时不调用 fromEvent
  • spyOn 不会触发ngAfterViewInit 调用。别的东西做了。所以问题是在覆盖fromEvent 之前或之后是否调用ngAfterViewInit,因为它可能在此之前被调用。

标签: angular unit-testing rxjs


【解决方案1】:

如果是ViewChild,只需触发它。

const input = fixture.debugElement.query(By.css('#companiesInput'));
input.triggerEventHandler('keyup', {/* some data */});

如果是输入 - 只需模拟它并添加 2 个方法

const handler: Function | undefined;

companyInput.nativeElement.addListener = (eventName: string, eventHandler: Function) => {
  if (eventName === 'keyup') {
    handler = eventHandler;
  }
};
companyInput.nativeElement.removeListener = () => {};

// call your code to subscribe

if (handler) {
  handler('value1');
  handler('value2');
  handler('value3');
  handler('value4');
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-03
    • 1970-01-01
    • 2020-02-14
    • 2018-07-03
    • 2021-12-19
    • 2018-12-29
    • 2018-12-13
    相关资源
    最近更新 更多