簡體   English   中英

Angular Reactive Form 單元測試:HTML 值和控制值不同步

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

我在此處遵循 Angular 反應式單元測試指南,但始終無法獲得要同步的控制值和 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 實現,但formGroup指令似乎無法在 Jasmine 下被識別; 我正在將ReactiveFormsModule導入到 app.module 中。 該鏈接位於此處,以防任何人可以提供有關我在這方面缺少的內容的見解。

編輯:這里的問題似乎實際上與我的單元測試工作有關。 當我直接使用該組件時,默認值正確顯示在 HTML 輸入元素上; 但是,在運行 Karma 的 Chrome 上通過控制台檢查消息時,我看到相同的錯誤消息,指示無法識別formGroup指令。 我已經相應地更新了標題。

這個問題實際上純粹是在單元測試的設置中,當組件被實時使用時,控件和表單之間的綁定工作正常。 單元測試中的問題是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();
    });

事實證明這是一個騙局 將此問題保留在這里,以防對其他人有幫助; 直到我開始搜索與測試相關的問題,我才發現另一個。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM