Q: Invoke function present inside component from spec.ts file in angular 8 I am new in writing Angular test cases using Jasmine, I am trying to invoke a function getRoleModulePermissionById(event,id) from manage-permissions.component.spec.ts which is inside manage-permissions.component.ts
Manage Permission Component:
getRoleModulePermissionById(event,id) {
        this. moduleNameStr = event.target.innerText
        console.log("this. moduleNameStr",this. moduleNameStr)
        console.log("id-----------------",id,);
        this.moduleId=id;
        this.roleService.getRoleModulePermission(id).subscribe(
            (response) => {
                this.isShow = true;
                this.getHide = true;
                this.roleList = response;
                console.log('inside get ' + JSON.stringify(this.roleList))
            },
            (httpErrorRes) => {
                alert(constants.roleModuleNotFound);
            }
        );
        this.prepareBreadcrumb();
    }

Manage Permissions Spec:
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { constants } from '../../../shared/static/constants';
import { ModuleServiceService } from '../../services/module-service.service';

import { ManagePermissionsComponent } from './manage-permissions.component';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';

// mock the service
class MockModuleservice extends ModuleServiceService {
    // mock everything used by the component
  };

describe('ManagePermissionsComponent', () => {
  let component: ManagePermissionsComponent;
  let fixture: ComponentFixture<ManagePermissionsComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
        imports: [RouterTestingModule,HttpClientTestingModule],
      declarations: [ ManagePermissionsComponent ],
      providers: [{
        provide: ModuleServiceService ,
        useClass: MockModuleservice
      }]
    })
    .compileComponents();
  });

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

  it('should create manage-permission', () => {
    expect(component).toBeTruthy();
  });

  it('should able to getRoleModulePermissionById', () => {
    component.getRoleModulePermissionById(null,1);
    expect(component).toBeTruthy();
  })

});

I am not able to figured out, how to invoke function,as instance of ManagePermissionsComponent has already been created in beforEach() . I am trying to prepare the code coverage report,so I want to cover the entire lines of code inside the function getRoleModulePermissionById, but not able to do so
Kindly correct me If I am doing something wrong, also provide me the Jasmine best practice guide.
Karma.conf.js file
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'),
      require('karma-coverage'),
      require('@angular-devkit/build-angular/plugins/karma')
    ],
    client: {
      jasmine: {
        // you can add configuration options for Jasmine here
        // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
        // for example, you can disable the random execution with `random: false`
        // or set a specific seed with `seed: 4321`
      },
      clearContext: false // leave Jasmine Spec Runner output visible in browser
    },
    jasmineHtmlReporter: {
      suppressAll: true // removes the duplicated traces
    },
    coverageReporter: {
      dir: require('path').join(__dirname, '../../coverage'),
      subdir: '.',
      reporters: [
        { type: 'html' },
        { type: 'text-summary' }
      ]
    },
    angularCli: {
      environment: 'dev'
    },
    reporters: ['progress', 'kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false,
    restartOnFileChange: true
  });
};


A: You need to do a couple of things for the lines to get covered in the report.

*

*Cover the lines which are not in subscribe() function

*Cover the lines which are in subscribe() function.

Please do the following:
@Injectable()
class MockRoleService extends RoleService {
  getRoleModulePermission(): any {
    const mockData = {} // Fill the type of response here
    return of(mockData); // Import 'of' from 'rxjs'
  }
}

// Add this in the providers: 

// Add a service mocker here;
let roleService: RoleService;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
        imports: [RouterTestingModule,HttpClientTestingModule],
      declarations: [ ManagePermissionsComponent ],
      providers: [
        {
          provide: ModuleServiceService ,
          useClass: MockModuleservice
        },
        {
          provide: RoleService ,
          useClass: MockRoleService
        }
      ]
    })
    .compileComponents();
  });
roleService = TestBed.get(RoleService); <-- this line is important to mock API Failure scenario

// Now the test cases: 

// HTTP Success scenarios
it('should run the #getRoleModulePermissionById() + success response of subscribe', () => {
   spyOn(component, 'getRoleModulePermissionById').and.callThrough();
   const event = {
     target: {
       innerText: 'someInnerText'
     }
   };
   component.getRoleModulePermissionById(event, 'someId');
   expect(component.getRoleModulePermissionById).toHaveBeenCalled();
});

// HTTP Failure error scenario
it('should run #getRoleModulePermissionById() method, API-Failure scenario', () => {
   const errorResponse = { status: 500 };
   spyOn(roleService, 'getRoleModulePermission').and.returnValue(throwError(errorResponse));
   spyOn(component, 'getRoleModulePermissionById').and.callThrough();
   const event = {
     target: {
       innerText: 'someInnerText'
     }
   };
   component.getRoleModulePermissionById(event, 'someId');
   expect(component.getRoleModulePermissionById).toHaveBeenCalled();
})

These 2 test cases should cover both the scenarios perfectly.

A: You need to mock the role service correctly and return the mock response in your test case to test the subscribe block, In jasmine this is how we create a stub:
  const roleServiceStub = jasmine.createSpyObj('RoleService', ['getRoleModulePermission']);

and then you will need to provide this service to your test Angular module, like this:
{ provide: RoleService, useValue: roleServiceStub }

Here is the complete test for subscribe block and error block:
describe('ManagePermissionsComponent', () => {
    let component: ManagePermissionsComponent;
    let fixture: ComponentFixture<ManagePermissionsComponent>;
    const roleServiceStub = jasmine.createSpyObj('RoleService', ['getRoleModulePermission']);


    beforeEach(async () => {
        await TestBed.configureTestingModule({
            imports: [RouterTestingModule, HttpClientTestingModule],
            declarations: [ManagePermissionsComponent],
            providers: [{
                provide: ModuleServiceService,
                useClass: MockModuleservice
            }, { provide: RoleService, useValue: roleServiceStub },]
        })
            .compileComponents();
    });

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

    it('should create manage-permission', () => {
        expect(component).toBeTruthy();
    });

    it('should able to getRoleModulePermissionById', () => {
        const mockRoleResponse = {

        }; // Keep is as your response
        roleServiceStub.getRoleModulePermission.and.returnValue(of(mockRoleResponse));
        component.getRoleModulePermissionById(null, 1);
        expect(component.roleList).toBeTruthy();
        // Write other assertion based on your mock respone
    });

    it('should handle error', () => {
        const mockRoleResponse = {

        }; // Keep is as your response

        spyOn(window, 'alert');
        roleServiceStub.getRoleModulePermission.and.returnValue(throwError({ error: 'some error'));
        component.getRoleModulePermissionById(null, 1);
        expect(window.alert).toHaveBeenCalled();
    });

});

