Exploring the Potential of Jest Testing for Angular 6 Services

Hey there, I seem to be facing a bit of a roadblock and could use some assistance. Here's the situation - I'm trying to test a service using Jest, but all the tests pass without any issues even when they shouldn't.

Here are the details of the software version being used:

Angular v6.0.1 RxJs v6.2.1 Jest v23.1.0

The structure of my service is as follows (it should be quite simple at this stage):

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';

import { BaseApiService } from './base-api.service';

@Injectable({ providedIn: 'root' })
export class ListsService extends BaseApiService {
  private static readonly LISTS_API = 'http://localhost:3000/lists';
  constructor(protected httpClient: HttpClient) {
    super();
  }
  public list(): Observable<BasicList[]> {
    return this.httpClient
      .get<BasicList[]>(ListsService.LISTS_API, BaseApiService.httpOptions)
      .pipe(map((res: Response) => res.json()));
  }
}

I currently have two tests for the same purpose as I am attempting to learn how to perform testing without TestBed based on an article. The first one uses TestBed:

import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { inject, TestBed } from '@angular/core/testing';

import { ListsService } from './lists.service';

const basicListData = [
  {
    id: 1,
    name: "name 1"
  },
  {
    id: 2,
    name: "name 2"
  }
];

describe('Service: List Service', () => {
  let httpMock: HttpTestingController;
  let service: ListsService;

  beforeEach(() => {
    TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [ListsService] });
  });

  beforeEach(inject([ListsService, HttpTestingController], (_service, _httpMock) => {
    service = _service;
    httpMock = _httpMock;
  }));

  it('list: should return a sorted list', () => {
    service.list().subscribe(lists => {
      expect(lists.length).toBe(2);
    });

    const req = httpMock.expectOne('http://localhost:3000/lists');
    req.flush(basicListData);
    httpMock.verify();
  });
});

The issue lies with the `expect.ToBe(2)` statement. Regardless of what number I input, the test passes. It seems like something is amiss, but I can't pinpoint the problem.

Additionally, here is the same test but without Test Bed:

import { of } from 'rxjs';

import { ListsService } from './lists.service';

const basicListData = [
  {
    id: 1,
    name: "name 1"
  },
  {
    id: 2,
    name: "name 2"
  }
];

const provide = (mock: any): any => mock;

describe('Service: Lists', () => {
  let listsService: ListsService;

  const http = { get: jest.fn(() => of(basicListData)) };
  beforeEach(() => {
    listsService = new ListsService(provide(http));
  });

  it('list$: Should return a list of List definitions', () => {
    listsService.list().subscribe(lists => {
      expect(http.get).toBeCalledWith('http://localhost:3000/lists');
      expect(lists.length).toBe(3);
    });
  });
});

In this case, the endpoint isn't even being checked, leaving me feeling even more adrift.

Any help would be greatly appreciated, and I hope that the question has been adequately explained. Thank you!

Answer №1

Encountering the same issue led me to a solution using done. By utilizing done, I could ensure that the test waits for subscribe to finish executing before proceeding.

 it('list$: Should return a list of List definitions', (done) => {
    listsService.list().subscribe(lists => {
      expect(http.get).toBeCalledWith('http://localhost:3000/lists');
      expect(lists.length).toBe(3);

done();

    });
  });

Answer №2

It appears that an assertion is necessary in this scenario. Due to the asynchronous nature of the operation, your tests are passing because the case is executed before the callback is invoked. As a result, 'expect' is not being called. To address this issue, you can try returning a promise after invoking the assertion as shown below:

it('list$: Should return a list of List definitions', () => {
    expect.assertions(1);
    return listsService.list().toPromise().then(
      lists => {
        expect(http.get).toBeCalledWith('http://localhost:3000/lists');
        expect(lists.length).toBe(3);
      });
  });

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 display an object in the template that does not have a specified property

I am dealing with an object that can have a type of WithBalance | WithoutBalance withBalance : { balance:number, name:string } withoutBalance : { name : string} <span>{{object?.balance ?? 0}} </span> However, when I attempt to access the bal ...

When working with the latest version of Angular CLI, make sure to include a @NgModule annotation in

Just a heads up: I'm diving into Angular for the first time, so bear with me if I make some rookie mistakes. The Lowdown I've got the latest version of Angular CLI up and running The default app loads without a hitch after 'ng serve' ...

Ways to showcase product information (Using Angular and Firebase)

Information product.model.ts id?: string; name: string; price: number; sale_price: number; description: string; tech_sheet: string; imageUrls: string[]; category: string; createdAt: Date; } Initialize file product.service.ts The latest f ...

The Battle of Identifiers: Named Functions against Anonymous Functions in TypeScript

When it comes to performance and performance alone, which option is superior? 1) function GameLoop() { // Performing complex calculations requestAnimationFrame(GameLoop); } requestAnimationFrame(GameLoop); 2) function GameLoop() { // ...

react-navigation hook for navigating

Currently, I am utilizing the react-navigation hook and instead of repeating the hook in various components, my goal is to pass navigation as a prop. const navigation = useNavigation(); ... <MyButton resetLocation={resetLocation} navigation= ...

The exclusion feature in TSLint does not seem to be functioning properly

It seems that the ts lint -e/--exclude feature is not functioning properly, or perhaps I am doing something incorrectly. I currently have tslint 4.5.1 installed. Whenever I attempt to use the CLI with tslint -e path_to_file, it gives me an error stating ...

Using Axios and Typescript to filter an array object and return only the specified properties

I'm currently working on creating an API to retrieve the ERC20 tokens from my balance. To accomplish this, I am utilizing nextjs and axios with TypeScript. However, I'm encountering an issue where the response from my endpoint is returning exces ...

Finding the appropriate method to access a template variable reference in a designated row of an Angular Material table (Angular 7)

Currently, I am working on implementing a more intricate version of a behavior inspired by Angular Material's tutorials. In my simplified example, an Angular Material table is populated with data from a string array. The first column contains input fi ...

What is the best way to send an action based on the HTTP method being used?

I've been utilizing NGXS for handling state in my angular project. What would be considered a best practice? Should I make the HTTP call first and then dispatch an action within its subscription? Or should I dispatch the action first and then make t ...

Ordering Server Responses with Angular's httpClientAngular's httpClient allows

Utilizing theHTTPClient module to automatically map data in a service, which then uses http.get to connect to a remote API. I subscribe to this service in a component that calls it multiple times within a loop. for (let i of this.symbols) { this.serv ...

NGRX 8 reducer now outputting an Object rather than an Array

I am facing an issue where the data returned from the reducer is an object instead of an array. Despite trying to return action.recentSearches, it doesn't seem to work as expected. The data being returned looks like this: { "loading": false, "recent ...

Using Typescript: Compiling specific files within a directory

According to the documentation for typescript, we have the option in tsconfig.json to manage input files using either the files property where all files are listed, or with the exclude property. I have organized all my source files within a directory named ...

guide to utilizing npm/yarn with tsx react

I've recently made the switch to using TypeScript with React, but I'm encountering a problem. After installing certain packages from npm or yarn, I'm having trouble using them in my .tsx components. The error message suggests looking for @ty ...

What is preventing me from loading Google Maps within my Angular 2 component?

Below is the TypeScript code for my component: import {Component, OnInit, Output, EventEmitter} from '@angular/core'; declare var google: any; @Component({ selector: 'app-root', templateUrl: './app.component.html', st ...

Learn how to define an array of member names in TypeScript for a specific type

Is there a way to generate an array containing the names of members of a specific type in an expression? For example: export type FileInfo = { id: number title ?: string ext?: string|null } const fileinfo_fields = ["id","ext&qu ...

Tips for showcasing unique validation error messages

My form includes a text area for the user to input JSON Code. If the entered text is not valid JSON, an error message should be displayed but unfortunately, it's not working as expected. Below is my custom validator code: import { AbstractControl, V ...

Another return payload failing to retrieve the return value

I'm currently facing an issue where a function that should return a value is not being passed on to another function. Below is the code snippet in question: public _getProfileToUpdate() { return { corporateId: this.storeService.setStoreData().p ...

Comparable to LINQ SingleOrDefault()

I frequently utilize this particular pattern in my Typescript coding: class Vegetable { constructor(public id: number, public name: string) { } } var vegetableArray = new Array<Vegetable>(); vegetableArray.push(new Vegetable(1, "Carrot")); ...

"Error occurs as a result of an unspecified attribute in the map

Hello, I am currently traversing a tree structure recursively. To handle undefined nodes in the tree, I have implemented guards to prevent any failures. However, during the mapping of children nodes, I encountered the following error: Error Output Adri ...

"Error: Unable to locate module - 'electron-is-dev'" in my web development project using electron, typescript, and webpack

I'm currently working on a project using Electron, Typescript, and webpack. I am planning to integrate react.js into the project. However, when I ran "npx webpack" in the terminal, I encountered an error message. The error stated that the "electron- ...