Shankze
Shankze

Reputation: 4099

Run unit test with *ngFor and Input

I am new to Angular. I have created a component that displays buttons using *ngFor.

ts file:

        import { Component, OnInit, Input } from '@angular/core';

    @Component({
      selector: 'display-button',
      templateUrl: './display-button.component.html',
      styleUrls: ['./display-button.component.scss']
    })
    export class DisplayButtonComponent implements OnInit {

      @Input() compInput: any;
      buttons: any;

      constructor() { }

      ngOnInit() {
        if (this.compInput) {
          this.buttons = this.compInput.scriptButtonData.buttons;
        }
      }

      buttonClicked(selectedValue) {
        //do something
        }
      }
    }

html file:

<button class="scriptButton" *ngFor="let button of buttons" (click)="buttonClicked(button.value)" >{{button.name}}</button>

spec.ts file:

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { InlineScriptButtonComponent } from './display-button.component';
import {By} from '@angular/platform-browser';

describe('DisplayButtonComponent', () => {
  let component: DisplayButtonComponent;
  let fixture: ComponentFixture<DisplayButtonComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ DisplayButtonComponent]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(DisplayButtonComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  fit('should contain label', () => {
    component.compInput= {
      scriptButtonData: {
        type: "scriptButton",
        buttons: [
          {
            name: "Proceed",
            value: "Yes"
          },
          {
            name: "Cancel",
            value: "No"
          },
        ]
      },
      someOtherProperty: null,
    };
    fixture.detectChanges();
    let buttonLabels = fixture.debugElement.queryAll(By.css('scriptButton'));
    expect( buttonLabels.length).toBe(2);
  });

});

I am writing unit tests to test if 2 buttons are displayed. When I run the tests, it fails because buttonLabels.length is 0. Even if I am initialting the input variable compInput in the test, it seems to be null when it encounters the line

if (this.compInput) {

Why is this null? What am I doing wrong? Also, a way to cheat is by initializing the test this way:

component.buttons = [
  {
    name: "Proceed",
    value: "Yes"
  },
  {
    name: "Cancel",
    value: "No"
  },
]

Though the test passes by adding the above line, this is cheating as I am not testing the code in the ngOnInit function.

Why are the values I am setting component.compInput to not available to the test. What is the correct way to test this functionality?

Upvotes: 1

Views: 3462

Answers (2)

Jason Woods
Jason Woods

Reputation: 544

Call ngOnInit() from your test, otherwise it's done before you set component.compInput. Also look for document.getElementsByClass('scriptButton') to get your elements.

I would also NOT call your if statement directly from your ngOnInit() but put it in a method that's called from ngOnInit(). It's a stylistic thing that I personally like, keeps the lifecycle hooks a bit cleaner.

Here's your fit statement, with the updates.

fit('should contain label', () => {
    component.compInput = {
        scriptButtonData: {
        type: 'scriptButton',
        buttons: [
        {
          name: 'Proceed',
          value: 'Yes'
        },
        {
          name: 'Cancel',
          value: 'No'
        }
      ]
    },
    someOtherProperty: null
  };

  component.ngOnInit();  //need to invoke ngOnInit()

  fixture.detectChanges();
  let buttonLabels = document.getElementsByClassName('scriptButton');
  expect(buttonLabels.length).toBe(2);
 });

Upvotes: 1

cat tourist
cat tourist

Reputation: 249

you're specifying the wrong CSS class, so it's not finding any buttons with that class. use 'scriptButton' instead.

Upvotes: 1

Related Questions