【问题标题】:Angular Reactive Form Unit Testing: HTML value and control value out of syncAngular Reactive Form Unit Testing:HTML 值和控件值不同步
【发布时间】:2021-11-23 11:41:03
【问题描述】:

我正在遵循 Angular 反应式表单单元测试指南here,但始终无法获得控制值和 HTML 值以进行同步。下面是我的实现;请注意,除了指定默认值之外,我还尝试调用 setValue

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

@Component({
    selector: 'user',
    templateUrl: './user.component.html',
    styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {

    loginForm!: FormGroup;

    constructor(private formBuilder: FormBuilder) { }

    ngOnInit(): void {
        this.initLoginForm();

        const usernameControl = this.loginForm.get('username');
        usernameControl?.valueChanges.subscribe(username => {
            debugger; // This doesn't fire
            this.loginForm.patchValue({username: username});
        });
    }

    initLoginForm() {
        this.loginForm = this.formBuilder.group({
            username: ['jack', Validators.compose([Validators.required])],
            password: ['JacksPassword']
        });

        this.loginForm.setValue({
            username: 'jack',
            password: 'JacksPassword'
        })

        this.loginForm.updateValueAndValidity();
    }
}
<form [formGroup]="loginForm" id="loginForm">
    <div>
        <input formControlName="username" placeholder="Username" required id="usernameInput"/>
    </div>
    <div>
        <input formControlName="password" placeholder="Password" type="password"/>
    </div>
</form>

这是我的测试:

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormBuilder } from '@angular/forms';
import { UserComponent } from './user.component';

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

    beforeEach(async () => {
        await TestBed.configureTestingModule({
            declarations: [UserComponent],
            providers: [FormBuilder]
        })
            .compileComponents();
    });

    beforeEach(() => {
        fixture = TestBed.createComponent(UserComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    it('should have same values between control and UI', () => {
        const loginFormUserElement: HTMLInputElement = fixture.debugElement.nativeElement.querySelector('#loginForm').querySelector('#usernameInput');
        const userNameValueFromGroup = component.loginForm.get('username');
        expect(loginFormUserElement.value).toEqual(userNameValueFromGroup?.value);
    });

    it('should accept username', () => {
        const loginFormUserElement: HTMLInputElement = fixture.debugElement.nativeElement.querySelector('#loginForm').querySelector('#usernameInput');
        loginFormUserElement.value = 'joe';
        loginFormUserElement.dispatchEvent(new Event('input'));
        fixture.detectChanges();
        fixture.whenStable().then(() => {
            const userNameValueFromGroup = component.loginForm.get('username');
            expect(loginFormUserElement.value).toEqual('joe');
            expect(loginFormUserElement.value).toEqual(userNameValueFromGroup?.value);
        });
    });
});

这是结果。设置默认值不会更新 UI。调用 setValue 不会更新 UI。并且在 UI 元素上设置值不会更新控件。

它必须是一些基本的东西。我错过了什么?

编辑:我试图基于一个独立的单元测试示例设置一个 StackBlitz 实现,但在 Jasmine 下似乎无法识别 formGroup 指令;我正在将ReactiveFormsModule 导入 app.module。链接是here,以防任何人都可以提供有关我在这方面缺少的内容的见解。

编辑:这里的问题似乎实际上与我的单元测试工作有关。当我直接使用组件时,默认值会正确显示在 HTML 输入元素上;但是,在运行 Karma 的 Chrome 上通过控制台检查消息时,我看到相同的错误消息,表明 formGroup 指令无法识别。我已经相应地更新了标题。

【问题讨论】:

    标签: javascript html angular typescript


    【解决方案1】:

    问题实际上纯粹是在单元测试的设置中,当组件被实时使用时,控件和表单之间的绑定工作正常。单元测试的问题是ReactiveFormsModule必须通过TestBed.configureTestingModule导入;在设置过程中我也没有打电话给ngOnInit, 虽然它的缺席似乎没有任何影响(还)。

    我更新的设置代码如下。奇怪的是,尝试在 StackBlitz 设置中以相同的方式导入 ReactiveFormsModule 会产生错误“超出最大调用堆栈大小”,但它在我的机器上运行良好。

        beforeEach(() => {
            TestBed.configureTestingModule({
                declarations: [TimeRangeSelectorComponent],
                imports: [ReactiveFormsModule], // This is new
                providers: [
                    FormBuilder,
                    { provide: TimeRangeSelectorDefaultsBase, useValue: new TestTimeRangeSelectorDefaults() },
                ]
            });
            fixture = TestBed.createComponent(TimeRangeSelectorComponent);
            component = fixture.componentInstance;
            component.ngOnInit(); // This is new
            fixture.detectChanges();
        });
    

    原来这是dupe。把这个问题留在这里,以防它帮助别人;在我开始搜索与测试相关的问题之前,我没有发现另一个。

    【讨论】:

      猜你喜欢
      • 2019-12-26
      • 2018-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多