首页 > 解决方案 > Angular 9 Karma-Jasmine 测试不适用于 ViewChild

问题描述

我使用 Jasmine 在 Angular9 中为我的应用程序进行测试。我在执行应该可以工作的测试时遇到问题。我有一个文件“book-edit.component.html”,其中包含我要测试的页面的视图,特别是这部分:

<form *ngIf='activeForm == "templateDriven"' #templateForm='ngForm'>
    <div class="row mt-3">
        <div class="col-6">
            Template-Driven Form
        </div>
    </div>
    <!-- "touched" indicates modified -->
    <div class="row">
        <div class="col-12 form-group title-group">
            <label for="title">Title</label>
            <input [(ngModel)]='book.title' name='title2' type='text' id='title2' class='title form-control'
                #title2='ngModel' minlength='3' required>
            <!-- in order to prevent an error signal in case of title2 is invalid, is useful to check that client have touch that 
            filed. Initially title2 condition are not valid, but just because client doesn't touch that field. For this reason it
            in enough to add AND clause in with we can check that that field is dirty(when a client text into that field) or toched
            anyay () (AND invalid). Thus, if it is invalid it show the parent div. In a more specific way, it will visualize the child
            div based on the type of error (required or minlenght) -->
            <div *ngIf='!title2.valid && (title2.dirty || title2.touched)' class='invalid-feedback'
                style='display: block;'>
                <div *ngIf='title2?.errors?.required'>
                    Title is required.
                </div>
                <div *ngIf='title2?.errors?.minlength'>
                    Title must have at least 3 characters long.
                </div>
            </div>
        </div>

我想测试这部分代码:如果 title2 包含少于 3 个字母,它会给我错误(它有效,我尝试过没有测试)。因此,我想使用这样的测试来信任它(book-edit.component.spec.ts”:

  it('should have title error if less than 3 symbols provided',
    fakeAsync(() => {
      component.activeForm = 'templateDriven';
      fixture.detectChanges();
      // get our form on the page by using templateForm. To do this add @ViewChild(NgForm) in book-edit.component.ts
      let form = component.templateForm.form;
      // tick() to say to other engine to go ahead and apply the separtions
      tick();
      form.setValue({
        title2: 'te',
        image2: 'http://test.com',
        description2: 'none',
        price2: 100
      });
      form.controls.title2.markAsTouched();
      debugger;
      //expect(form.controls.title2.errors).toBeTruthy();
      expect(nativeElement.querySelector('.title-group').textContent).
        toContain('Title must have at least 3 characters long.');
    })
  );

具有以下组件(book-edit.component.ts):

import { Component, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { FormBuilder, FormGroup, Validators, AbstractControl, FormControl, NgForm } from '@angular/forms';

import { BookModel } from "../../models/book/book.model";

@Component({
  selector: 'book-edit',
  templateUrl: './book-edit.component.html',
  styleUrls: ['./book-edit.component.css']
})
export class BookEditComponent implements OnInit {
  bookEditForm: FormGroup;
  book: BookModel;
  activeForm: string = 'reactive';
  // ViewChild: Property decorator that configures a view query.
  // The change detector looks for the first element or the directive matching the selector in the view DOM. If the view DOM changes, and a new child matches the selector, the property is updated.
  @ViewChild(NgForm) templateForm: NgForm;

  constructor(fb: FormBuilder, private route: ActivatedRoute) {
    this.bookEditForm = fb.group({
      //define a group and optionally defide if it is required
      title: ['', Validators.required],
      image: ['', Validators.required],
      description: [''],
      price: ['']
    });
    // subscribe to some changes
    route.params.subscribe(res => {
      if(this.book == null){
        this.book = new BookModel('','','',0);
      }
    })
   }

  submitReactiveForm() {
    let bookData = this.prepareSaveBook();
    this.book = new BookModel(bookData.image,
      bookData.title,
      bookData.description,
      bookData.price
    );
    this.book.save();
  }

  prepareSaveBook() {
    const formModel = this.bookEditForm.value;
    return formModel;
  }

  ngOnInit(): void {
  }

}

当然,我放了“@ViewChild”是为了让测试检测表单上的变化。事实上,在测试中,我试图输入一个少于 3 个字母的名称,只是为了检查是否有错误和消息“标题必须至少有 3 个字符长”。出现。因此,最后我尝试expect(nativeElement.querySelector('.title-group').textContent).toContain('Title must have at least 3 characters long.');检查我的主要 div(在 book-edit.component.html 中)是否还包含错误消息,因为 *ngIf 已满足,但不包含。它不起作用,并且控制台仅捕获“测试”值(通过该 div 清晰显示的文本)而不是“测试标题必须至少有 3 个字符长。”。我调试了代码并检查了表单是否正确初始化(title2:“te”,title2被触摸并且title2无效)但它似乎无法读取由*ngIf解锁的div的包含,

标签: angularkarma-jasmineangular-ng-ifviewchildqueryselector

解决方案


推荐阅读