Home > OS >  TypeError: Cannot read properties of undefined (reading '<myvariable>')
TypeError: Cannot read properties of undefined (reading '<myvariable>')

Time:09-24

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>{};
...
  • Related