Реактивные формы Выбор элемента управления - Сбой теста Жасмин: не удается найти разницу - PullRequest
0 голосов
/ 10 июля 2019

У меня есть реактивная форма с выбором элемента управления. Все работает нормально, но я не могу запустить тест по умолчанию Жасмин, я получаю эту ошибку:

xxxxComponent> должен создать Ошибка: не удается найти другой поддерживающий объект '[object Object]' типа 'object'. NgFor поддерживает только привязку к итерациям, таким как массивы.

Вот моя разметка:

    <div class="container-fluid">
    <div class="row">
      <div class="col-md-3">
        <h1 class="blue">Jobs</h1>
     </div>
    </div>
    <form [formGroup]="jobsFilterForm" (ngSubmit)="onSubmitGetAllJobs(jobsFilterForm.value)">
    <div id="filtercontrols" class="row">
    <div class="col-sm-12 col-md-3">
      <div class="form-group d-flex" style="text-align: left">
        <label [for]="startDate" class="col-form-label w-25">Date From</label>
        <input type="date" formControlName="from"  class="form-control">
      </div>
      <div>
        <ul *ngFor="let validation of filterValidationMessages.from">
          <li class="error-message" *ngIf="jobsFilterForm.get('from').hasError(validation.type)">{{validation.message}}</li>
        </ul>
      </div>
      <div class="form-group d-flex" style="text-align: left">
          <label [for]="endDate" class="col-form-label w-25">Date To</label>
          <input type="date" formControlName="to"  class="form-control">
      </div>         
      <div>
          <ul *ngFor="let validation of filterValidationMessages.to">
            <li class="error-message" *ngIf="jobsFilterForm.get('to').hasError(validation.type)">{{validation.message}}</li>
          </ul>
      </div>
    </div>
    <div class="col-sm-12 col-md-3">
        <div class="form-group d-flex" style="text-align: left">
            <label [for]="reportingPeriod" class="col-form-label w-25">and/or</label>
            <select formControlName="reportingPeriod" class="form-control" id="reportingPeriod">
              <option [ngValue]="null" hidden>Reporting Period</option>
              <option *ngFor="let reportingPeriod of (reportingPeriods$ | async)" [ngValue]="reportingPeriod">{{ reportingPeriod.name }}</option>
            </select>
        </div>
    </div>
    <div class="col-sm-12 col-md-3">
        <div class="form-group d-flex flex-row-reverse">
            <select formControlName="restateVersion" class="form-control" id="restateVersion" style="width:80%">
              <option [ngValue]="null" hidden>Restate Version</option>
              <option *ngFor="let restateVersion of (restateVersions$ | async)" [ngValue]="restateVersion">{{ restateVersion.name }}</option>
            </select>
        </div>
    </div>
      <div class="col-sm-12 col-md-3">
        <div class="form-group d-flex">
          <button type="submit" [disabled] = "jobsFilterForm.invalid || (!jobsFilterForm.get('from').value && !jobsFilterForm.get('restateVersion').value && !jobsFilterForm.get('reportingPeriod').value)" class="btn btn-primary">Refresh <i class="fa fa-refresh"></i></button>
          <button type="button" (click) = "onReset()" class="btn btn-warning">Reset <i class="fa fa-times"></i></button>
        </div>
      </div>







    </div>
    </form>
<div class="jobs-card border rounded">
    <div class="row">
      <div class="col-sm-12" >
      <ag-grid-angular 
          domLayout='autoHeight'
          style="width: 100%;" 
          class="ag-theme-balham"
          [rowData]="(jobs$ | async)" 
          [columnDefs]="columnDefs"
          >
      </ag-grid-angular>
    </div>
    </div>
</div>
</div>

Это сложный компонент, но код, где я создаю форму, находится здесь:

this.jobsFilterForm = new FormGroup({
  from: new FormControl(),
  to: new FormControl(),
  restateVersion: new FormControl(null)
});

У кого-нибудь есть идеи?

Полный код компонента здесь:

import { Component, OnInit } from '@angular/core';
import { Store, select } from '@ngrx/store';
import { distinctUntilChanged } from 'rxjs/operators';
import { LoadJobs, LoadReportingPeriods, LoadRestateVersions } from '../../actions/jobs.actions';
import { Filter,  FilterExpression, GetAllRequest, Pagination, SortOrder, SortOrderExpression } from '../../../services/client';
import { AbstractControl, FormControl, FormGroup, Validators, ValidatorFn } from '@angular/forms';
import { JobsValidator } from '../../validators/jobs.validator';
import 'date-input-polyfill';
import * as moment from 'moment';


@Component({
  selector: 'app-jobs',
  templateUrl: './jobs.component.html',
  styleUrls: ['./jobs.component.scss']
})



export class JobsComponent implements OnInit {

  columnDefs = [
    {headerName: 'Reporting Period', field: 'reportingPeriod' },
    {headerName: 'Restate Version', field: 'restateVersion' },
    {headerName: 'Model Name', field: 'model'},
    {headerName: 'Company', field: 'company'},
    {headerName: 'Purpose', field: 'reportingPurpose'},
    {headerName: 'Data Set Category', field: 'dataSetCategory'},
    {headerName: 'Data Set Name', field: 'dataSetName'},
    {headerName: 'Data Set Version', field: 'dataSetVersion'},
    {headerName: 'Job Status', field: 'jobStatus'},
    {headerName: 'Job Priority', field: 'jobPriority'},
    {headerName: 'Number of Sims', field: 'numberOfSimulations'},
    {headerName: 'Random Seed', field: 'randomSeed'}
];


  filterValidationMessages = {
    from: [
      { type: 'required', message: 'From date is required' }
    ],
    to: [
      { type: 'invalidDateRange', message: 'Date To should be earlier than Date From' },
      { type: 'required', message: 'To date is required' }
    ]
  };
  constructor(private store: Store<any>) {}

  jobsFilterForm: FormGroup;


  startDate: Date;
  endDate: Date;

  jobs$ = this.store.pipe(select
    (
    (state) =>
    state.jobs.jobsList
  )
  );

  reportingPeriods$ = this.store.pipe(select
    (
    (state) =>
    state.jobs.reportingPeriods
  )
  );

  restateVersions$ = this.store.pipe(select
    (
    (state) =>
    state.jobs.restateVersions
  )
  );
  ngOnInit() {
    this.createForm();
    this.loadReportingPeriods();
    this.loadRestateVersions();
  }

  createForm() {
    this.jobsFilterForm = new FormGroup({
      from: new FormControl(),
      to: new FormControl(),
      reportingPeriod: new FormControl(null),
      restateVersion: new FormControl(null)
    });
    const {from, to } = this.jobsFilterForm.controls;
    from.valueChanges.pipe(distinctUntilChanged()).subscribe(() => this.onFilterDateChange());
    to.valueChanges.pipe(distinctUntilChanged()).subscribe(() => this.onFilterDateChange());
  }
  // dynamically set / remove validators on date controls depending on their selected state
  onFilterDateChange() {
    const {from, to } = this.jobsFilterForm.controls;
    // neither date is set so no validation needed
    if (!from.value && !to.value) {
      this.setDateValidators(from, null);
      this.setDateValidators(to, null);
    }
    if (!(from.validator)) {// no need to check both, if validation is on one, it's on the other
      this.setDateValidators(from, [Validators.required]);
      // only need to have date range validator on one control
      this.setDateValidators(to, [Validators.required, JobsValidator.validDateRange(this.jobsFilterForm)]);
    }
    // need to call updateValueAndValidity after setting the validators because calling either will trigger
    // valueChanges and onFilterDateChange is called again before the original call completes
    // and the desired sequence isn't completed and results are unpredictable.
    from.updateValueAndValidity();
    to.updateValueAndValidity();
  }


      setDateValidators(control: AbstractControl, validators: ValidatorFn[]) {
        control.setErrors(null);
        control.clearValidators();
        control.setValidators(validators);
      }
     onSubmitGetAllJobs(value) {
    const request = new GetAllRequest(
      {
        filter: new Filter({
        filterExpressions: [
      ]
      }),

      sortOrder: new SortOrder({
        sortOrderExpressions: [
          new SortOrderExpression({
            sortOrderColumnName: 'reportingPeriod',
            sortOrderDirection: 1
          })
      ]
      }),
      pagination: new Pagination({ startIndex: 0,  pageSize: 25})
      }
    );

    if (value.from && value.to) {
      request.filter.filterExpressions.push(
      new FilterExpression({filterColumnName: 'SubmittedDate', filterOperator: 3, filterValue: moment(value.from).format('YYYY/MM/DD')}),
      new FilterExpression({filterColumnName: 'SubmittedDate', filterOperator: 4, filterValue: moment(value.to).format('YYYY/MM/DD')})
      );
    }
    if (value.reportingPeriod) {
      request.filter.filterExpressions.push(
      new FilterExpression({filterColumnName: 'ReportingPeriod', filterOperator: 1, filterValue: value.reportingPeriod.name})
      );
    }
    if (value.restateVersion) {
      request.filter.filterExpressions.push(
      new FilterExpression({filterColumnName: 'RestateVersion', filterOperator: 1, filterValue: value.restateVersion.name})
      );
    }
    this.store.dispatch(new LoadJobs(request));
  }

      loadReportingPeriods() {
    this.store.dispatch(new LoadReportingPeriods());
 }

 loadRestateVersions() {
   this.store.dispatch(new LoadRestateVersions());
 }

После комментария пользователя 2216584 я исправил это, назначив наблюдаемое для restteVersions $ (и reportsPeriod $) в component.spec.ts:

  beforeEach(() => {
fixture = TestBed.createComponent(JobsComponent);
component = fixture.componentInstance;
Object.defineProperty(component, 'reportingPeriods$', { writable: true });  
component.reportingPeriods$ = of([]);  
Object.defineProperty(component, 'restateVersions$', { writable: true }); 
component.restateVersions$ = of([]); 
fixture.detectChanges();

});

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...