FormGroup не присваивает значение для моего ввода HTML в моем тесте

У меня есть презентационный / немой компонент, который использует ввод для заполнения шаблона HTML с помощью formBuilder. Все это прекрасно работает, но когда я начинаю тестировать, все не так гладко, как должно быть.

Я хочу проверить, что некоторые текстовые поля правильно заполняются значением моего ввода. Я ожидаю, что formGroup обновит мой HTML после того, как я:

  1. Установите вход
  2. Вызов обнаружит изменения
  3. Вызовите ngOnInit

В моем тесте я переопределяю стратегию обнаружения OnPush с поведением по умолчанию.

В конечном счете, моя цель - провести тестирование снимков с использованием Jest для таких компонентов, потому что это значительно упрощает сравнение свойств, но для этого сначала нужно правильно отобразить HTML.

Я запускаю тесты с Jest, который, я считаю, использует JsDOM.

@Component({
  selector: 'network',
  templateUrl: './network.component.html',
  styleUrls: ['./network.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class NetworkComponent implements OnInit {
  @Input() network: Network;

  public formGroup: FormGroup;


  constructor(private formBuilder: FormBuilder) {}

  ngOnInit() {
    this.formGroup = this.formBuilder.group({
      details: [this.network || null],
    });
  }
}
<div class="container-fluid">
  <form [formGroup]="formGroup" novalidate (ngSubmit)="submit()">
    <div class="row">
      <div class="col-4">
        <h2>Details</h2>
        <app-network-details formControlName="details"></app-network-details>
      </div>  
    </div>    
    <div class="row">
      <button class="btn btn-primary" type="submit">{{submitButtonText}}</button>
    </div>
  </form>
</div>

Мой компонент app-network-details выглядит так:

@Component({
  selector: 'app-network-details',
  templateUrl: './network-details.component.html',
  styleUrls: ['./network-details.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => NetworkDetailsComponent),
      multi: true
    }
  ],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class NetworkDetailsComponent implements OnInit, ControlValueAccessor, OnChanges {
  public details = {};
  @Output() change = new EventEmitter<number>();

  propagateChange = (_: any) => {};

  ngOnChanges(changes: SimpleChanges): void {
    this.propagateChange(this.details);
  }
  writeValue(obj: any): void {
    if (obj) {
      this.details = obj;
    }
  }
  registerOnChange(fn: any): void {
    this.propagateChange = fn;
  }
  registerOnTouched(fn: any): void {}

  setDisabledState?(isDisabled: boolean): void {
    // throw new Error('Method not implemented.');
  }

  public onChange(e: any) {
    this.details[e.target.name] = e.target.value;
    this.propagateChange(this.details);
  }
  constructor() {
    this.details = {};
  }

  ngOnInit() {}
}
<div class="form-group">
  <input class="form-control" type="text" placeholder="Name" name="name" (change)="onChange($event)" [value]="details.name || null"
  />
</div>
<div class="form-group">
  <input class="form-control" type="text" placeholder="Description" name="description" (change)="onChange($event)" [value]="details.description || null"
  />
</div>
<div class="form-group">
  <input class="form-control" type="text" placeholder="Local Code" name="localCode" (change)="onChange($event)" [value]="details.localCode || null"
  />
</div>

И вот моя тестовая установка:

describe('NetworkComponent', () => {
  let component: NetworkComponent;
  let fixture: ComponentFixture<NetworkComponent>;
  const compilerConfig = { preserveWhitespaces: false } as any;

  beforeEach(
    async(() => {
      TestBed.configureCompiler(compilerConfig)
        .configureTestingModule({
          declarations: [
            NetworkComponent,
            NetworkDetailsComponent,
            NetworkAuthorisationComponent,
            MailboxListStubComponent,
            AddMailboxStubComponent,
            UpdateMailboxStubComponent,
            DropdownStubComponent
          ],
          imports: [ReactiveFormsModule],
          providers: [{ provide: ComponentFixtureAutoDetect, useValue: true }]
        })
        .overrideComponent(NetworkComponent, {
          set: {
            changeDetection: ChangeDetectionStrategy.Default
          }
        })
        .compileComponents();
    })
  );

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

  it('should intialize inputs with values from network', () => {
    const network: Network = {
      id: 1,
      name: 'a',
      description: 'b',
      localCode: 'c',
      authorisation: 'd',
      company: 'e',
      networkType: 'oftp'
    };
    component.network = network;
    fixture.detectChanges();
    component.ngOnInit();

    const inputElement = fixture.nativeElement.querySelector('input[name="description"]');

    inputElement.dispatchEvent(new Event('change'));
    fixture.detectChanges();

    expect(inputElement.value).toEqual('b');
  });
});

Изменить: мне удалось изолировать проблему. Мой тест не пройден из-за моего NetworkDetailsComponent. Я, вероятно, не реализую должным образом интерфейс ControlValueAccessor. Если я переписываю свой тест и утверждаю элемент ввода, имеющий директиву formControlName, это работает.

0 ответов

Другие вопросы по тегам