0
votes

I am using Angular 8 with Karma. New to Karma, so i expect this is something simple.

I am getting "Failed: Cannot read property 'subscribe' of undefined" when I run my unit test. Call stack indicates the TimesheetComponent.getUserRole method in which i am using a subscribe. So, the error is that datasvc in that component method is undefined in Karma. Not sure how to define it.

I have created createSpyObj on my service the component use, but I stll get the error. Here is the code-

tk-timesheet.component.ts-

import { Component, OnInit } from '@angular/core';
import 'ag-grid-community';
import { throwError, Subscription, forkJoin } from 'rxjs';
 import {GridOptions} from 'ag-grid-community';

import { TkDataService } from '../tk-services/tk-data/tk-data.service';

interface DayAssignments {
  dayOfWeek: string;
  date: string;
}

@Component({
 selector: 'app-timesheet',
 templateUrl: './tk-timesheet.component.html',
 styleUrls: ['./tk-timesheet.styles.scss']
})

export class TimesheetComponent implements OnInit {
  public gridOptions: GridOptions;
  public columnDefs: any;
  public defaultColDef: any;
  public rowData: any;
  public chargeCodes: any;
  public weekOfOptions: any;
  public weekDates: object[] = [];
  public userRoles: {};
  public shifts: []
  public thisUser: {User}
  public thesePayPeriods: any
  public thisPayPeriod: any
  public commentCode: any
  public commentCodes: any
  subscription: Subscription;
  weekOf: any = 'current';
  comment = '';


  constructor(
   private dataSvc: TkDataService
  ) {
  this.gridOptions = {
      enableSorting: true,
      enableFilter: false,
      rowStyle: {color: '#84613D'},
      headerStyle: {color: '#84613D'}

    } as GridOptions;

  this.defaultColDef = [
        {
        resizable: true,
      }
    ];


  this.weekOfOptions = [
        'current',
        'previous'
    ];
  this.commentCodes = [
    'CH', 'PTO', 'HOL'

  ]
  }


   private canWrite: boolean;

   getUserRole(): any {
     return this.dataSvc.post('getuserdata', {})
     .subscribe(res =>  {
       this.userRoles = res;
       console.log('this.userRoles inside tk-timesheet component::: ', this.userRoles);
    });
   }


    forkJoin([
      this.dataSvc.getUserId('userid', ''),
      this.dataSvc.getOpenPayPeriods("payperiods/open", {status: "open"}),
      this.dataSvc.getChargeCodes('chargeCodes', '')
    ])
    .subscribe((data) => { 
      let userData = data[0]
      let payPeriods = data[1]
      this.thesePayPeriods = payPeriods
      this.weekOfOptions = this.thesePayPeriods.map(period => {
        let dateString = period.startdate  //use thesePayPeriods to set weekOfOptions options.
        let newDate = new Date(dateString.replace('T', ' '))
        let shortNewDate = newDate.toString().split(' ')
        console.log('shortNewDate', shortNewDate)
        let result = `${shortNewDate[0]} ${shortNewDate[1]} ${shortNewDate[2]} ${shortNewDate[3]}`
        return result

      })
      this.thisPayPeriod = payPeriods[0]  //use weekOfOptions selection to set this.thisPayPeriod dynamically.
      let chargeCodes = data[2]
      this.chargeCodes = chargeCodes
      console.log('data  from forkJoin:: ', data, 'userData::: ', userData[0].userid, 'payPeriods:: ', payPeriods, 'chargeCodes:: ', chargeCodes)
      this.dataSvc.getShifts(`shifts/${userData[0].userid}/${payPeriods[0].payperiodid}`, data).subscribe((shifts: any) => {
        this.shifts = shifts
        this.rowData = this.buildRowData(shifts, chargeCodes)
      })

    }, (err) => { /* do error stuff*/})


    //this.getUserRole();
    this.getUserRole();
    this.getMonday();


 }

tk-timesheet.spec.ts-

 import { TestBed, async, ComponentFixture, inject, tick, fakeAsync} from '@angular/core/testing';
 import { TimesheetComponent } from './tk-timesheet.component';
 import { HttpClientTestingModule } from '@angular/common/http/testing';
 import { of } from 'rxjs';
 import { TkDataService } from '../tk-services/tk-data/tk-data.service';

describe('TimesheetComponent', async () => {


let dataService;
  // tslint:disable-next-line: max-line-length
dataService = jasmine.createSpyObj('TkDataService', ['get', 'post', 'getUserId', 'getOpenPayPeriods', 'getChargeCodes', 'getUserRole', 'getuserdata']);

let component: TimesheetComponent;
let fixture: ComponentFixture<TimesheetComponent>;

beforeEach( async( () => {
 TestBed.configureTestingModule({
    declarations: [ TimesheetComponent ],
    imports: [ HttpClientTestingModule ],
    providers: [{ provide: TkDataService,  useValue: dataService }]
  })
  .compileComponents()

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

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

it('should populate column headers with monday of the current week on initial view ', async(() => {
    fixture.detectChanges();

    let thisMonday = () => {
        let date = new Date();
        let day = date.getDay();
        let diff = date.getDate() - day + (day == 0 ? -6 : 1); // adjust when day is sunday
        let mon = new Date(date.setDate(diff));

        return `${mon.getMonth() + 1}/${mon.getDate()}/${mon.getFullYear().toString().slice(-2)}`;
    };
    spyOn(component, 'getUserRole').and.returnValue(of({}));;
    expect(component.weekDates[0]['date']).toEqual(null);
}));

TkDataservice-

 import { environment } from 'src/environments/environment';
 import { Injectable } from '@angular/core';
 import { HttpClientModule, HttpClient, HttpHeaders, HttpResponse, HttpParams } from '@angular/common/http';
 import { Observable } from 'rxjs';
 import { OidcSecurityService } from 'angular-auth-oidc-client';
 import { TimekardResponse } from 'src/app/tk-models/tk-response';
 import { AuthService } from '../auth.service';

 @Injectable({
    providedIn: 'root'
 })
 export class TkDataService {
  constructor(
    private http: HttpClient
    ) {

    }


post(route: string, data: any, responseType?){
    if(localStorage.getItem('userRole') === null || localStorage.getItem('userRole') === undefined) {
        this.getUserRole();
    }

    const observe = responseType === 'blob' ? 'response' : 'body';

    let requestHeaders = new HttpHeaders();
    requestHeaders = requestHeaders.set('Authorization', localStorage.getItem('bearerToken'));
     // tslint:disable-next-line: max-line-length
    return this.http.post<TimekardResponse>(environment.baseAPIUrl + route, data, {withCredentials: false, headers: requestHeaders, responseType,      observe: observe as 'body'} );
}


}}

Thanks in advance for the help!

1

1 Answers

0
votes

Your code component is not complete. I assume where you call getUserRole() is inside the ngOnInit method. So, if it is, in your test you must to define first the spyOn, before the fixture.detectChanges

it('should populate column headers with monday of the current week on initial view ', async(() => {

    spyOn(component, 'getUserRole').and.returnValue(of({}));
    fixture.detectChanges();

    let thisMonday = () => {
        let date = new Date();
        let day = date.getDay();
        let diff = date.getDate() - day + (day == 0 ? -6 : 1); // adjust when day is sunday
        let mon = new Date(date.setDate(diff));

        return `${mon.getMonth() + 1}/${mon.getDate()}/${mon.getFullYear().toString().slice(-2)}`;
    };

    expect(component.weekDates[0]['date']).toEqual(null);
}));