【问题标题】:Angular - Unit testing focusing on buttonAngular - 专注于按钮的单元测试
【发布时间】:2018-08-30 09:23:11
【问题描述】:

我正在尝试对我的按钮是否被聚焦,但我似乎无法让间谍正常工作?

我看到了 [this post][1],但没有完全帮助。

我是否遗漏了一些明显的东西?

component.ts

ngOnInit() {
    // autofocus on the cancel button to guard against mistakes
    document.getElementById('cancel').focus();
  }

【问题讨论】:

    标签: javascript angular testing karma-runner


    【解决方案1】:

    焦点一开始就有缺陷。

    使用 Angular 时,您不应该使用 document 来获取您的元素。

    改用 viewChild。

    @ViewChild('cancel') cancelButton: ElementRef<HtmlButtonElement>;
    ngAfterViewInit() {
      this.cancelButton.nativeElement.focus();
    }
    

    现在你的测试看起来像这样

    it('should focus cancel button', () => {
      spyOn(component.cancelButton.nativeElement, 'focus');
      component.ngAfterViewInit();
      expect(component.cancelButton.nativeElement.focus).toHaveBeenCalledWith();
    });
    

    编辑如果你仍然想使用你的方式,考虑使用By.css()

    it('should autofocus on cancel button on init', () => {
      const cancelButton = fixture.debugElement.query(By.css('#cancel'));
      spyOn(cancelButton, 'focus');
      component.ngOnInit();
      expect(cancelButton.focus).toHaveBeenCalled();
    });
    

    【讨论】:

    • 是的,利用fixture而不是依赖document来获取html元素。
    • @trichetriche - 我实现了@ViewChild,但它说它找不到名称'cancelButton'?
    • 您的按钮类似于&lt;button #cancel&gt;Cancel&lt;/button&gt; 吗?你需要给它一个模板变量引用#cancel
    • 是的,我在谷歌搜索后才注意到。看来您不需要('cancel') : 之后的第一个冒号“:”?它应该是 HTML 而不是 HtmlButtonElement 中的 Html :-)
    • @physicsboy 哎呀,打字错误!此外,ElementRef&lt;HtmlButtonElement&gt; 用于键入您的元素:当您编写 this.cancelButton.nativeElement 时,如果您附加一个点,您将拥有 HTML 按钮元素的智能感知。不是强制性的,但实用的!
    【解决方案2】:

    在您的规范中创建 spy 后调用 ngOnInit(),正如 @trichietrichie 所指出的那样

    另外,利用 fixture 而不是依赖 document 来获取 html 元素。

    beforeEach(() => {
        TestBed.configureTestingModule({
          declarations: [ ConfirmationComponent ],
          providers: [ MessageService]
        });
    
        fixture = TestBed.createComponent(ConfirmationComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();    
        component.ngOnInit();
      });
    
      it('should autofocus on cancel button on init', () => {
        const cancelButton = fixture.debugElement.query(By.css('#cancel'));
        spyOn(cancelButton.nativeElement, 'focus'); // create spy here   
        component.ngOnInit();
        expect(cancelButton.focus).toHaveBeenCalled();
      });
    

    【讨论】:

    • 或召回ngOnInit,这样您就不会创建[it.count] 次您使用一次的间谍?
    • 嗯,我看到了问题,所以他不得不推迟ngOnInit() 调用。
    • Yes & no : ngOnInit 将在每个组件实例化时被调用(这是在每个it,因为我们在beforeEach 中创建它):但ngOnInit 只是一个专门命名的函数,您可以再次调用它,这次使用间谍,以便您可以监视它。所以不是真的推迟了,而是召回了。
    • 再次,不!生命周期挂钩可确保您可以访问特定元素(例如,您不会在 ngOnInit 中获得 ViewContainerRef,但您会在 ngAfterViewInit 中获得)。 Hooks 只是 Angular 调用的函数。例如,我用装饰器实现了类似的东西,它会被事件触发。运行的函数称为 ngOnCustomEvent(eventType: string) :没有什么能阻止我在需要时运行它们,但我知道它们将在发生自定义事件时运行,而无需我手动调用它们。
    • 甚至比删除反对票更好!完全有效的答案值得投票:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多