首页 > 解决方案 > 在反应式表单模块的 auditTime 方法的订阅块中测试值

问题描述

我正在尝试在.subscribe使用方法的 angular4/typescript jasmine 单元测试中测试块内的值rxjs auditTime。我已经阅读了很多与此类似的帖子,这些帖子似乎并没有让我进入那个街区。

我有以下示例组件:

地址.component.ts:

export class AddressComponent implements OnInit {

  public form: FormGroup;

  constructor (
    private fb: FormBuilder
  ) {}

  public ngOnInit (): void {
    this.createForm();
  }

  public createForm (): void {
    this.form = this.fb.group({
      lineOne: [this.address.lineOne],
    });

    this.form.valueChanges.auditTime(500).subscribe(() => {
      this.address.lineOne = this.form.value.lineOne;
    });
  }
}

地址.component.html:

<div class="address">
  <form [formGroup]="form">
    <div class="row">
      <div class="col-12 address-body">
        <div class="form-group-main">
          <div class="row">

            <div class="address-input col-12">
              <label for="address-line-one" [class.required]="isMandatory">Address Line 1</label>
              <input class="form-control" id="address-line-one" type="text" formControlName="lineOne">
            </div>

          </div>
        </div>
      </div>

      <div class="col-12 address-body">
        <display-address [body]="address.lineOne"></display-address>
      </div>

      <div class="col-12">
        <button class="btn btn-full-width btn-primary btn-sm btn-edit" id="address-edit" type="button" (click)="...">Edit</button>
      </div>

    </div>
  </form>
</div>

地址.component.spec.ts:

describe('Address Component', () => {
  let component: AddressComponent;
  let fixture: ComponentFixture<AddressComponent>;

  beforeEach(async(() => {

    TestBed.configureTestingModule({
      declarations: [AddressComponent],
      imports: [ReactiveFormsModule],
      schemas: [NO_ERRORS_SCHEMA],
    }).compileComponents().then(() => {
      fixture = TestBed.createComponent(AddressComponent);
      component = fixture.componentInstance;
    });

  }));

  it('should update address', fakeAsync(() => {
    component.address = {lineOne: 'street'};
    fixture.detectChanges();

    //do something.. 

  }));

});

假设上述设置正确,并且我没有错过明显的东西,这就是为什么我的测试从未提供正确结果的原因,我尝试使用以下想法修改我的测试:

监视 auditTime 并通过以下方式调用:

spyOn(component.form.valueChanges, 'auditTime').and.callThrough();

监视 auditTime 并调用假函数:

spyOn(component.form.valueChanges,'auditTime').and.callFake(()=> {
    return {
        subscribe: () => {}
    }
});

监视 auditTime 并返回一个值 Observable.of:

spyOn(component.form.valueChanges,'auditTime').and.returnValue(Observable.of('hello'));

直接调用它:

component.form.valueChanges.auditTime().subscribe(result => {
   //never get in here
});

试图等待 using:tick()并试图刷新 using: flushMicrotasks()

监视 createForm 函数:

spyOn(component, 'createForm').and.callFake(() => {
    return Observable.of('hello');
});

如果我使用以下内容,使用 debugElement 访问和更新 lineOne 总是返回错误:

const el = fixture.nativeElement.querySelector(By.css('#address-line-one'));
el.value = 'something';
el.dispatchEvent(new Event('input'));
fixture.detectChanges();

因为它看起来只能看到 html 和 的编辑按钮<display-address></display-address>,这表明它当时可能没有编译。

我还尝试将所有内容包装在:

fixture.whenStable().then(() => {
    // do something.. 
});

现在我没有想法了,如果有人能理解上述内容并指出我正确的方向,那就太好了..


解决方案


多亏了 Amir,在这个特定的例子中,我似乎过度思考了所需的答案,并且使用NO_ERRORS_SCHEMA隐藏了真正的问题。事实证明我需要导入需要的组件<display-address>

imports: [ReactiveFormsModule, DisplayAddressComponent],

这允许模板正确编译,这意味着我可以看到所有表单值,而不仅仅是<display-address>. 按照建议,我使用 和 的组合fakeAsynctick(600)对表单进行更改:

it('should update address', fakeAsync(() => {
    component.address = {lineOne: 'street'};
    fixture.detectChanges();

    expect(component.address.lineOne).toBe('street');
    component.form.controls['lineOne'].setValue('test');
    tick(600);

    expect(component.address.lineOne).toBe('test');
  }));

只是如果有人有类似的问题。

标签: angulartypescriptrxjskarma-jasmineangular-reactive-forms

解决方案


好的,我将在这里发布我的假设,检查它是否有帮助:

  1. 创建组件后直接调用 ngOnInit()或 使用detectChanges()
  2. 仅当您使用fakeAsync + tick(600);时,测试才应该同步工作;
  3. 执行tick(600)尝试将值发射到this.form.valueChanges中,您可以通过替换 FormBuilder来做到这一点,这样它将使用您自己的发射器(主题)返回对象,或者通过在 html 中查找元素使用 DOM 事件输入值.
  4. 如果您决定使用 html 作为 input,请删除 NO_ERRORS_SCHEMA并查看它可能由于某些错误而未呈现(因为您说 html 的一部分不存在)。

推荐阅读