角度测试 - ngBootstraps typeahead

Mar*_*oLe 7 rxjs karma-jasmine ng-bootstrap angular angular-test

我目前正在使用ngBootstrap的自动完成机制(typeahead).现在我想要对输入事件的每个序列调用一个方法进行单元测试.我的测试用例的错误目前是:Cannot read property 'pipe' of undefined

HTML:

<input id="locationEdit" type="text" class="form-control"
         [(ngModel)]="user.location" name="location [ngbTypeahead]="search"/>
Run Code Online (Sandbox Code Playgroud)

零件:

public ngOnInit() {
    this.search = (text$: Observable<string>) =>
      text$.pipe(
        tap(() => {
          this.isSearching = true;
          this.searchFailed = false;
        }),
        debounceTime(750),
        distinctUntilChanged(),
        switchMap(term =>
          this.cityService.getLocation(term).pipe(
            tap((response) => {
              this.searchFailed = response.length === 0;
              this.isSearching = false;
            })))
      );
  }
Run Code Online (Sandbox Code Playgroud)

spec.ts

  it('should call spy on city search', fakeAsync(() => {
    component.user = <User>{uid: 'test', username: 'mleko', location: null, description: null};
    const spy = (<jasmine.Spy>cityStub.getLocation).and.returnValue(of['München Bayern']);

    fixture.detectChanges();
    const compiled: DebugElement = fixture.debugElement.query(By.css('#locationEdit'));
    compiled.nativeElement.value = 'München';
    compiled.nativeElement.dispatchEvent(new Event('input'));

    tick(1000);
    fixture.detectChanges();

    expect(spy).toHaveBeenCalled();
  }));
Run Code Online (Sandbox Code Playgroud)

有人可以帮我嘲笑这个.搜索得当吗?

编辑

通过@dmcgrandle的精彩建议,我不需要渲染HTML并模拟输入事件,以检查输入事件是否正常工作.我宁愿做一个Observable,它会发出值并将它分配给函数.一种方法是:

  it('should call spy on city search', fakeAsync(() => {
    const spy = (<jasmine.Spy>cityStub.getLocation).and.returnValue(of['München Bayern']);

    component.ngOnInit();
    const textMock = of(['M', 'Mün', 'München']).pipe(flatMap(index => index));

    component.search(textMock);

    tick();

    expect(spy).toHaveBeenCalled();
  }));
Run Code Online (Sandbox Code Playgroud)

但问题仍然是,component.search不要打电话给间谍.在switchMap运算符的搜索函数中,我添加了一个console.log以查看函数是否发出了值.但事实并非如此.也许有人可以为我的问题提供stackblitz.:)

dmc*_*dle 6

我认为您实际上不想在测试期间调用任何 ngBootstrap 代码 - 毕竟您想对您的代码进行单元测试,而不是他们的代码。:)

\n\n

因此,我建议通过设置您自己的定时 Observable 并用它调用您的函数来模拟实际输入的用户。也许模拟每 100 毫秒发送一个字符。像这样的东西:

\n\n
it(\'should call spy on city search\', fakeAsync(() => {\n    component.user = <User>{uid: \'test\', username: \'mleko\', location: null, description: null};\n    // Change next line depending on implementation of cityStub ...\n    const spy = spyOn(cityStub, \'getLocation\').and.returnValue(of(\'M\xc3\xbcnchen Bayern\'));\n\n    fixture.detectChanges();\n    let inputTextArray = [\'M\', \'M\xc3\xbc\', \'M\xc3\xbcn\', \'M\xc3\xbcnc\', \'M\xc3\xbcnch\', \'M\xc3\xbcnche\', \'M\xc3\xbcnchen\'];\n    let textMock$ : Observable<string> = interval(100).pipe(take(7),map(index => inputTextArray[index]));\n    component.search(textMock$);\n    tick(1000);\n    expect(spy).toHaveBeenCalled();\n}));\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

更新:

\n\n

我在这里整理了一个 stackblitz 来测试一下:https://stackblitz.com/edit/stackoverflow-question-52914753(打开左侧的应用程序文件夹,然后单击 my.component.spec.ts 查看测试文件)

\n\n

一旦我把它放在那里,很明显出了什么问题——可观察量没有被订阅,因为订阅似乎是由 ngBootstrap 完成的,所以为了测试我们需要显式订阅。这是我新建议的规范(取自 stackblitz):

\n\n
it(\'should call spy on city search\', fakeAsync(() => {\n    const cityStub = TestBed.get(CityService);\n    const spy = spyOn(cityStub, \'getLocation\').and.returnValue(of(\'M\xc3\xbcnchen Bayern\'));\n\n    fixture.detectChanges();\n    let inputTextArray = [\'M\', \'M\xc3\xbc\', \'M\xc3\xbcn\', \'M\xc3\xbcnc\', \'M\xc3\xbcnch\', \'M\xc3\xbcnche\', \'M\xc3\xbcnchen\'];\n    let textMock$ : Observable<string> = interval(100).pipe(take(7),map(index => inputTextArray[index]));\n    component.search(textMock$).subscribe(result => {\n         expect(result).toEqual(\'M\xc3\xbcnchen Bayern\');\n    });\n    tick(1000);\n    expect(spy).toHaveBeenCalled();\n}));\n
Run Code Online (Sandbox Code Playgroud)\n