在 Jasmine 中通过 @input 模拟父 FormGroup

Posted

技术标签:

【中文标题】在 Jasmine 中通过 @input 模拟父 FormGroup【英文标题】:Mocking a parent FormGroup via @input in Jasmine 【发布时间】:2018-08-16 04:11:08 【问题描述】:

所以我有一个类似这样的子组件

export class ChildComponent implements OnInit 

  @Input('parentForm')
  public parentForm: FormGroup;

  constructor(private fb: FormBuilder, private cd: ChangeDetectorRef)  

  ngOnInit() 
    this.parentForm.addControl('newControl', <Some Control>);
  

接下来我有一个像这样的准系统单元测试文件

describe('ChildComponent', () => 
  let component: ChildComponent;
  let fixture: ComponentFixture<ChildComponent>;

  beforeEach(async(() => 
    TestBed.configureTestingModule(
      imports: [ReactiveFormsModule, FormsModule],
      declarations: [ ChildComponent ],
      providers: [ FormBuilder, FormGroup ]
    )
    .compileComponents();
  ));

  beforeEach(inject([FormBuilder], (fb: FormBuilder) => 
    fixture = TestBed.createComponent(ChildComponent);
    component = fixture.componentInstance;
    component.parentForm = fb.group();
    component.ngOnInit();
    fixture.detectChanges();
  ));

  fit('should be created', () => 
    expect(component).toBeTruthy();
  );
);

以前我遇到了一个未定义 parentForm 的问题,所以我尝试通过在 beforeEach 中注入 FormBuilder 来自己构建它,方法是这样做 component.parentForm = fb.group();。但是现在的问题是 karma/jasmine 找不到 FormBuilder

Cannot find name 'FormBuilder'.

我要做的就是在单元测试期间创建组件实例时尝试获取或模拟 parentForm,我需要它,因为我在 for each 期间调用 ngOnInit,因为它是一个新控件.

任何想法。谢谢

【问题讨论】:

你能解决这个问题吗?我的情况也一样。但我收到“无法解析 FormGroup 的所有参数:(?, ?, ?)”错误。 我注意到您的代码中有错字:inject([FormBuidler], (fb: FormBuilder) 应该是:inject([FormBuilder], (fb: FormBuilder) 【参考方案1】:

我能够为 Reactive Form Parent Child 组件设置成功的 Karma 规范测试。希望下面的示例将有助于指导您的设置。我已经从我的代码库中简化了尽可能多的代码,以专注于您要解决的核心问题。

父组件

parent.component.html

...
<div [stepControl]="childFormGroup">
  <child-form-group [formGroup]="childFormGroup"></child-form-group>
</div>
...

parent.component.ts

import  Component, OnInit  from '@angular/core';
import  FormBuilder, FormGroup, Validators, FormControl  from '@angular/forms';

@Component(
  selector: 'form-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss']
)
export class FormParentComponent implements OnInit 
  // childFormGroup will be available on the parent DOM
  // so we can inject it / pass it to the ChildFormComponent
  public childFormGroup : FormGroup;

  constructor(private _formBuilder: FormBuilder) 
    this.createForm();
  

  private createForm() : void 
    this.childFormGroup = this._formBuilder.group(
      name:  ['Sample Name', Validators.required],
      email: ['', Validators.required]
    );
  

子组件

child.component.html

...
<form [formGroup]="formGroup">
  <p>This is the childFormGroup</p>
  <br>

  <div>
    <input  placeholder="Name"
            formControlName="name"
            autocomplete="off">
  </div>

  <div>
    <input  placeholder="Email"
            formControlName="email"
            autocomplete="off">
  </div>
</form>
...

child.component.ts

import  Component, Input, Output, EventEmitter  from '@angular/core';
import  FormGroup  from '@angular/forms';

@Component(
  selector: 'child-form-group',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss'],
)
export class ChildFormComponent 
  // This declares an inherited model available to this component
  @Input() formGroup : FormGroup;

  constructor()  

  /* There is no need to create the formGroup here
     hence no constructor method call or ngOnInit() hook...
     It will simply inherit the formGroup by passing it as an
     attribute on the DOM from parent.component.html
  */

child.component.spec.ts

import  async, ComponentFixture, TestBed, inject  from '@angular/core/testing';
import  CUSTOM_ELEMENTS_SCHEMA  from '@angular/core';
import  FormsModule, ReactiveFormsModule, FormGroup, FormBuilder, Validators  from '@angular/forms';

import  ChildFormComponent  from './child.component';

describe('ChildFormComponent', () => 
  let component: ChildFormComponent;
  let fixture: ComponentFixture<ChildFormComponent>;

  beforeEach(async(() => 
    TestBed.configureTestingModule(
      schemas: [
        CUSTOM_ELEMENTS_SCHEMA
      ],
      imports: [
        FormsModule,
        ReactiveFormsModule
      ],
      declarations: [
        ChildFormComponent
      ]
    )
    .compileComponents();
   ));

  beforeEach(inject([FormBuilder], (fb: FormBuilder) => 
    fixture = TestBed.createComponent(Step2Component);
    component = fixture.componentInstance;

    /* This is where we can simulate / test our component
       and pass in a value for formGroup where it would've otherwise
       required it from the parent
    */
    component.formGroup = fb.group(
      name:  ['Other Name', Validators.required],
      email: ['', Validators.required]
    );
    fixture.detectChanges();
  ));

  it('should create', () => 
    expect(component).toBeTruthy();
  );
);

【讨论】:

这太棒了。谢谢!仅供参考,在第二个 beforeEach 末尾缺少第二个右括号... @JamesYoung 感谢您告诉我,很高兴这对您有所帮助! :) 虽然我不再做这种类型的编码我很感激你的回答!希望我遇到问题时能找到这个哈哈 啊,很不幸我迟到了这个问题!希望它在未来对其他人有所帮助。我遇到了同样的问题,所以这让我解决了它,我学会了如何自己解决它。 @Pixxl 它只是帮助了我。非常感谢和来自未来的问候!

以上是关于在 Jasmine 中通过 @input 模拟父 FormGroup的主要内容,如果未能解决你的问题,请参考以下文章

在 React 中通过更改父级的道具来更新子组件

在桌面应用程序中通过 *** 模拟用户

如果用户在 iframe 中通过身份验证而不是重定向父窗口,则 iframe

在 aspnet 应用程序中通过模拟获取 WindowsIdentity 的不同方法

如何使用 AFNetworking 在 iPhone 模拟器中通过 *** IP 地址进行连接?

Vue3中通过 input 标签 发送文件/图片给后端