Невозможно прочитать свойство 'значение' из неопределенного в угловых 4 - PullRequest
0 голосов
/ 12 мая 2018

Я пишу тест в Jasmine для моего углового компонента 4 и получаю сообщение об ошибке «Не удается прочитать свойство 'значение' из неопределенного". Где и как мне инициализировать свойство? Сначала я думал об изменении [(ngModel)]="fedExTax.value" на [ngModel]="fedExTax?.value", но мне нужно двустороннее связывание. Может ли кто-нибудь предложить мне решение

Вы можете увидеть [(ngModel)]="fedExTax.value" в HTML-код ниже

HTML-код

<div class="col-lg-3 col-6 mb-3">
        <label class="col-form-label">{{'CAPTIVES.LINES.INCCAPTIVEEXPENSE.' + FedExciseKey|uppercase|translate}}</label>
        <div class="input-group">
          <input type="text" [readonly]="isReadOnly" class="form-control form-control-sm" [(ngModel)]="fedExTax.value"  name="{{FedExciseKey}}" numberFormat="numberPercent:.0-2" (ngModelChange)="change()" [required]="true" tooltip="{{'CAPTIVES.LINES.INCCAPTIVEEXPENSE.' + FedExciseKey + 'TOOLTIP'|uppercase|translate}}"
            placement="bottom">
          <span class="input-group-addon">%</span>
        </div>
      </div>

Мой тестовый код

import { NO_ERRORS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { TranslateModule, TranslateLoader, TranslateFakeLoader } from '@ngx-translate/core';
import { FormsModule } from '@angular/forms';
import { UniqueIdPipe } from '@wtw/toolkit/src/pipes/unique-id.pipe';
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
import { IncrementalCaptiveAssumptionsComponent  } from './incremental-captive-expenses.component';
import { createIncrementalExpenses, createFedExciseExpenses } from '../../../../../../test/models';
import { Component, ViewChild } from '@angular/core';

describe('IncrementalCaptiveAssumptionsComponent', () => {
  let harness: HostFormTestComponent;
  let sut: IncrementalCaptiveAssumptionsComponent;
  let fixture: ComponentFixture<HostFormTestComponent>;
  const IncrementalExpenses = createIncrementalExpenses();
  const fedExciseTaxExpenses = createFedExciseExpenses();

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        BrowserAnimationsModule,
        FormsModule,
        TranslateModule.forRoot({
          loader: { provide: TranslateLoader, useClass: TranslateFakeLoader }
        })
      ],
      declarations: [ HostFormTestComponent, IncrementalCaptiveAssumptionsComponent, UniqueIdPipe ],
      schemas: [NO_ERRORS_SCHEMA]
    });

    TestBed.overrideModule(BrowserDynamicTestingModule, {
      set: {
          entryComponents: [IncrementalCaptiveAssumptionsComponent],
      }
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(HostFormTestComponent);
    harness = fixture.componentInstance;
    fixture.detectChanges();
    sut = harness.componentUnderTest;
    harness.incrementalExpensesInputs = IncrementalExpenses;
    harness.fedExciseExpensesInputs = fedExciseTaxExpenses;
    fixture.detectChanges();
  });

   fit('should set fields correctly when the form is displayed', () => {
    expect(JSON.stringify(sut.managerFees)).toEqual(JSON.stringify(IncrementalExpenses.find(x => x.fieldInfo.key === 'mgmgtFee')));
    expect(JSON.stringify(sut.actuaryFees)).toEqual(JSON.stringify(IncrementalExpenses.find(x => x.fieldInfo.key === 'actuaryFee')));
    expect(JSON.stringify(sut.auditorFees)).toEqual(JSON.stringify(IncrementalExpenses.find(x => x.fieldInfo.key === 'auditFee')));
  });

  @Component({
    template: `
    <form #pageForm="ngForm">
      <incremental-captive-expenses *ngIf="incrementalExpensesInputs"
      [(incrementalExpensesInputs)]="incrementalExpensesInputs"
      [(fedExciseExpensesInputs)]="fedExciseExpensesInputs"
      [currentSelectedCurrency]="currentSelectedCurrency"
      [currentSelected953D]= "currentSelected953D"
      (isValid)="incrementalExpensesValid($event)"></incremental-captive-expenses>
    </form>
    `
  })
  class HostFormTestComponent {
    @ViewChild(IncrementalCaptiveAssumptionsComponent)
    public componentUnderTest: IncrementalCaptiveAssumptionsComponent;
    public incrementalExpensesInputs = createIncrementalExpenses();
    public fedExciseExpensesInputs = createFedExciseExpenses();
    public currentSelectedCurrency = 'USD';
    public currentSelected953D = 0;

    constructor() {
    }

    incrementalExpensesValid(valid) {

    }
  }
});

Код компонента

import { Component, SimpleChanges, OnInit, OnChanges, Input, Output, ViewChild, EventEmitter } from '@angular/core';
import { NgForm, NgModelGroup, ControlContainer, FormGroup } from '@angular/forms';
import { Base } from '@wtw/toolkit';
import * as BackendDto from '../../../../../api/dtos';

const ManagerFeesFieldKey = 'mgmgtFee';
const ActuaryFeesFieldKey = 'actuaryFee';
const AuditorFeesFieldKey = 'auditFee';
const FedExTaxFieldKey = 'fedExciseTax';

@Component({
  // tslint:disable-next-line:component-selector
  selector: 'incremental-captive-expenses',
  templateUrl: './incremental-captive-expenses.component.html',
  viewProviders: [{ provide: ControlContainer, useFactory: Base.DynamicFormFactory, deps: [IncrementalCaptiveAssumptionsComponent] }]
})

export class IncrementalCaptiveAssumptionsComponent extends Base.DynamicFormComponent implements OnInit, OnChanges {
  @Input() incrementalExpensesInputs: Array<BackendDto.IncrementalExpense>;
  @Input() fedExciseExpensesInputs: Array<BackendDto.FedExciseExpense>;
  @Input() currentSelectedCurrency: string;
  @Input() currentSelectedCoveragePolicy: number;
  @Input() currentSelected953D: number;
  @Input() show: boolean;
  @Output() isValid = new EventEmitter<boolean>();
  public FieldCategory = BackendDto.DynamicFieldCategory;
  public FedExciseKey = FedExTaxFieldKey;
  public isReadOnly = false;
  private _fedExTax: BackendDto.FedExciseExpense = { value: 0, coveragePolicyTypeId: null, is953D: null };
  @ViewChild('incrementalExpensesGroup') private incrementalExpensesGroup: NgModelGroup;

  constructor(form: NgForm) {
    super(form);
  }

  ngOnInit() {

  }

  ngOnChanges(changes: SimpleChanges) {
    if (changes.show && changes.show.currentValue) {
      setTimeout(() => {
        this.markFormGroupTouched(<FormGroup>this.formDirective.controls[this.incrementalExpensesGroup.name]);
      }, 1);

      this.emitFormValidity();
    }
  }

  change() {
    this.emitFormValidity();
  }

  emitFormValidity() {
    setTimeout(() => {
      this.isValid.emit(this.incrementalExpensesGroup.valid);
    }, 1);
  }

  get managerFees(): BackendDto.IncrementalExpense {
    return this.incrementalExpensesInputs.find(x => x.fieldInfo.key === ManagerFeesFieldKey);
  }

  get actuaryFees(): BackendDto.IncrementalExpense {
    return this.incrementalExpensesInputs.find(x => x.fieldInfo.key === ActuaryFeesFieldKey);
  }

  get auditorFees(): BackendDto.IncrementalExpense {
    return this.incrementalExpensesInputs.find(x => x.fieldInfo.key === AuditorFeesFieldKey);
  }

  get fedExTax(): BackendDto.FedExciseExpense {
    if (this.currentSelectedCoveragePolicy !== 0) {
      this.isReadOnly = false;
      return this.fedExciseExpensesInputs.find(x => x.coveragePolicyTypeId === this.currentSelectedCoveragePolicy && x.is953D === this.currentSelected953D);
    } else {
      this.isReadOnly = true;
      return this._fedExTax;
    }
  }

  private markFormGroupTouched(formGroup: FormGroup) {
    if (formGroup && formGroup.controls) {
      Object.keys(formGroup.controls).forEach(key => {
        const control = formGroup.controls[key];
        if (control) {
          control.markAsTouched();
        }
      });
    }
  }

}

models.ts

export const createFedExciseExpenses = (): Array<BackendDto.FedExciseExpense> => {
    return [
        {is953D : 1, coveragePolicyTypeId : 1, value : 0},
        {is953D : 0, coveragePolicyTypeId : 1, value : 1},
        {is953D : 0, coveragePolicyTypeId : 2, value : 4},
        {is953D : 1, coveragePolicyTypeId : 2, value : 0}
    ];
};

1 Ответ

0 голосов
/ 13 мая 2018

Похоже, вы неправильно настраиваете свои издевательства. В производстве вы говорите, что свойство fedEx всегда определяется, но это не так во время тестирования.

Это означает, что получатель возвращает неопределенное значение. Скорее всего именно эта строка:

return this.fedExciseExpensesInputs
  .find(x => 
    x.coveragePolicyTypeId === this.currentSelectedCoveragePolicy && 
    x.is953D === this.currentSelected953D);

Не зная ничего о вашем коде, но зная немного о модульном тестировании, я в первую очередь хотел бы проверить, что this.fedExciseExpensesInputs не пусто и содержит значение, которое может быть возвращено получателем. Вы не показываете, где в коде, который инициализируется.

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