[英]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.