【问题标题】:Is it possible to trigger (ngModelChange) event on a custom child component in a parent via Jest test?是否可以通过 Jest 测试在父级中的自定义子组件上触发 (ngModelChange) 事件?
【发布时间】:2021-06-14 02:38:53
【问题描述】:

我正在 Jest 中为一个组件进行单元测试。我要验证的功能之一是,当组件中呈现的子组件(实现ControlValueAccessor)修改其ngModel 绑定并触发父组件执行相应操作的(ngModelChange) 事件时。

为简洁起见,这里是父级的相关代码,包含对子级的引用,<child-component>

<div>I am the parent component</div>
<child-component
  [(ngModel)]="myModel"
  (ngModelChange)="doAThing($event)"
>
</child-component>

在测试中我尝试过这样的测试:

it('Binds to the child properly', () => {
  // Bunch of set up where I use Angular's TestBed utility to get a reference to the component
  // and the testing fixture 

  spyOn(component, 'doAThing');
  component.myModel = 'new data';
  fixture.detectChanges();
  expect(component.doAThing).toHaveBeenCalled();
});

但间谍从未检测到任何呼叫。现在这种方法是有道理的,因为我直接在父级上修改模型,该模型将传递给子级,但不应该备份给父级-在这种情况下,您最终会陷入递归循环。

那么问题是:我如何在父组件的 Jest 测试中使 &lt;child-component&gt; 触发其 (ngModelChange) 事件?

阅读文档后,我唯一的想法是 stub out the child component 并以某种方式获取对它的引用并手动触发事件。但这似乎需要做很多工作。有没有更简单的方法?

感谢您对如何最好地测试此功能的任何想法。

【问题讨论】:

    标签: javascript angular testing jestjs


    【解决方案1】:

    事实证明,当我发布有关 stubbing out the child like is described in the Angular docs 的信息时,我的思路是正确的。

    我基本上不得不像这样在父测试的顶部删除孩子:

    @Component({
        selector: 'child-component',
        template: '',
        providers: [
            {
                provide: NG_VALUE_ACCESSOR,
                useExisting: ChildComponent,
                multi: true
            }
        ]
    })
    class ChildComponent implements ControlValueAccessor {
        _model: any;
        get model() {
            return this._model;
        }
        set model(val: any) {
            this._model = val || null;
            this.propagateChange(this._model);
        }
        propagateChange = (_: any) => {};
        writeValue(value: any): void {
            this._model = value;
        }
        registerOnChange(fn: any): void {
            this.propagateChange = changed => {
                return fn.call(this, changed);
            };
        }
        registerOnTouched(): void {}
    }
    

    需要注意的重要一点是它必须实现ControlValueAccessor,这样我们才能绑定到(ngModelChange) 事件。这包括 providers 位,否则 Angular 将无法正确设置它。

    然后测试最终看起来像这样:

    it('Binds to the child properly', () => {
        const childDebugElement = fixture.debugElement.query(
            By.directive(ChildComponent)
        );
        spyOn(component, 'doAThing');
    
        childDebugElement.componentInstance.model = 'new data';
        fixture.detectChanges();
    
        expect(component.doAThing).toHaveBeenCalled();
    });
    

    我们可以在fixture 上使用debugElement.query,我们使用Angular 的TestBed 实用程序来获取我们需要的组件的引用。由于我们提供了一个存根,我们可以通过childDebugElement.componentInstance 获得对我们提供的实际组件的引用。然后只需确保调用propagateChanges 即可。在这种情况下,这是通过 model 上的设置器。


    我并不激动,它需要为一个存根编写一大堆代码,而存根只是父级中实际组件的代理。但我想这就是你基本上想要一个集成测试时得到的结果。

    【讨论】:

      猜你喜欢
      • 2021-05-05
      • 2019-04-12
      • 2022-01-20
      • 1970-01-01
      • 2021-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-29
      相关资源
      最近更新 更多