在反应式表单模块的 auditTime 方法的订阅块中测试值

test values within a subscribe block of a reactive form module's auditTime method

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

我有以下示例组件:

address.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;
    });
  }
}

address.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>

address.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
});

尝试使用 tick() 等待并尝试使用 flushMicrotasks().

刷新

监视 createForm 函数:

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

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

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');
  }));

如果有人有类似的问题。

好的,我只是post这里是我的假设,检查它是否有帮助:

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