While running the ng test in one of the components I am facing the below error.
TypeError: Cannot read properties of undefined (reading 'dateOfLeaving') error properties: Object({ ngDebugContext: DebugContext_({ view: Object({ def: Object({ factory: Function, nodeFlags: 33669121, rootNodeFlags: 33554433, nodeMatchedQueries: 0, flags: 0, nodes: [ Object({ nodeIndex: 0, parent: null, renderParent: null, bindingIndex: 0, outputIndex: 0, checkIndex: 0, flags: 33554433, childFlags: 114688, directChildFlags: 114688, childMatchedQueries: 0, matchedQueries: Object({ }), matchedQueryIds: 0, references: Object({ }), ngContentIndex: null, childCount: 1, bindings: [ ], bindingFlags: 0, outputs: [ ], element: Object({ ns: '', name: 'app-view-employee', attrs: [ ], template: null, componentProvider: Object({ nodeIndex: 1, parent: , renderParent: , bindingIndex: 0, outputIndex: 0, checkIndex: 1, flags: 114688, childFlags: 0, directChildFlags: 0, childMatchedQueries: 0, matchedQueries: Object, matchedQueryIds: 0, references: Object, ngContentIndex: -1, childCount: 0, bindings: Array, bindingFlags: 0, outputs ... TypeError: Cannot read properties of undefined (reading 'dateOfLeaving') at ViewEmployeeComponent.ngOnInit (http://localhost:9876/karma_webpack/webpack:/src/app/employee/view/view-employee/view-employee.component.ts:22:17) at checkAndUpdateDirectiveInline (http://localhost:9876/karma_webpack/webpack:/node_modules/@angular/core/fesm2015/core.js:24503:1) at checkAndUpdateNodeInline (http://localhost:9876/karma_webpack/webpack:/node_modules/@angular/core/fesm2015/core.js:35163:1) at checkAndUpdateNode (http://localhost:9876/karma_webpack/webpack:/node_modules/@angular/core/fesm2015/core.js:35102:1) at debugCheckAndUpdateNode (http://localhost:9876/karma_webpack/webpack:/node_modules/@angular/core/fesm2015/core.js:36124:36) at debugCheckDirectivesFn (http://localhost:9876/karma_webpack/webpack:/node_modules/@angular/core/fesm2015/core.js:36067:1) at Object.eval [as updateDirectives] (ng:///DynamicTestModule/ViewEmployeeComponent_Host.ngfactory.js:10:5) at Object.debugUpdateDirectives [as updateDirectives] (http://localhost:9876/karma_webpack/webpack:/node_modules/@angular/core/fesm2015/core.js:36055:1) at checkAndUpdateView (http://localhost:9876/karma_webpack/webpack:/node_modules/@angular/core/fesm2015/core.js:35067:1) at callWithDebugContext (http://localhost:9876/karma_webpack/webpack:/node_modules/@angular/core/fesm2015/core.js:36407:1)
employee.ts
export class Employee
{
id:number;
name:string;
dateOfBirth:string;
designation:string;
dateOfJoining:string;
workLocation:string;
email:string;
contactNo:number;
dateOfLeaving:string
constructor(){}
static getEmployee(id:number,
name:string,
dob:string,
designation:string,
dateOfJoining:string,
workLocation:string,
email:string,
contactNo:number,
dateOfLeaving:string
) :Employee
{
let emp = new Employee();
emp.id = id;
emp.name = name;
emp.dateOfBirth = dob;
emp.designation =designation;
emp.dateOfJoining = dateOfJoining;
emp.workLocation = workLocation;
emp.email = email;
emp.contactNo =contactNo;
emp.dateOfLeaving = dateOfLeaving
return emp;
}
}
view-component.ts
import { Component, OnInit } from '@angular/core';
import { CommonService } from 'src/app/service/common.service';
import { Employee } from '../../employee';
import { EmployeeService } from '../../employee.service';
@Component({
selector: 'app-view-employee',
templateUrl: './view-employee.component.html',
styleUrls: ['./view-employee.component.css']
})
export class ViewEmployeeComponent implements OnInit {
constructor(private employeeService: EmployeeService, private genericServices: CommonService) { }
emp:Employee;
availableLocations: string[] = [];
msg:string;
ngOnInit()
{
this.emp = this.employeeService.selectedEmployee;
if(this.emp.dateOfLeaving == null)
{
this.emp.dateOfLeaving = '';
}
this.genericServices.getWorkLocations().subscribe(
(resp:string[]) =>
{
this.availableLocations = this.availableLocations.concat( resp);
},
(err: any) =>
{
console.log("err" err)
}
);
}
saveEmployee()
{
this.employeeService.updateEmployee(this.emp).subscribe(
(resp) =>
{
if(resp['status'] ==200)
{
let existingEmpIndex = this.employeeService.employees.findIndex((exitsEmp) => this.emp.id == exitsEmp.id);
this.employeeService.employees[existingEmpIndex] = this.emp;
this.msg = resp['message'];
}
},
(errMsg) =>
{
this.msg = errMsg['error']['errorMessage'];
}
)
}
}
view-employee.component.spec.ts
import { HttpClientModule } from '@angular/common/http';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { CommonService } from 'src/app/service/common.service';
import { Employee } from '../../employee';
import { EmployeeService } from '../../employee.service';
import { ViewEmployeeComponent } from './view-employee.component';
describe('ViewEmployeeComponent', () => {
let component: ViewEmployeeComponent;
let fixture: ComponentFixture<ViewEmployeeComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ViewEmployeeComponent ],
imports: [FormsModule, HttpClientModule],
providers: [EmployeeService, CommonService]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ViewEmployeeComponent);
component = fixture.debugElement.componentInstance;
component.emp = new Employee();
component.emp.id =1;
component.emp.dateOfLeaving ="Today";
fixture.detectChanges();
});
it('should create', () => {
fixture.whenStable().then( ()=> {
fixture.detectChanges();
// expect(component).toBeTruthy();
})
});
});
employee-service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { env } from 'process';
import { environment } from 'src/environments/environment';
import { URLMapping } from '../shared/URLMapping';
import { Employee } from './employee';
@Injectable({
providedIn: 'root'
})
export class EmployeeService {
employees:Array<Employee> =[];
selectedEmployee:Employee;
constructor(private httpClient: HttpClient)
{ }
fetchEmployee(emp:Employee)
{
console.log(emp)
// return this.httpClient.post(environment.applicationURL URLMapping.EMPLOYEE_VIEW, emp);
return this.selectedEmployee = emp;
}
createEmployee(emp:Employee)
{
return this.httpClient.post(environment.applicationURL URLMapping.EMPLOYEE_ADD, emp);
}
getEmployees()
{
return this.httpClient.post(environment.applicationURL URLMapping.EMPLOYEE_LIST, {});
}
updateEmployee(emp:Employee)
{
return this.httpClient.post(environment.applicationURL URLMapping.EMPLOYEE_SAVE, emp);
}
deleteEmployee(employees: Employee[]) {
return this.httpClient.post(environment.applicationURL URLMapping.EMPLOYEE_DELETE, employees);
}
}
Facing the same issue for the id attribute as well. Any references or solutions are greatly appreciated.
CodePudding user response:
The issue here is, Angular lifecycle method will only be called when you call fixture.detectChanges() and you are initializing emp object inside ngOnInit(). So you can't access emp object properties before calling fixture.detectChanges()
Try below code (view-employee.component.spec.ts):
beforeEach(() => {
fixture = TestBed.createComponent(ViewEmployeeComponent);
fixture.detectChanges();
component = fixture.debugElement.componentInstance;
component.emp = new Employee();
component.emp.id =1;
component.emp.dateOfLeaving ="Today";
});
Also I assume that this.employeeService.selectedEmployee would at least return empty object else you will have to mock EmployeeService as well.
service -
...
export class EmployeeService {
employees:Array<Employee> =[];
selectedEmployee:Employee = <Employee>{};
...
