使用 async、querySelectorAll、focus 测试整个方法

Test the entire method with async, querySelectorAll, focus

如何测试整个方法onShowSidebar

   public async onShowSidebar() {
        await delay();

        const inputList = this.elem.nativeElement.querySelectorAll('#form input, #form textarea') as NodeListOf<HTMLInputElement | HTMLTextAreaElement>;
        const selected = Array.from(inputList).find(f => !f.disabled);
        if (selected)
            selected.focus();
    }

constructor(
    private elem: ElementRef
) { }

delay = (ms: number = 100): Promise<boolean> => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(true);
    }, ms);
  });
};

我的困难在于将 querySelectorAll 模拟为 return 元素。然后测试是否调用了焦点

注意:需要使用querySelectorAll,因为使用了自定义输入组件,简单的示例渲染如下:

<form id="form">
  <custom-input><input></custom-input>
  <custom-area><textarea></custom-area>
</form>

经过一段时间尝试做一个有效的测试:

it('test onShowSidebar input1 focus', async () => {
    const element = spyOn(component['elem'].nativeElement, 'querySelectorAll').and.callThrough();

    await component.onShowSidebar();

    expect(element).toHaveBeenCalled();

    const input1 = element.calls.first().returnValue[0] as HTMLInputElement; //in the following tests just increase the index
    const inputFocused = fixture.nativeElement.querySelector(`:focus`);

    expect(inputFocused).toBeTruthy();
    expect(inputFocused).toEqual(input1);
});

// disable the next input and do as many tests as needed and returnValue[1]

it('test onShowSidebar without focus', async () => {
    component.formGroup.get('input1').disable();
    component.formGroup.get('input2').disable();
    component.formGroup.get('input3').disable();
    fixture.detectChanges();

    const element = spyOn(component['elem'].nativeElement, 'querySelectorAll').and.callThrough();

    await component.onShowSidebar();

    expect(element).toHaveBeenCalled();

    const inputs = element.calls.first().returnValue as Array<HTMLInputElement | HTMLTextAreaElement>;
    const inputFocused = fixture.nativeElement.querySelector(`:focus`);

    expect(inputFocused).toBeFalsy();
    inputs.forEach(input => {
        expect(inputFocused).not.toEqual(input);
    });
});

一些要点:

  1. 有必要使用 component['elem'] 而不是模拟 ElementRef
  2. callThrough 用于进行真实调用,return 用于渲染 元素
  3. 因为 element 只是一个 HTMLInputElement return 而不是模拟,它 无法测试是否调用了焦点,因此解决方案 是检查谁被关注,以及是否与 屏幕上的输入序列