【问题标题】:How to set NgForm value in Observable and test that it was set?如何在 Observable 中设置 NgForm 值并测试它是否已设置?
【发布时间】:2019-01-06 10:59:42
【问题描述】:

我正在尝试测试NgForm 并检查是否在商店状态更新时设置了表单的值。

@ViewChild('form') form: NgForm;

ngOnInit() {
this.subscription = this.store.select('shoppingList').subscribe(data => {
    this.editedItem = data.editedIngredient;
    this.form.setValue({ 
      name: this.editedItem.name,
      amount: this.editedItem.amount
    })
});

}

但是在设置我得到的值时

There are no form controls registered with this group yet.  
If you're using ngModel, you may want to check next tick (e.g. use setTimeout).

还尝试创建假表单并设置它而不是NgForm

TestBed.createComponent(ShoppingEditComponent).debugElement.componentInstance.form = { value: {}, setValue: (newValue) => { this.value = newValue }};

但在测试中它的值永远不会更新,变成空的value 对象。

测试这种情况的最佳方法是什么?

【问题讨论】:

    标签: javascript angular unit-testing testing


    【解决方案1】:

    @ViewChild('form') 表单:NgForm;

    在 ngOnInit 生命周期钩子中不可用。

    首先,您需要在构造函数或 ngOnInit 中创建一个表单。

    只有这样你才能在现有表单上执行方法。

    例子

    export class MyComponent {
      form: FormGroup;
      editedItem;
    
      constructor(
        private formBuilder: FormBuilder
      ) {}
    
      ngOnInit() {
        this.createForm();
        this.subscribeToShoppingList();
      }
    
      private createForm() {
        this.form = this.formBuilder.group({
          name: null,
          amount: null
        });
      }
    
      private subscribeToShoppingList() {
        this.store.select('shoppingList').subscribe(data => {
          this.editedItem = data.editedIngredient;
          this.form.setValue({ 
            name: this.editedItem.name,
            amount: this.editedItem.amount
          });
        });
      }
    }
    

    在这种情况下,您不需要测试 Store 返回给您的内容,您可以对以下内容进行单元测试:

    const mocks = {
      store: {
        select: sinon.stub().withArgs('shoppingList').returns(new Subject())
      }
    };
    
    let component: MyComponent;
    
    describe('MyComponent', () => {
      beforeEach(() => {
        component = new MyComponent(
          new FormBuilder(),
          <any> mocks.store
        );
      });
    
      describe('ngOnInit', () => {
        beforeEach(() => {
          component.ngOnInit();
        });
    
        it('should create form', () => {
          expect(component.form).to.be.instanceof(FormGroup);
        });
    
        it('should create form with correct fields', () => {
          expect(component.form.value).to.haveOwnProperty('name');
          expect(component.form.value).to.haveOwnProperty('amount');
        });
    
        it('should subscribe to store.shoppingList', () => {
          expect(component.store.select).to.be.calledOnce.and.calledWith('shoppingList');
        });
    
        it('should set correct data from store to component', () => {
          component.store.select.next({
            editedIngredient: {
              name: 'new',
              amount: 100
            }
          });
    
          expect(component.editedItem.amount.to.eql(100));
    
          expect(component.form.value.name).to.eql('new');
        });
    
      });
    });
    

    我没有测试过代码,可能有问题,但我希望我已经解释了主要思想。

    【讨论】:

    • 似乎合法,但我不想将模板驱动的方法更改为 Reactive。
    • 你不能在模板驱动上使用 form.setValue
    • 但它可以在浏览器中运行,问题是无法为其编写单元测试:)
    猜你喜欢
    • 2016-11-09
    • 1970-01-01
    • 2012-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多