TypeError: Cannot read properties of undefined (reading '<myvariable>')
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>{};
...
Related videos on Youtube
Vineel Pellella
Interests in learning, Art, Fashion, Business and much more
Updated on July 09, 2022Comments
-
Vineel Pellella almost 2 years
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: <circular reference: Object>, renderParent: <circular reference: Object>, 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.
-
Vineel Pellella over 2 yearsStill getting the same error. I even tried the below code for selectedEmployee object as well for mocking at beforeEach. spyOnProperty(employeeService, 'selectedEmployee', 'set').and.returnValue(new Employee());
-
Suneet Bansal over 2 yearsThat means your service is not returning empty object and your emp object is not getting initialised properly. Check you have to then mock service properly as I explained above. Attach your service then will add the mock code above.
-
Vineel Pellella over 2 yearsI am not very clear with mocks. I included the employee service as well. Can you please check once again.
-
Suneet Bansal over 2 yearsyou don't even need to add mock, just update the service class as I mentioned in the edited post.
-
Vineel Pellella over 2 yearssetting the selectEmployee in service resolved this issue. Thanks a lot.
-
Suneet Bansal over 2 yearsAlways welcome!