Tips for testing the logic of rxjs debounceTime in an Angular project?

After diving headfirst into coding with RxJs without much prior knowledge, I found myself copying and pasting code snippets, tweaking them to fit my needs, only to hit roadblocks when trying to test the code...

Let me share the entire component for context:

import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { map } from 'rxjs/operator/map';
import { debounceTime } from 'rxjs/operator/debounceTime';
import { distinctUntilChanged } from 'rxjs/operator/distinctUntilChanged';
import { _catch } from 'rxjs/operator/catch';
import { _do } from 'rxjs/operator/do';
import { switchMap } from 'rxjs/operator/switchMap';
import { of } from 'rxjs/observable/of';

import { ApiService } from '../../services/api/api.service';

import { ISearchSuggestion } from './search.interface';

@Component({
  selector: 'msm-search',
  templateUrl: './search.component.html'
})
export class SearchComponent {
  public model: string;

  private _isSearching = false;
  get isSearching() { return this._isSearching; }

  constructor(
    private router: Router,
    private apiService: ApiService
  ) {}

  search = (text$: Observable<string>) => {
    return _do.call(
      switchMap.call(
        _do.call(
          distinctUntilChanged.call(
            debounceTime.call(text$, 300)),
            this.enableSearching.bind(this)
          ),
        this.performSearch.bind(this)
      ),
      () => {
        this._isSearching = false;
      }
    );
  }

  private enableSearching(term: string) {
    if (term.length > 2) {
      this._isSearching = true;
    }
  }

  private performSearch(term: string) {
    if (term.length > 2) {
      return _catch.call(
        _do.call(this.apiService.getSearchSuggestions(term)),
        () => of.call([])
      )
    }
  }
}

I'm struggling to test the search functionality using setTimeout and jasmine.tick(), here's a snippet of my attempt:

it('Should get suggestions if search term is longer than 2 characters', (done) => {
  const searchTerm = '123test';
  const stringObservable = new Observable<string>(observer => {
    setTimeout(() => {
      observer.next(searchTerm);
      observer.complete();
    }, 50);
  });
  spyOn(apiService, 'getSearchSuggestions');
  component.search(stringObservable);
  setTimeout(() => {
    expect(apiService.getSearchSuggestions).toHaveBeenCalledWith(searchTerm);
    done();
  }, 500);
});

Any insights on what might be going wrong in my testing approach?

Answer №1

tick is the key to accomplishing this goal

component.search(stringObservable);
tick(500);
expect(apiService.getSearchSuggestions).toHaveBeenCalledWith(searchTerm);

Not getting the desired results?

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to compile a standalone c++ file without using an Integrated Development Environment (IDE)

Currently, I am developing a C++ unit testing tool as a way to enhance my skills, but I have hit a roadblock. The concept behind this project is: To extract all the class and function names from .hpp files located in a designated test directory and its ...

Angular 4 async pipe not functioning as expected for Observable to update UI

I have a simple dataset loaded into an observable as shown below: public tasks: Observable<UserTask[]>; constructor(private dataService: HttpdataService, private changeDetector: ChangeDetectorRef) { } ngOnInit() { this.loadTasks(); } loadTasks() ...

Specify the route in tsconfig.app.json for your Angular project

Using the angular CLI, the project has been created with the following folder structure: https://i.sstatic.net/lqGMo.png The aim is to establish a path to a bar folder in tsconfig.app.json and import Car to Garage. The tsconfig.app.json file: { "exte ...

Defining a TypeScript conditional return type that may include undefined

Here is the function I currently have, but unfortunately I encountered the following error: Type '(T & undefined) | { obj: T & ({} | null); }' is not assignable to type 'T extends undefined ? undefined : { obj: T; }'. Type & ...

A guide on accessing a dynamic object key in array.map()

How can I dynamically return an object key in array.map()? Currently, I am retrieving the maximum value from an array using a specific object key with the following code: Math.max.apply(Math, class.map(function (o) { return o.Students; })); In this code ...

"Error encountered while executing a code snippet using Navalia in TypeScript

I have been attempting to execute this code snippet from https://github.com/joelgriffith/navalia but despite my efforts, I have not been able to get it running smoothly without encountering errors: navaliatest.ts /// <reference path="typings.d.ts" /&g ...

Is it possible to link multiple references to a single Element/Node?

I am working on a function component that needs to pass the incoming ref from the parent to a div it is rendering. Additionally, I want to create and assign a separate ref inside the component to the same div. However, due to an element only accepting one ...

The attribute 'locations' is not found within the 'Object' datatype

import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import 'rxjs/add/operator/map'; @Injectable() export class LocationsProvider { data: any; constructor(public http: HttpClie ...

Having trouble with my Angular subscription - not behaving as I anticipated

I am facing an issue on my shop page where I have a FilterBarComponent as a child component. On initialization, I want it to emit all the categories so that all products are rendered by default. However, on my HomePageComponent, there is a button that allo ...

Encountered a problem when trying to show a PDF viewer within a Bootstrap modal

Trying to preview a PDF using a bootstrap modal, but encountering an error: Error: Unable to initialize viewer. TypeError: Cannot read property 'div' of undefined When the modal is called, the PDF does not display initially. However, if the s ...

Opting for Angular 4 over the alpha version of bootstrap 4 opens up a world of possibilities

Implementing Bootstrap in my recent Angular 4 Project has been a challenge. Upon installing it with npm, I realized that the Alpha version of Bootstrap was installed, which is not what my client wants. They prefer to avoid using any Alpha versions. Could ...

Changing the color of multiple rows in Angular MaterialUI when clicked

I've come across an issue where I'm able to change the color of a cell when I click on showProfile(), but if I click on the next row, the previous color disappears. How can I make sure that the color remains persistent each time I click on any ro ...

The Angular NgRx Selector fails to return the expected value and instead

Sharing my current app.state.ts setup: export interface AppState { availableItems: Item[]; selectedItems: Item[]; currentUser: boolean; totalScore: number; error: string; } export const initialState: AppState = { availableItems: [], selected ...

Ionic is encountering a problem with module build, specifically an error related to the absence of a file or directory

Using Ionic has led to encountering the following error message: Runtime Error Uncaught (in promise): Error: Module build failed: Error: ENOENT: no such file or directory, open '/Users/richardmarais/Development/ionic/theWhoZoo/src/pages/model/r ...

Is there a different approach available since the array function "some" does not restrict type even when a type predicate is implemented?

It is expected that when using the array function "some" along with a type predicate and return statement, the TypeScript compiler would narrow down the type of dashArray. Is it reasonable to expect this behavior from the TypeScript compiler or am I incor ...

ZAP may be falsely flagging a path traversal vulnerability in an Angular application

I have integrated OWASP ZAP into our automated CI/CD workflow, running both a spider and active scan. The report flagged a Path Traversal error. However, the site is built on Angular 2, so there is no sensitive information stored on the server. Additional ...

What is the reason behind referring to Angular as a single-page application?

One term frequently linked with Angular(JS) is SPA. What makes Angular(JS) known as a single-page application? If the URL changes on an Angular(JS) site, can it still be considered an SPA? Do all websites built using Angular(JS) qualify as single page app ...

Jenkins is causing the npm test to fail, whereas the test passes without any

Encountering Issue with npm test Below is the error message received: FAIL src/Tests/Workflow.test.js ● Test suite failed to run ENOENT: no such file or directory, mkdir '/tmp/jest_4df/jest-transform-cache-4e6d562894209be60da269aa86f9333c-d1 ...

Having trouble capturing errors thrown within a React component during testing with testing-library

Component to evaluate function EvaluateShopStats({ id, name }) { return ( <ShopStatsContext.Consumer> {(context) => { if (!(context || {}).state) { throw new Error('ERROR'); } return <Shop ...

Leverage the power of forkJoin alongside activatedRoute

One of the observables I'm working with is the following: formData$ = forkJoin([ this.httpService.getProgramsLevelsList(), this.httpService.getProgramsTypesList(), this.httpService.getQuestionnaireReasonsList() ]).pipe( tap((res: any) => ...