2

我有一个演示/哑组件,它使用输入来使用 formBuilder 填充 HTML 模板。这一切都很好,但是当我开始测试它时,事情并不像他们应该的那样顺利。

我想测试一些文本框是否正确填充了我的输入值。我希望 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 指令的输入元素上断言,它可以工作。

4

0 回答 0