简体   繁体   English

Angular Reactive Form 单元测试:HTML 值和控制值不同步

[英]Angular Reactive Form Unit Testing: HTML value and control value out of sync

I am following the Angular reactive form unit testing guide here but am perpetually unable to get the control value and the HTML value to synchronize.我在此处遵循 Angular 反应式单元测试指南,但始终无法获得要同步的控制值和 HTML 值。 Below is my implementation;下面是我的实现; note that I am trying to call setValue in addition to specifying default values:请注意,除了指定默认值外,我还尝试调用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>

And here are my tests:这是我的测试:

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);
        });
    });
});

And here are the results.这是结果。 Setting defaults doesn't update the UI.设置默认值不会更新 UI。 Calling setValue doesn't update the UI.调用setValue不会更新 UI。 And setting a value on the UI element doesn't update the control.在 UI 元素上设置值不会更新控件。

在此处输入图像描述

It must be something basic.它必须是基本的东西。 Whatever am I missing?我错过了什么?

EDIT : I attempted to set up a StackBlitz implementation based on an isolated unit testing example, but the formGroup directive doesn't seem to be recognized under Jasmine;编辑:我试图根据一个独立的单元测试示例设置一个 StackBlitz 实现,但formGroup指令似乎无法在 Jasmine 下被识别; I am importing ReactiveFormsModule into app.module.我正在将ReactiveFormsModule导入到 app.module 中。 The link is here in case anyone can provide insight about what I'm missing on this front.该链接位于此处,以防任何人可以提供有关我在这方面缺少的内容的见解。

EDIT : The problem here seems actually seems related to my unit testing effort.编辑:这里的问题似乎实际上与我的单元测试工作有关。 When I use the component directly, default values are displayed on the HTML input element correctly;当我直接使用该组件时,默认值正确显示在 HTML 输入元素上; however, when inspecting messages via the console on Chrome running Karma, I see the same error message indicating that the formGroup directive isn't recognized.但是,在运行 Karma 的 Chrome 上通过控制台检查消息时,我看到相同的错误消息,指示无法识别formGroup指令。 I've updated the title accordingly.我已经相应地更新了标题。

The issue actually was purely in the setup of the unit test, binding between the control and the form worked fine when the component was used live.这个问题实际上纯粹是在单元测试的设置中,当组件被实时使用时,控件和表单之间的绑定工作正常。 The problem in the unit test was that ReactiveFormsModule must be imported via TestBed.configureTestingModule ;单元测试中的问题是ReactiveFormsModule必须通过TestBed.configureTestingModule导入; I also was not calling ngOnInit during setup, although its absence doesn't seem to have any effect (yet).我在安装过程中也没有调用ngOnInit ,尽管它的缺失似乎没有任何效果(目前)。

My updated setup code is below.我更新的设置代码如下。 Curiously, attempting to import ReactiveFormsModule the same way in the StackBlitz setup produces an error 'Maximum call stack size exceeded', but it works fine on my machine.奇怪的是,尝试在 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();
    });

Turns out this is a dupe .事实证明这是一个骗局 Keeping this issue here in case it helps someone else;将此问题保留在这里,以防对其他人有帮助; I didn't discover the other until I started searching for test-related issues.直到我开始搜索与测试相关的问题,我才发现另一个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 带HTML字符串的角反应形式设置值 - Angular reactive form setting value with HTML string 故障单元测试角度的反应形式字段 - trouble unit testing reactive form fields in angular Angular 5反应性表单-通过html更新formControl不会更新值,只有控件 - Angular 5 reactive form- updating formControl through the html does not update the value, only the control "故障单元测试从按钮单击重置角度反应形式控制" - Trouble unit testing angular reactive form control reset from button click Angular - 测试响应式表单控件启用值更改 - Angular - test reactive form control enable on value changes 如何在角度反应形式控件中添加小数,其值从 1 和更大开始 - how to add decimal in angular reactive form control with value starting with 1 and greater 角反应形式克隆值 - Angular Reactive Form clone value Angular 反应式表单 - 禁用所需的表单控件使表单有效,即使没有给出值 - Angular reactive form - Disabling a required form control makes the form valid even if no value is given 以 angular 反应形式绑定表格数组值 - Bind form array value in angular reactive form 如何使用从回调函数获得的值以角度设置反应形式控件的值? - How to set value in a reactive form control in angular, using the value obtained from the call back function?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM