Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular testing Cannot read property 'name' of undefined

I've got a ModalComponent which accepts some properties from parent via @Input.

That causes the problem with testing

TypeError: Cannot read property 'name' of undefined

Name is being used in ngOnInit and should come from @Input displayeddata.

How do I pass it in my unit test?

Currently my test looks so

beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [ModalComponent, FilterComponent],
            imports: [ReactiveFormsModule, TranslateModule]
        })
            .compileComponents();
    }));

    beforeEach(async () => {
    fixture = TestBed.createComponent(ModalComponent);
    component = fixture.componentInstance;
    component.displayeddata = {
        name: 'One component',
        caption: 'Caption',
        componentName: 'TextareaComponent'
    };
    fixture.detectChanges();
});

it('should create', async () => {
    fixture.detectChanges();
    fixture.whenStable().then(() => {
        expect(component).toBeTruthy();
    });
});

That is the one test for my component and fails.

Update #1

Here is what I get on console.log(this.displayeddata);

Object
caption: "Caption"
component: "TextareaComponent"
name: "One component"

I also changed my code a bit (updated code) and now getting a new error TypeError: Cannot read property 'caption' of undefined

Update #2

modal.component.ts

export class ModalComponent implements OnInit {
@Input() showenpunctsnow;
@Input() displayeddata;
@Output() ComponentParametrsInputs: FormGroup = this.fb.group({
        name: ['', Validators.required],
        caption: ['', Validators.required],
        component: ['']
    });
constructor(private fb: FormBuilder) {}
ngOnInit() {

        console.log(this.displayeddata);

        this.ComponentParametrsInputs = this.fb.group({
            name: [this.displayeddata.name, Validators.required],
            caption: [this.displayeddata.caption, Validators.required],
            component: [this.displayeddata.componentName]
        });
    }
like image 728
Sergey Avatar asked Oct 31 '18 14:10

Sergey


Video Answer


3 Answers

Just gonna comment here even though this has already been solved in case anyone else runs into the same issue.

The issue most likely arrises from the html file rather than the unit test or component itself.

Within your html file:

  • Go to where you are using {variable}.name
  • within the respective section, div, or otherwise add *ngIf="{variable}"

This should check to see if this variable exists first. Then within your unit tests, simply do:

it('should create', ()=> {
   expect(component).toBeTruthy();
}

If you want to then check to see if the component will load with a specified name:

it('should create with specified name', () => {
   component.{variable}.name = 'Foo'

   fixture.detectChanges();
   expect(fixture.debugElement.nativeElement.innerHTML)
    .toContain(component.{variable}.name)
}
like image 77
SirajB Avatar answered Oct 17 '22 02:10

SirajB


I am putting this update as an "answer" because it won't fit in a comment. :)

Thank you for posting the component logic. With this information I had enough to throw together a quick stackblitz testing environment here: https://stackblitz.com/edit/stackoverflow-q-53086352?file=app%2Fmy.component.spec.ts

I had to deviate slightly from your code above in the following ways:

  • Both FilterComponent and TranslateModule are commented out since I don't have access to that code and you aren't testing them at this point.
  • You were using 'async' incorrectly in the second 'beforeEach' function as well as the 'it' spec - you weren't wrapping the arrow function inside an async, you were using the async reserved word to define the function as asynchronous - part of async/await, which is a totally different thing. You need another set of brackets after the word async to call it as the angular/core/testing function and not the javascript reserved word. :)
  • I added a simple template which displays one of the displaydata variables

However, the surprising thing was when I put your code in stackblitz - it all works just fine! So clearly the issue you are running into is being caused by some code that is outside of what you have presented so far.

My suggestion for next steps:

  • Either edit the existing stackblitz I put together or fork it to your own account to play with it.
  • add additional code/data until the problem reoccurs. This will point to where the actual error is.

Good luck!

like image 25
dmcgrandle Avatar answered Oct 17 '22 00:10

dmcgrandle


Your approach is good, I think it's failing because of the async. Try this :

it('should create', () => {
    component.displayeddata = {
        name: 'One component',
        caption: 'Caption',
        component: 'TextareaComponent'
    };
    fixture.detectChanges();
    expect(component).toBeTruthy();
});
like image 1
Enima Avatar answered Oct 17 '22 01:10

Enima