Vinicius Lustosa
Vinicius Lustosa

Reputation: 64

How to create component with @input on unit tests Angular?

I'm having problems with creating a component for testing that has an @input. Inside the component it makes use of properties that are in the model feedback, I did the import in the test file but it displays errors. Can someone help me?

feedback-card.component.ts

import { Component, OnInit, Input, HostBinding } from '@angular/core';
import { FeedbackCommentsComponent } from '../feedback-comments/feedback-comments.component';
import { routerAnimation } from '../../../../utils/page.animation';
import { AuthService } from '../../../../services/auth.service';
import { Feedback } from '../../../../models/feedback';
import { FirestoreService } from '../../../../services/firestore.service';
import * as firebase from 'firebase/app';
import 'firebase/firestore';
import { first } from 'rxjs/operators';
import { MatBottomSheet } from '@angular/material/bottom-sheet';
import { MatSnackBar } from '@angular/material/snack-bar';

@Component({
  selector: 'app-feedback-card',
  templateUrl: './feedback-card.component.html',
  styleUrls: ['./feedback-card.component.scss'],
  animations: [routerAnimation]
})

export class FeedbackCardComponent implements OnInit {

  @HostBinding('@routerAnimation') routerAnimation = true;
  @Input() feedback: Feedback
  @Input() isAdmin = false
  input
  userId
...

feedback-card.component.spec.ts

import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { MatBottomSheet } from '@angular/material/bottom-sheet';
import { MatSnackBar } from '@angular/material/snack-bar';
import { FirestoreService } from '../../../../services/firestore.service';
import { AuthService } from '../../../../services/auth.service';
import { FeedbackCardComponent } from './feedback-card.component';
import { CommonModule } from '@angular/common';
import { Feedback } from '../../../../models/feedback';
import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AppModule } from 'src/app/app.module';
import { MatDialogModule } from '@angular/material/dialog';
import { TranslateFakeLoader, TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/compiler';
import { FunctionsService } from 'src/app/services/functions.service';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { Skill } from 'src/app/models/skill';

fdescribe('FeedbackCardComponent', () => {
  let component: FeedbackCardComponent;
  let fixture: ComponentFixture<FeedbackCardComponent>;

  beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
        imports: [
          CommonModule,
          ReactiveFormsModule,
          FormsModule,
          AppModule,
          MatDialogModule,
          TranslateModule.forRoot({
              loader: {
                provide: TranslateLoader,
                useClass: TranslateFakeLoader
              }
          })
      ],
      schemas: [
        CUSTOM_ELEMENTS_SCHEMA
      ],
      declarations: [ 
        FeedbackCardComponent,
      ],
      providers: [
        FirestoreService
        MatSnackBar,
        MatProgressBarModule,
        FirestoreService,
        FunctionsService,
        TranslateService,
    ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(FeedbackCardComponent);
    fireStoreServiceMock = TestBed.inject(FirestoreService);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

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

This is the error log

TypeError: Cannot read property 'skill' of undefined
TypeError: Cannot read property 'skill' of undefined
    at FeedbackCardComponent_Template (ng:///FeedbackCardComponent.js:305:52)
    at executeTemplate (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9545:1)
    at refreshView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9414:1)
    at refreshComponent (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10580:1)
    at refreshChildComponents (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9211:1)
    at refreshView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9464:1)
    at renderComponentOrTemplate (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9528:1)
    at tickRootContext (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10754:1)
    at detectChangesInRootView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10779:1)
    at RootViewRef.detectChanges (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:22792:1)

Upvotes: 1

Views: 4847

Answers (1)

AliF50
AliF50

Reputation: 18849

The first fixture.detectChanges() calls ngOnInit so make sure your inputs are defined before then.

Try this:

beforeEach(() => {
    fixture = TestBed.createComponent(FeedbackCardComponent);
    fireStoreServiceMock = TestBed.inject(FirestoreService);
    component = fixture.componentInstance;
    component.feedback = // mock your feedback
    component.isAdmin = // optional because I see it is set to false, but you can mock it here too.
    fixture.detectChanges();
  });

Upvotes: 7

Related Questions