Angular 2测试ngModel工作流程

时间:2017-10-06 13:41:42

标签: javascript angular unit-testing typescript

这是我的问题:

我有一个自定义组件,其中包含一个带有ngModel的模板。



import { Component, Input, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

const listaMesi = [
  {
    value: '01',
    text: 'Gennaio'
  }, {
    value: '02',
    text: 'Febbraio'
  }, {
    value: '03',
    text: 'Marzo'
  }, {
    value: '04',
    text: 'Aprile'
  }, {
    value: '05',
    text: 'Maggio'
  }, {
    value: '06',
    text: 'Giugno'
  }, {
    value: '07',
    text: 'Luglio'
  }, {
    value: '08',
    text: 'Agosto'
  }, {
    value: '09',
    text: 'Settembre'
  }, {
    value: '10',
    text: 'Ottobre'
  }, {
    value: '11',
    text: 'Novembre'
  }, {
    value: '12',
    text: 'Dicembre'
  }
]

const annoCorrente = new Date().getFullYear();

@Component({
  selector: 'seg-month-picker',
  templateUrl: './month-picker.component.html',
  styleUrls: ['./month-picker.component.scss'],
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => MonthPickerComponent),
    multi: true
  }]
})
export class MonthPickerComponent implements ControlValueAccessor {

  private propagateChange: Function;
  private checkedValue: string;
  private isDisabled = true;
  public meseSelezionato: string;
  public annoSelezionato: string;
  public yearList = [];
  public monthList = listaMesi;

  private _min: string;
  private _max: string;
  @Input() set min(value: string) {
    this._min = value;
    if (value) {
      const [ year, month ] = value.split('-');
      const maxYear = this._max ? +this._max.slice(0, 4) : annoCorrente;
      this.yearList = Array.from({ length: maxYear + 1 - +year }).map((_, index) => +year + index);
    }
  }
  get min() {
    return this._min;
  }

  @Input() set max(value: string) {
    this._max = value;
    if (value) {
      const [ maxYear, month ] = value.split('-');
      const year = this._min ? +this.min.slice(0, 4) : annoCorrente;
      this.yearList = Array.from({length: +maxYear - year + 1}).map((_, index) => year + index);
    }
  }
  get max() {
    return this._max;
  }

  updateYear(year: string) {
    this.annoSelezionato = year;
    this.updateValue();
  }

  updateMonth(month: string) {
    this.meseSelezionato = month;
    this.updateValue();
  }

  updateValue() {
    if (this.annoSelezionato && this.meseSelezionato && this.propagateChange) {
      this.propagateChange(`${this.annoSelezionato}-${this.meseSelezionato}`);
    }
  }

  writeValue(yearMonth: string): void {
    const [ year, month ] = yearMonth.split('-');
    this.annoSelezionato = year;
    this.meseSelezionato = month;
  }

  registerOnChange(fn: Function): void {
    this.propagateChange = fn;
  }

  registerOnTouched(fn: Function): void { }

  setDisabledState(isDisabled: boolean): void {
    this.isDisabled = isDisabled;
  }

}

<div>
  <select id="anno" name="anno" [ngModel]="annoSelezionato" (ngModelChange)="updateYear($event)">
    <option *ngFor="let anno of yearList" [value]="anno.value">{{anno.value}}</option>
  </select>
  <select id="mese" name="mese" [ngModel]="meseSelezionato" (ngModelChange)="updateMonth($event)">
    <option *ngFor="let mese of monthList" [value]="mese.value">{{mese.text}}</option>
  </select>
</div>
&#13;
&#13;
&#13;

问题是:我如何在单元测试中跟踪ngModule的变化?我将粘贴我的单元测试,但不能正常工作;我试过@viewChild(),但我肯定有问题。

&#13;
&#13;
import { Component, ViewChild } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';

import { MonthPickerComponent } from './month-picker.component';

@Component({
  selector: 'seg-month-picker',
  template: `<seg-month-picker>`
})
export class TestComponent {
  @ViewChild(MonthPickerComponent) picker;
}

function getComponent(): Promise<TestComponent> {
  const fixture = TestBed
    .createComponent(TestComponent);

  fixture.detectChanges();

  return fixture.whenStable().then(() => fixture.componentInstance);
}



describe('MonthPickerComponent', async() => {
  let component: MonthPickerComponent;
  let fixture: ComponentFixture<MonthPickerComponent>;
  let element: HTMLElement;
  const mockedComponent = await getComponent();

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [MonthPickerComponent, mockedComponent],
      imports: [FormsModule]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MonthPickerComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should be created', () => {
    expect(component).toBeTruthy();
  });

  describe('setMin', () => {
    it('deve impostare la lista di anni in base al minimo dato', () => {
      component.min = '2014-03';
      fixture.detectChanges();
      expect(component.yearList).toEqual([2014, 2015, 2016, 2017]);
    })
  });

  describe('getMin', () => {
    it('deve restituire l\'anno minimo della lista', () => {
      component.min = '2014-03';
      fixture.detectChanges();
      const result = component.min;
      expect(result).toBe('2014-03');
    });
    it('deve restituire null se non ho un valore minimo', () => {
      component.min = undefined;
      fixture.detectChanges();
      const result = component.min;
      expect(result).toBe(undefined);
    })
  });

  describe('setMax', () => {
    it('deve restituire la lista di anni in base al massimo dato', () => {
      component.max = '2018-01';
      fixture.detectChanges();
      expect(component.yearList).toEqual([2017, 2018]);
    });
    it('deve restituire la lista di anni in base al range dato', () => {
      component.max = '2018-01';
      component.min = '2014-01';
      fixture.detectChanges();
      expect(component.yearList).toEqual([2014, 2015, 2016, 2017, 2018]);
    });
  });

  describe('getMax', () => {
    it('deve restituire l\'anno massimo della lista', () => {
      component.max = '2018-01';
      fixture.detectChanges();
      const result = component.max;
      expect(result).toBe('2018-01');
    });
    it('deve restituire null se non ho un valore massimo', () => {
      component.max = undefined;
      fixture.detectChanges();
      const result = component.max;
      expect(result).toBe(undefined);
    });
  });

  describe('writeValue', () => {
    fit('deve modificare il valore all\'ngModel del componente', async () => {
      console.log(mockedComponent.picker);
      mockedComponent.picker.writeValue('2016-03');
      fixture.detectChanges();
      const result = component.max;
      expect(result).toBe('2018-01');
    });
    it('deve restituire null se non ho un valore massimo', () => {
      component.max = undefined;
      fixture.detectChanges();
      const result = component.max;
      expect(result).toBe(undefined);
    });
  });

});
&#13;
&#13;
&#13;

问题是我必须从组件控制器测试writeValue()函数和其他函数,跟踪ngModel假设的值。我真的不知道如何解决这个问题。 谢谢你的帮助!

---编辑--- 至少我可以在组件视图中对<select>进行html引用,并以编程方式更改其值,但我认为这是一种更好的方法。

1 个答案:

答案 0 :(得分:0)

试试这个:

&#13;
&#13;
import { Component, Input, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

const listaMesi = [
  {
    value: '01',
    text: 'Gennaio'
  }, {
    value: '02',
    text: 'Febbraio'
  }, {
    value: '03',
    text: 'Marzo'
  }, {
    value: '04',
    text: 'Aprile'
  }, {
    value: '05',
    text: 'Maggio'
  }, {
    value: '06',
    text: 'Giugno'
  }, {
    value: '07',
    text: 'Luglio'
  }, {
    value: '08',
    text: 'Agosto'
  }, {
    value: '09',
    text: 'Settembre'
  }, {
    value: '10',
    text: 'Ottobre'
  }, {
    value: '11',
    text: 'Novembre'
  }, {
    value: '12',
    text: 'Dicembre'
  }
]

const annoCorrente = new Date().getFullYear();

@Component({
  selector: 'seg-month-picker',
  templateUrl: './month-picker.component.html',
  styleUrls: ['./month-picker.component.scss'],
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => MonthPickerComponent),
    multi: true
  }]
})
export class MonthPickerComponent implements ControlValueAccessor {

  private propagateChange: Function;
  private checkedValue: string;
  private isDisabled = true;
  public meseSelezionato: string;
  public annoSelezionato: string;
  public yearList = [];
  public monthList = listaMesi;

  private _min: string;
  private _max: string;
  @Input() set min(value: string) {
    this._min = value;
    if (value) {
      const [ year, month ] = value.split('-');
      const maxYear = this._max ? +this._max.slice(0, 4) : annoCorrente;
      this.yearList = Array.from({ length: maxYear + 1 - +year }).map((_, index) => +year + index);
    }
  }
  get min() {
    return this._min;
  }

  @Input() set max(value: string) {
    this._max = value;
    if (value) {
      const [ maxYear, month ] = value.split('-');
      const year = this._min ? +this.min.slice(0, 4) : annoCorrente;
      this.yearList = Array.from({length: +maxYear - year + 1}).map((_, index) => year + index);
    }
  }
  get max() {
    return this._max;
  }

  updateYear(year: string) {
    this.annoSelezionato = year;
    this.updateValue();
  }

  updateMonth(month: string) {
    this.meseSelezionato = month;
    this.updateValue();
  }

  updateValue() {
    if (this.annoSelezionato && this.meseSelezionato && this.propagateChange) {
      this.propagateChange(`${this.annoSelezionato}-${this.meseSelezionato}`);
    }
  }

  writeValue(yearMonth: string): void {
    const [ year, month ] = yearMonth.split('-');
    this.annoSelezionato = year;
    this.meseSelezionato = month;
  }

  registerOnChange(fn: Function): void {
    this.propagateChange = fn;
  }

  registerOnTouched(fn: Function): void { }

  setDisabledState(isDisabled: boolean): void {
    this.isDisabled = isDisabled;
  }

}
&#13;
&#13;
&#13;