angular httpClientTestingModule httpMock giving error: found 2 requests
Asked Answered
C

1

1

I have written first test to test service class:

service class:

import { Injectable } from '@angular/core';
import {HttpClient} from '@angular/common/http'
import {IComment} from "../../models/comments";
import {Observable} from "rxjs/observable";
import { mergeMap } from 'rxjs/operators';

@Injectable()
export class CommentsDataService {

  public _url:string = "../../../../assets/json/comments.json";
  constructor(private http: HttpClient) {  }

  /**
   * Return Sample json for
   * Comment listing.
   * @returns {json)
   */
  getComments():Observable<IComment>
  {
    return this.http.get<IComment>(this._url)
  }

  /**
   *
   * @param commentObj
   */

  saveComment(commentObj){

    console.log(commentObj);

  }

}

spec file:

import { async, ComponentFixture, TestBed,fakeAsync, tick, inject } from '@angular/core/testing';
import { HttpClientModule, HttpClient, HttpEvent, HttpEventType} from '@angular/common/http';
import { Component,DebugElement} from  "@angular/core";
import 'reflect-metadata';

import {By} from "@angular/platform-browser";
import { FormsModule } from '@angular/forms';
import {of} from 'rxjs/observable/of';
import { ListCommentsComponent } from './list-comments.component';
import {CommentsDataService} from '../../services/comments/comments-data.service'
// import {BaseRequestOptions, RequestOptions,Http, ResponseOptions} from '@angular/http';
// import {MockBackend} from "@angular/http/testing";
import {HttpClientTestingModule,HttpTestingController} from '@angular/common/http/testing';

import { Observable } from 'rxjs/Observable';

describe('ListCommentsComponent', () => {



  let component: ListCommentsComponent;
  let fixture: ComponentFixture<ListCommentsComponent>;
  let debugElement:DebugElement;
  let htmlElement:HTMLElement;
  let addCommentBtn:DebugElement;
  let httpMock: HttpTestingController;
  let commentService:CommentsDataService;
  // let service: CommentsDataService;
  // let backend: MockBackend;


  beforeEach(async(() => {


    TestBed.configureTestingModule({

      imports: [ FormsModule, HttpClientModule, HttpClientTestingModule],

      declarations: [ ListCommentsComponent  ],

      providers: [
        CommentsDataService
        // MockBackend,
        // BaseRequestOptions,
        // {
        //   provide: Http,
        //   useFactory: (backend, options) => new Http(backend, options),
        //   deps: [MockBackend, BaseRequestOptions]
        // }
      ]
      // providers:[HttpClientModule, HttpClient]


    })
      .compileComponents();
    httpMock = TestBed.get(HttpTestingController);
    commentService = TestBed.get(CommentsDataService);

    /*
        // Get the MockBackend
        backend = TestBed.get(MockBackend);

        // Returns a service with the MockBackend so we can test with dummy responses
        service = TestBed.get(CommentsDataService);
    */


  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(ListCommentsComponent);
    component = fixture.componentInstance;

    fixture.detectChanges();


  });


  fit('should have a defined component', () => {
    expect(component).toBeDefined();
  });


  fit(
    'should return comments',() => {

      const mockComments = [
        {
          "id": "123",
          "root_id": "234",
          "target_id": "2",
          "object": "Nice!",
          "actor": "user:123",
          "time_stamp": "2 min ago",
          "profile_image": "/../../assets/images/no-user.png",
          "first_name": "john",
          "comment": [
            {
              "id": "124",
              "root_id": "234",
              "target_id": "3",
              "object": "Well!!",
              "actor": "user:123",
              "time_stamp": "2 min ago",
              "first_name": "john",
              "profile_image": "/../../assets/images/no-user.png"
            },
            {
              "id": "125",
              "root_id": "234",
              "target_id": "3",
              "object": "Great!",
              "actor": "user:125",
              "time_stamp": "2 min ago",
              "first_name": "john",
              "profile_image": "/../../assets/images/no-user.png"
            }
          ]
        },

      ];

      commentService.getComments().subscribe((comments) => {

        expect(comments).toBe('json');
        expect(comments).toContain('comments');


      });

      const mockReq = httpMock.expectOne(commentService._url);

      // expect(mockReq.cancelled).toBeFalsy();
      expect(mockReq.request.method).toEqual('GET');
      mockReq.flush(mockComments);

      httpMock.verify();

    }
  );

});

I am getting error for which I have not find any solution on internet and as I am not familiar with how httpClientTestingModule actually work and what These line of code means I am not able to debug or understand the error and hence helpless.

commentService.getComments().subscribe((comments) => {

        expect(comments).toBe('json');
        expect(comments).toContain('comments');


      });

      const mockReq = httpMock.expectOne(commentService._url);

      // expect(mockReq.cancelled).toBeFalsy();
      expect(mockReq.request.method).toEqual('GET');
      mockReq.flush(mockComments);

      httpMock.verify();

Error:

Error: Expected one matching request for criteria "Match URL: ../../../../assets/json/comments.json", found 2 requests.

Comments.json file to which I am making request in service file:

[{ "id":"123",
  "root_id":"234",
  "target_id": "2",
  "object":"Nice!",
  "actor":"user:123",
  "time_stamp": "2 min ago",
  "profile_image":"/../../assets/images/no-user.png",
  "first_name" : "john",
  "comment":[
    {
      "id": "124",
      "root_id":"234",
      "target_id":"3",
      "object":"Well!!",
      "actor":"user:123",
      "time_stamp": "2 min ago",
      "first_name" : "john",
      "profile_image":"/../../assets/images/no-user.png"
    },
    {
      "id": "125",
      "root_id":"234",
      "target_id":"3",
      "object":"Great!",
      "actor":"user:125",
      "time_stamp":"2 min ago",
      "first_name" : "john",
      "profile_image":"/../../assets/images/no-user.png"
    }
  ]
},
  {
    "id":"126",
    "root_id":"234",
    "target_id": "2",
    "object":"Super.",
    "actor":"user:124",
    "time_stamp": "2 min ago",
    "first_name" : "Jill",
    "profile_image":"/../../assets/images/no-user.png",
    "comment":[
      {
        "id": "234",
        "root_id":"234",
        "target_id":"",
        "object":"Cool.",
        "actor":"user:123",
        "first_name" : "john",
        "profile_image":"/../../assets/images/no-user.png"

      },
      {
        "id": "236",
        "root_id":"234",
        "target_id":"3",
        "object":"hiii.",
        "actor":"user:123",
        "first_name" : "jack",
        "profile_image":"/../../assets/images/no-user.png"

      }
    ]
  },  {
  "id":"345",
  "root_id":"234",
  "target_id": "12",
  "object":"Interesting.",
  "actor":"user:124",
  "time_stamp": "2 min ago",
  "first_name" : "john",
  "profile_image":"/../../assets/images/no-user.png"
},  {
  "id":"444",
  "root_id":"234",
  "target_id": "12",
  "actor":"user:125",
  "object":"Cool.",
  "time_stamp": "2 min ago",
  "first_name" : "Simon",
  "profile_image":"/../../assets/images/no-user.png"
},
  {
    "id":"567",
    "root_id":"234",
    "target_id": "12",
    "object":"Last Comment..",
    "actor":"user:125",
    "time_stamp": "2 min ago",
    "first_name" : "jack",
    "profile_image":"/../../assets/images/no-user.png"
  }
]
Clovah answered 20/4, 2018 at 11:3 Comment(0)
W
2

I'm sorry if my answer is not as complete as the previous one, but I am on phone. If you need more explanation, notify me on Monday, il will have a computer to help you.

I can see here that you're testing a component.

In unit testing, you are supposed to test the feature you're on. Since the http calls are made by your service, you should test if they are correct in the tests of your service, not in your component.

This means that in your component, you only test if the correct method of your service is called. This is done by using jasmine spies.

This also means that you can mock your service. If you mock your service, you won't have to mock its dependencies, because you will provide a simple object that has no dependency.

To mock a service, you will need to provide all the properties you are using in your component to your mock. From what I see, you only use getComments, so let's mock :

const serviceMock = {
  provide: YourServiceName, 
  useValue: {
    getComments: () => Observable.of(null)
  }  
};

This is the format of a mock. It must respect some conditions :

  • as said previously, it must contain all of the properties used.
  • those properties must have the same signature. Here, getComments is a function that returns an observable of comments (null is every type), just like in your service.

Now, you can put this mock into your test bed :

providers: [serviceMock]

The logic to get the service instance is the same I explained in your previous question.

Now, you can write a test that checks if the component is calling the service correctly ! You just have to make a spy, call your component function, and expect.

spyOn(serviceInstance, 'getComments').and.callThrough(); // use returnValue(Observable.of(commentsMock)) instead of callThrough() if you want to test your logic made on the value returned by the function
component.functionCall();
expect(serviceInstance.getComments).toHaveBeenCalled();

And voilà !

Worriment answered 21/4, 2018 at 11:38 Comment(1)
Thank you for answering, I need to understand and implement your answer. Will get back soon. :)Clovah

© 2022 - 2024 — McMap. All rights reserved.