MD10
MD10

Reputation: 1521

Mocking A Service in angular Karma Jasmine Testing

I am trying to mock a service by adding it to the providers array in the spec and adding createSpyObj with it's functions but I get the following error:

Access to XMLHttpRequest at ''ng://DynamicTestModule/mycomponent_Host.ngfactory.js' from origin 'http:localhost:9876'

what am I doing wrong?

// .... import the service

mockService = jasmine.createSpyObj(['function1'])
testBed.configureTestingModule({
  providers:[{
      {provide: myService, useValue: mockService}
  }]
}).compileComponents()

Upvotes: 3

Views: 14006

Answers (3)

Shashank Vivek
Shashank Vivek

Reputation: 17494

The way you have created spy itself is wrong. From the error, it seems to be more related to invalid import or something else.

The correct way to do this is:

describe("UserDetailComponent", () => {
  let component: UserDetailComponent;
  let fixture: ComponentFixture<UserDetailComponent>;
  const mockUserService = jasmine.createSpyObj("UserSvcService", ["getUserDetail"]);

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [UserDetailComponent],
      providers: [
        { provide: UserSvcService, useValue: mockUserService }
      ]
    }).compileComponents();
  }));
....
...
 it('should set some values using service',()=>{
   mockUserService.getUserDetail.and.returnValue(
      of({ data: 'somevalue'})
    );
   expect(someCondition).toBeDefined();
 })
)}

There are other ways to do this, using Stubs and inserting then in component using useClass . you can refer to this article of mine to get the idea

Upvotes: 4

thenolin
thenolin

Reputation: 1064

What I would do is provide the service, but leverage Angular's HttpClientTestingModule and HttpTestingController to configure each unit test's individual http response you want.

beforeEach(async(() => {
    TestBed.configureTestingModule({
        imports: [],
        providers: [SharedService]
    }).compileComponents();
}));

Once you have the Service provided, you're able to access everything inside of it.

Essentially, you're able to create mock responses and 'flush' them through the testing suite for each individual test you write. This enables to to configure the HTTP response for each test rather than providing you're entire Service test suite with one response.

Here's an example:

it("should return valid response", fakeAsync(
   inject([HttpTestingController], (httpMock: HttpTestingController) => {
      let mockResponse = { success: true }

      httpMock.expectOne('endpoint name here').flush(mockResponse);

      fixture.whenStable().then(() => {
          //here's your acceptance criteria
      });
   });
));

Here's some documentation on it: https://medium.com/netscape/testing-with-the-angular-httpclient-api-648203820712

Upvotes: 0

Pankaj
Pankaj

Reputation: 29

let just say you have a service named SharedService to test

// import the service from the desired location, i just indicated with @
import { SharedService } from "@services"

// create an instance inside describe
let sharedService: SharedService

// declare under providers in beforeEach
providers: [SharedService]

// create component and test fixture
fixture = TestBed.createComponent(yourComponentName);
component = fixture.componentInstance;
sharedService = fixture.debugElement.injector.get(SharedService)

// use compileComponents only if you are not using webpack or angular CLI 

it('Should call MethodOne - sharedService ==> resolved', () => {
        let MockedData = {};
        spyOn(sharedService, 'someMethod').and.returnValue(Observable.of(MockedData));
        component.MethodOne();
        expect(sharedService.someMethod).toHaveBeenCalled();
    });

Upvotes: 1

Related Questions