I am getting following errors while do the test:
TypeError: Cannot read properties of undefined (reading 'subscribe')
Error: <toHaveBeenCalled> : Expected a spy, but got Function.
Not able to understand with these erros.
Here is my spec file:
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { TranslateModule } from '@ngx-translate/core';
import { HfsTableComponent } from '../../../../../shared/hfs-table/hfs-table.component';
import { SharedModule } from '../../../../../shared/shared.module';
import { AddClinicDataService } from '../services/personnel-add-clinic-data.service';
import { PersonnelDataService } from '../services/personnel-data.service';
import { PersonnelTranslateService } from '../services/personnel-translate.service';
import { PersonnelViewDataService } from '../services/personnel-view-data.service';
import { DetailsComponent } from './details.component';
import { HFSTaleSchema } from './hfs-table.schema';
fdescribe('DetailsComponent', () => {
let component: DetailsComponent;
let fixture: ComponentFixture<DetailsComponent>;
const mockPersonnelViewDataService = {
fetchUserProfileWithCode: () => {
const userProfileWithCodes$ = {
sjmAccDTO: {
sjmAccDTO: {
lastUpdtUserId: '',
createUserId: '',
firstName: null,
middleName: '',
lastName: '',
mainPhone: {
phoneNum: '',
areaCode: '',
countryCode: '',
},
timeZoneCd: '',
status: '',
hfsUserCountries: [],
hfsUserClinics: [],
},
customerDTO: [],
},
customerDTO: [],
countryCds: [],
timeZoneDTO: [],
};
return { subscribe: () => userProfileWithCodes$ };
},
};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [DetailsComponent, HfsTableComponent],
imports: [
SharedModule,
HttpClientTestingModule,
BrowserAnimationsModule,
TranslateModule.forRoot(),
],
providers: [
{
provide: PersonnelViewDataService,
useValue: mockPersonnelViewDataService,
},
PersonnelDataService,
PersonnelTranslateService,
AddClinicDataService,
],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DetailsComponent);
component = fixture.componentInstance;
component.tableSchema = HFSTaleSchema;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
fit('should service available', () => {
fixture.detectChanges();
expect(
mockPersonnelViewDataService.fetchUserProfileWithCode
).toHaveBeenCalled();
});
});
what i missed or what i did not provide here? any one help me to understand please?
component:
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
OnDestroy,
OnInit,
ViewChild,
ViewEncapsulation,
} from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { HfsFormComponent } from '../../../../../shared/hfs-form/hfs-form.component';
import { ColumnSorter } from '../../../../../shared/utils/column-sort.helper';
import { AddClinicDataService } from '../services/personnel-add-clinic-data.service';
import { PersonnelTranslateService } from '../services/personnel-translate.service';
import {
PersonnelViewDataService,
UserProfileCombinedProps,
} from '../services/personnel-view-data.service';
import { AddClinicComponent } from './add-clinic';
import { HFSPersonnelFormSchema } from './hfs-personnel-form.schema';
import { HFSTaleSchema } from './hfs-table.schema';
const hfsUserClinics = [
{
hfsUserCountryId: 2895,
countryCd: 140,
},
];
@Component({
selector: 'app-details',
templateUrl: './details.component.html',
styleUrls: ['./details.component.scss'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DetailsComponent
extends AddClinicComponent
implements OnInit, AfterViewInit, OnDestroy
{
personnelFormSchema;
tableSchema;
@ViewChild('profileForm', { static: false })
profileForm: HfsFormComponent;
error;
show: boolean = false;
constructor(
private personnelViewDataService: PersonnelViewDataService,
private personnelTranslateService: PersonnelTranslateService,
private cdr: ChangeDetectorRef,
public dialog: MatDialog,
protected aAddClinicDataService: AddClinicDataService
) {
super(aAddClinicDataService);
}
ngOnInit(): void {
this.personnelFormSchema = HFSPersonnelFormSchema;
this.tableSchema = HFSTaleSchema;
this.personnelViewDataService.fetchUserProfileWithCode();
}
handleRemoveClinic(): void {
const rowsUpdate = this.tableSchema.rows.filter((row) => !row.checked);
const headerUpdate = this.tableSchema.headers.map((item) => ({
...item,
...(item.checked === undefined ? undefined : { checked: false }),
}));
this.tableSchema = {
...this.tableSchema,
headers: headerUpdate,
rows: rowsUpdate,
};
}
formValueUpdater(field, response, countryCds, timeZoneDTO): void {
switch (field.controlName) {
case 'userName':
field.value = response.lastUpdtUserId;
return field;
case 'areacode':
field.value = response.mainPhone.areaCode;
return field;
case 'countrycode':
field.value = response.mainPhone.countryCode;
return field;
case 'mainphone':
field.value = response.mainPhone.phoneNum;
return field;
case 'firstName':
field.value = response.firstName;
return field;
case 'middleName':
field.value = response.middleName;
return field;
case 'lastName':
field.value = response.lastName;
return field;
case 'countries':
field.options =
this.personnelTranslateService.translator(countryCds);
console.log('response.hfsUserClinics', response.hfsUserClinics);
field.value = response.hfsUserClinics;
return field;
case 'timezone':
field.options =
this.personnelTranslateService.translator(timeZoneDTO);
field.value = response.timeZoneCd || 228;
return field;
case 'slide':
field.value = !response.timeZoneCd ? false : true;
return field;
default:
return field;
}
}
rowGenerator(rows) {
if (!rows) return;
return rows.reduce((p, c) => {
p.push({
adminUserName: c.adminUserName,
customerName: c.customer.customerName,
address: Object.values(c.customer.address).filter(
(v) => v != null
),
phoneNum: c.customer.mainPhone.phoneNum,
checked: false,
});
return p;
}, []);
}
formGenerator(sjmAccDTO, countryCds, timeZoneDTO): void {
const { formProps } = this.personnelFormSchema;
const fieldMaker = (field) => {
const { group } = field;
if (group) {
return field.groupElements.map((field) =>
this.formValueUpdater(
field,
sjmAccDTO,
countryCds,
timeZoneDTO
)
);
}
field = this.formValueUpdater(
field,
sjmAccDTO,
countryCds,
timeZoneDTO
);
return field;
};
const nwF = formProps.map((row, i) => {
row.column?.map((column) => {
column?.fields.map((field, i) => {
return fieldMaker(field);
});
return column;
});
return row;
});
return { ...this.personnelFormSchema, formProps: nwF };
}
ngAfterViewInit(): void {
this.setPage();
}
ngOnDestroy() {}
setPage(): void {
this.personnelViewDataService.userProfileWithCodes$.subscribe(
(userProfile: UserProfileCombinedProps) => {
if (!userProfile) return;
const { sjmAccDTO, customerDTO, countryCds, timeZoneDTO } =
userProfile;
this.tableSchema = {
...this.tableSchema,
rows: this.rowGenerator(customerDTO),
};
this.personnelFormSchema = this.formGenerator(
sjmAccDTO,
countryCds,
timeZoneDTO
);
this.error = null;
this.show = true;
this.cdr.detectChanges();
},
(err) => this.errorHandler(err)
);
}
errorHandler(err): void {
const { status, statusText } = err;
this.error = { status, statusText };
this.cdr.detectChanges();
}
handleFormSubmit(formValues): void {
console.log('form-values', formValues);
}
resetPage(): void {
this.setPage();
}
postProfile(): void {
this.profileForm.formOnSubmit();
}
handleColumSort(column): void {
ColumnSorter(
this.tableSchema.rows,
column.label,
column.dir,
column.sortType
);
}
protected rowTransformer(inRow): void {
console.log(this.tableSchema.rows.length);
this.tableSchema = {
...this.tableSchema,
rows: this.tableSchema.rows.concat(inRow),
};
this.cdr.detectChanges();
}
}
Service:
import { Location } from '@angular/common';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { combineLatest, Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { environment } from '../../../../../../environments/environment';
import { PersonnelDataService } from './personnel-data.service';
export interface UserCountriesProps {
[key: string]: number;
}
export interface UserClinicsProps {
[key: string]: number;
}
export interface CountryCdProps {
defaultOrder: number;
label: string;
codeId: number;
code: string;
codeDesc: string;
codeQualifier: string;
}
export interface TimeZoneDTOProps extends CountryCdProps {
defaultOrder: number;
label: string;
codeId: number;
code: string;
codeDesc: string;
codeQualifier: string;
}
export interface customerDTOProps {
adminUserName: string;
customer: {
customerName: string;
mainPhone: {
phoneNum: string;
};
address: {
stateProvince: string | null;
streetAddress: string | null;
streetAddress2: string | null;
streetAddress3: string | null;
city: string;
zipCode: string;
countryCd: number;
stateCd: number;
};
};
}
export interface UserProfileProps {
sjmAccDTO: {
lastUpdtUserId: string;
createUserId: string;
firstName: string | null;
middleName: string | null;
lastName: string | null;
mainPhone: {
countryCode: string;
areaCode: string;
phoneNum: string;
};
timeZoneCd: string | number | null;
status: string | number;
hfsUserCountries: UserCountriesProps[];
hfsUserClinics: UserClinicsProps[];
};
customerDTO: customerDTOProps[];
}
export interface UserProfileCombinedProps {
sjmAccDTO: UserProfileProps;
customerDTO: customerDTOProps[];
countryCds: CountryCdProps[];
timeZoneDTO: TimeZoneDTOProps[];
}
@Injectable()
export class PersonnelViewDataService {
private URL = environment.api_url;
private URLLocal = 'https://d1-hfcloudapim.products.abbott/';
public userProfile$: Observable<UserProfileCombinedProps | null>;
public userCodes$: Observable<TimeZoneDTOProps | null>;
public userProfileWithCodes$: Observable<UserProfileCombinedProps>;
constructor(
private http: HttpClient,
private personnelDataService: PersonnelDataService,
private _location: Location
) {
if (!this.UserDetails$) {
this._location.back();
}
}
get UserDetails$() {
return this.personnelDataService.userDetails$.getValue();
}
fetchUserProfileWithCode() {
this.userProfileWithCodes$ = combineLatest([
this.fetchUserDetails(),
this.fetchUserCode(),
]).pipe(map((data: any[]) => ({ ...data[0], ...data[1] })));
return this.userProfileWithCodes$;
}
fetchUserDetails() {
this.userProfile$ = this.http
.get<UserProfileCombinedProps>(
this.URL
`hfs-admin/hfs-users/user-details?sjmAccountId=108843`
// `hfs-admin/hfs-users/user-details?sjmAccountId=${this.UserDetails$?.sjmAccountId}`
// `hfs-admin/hfs-users/user-details?sjmAccountId=108843`
)
.pipe(
map((profile) => profile),
catchError(this.handleError)
);
return this.userProfile$;
}
fetchUserCode() {
this.userCodes$ = this.http
.get<TimeZoneDTOProps>(this.URL `hfs-admin/codes`)
.pipe(
map((userCode) => userCode),
catchError(this.handleError)
);
return this.userCodes$;
}
handleError(err: HttpErrorResponse) {
return throwError(err);
}
}
CodePudding user response:
Try the following things
- Inject the service into the testbed
- Use spyon in the test case to spy on the service method
- Inside mockPersonnelViewDataService add userProfileWithCodes$ as a property
let mockService: PersonnelViewDataService;
beforeEach(() => {
fixture = TestBed.createComponent(FileUploadComponent);
component = fixture.componentInstance;
mockService = TestBed.get(PersonnelViewDataService);
fixture.detectChanges();
});
it('should service available', () => {
const spy = spyOn(mockService, 'fetchUserProfileWithCode');
component.ngOnInit();
expect(spy).toHaveBeenCalled();
});
const mockPersonnelViewDataService = {
userProfileWithCodes$: of(),
fetchUserProfileWithCode: () => {
const userProfileWithCodes$ = {
...
}
}
}