0
votes

Am new to angular unit testing i had written spec file for a component and Getting following error in karma jasmine unit test case. Expected undefined to be truthy. please find the error snapshoot

Ts file:

import {Component, Inject, OnInit} from "@angular/core";
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material";
import {DataService} from "../../../services/data.service";

@Component({
  selector: 'admin-dialog',
  templateUrl: './admin-dialog.component.html',
  styleUrls: ['./admin-dialog.component.scss']
})

export class AdminDialogComponent implements OnInit {
  public accessHasSelected : any ='';
  public errorObj : any = {};
  public checkBoxSelected : boolean;
  public adminObj: any = {
    active:true,
    firstName:"",
    lastName:"",
   // emailId:"",
    access:[]
  };

  /***
   *
   * @param dialogRef
   * @param data
   * @param fromGroup
   * @param dataService
   */
  constructor(
    public dialogRef: MatDialogRef<AdminDialogComponent>,
    @Inject(MAT_DIALOG_DATA) public data: any,
    private dataService: DataService) {

    if (this.data.isNew){
      this.newAdmin();
    }
    else {
      this.editAdmin(this.data.adminObj);
    }


  }

  /*
  * This method will get called while loading new admin modal.
  * */
  newAdmin() {
    this.dataService.getAllAdminAccess().subscribe(
      response => {
        //component related success actions
        this.adminObj.access = response.access;
      },
      error => {
        //component related error actions
      });
  }
  /***
   * This method will get called while loading edit existing admin modal.
   * @param response
   */
  editAdmin(response){
    console.log(response);
    this.dataService.getAdminDetails(response.emailId).subscribe(
      response => {
        //component related success actions
        this.adminObj = response;
      },
      error => {
        //component related errorcurrent-workspace actions
      });
  }
  /**
   * This method will run will save is clicked.
   * */
  saveAdmin(){
    this.checkBoxSelected = true;
    this.accessHasSelected = this.adminObj.access.filter(t=>{
      if(this.checkBoxSelected){
        if(t.selected){this.checkBoxSelected = false;}
        else if(t.access !== null){
          t.access.filter(x=>{
            if(x.selected) {this.checkBoxSelected = false;}
          })
        }
      }
    });
    if(!this.checkBoxSelected) {
      this.dataService.saveAdmin(this.adminObj, this.data.isNew).subscribe(
        response => {
          //component related success actions
          this.dialogRef.addPanelClass('close-modal');
          setTimeout(() => {
            this.dialogRef.close({
              data: response
            });
          }, 500);
        },
        error => {
          this.errorObj = {};
          //component related error actions
          for (var v in error.error.errors) {
            this.errorObj[error.error.errors[v].field] = error.error.errors[v].messageId;
          }
        });
    }else{
        this.errorObj.access = "requiredAccessError";
      }
  }

  /**
   *
   */
  ngOnInit() {

  }

  onModalCancel(): void {
    this.dialogRef.addPanelClass('close-modal');
    setTimeout(()=>{
      this.dialogRef.close();
    },500);
  }
}

Spec file

import { AdminDialogComponent } from "./admin-dialog.component";
import { TestBed, ComponentFixture,async,inject  } from '@angular/core/testing';
import { FormsModule } from "@angular/forms";
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
import {TranslateModule,TranslateService} from "@ngx-translate/core";
import {NO_ERRORS_SCHEMA} from "@angular/core";
import {MAT_DIALOG_DATA, MatDialog, MatDialogModule, MatDialogRef} from '@angular/material/dialog';
import { OverlayContainer } from '@angular/cdk/overlay';
import {HttpClientModule} from "@angular/common/http";
import {RouterTestingModule} from "@angular/router/testing";
import {DataService} from "../../../services/data.service";

describe('Component: admin-dialog', () => {

  let component: AdminDialogComponent;
  let fixture: ComponentFixture<AdminDialogComponent>;
  let translate: TranslateService;
  let dialog: MatDialog;
  let overlayContainer: OverlayContainer;
  let dataService: DataService;
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [FormsModule, MatDialogModule, HttpClientModule,RouterTestingModule,TranslateModule.forRoot()],
      declarations: [AdminDialogComponent],
      providers: [TranslateService,
        { provide: MatDialogRef, useValue: {} },
        { provide: MAT_DIALOG_DATA, useValue: []},
        {provide: dataService, useValue: []}],
      schemas: [NO_ERRORS_SCHEMA]
  });
    TestBed.overrideModule(BrowserDynamicTestingModule, {
      set: {
        entryComponents: [AdminDialogComponent]
      }
    });

    TestBed.compileComponents();

    // create component and test fixture
    fixture = TestBed.createComponent(AdminDialogComponent);

    // get test component from the fixture
    component = fixture.componentInstance;
   // component.ngOnInit();
  });
  beforeEach(inject([MatDialog, OverlayContainer],
    (d: MatDialog, oc: OverlayContainer) => {
      dialog = d;
      overlayContainer = oc;
    })
  );
  afterEach(() => {
    overlayContainer.ngOnDestroy();
  });
  it('should create', () => {
    expect(component).toBeTruthy();
  });

});

Error

**TypeError: Cannot read property 'emailId' of undefined 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: 'admin-dialog', 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: ... at at AdminDialogComponent.emailId [as editAdmin] (http://localhost:9876/_karma_webpack_/webpack:/src/app/dashboard/manage-admin/admin-dialog/admin-dialog.component.ts:52:51) at new editAdmin (http://localhost:9876/_karma_webpack_/webpack:/src/app/dashboard/manage-admin/admin-dialog/admin-dialog.component.ts:30:18)

Expected undefined to be truthy.
Error: Expected undefined to be truthy.**

Spec file update

        import { AdminDialogComponent } from "./admin-dialog.component";
    import { TestBed, ComponentFixture,async,inject  } from '@angular/core/testing';
    import { FormsModule } from "@angular/forms";
    import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
    import {TranslateModule,TranslateService} from "@ngx-translate/core";
    import {Inject, NO_ERRORS_SCHEMA} from "@angular/core";
    import {MAT_DIALOG_DATA, MatDialog, MatDialogModule, MatDialogRef} from '@angular/material/dialog';
    import { OverlayContainer } from '@angular/cdk/overlay';
    import {HttpClientModule} from "@angular/common/http";
    import {RouterTestingModule} from "@angular/router/testing";
    import {DataService} from "../../../services/data.service";
    import {of} from "rxjs/internal/observable/of";

    describe('Component: admin-dialog', () => {

      let component: AdminDialogComponent;
      let fixture: ComponentFixture<AdminDialogComponent>;
      let translate: TranslateService;
      let dialog: MatDialog;
      let overlayContainer: OverlayContainer;
      let dataService: DataService;
      beforeEach(() => {


        TestBed.configureTestingModule({
          imports: [FormsModule, MatDialogModule, HttpClientModule,RouterTestingModule,TranslateModule.forRoot()],
          declarations: [AdminDialogComponent],
          providers: [TranslateService,
            { provide: MatDialogRef, useValue: {} },
            {
              provide: MAT_DIALOG_DATA, useValue: {
                isNew: false, // I guess it's boolean
                adminObj: {firstName: "AAAAAA", lastName: "AA", password: null, emailId: "[email protected]"}
              }
            },
            {provide: dataService, useValue: {}}],
          schemas: [NO_ERRORS_SCHEMA]
      });
        TestBed.overrideModule(BrowserDynamicTestingModule, {
          set: {
            entryComponents: [AdminDialogComponent]
          }
        });

        TestBed.compileComponents();

        // create component and test fixture
        fixture = TestBed.createComponent(AdminDialogComponent);

        // get test component from the fixture
        component = fixture.componentInstance;
       // component.ngOnInit();
      });
      beforeEach(inject([MatDialog, OverlayContainer],
        (d: MatDialog, oc: OverlayContainer) => {
          dialog = d;
          overlayContainer = oc;
        })
      );
      afterEach(() => {
        overlayContainer.ngOnDestroy();
      });
      it('should create', () => {
        expect(component).toBeTruthy();
      });
it('saveAdmin', () => {
    expect(component.saveAdmin()).toBeTruthy();
  });

    });

After fixing all the error i could find less overage for this .ts file as in screenshot. so how to over this subscribe code in unit testing

enter image description here

1

1 Answers

1
votes

If you would trace emailId property you find out that it's accessed in this line:

this.dataService.getAdminDetails(response.emailId).subscribe(

it's taken from response object which is directly passed into editAdmin method:

editAdmin(response){

and the place where editAdmin method is executed:

this.editAdmin(this.data.adminObj);

however you override that dependency in TestingModule with:

{ provide: MAT_DIALOG_DATA, useValue: []},

but value provided (empty array) is not right since it should have property adminObj.

Edit 1:

Change this:

{ provide: MAT_DIALOG_DATA, useValue: []},

to:

{
  provide: MAT_DIALOG_DATA, useValue: {
    isNew: false, // I guess it's boolean
    adminObj: {emailId: 'your value'}
  }
}

I've provide minimal properties that I found in code but If you access something more from this.data just add it. I also put here directly object after useValue but more flexible way could be to assign it to variable and change accordingly to test case.