53

I am writing unit test for angular app, I am testing if the service function returns a value.

component.spec.ts

import {TopToolBarService} from '../../top-toolbar/top-toolbar.service';

beforeEach(async(() => {
   TestBed.configureTestingModule ({
   declarations: [ UsersListComponent],
   providers: [TopToolBarService],//tried mocking service here,still test failed
   schemas:[CUSTOM_ELEMENTS_SCHEMA]
 })
  .compileComponents();
}));



beforeEach(() => {
    fixture = TestBed.createComponent(UserListComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });



  it('should return data from service function', async(() => {
    let mockTopToolBarService: jasmine.SpyObj<TopToolBarService>;
    mockTopToolBarService = jasmine.createSpyObj('TopToolBarService', ['getCustomer']);
    mockTopToolBarService.getCustomer.and.returnValue("king");
    fixture.detectChanges();
    expect(component.bDefine).toBe(true); //fails
  }))

component.ts

bDefine = false;
ngOnInit() {
 let customer = this.topToolBarService.getCustomer();
 if (customer == null) {
   bDefine = false;
 } else {
    bDefine = true;
   }
}

I believe I have mocked the service function in my test, so I expect it must have reached else part where variable is set to 'true'.

TopToolBarService.ts

import { EventEmitter, Injectable, Output } from "@angular/core";

@Injectable()
export class TopToolBarService {
customer = null;

  getCustomer() {
    return this.customer;
  }
}
1
  • 3
    Could you create a minimal, reproducible example, preferably on StackBlitz or similar? What is the rest of component.spec.ts and component.ts? Commented Oct 10, 2019 at 21:31

5 Answers 5

47

Try updating providers inside beforeEach(async(() => ...) and moving your mockedService variable on the top of it:

describe('Component TEST', () => {
   ...
   let mockToolBarService;
   ...
      beforeEach(async(() => {
      ...
      mockToolBarService = jasmine.createSpyObj(['getCustomer']);
      mockToolBarService.getCustomer.and.returnValue('king');
      TestBed.configureTestingModule ({
           ...
           providers: [ { provide: TopToolBarService, useValue: mockToolBarService } ]
           ...

Hope it helps!

Sign up to request clarification or add additional context in comments.

Comments

21

Change your provider value

beforeEach(() => {
   TestBed.configureTestingModule({
      declarations: [ UsersListComponent],
      providers: [{
         provide: TopToolBarService,
         useValue: jasmine.createSpyObj('TopToolBarService', ['getCustomer'])
      }],
      schemas:[CUSTOM_ELEMENTS_SCHEMA]
     });
     mockTopToolBarService = TestBed.get(TopToolBarService);

     mockTopToolBarService.getCustomer.and.returnValue(of([])); // mock output of function
   })

3 Comments

I have a question, why you used providers?
@RebaiAhmed sorry, can't tell now, it was more than 3 years ago. I haven't worked on frontend for while now.
@RebaiAhmed In the context of Typescript and Angular, components that take a service (or anything else) via dependency injection get that service in their constructor. You inject dependencies into the test component via the providers list.
4

You might consider usage of ng-mocks to avoid all that boilerplate to configure TestBed.

beforeEach(() => MockBuilder(UsersListComponent)
  .mock(TopToolBarService, {
    // adding custom behavior to the service
    getCustomer: jasmine.createSpy().and.returnValue('king'),
  })
);

it('should return data from service function', () => {
  const fixture = MockRender(UsersListComponent);
  // now right after the render the property should be true
  expect(fixtur.point.componentInstance.bDefine).toBe(true);
}));

5 Comments

How to mock the custom pipe using ng-mock , any example ?
There is MockPipe function: ng-mocks.sudo.eu/api/MockPipe
Why we combined ng-mocks and jasmine.createSpy()?
ng-mocks allows you to customize only what you want, for example getCustomer only. So you don't need to mock other dependencies if they exist.
What's the advantage of including ng-mocks here?
1

You have to configure the testing module before you run your code. It doesn't know about your spy object unless you pass it to the TestBed.configureTestingModule as an import.

https://angular.io/guide/testing#component-with-a-dependency

1 Comment

link broken, update to angular.io/guide/…
-1

Hi please try this.

import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { AppService } from './app.service';
import { of } from 'rxjs/internal/observable/of';

describe('AppComponent', () => {

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

  it('should render with mocked title', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const service = fixture.debugElement.injector.get(AppService);
    let mockData = {
      id: 1,
      title: 'Fjallraven - Foldsack No. 1 Backpack, Fits 15 Laptop',
      price: 109.95,
      description:
        'Your perfect pack for everyday use and walks in the forest. Stash your laptop (up to 15 inches) in the padded sleeve, your everyday',
      category: "women's clothing",
      image: 'https://fakestoreapi.com/img/81fPKd-2AYL._AC_SL1500_.jpg',
      rating: { rate: 3.9, count: 120 },
    };

    spyOn(service, 'getData').and.returnValue(of(mockData));
  
    fixture.detectChanges();
    const compiled = fixture.nativeElement as HTMLElement;
    expect(compiled.querySelector('h1')?.textContent).toContain('Hello, Fjallraven - Foldsack No. 1 Backpack, Fits 15 Laptop');
    
  });


});

for more details please visit my blog

https://code-js.in/angular/understanding-unit-testing-in-angular-mocked-service-api-calls-and-component-rendering/

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.