业力错误:“失败:无法读取未定义的属性'subscribe'”

时间:2020-05-20 15:08:50

标签: angular jasmine karma-jasmine

我正在将Angular 8与Karma一起使用。 Karma的新手,所以我希望这很简单。

运行单元测试时,我收到“失败:无法读取未定义的属性'subscribe'”。调用堆栈指示我正在使用订阅的TimesheetComponent.getUserRole方法。因此,错误是该组件方法中的datasvc在Karma中未定义。不确定如何定义。

我在组件使用的服务上创建了createSpyObj,但我收到错误消息。这是代码-

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'} );
}


}}

提前感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

您的代码组件不完整。我假设您调用getUserRole()的位置位于ngOnInit方法内。因此,如果是这样,则在测试中,必须先在夹具.detectChanges

之前定义spyOn。
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);
}));