Angular 单元测试 - 响应式表单值未更新 [英] Angular Unit testing - Reactive Form value not updating

查看:33
本文介绍了Angular 单元测试 - 响应式表单值未更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是角度单元测试的新手.测试场景:html中的表单视图值等于组件表单值.电子邮件值由共享值检索并在组件注册表中使用.我可以使用反应式表单从组件中检索电子邮件值,但是当尝试通过本机元素访问时,它给出了空值.下面是component.ts

ngOnit(public serviceEmail) {this.assignEmailAvailable();this.createRegistration();}分配电子邮件可用(){如果(服务.电子邮件){this.email = serviceEmail.email;}}创建注册(){this.registerForm = new FormGroup({email:new FormControl({value:this.email})})}

在 component.spec.ts 中,我将调用此函数并检查两个值是否相同.组件.spec.ts

 beforeEach(() => {夹具 = TestBed.createComponent(RegisterComponent);组件 = 夹具.componentInstance;服务 = TestBed.get(serviceEmail);});it('注册表格创建', fakeAsync(() => {service.email = "dsf@gmail.com";夹具.detectChanges();component.assignEmailAvailable();component.createRegisterForm();夹具.detectChanges();fixture.whenStable().then(() => {const email = fixture.debugElement.query(By.css('input[id="email"]')).nativeElement;//即使使用组件函数创建表单后,该值为空期望(email.value).toBe(component.emailValue);});//这将返回我设置的值期望(component.registerForm.get('email').value).toBe(component.emailValue);}));

解决方案

我只是花了大约 2 个小时试图找出这个问题.根据我的经验,您需要解决 beforeEach() 函数中的一些问题.首先,您需要将 ReactiveFormsModule 导入您的 TestBed,以便 Change Detection 正确执行所有操作.其次,您需要在 beforeEach() 调用中手动运行 ngOnInit() 和 fixture.detectChanges() 来设置表单.请参阅下面的 beforeEach() 函数.我还包含了其他与此问题相关的代码.

组件模板:

<form [formGroup]='emailForm' (ngSubmit)='handleSubmit()'>

<label for='email'>电子邮件地址</label><input type='email' class='form-control' id='email' placeholder='输入电子邮件'formControlName='email'>

组件 TS:

 构造函数(私有 apiService:ApiService,私人 fb:FormBuilder,专用路由器:路由器) { }ngOnInit() {this.initializeForm();}初始化表格():无效{this.formSubmitted = false;this.serverProcessing = false;this.emailForm = this.fb.group({电子邮件:['', Validators.compose([Validators.required, Validators.email])]});}get email() {return this.emailForm.get('email');}

Spec TS 中的两个 beforeEach() 调用:

beforeEach(异步(() => {apiServiceSpy = jasmine.createSpyObj('ApiService', ['sendResetPasswordEmail']);routerSpy = jasmine.createSpyObj('Router', ['navigateByUrl']);TestBed.configureTestingModule({声明:[ SendPasswordResetEmailComponent ],//如果我们弄乱了响应式表单输入,则需要导入它!!进口:[ReactiveFormsModule],供应商: [{提供:ApiService,useValue:apiServiceSpy},{提供:路由器,使用值:routerSpy},{提供:FormBuilder},]}).compileComponents();}));beforeEach(() => {夹具 = TestBed.createComponent(SendPasswordResetEmailComponent);组件 = 夹具.componentInstance;//ngOnInit() 不会被自动调用,所以我们必须自己做component.ngOnInit();//告诉夹具检测变化对于正确绑定数据非常重要//在调用 ngOnInit() 之后执行此操作,以便更改传播到模板夹具.detectChanges();});

样本测试规范:

it('should have an error for no username', () => {const componentElement: HTMLElement = fixture.nativeElement;const emailInput: HTMLInputElement = componentElement.querySelector('input');emailInput.value = '@gmail.com';emailInput.dispatchEvent(new Event('input'));夹具.detectChanges();期望(component.email.errors.email).toBeTruthy('@gmail.com 有效');});it('如果电子邮件有效,应该没有错误', () => {const componentElement: HTMLElement = fixture.nativeElement;const emailInput: HTMLInputElement = componentElement.querySelector('input');emailInput.value = 'joe@test.go';emailInput.dispatchEvent(new Event('input'));夹具.detectChanges();期望(component.email.errors).toBeFalsy('joe@test.go invalid');});

I am new to angular unit testing. Test Scenario: The form view value in the html is equal to the component form value. The email value is retrieved by a shared value and being used in the component registration form. I could retrieve the email value from the component using the reactive forms, but when trying to access via the native element, it gives empty. Below is the component.ts

ngOnit(public serviceEmail) {
    this.assignEmailAvailable();
    this.createRegistration();

    }
assignEmailAvailable() {
 if(service.email){
    this.email = serviceEmail.email;
  }
 }   
createRegistration() {
   this.registerForm = new FormGroup({
       email:new FormControl({value:this.email})
    })
}

In the component.spec.ts, I am gonna call this function and check whether both values are same. component.spec.ts

 beforeEach(() => {
    fixture = TestBed.createComponent(RegisterComponent);
    component = fixture.componentInstance;
    service = TestBed.get(serviceEmail);
  });
it('Registration Form Creation', fakeAsync(() => {
    service.email = "dsf@gmail.com";

    fixture.detectChanges();

    component.assignEmailAvailable();
    component.createRegisterForm();

    fixture.detectChanges();
    fixture.whenStable().then(() => {
    const email = fixture.debugElement.query(By.css('input[id="email"]')).nativeElement;
//The value is empty even after creating the form using the component function
    expect(email.value).toBe(component.emailValue);
    });
//THis returns me the value set
    expect(component.registerForm.get('email').value).toBe(component.emailValue);
  }));

解决方案

I just spent like 2 hours trying to figure out this problem. From my experience, you have a few problems in your beforeEach() function that you need to resolve. First, you need to import the ReactiveFormsModule into your TestBed so that Change Detection does everything correctly. Second, you need to manually run ngOnInit() and fixture.detectChanges() in your beforeEach() call to set up your form. See my beforeEach() functions below. I've also included the rest of my code that others with this problem may find relevant.

Component Template:


<form [formGroup]='emailForm' (ngSubmit)='handleSubmit()'>
  <div class='form-group'>
    <label for='email'>Email address</label>
    <input type='email' class='form-control' id='email' placeholder='Enter email'
      formControlName='email'>

Component TS:

  constructor(
    private apiService: ApiService,
    private fb: FormBuilder,
    private router: Router
  ) { }

  ngOnInit() {
    this.initializeForm();
  }

  initializeForm(): void {
    this.formSubmitted = false;
    this.serverProcessing = false;
    this.emailForm = this.fb.group({
      email: ['', Validators.compose([Validators.required, Validators.email])]
    });
  }

  get email() {return this.emailForm.get('email');}

Both beforeEach() calls in Spec TS:

beforeEach(
async(() => {

  apiServiceSpy = jasmine.createSpyObj('ApiService', ['sendResetPasswordEmail']);
  routerSpy = jasmine.createSpyObj('Router', ['navigateByUrl']);

  TestBed.configureTestingModule({
    declarations: [ SendPasswordResetEmailComponent ],

    // Need to import this if we're messing with Reactive Form inputs!!
    imports: [ReactiveFormsModule],

    providers: [
      {provide: ApiService, useValue: apiServiceSpy},
      {provide: Router, useValue: routerSpy},
      {provide: FormBuilder},
    ]
  })
  .compileComponents();
})
);

beforeEach(() => {
    fixture = TestBed.createComponent(SendPasswordResetEmailComponent);
    component = fixture.componentInstance;

    // ngOnInit() doesn't get called automatically, so we have to do it ourselves
    component.ngOnInit();

    // Telling the fixture to detect changes is really important to correctly bind data
    // Do this after calling ngOnInit() so changes propagate to the template 
    fixture.detectChanges();
});

Sample Test Specs:

it('should have an error for no username', () => {
    const componentElement: HTMLElement = fixture.nativeElement;
    const emailInput: HTMLInputElement = componentElement.querySelector('input');
    emailInput.value = '@gmail.com';
    emailInput.dispatchEvent(new Event('input'));
    fixture.detectChanges();
    expect(component.email.errors.email).toBeTruthy('@gmail.com valid');
});

it('should have no error if the email is valid', () => {
    const componentElement: HTMLElement = fixture.nativeElement;
    const emailInput: HTMLInputElement = componentElement.querySelector('input');
    emailInput.value = 'joe@test.go';
    emailInput.dispatchEvent(new Event('input'));
    fixture.detectChanges();
    expect(component.email.errors).toBeFalsy('joe@test.go invalid');
    });

这篇关于Angular 单元测试 - 响应式表单值未更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆