jeudi 30 avril 2020

Test a function called within a *ngFor and a FormGroup in Angular?

I am trying to unit test an Angular application, but I have been facing some problems with the variables within the components.

Here I have a *ngFor and a FormGroup and each one of them is causing an issue when I run the test, the second one gives me these error: Cannot read property '0' of undefined, the first one also gives me the same error, but only if I define component.parentProps.activeStepIndexSkills as 0, if I pass to it any other value over 0 I'll get: Cannot read property 'textContent' of null.

my test script (I am testing 'function onGoToStep':

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

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      declarations: [ ListEditComponent ]
    })
    .compileComponents();
  });

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

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

  it('function onGoToStep', fakeAsync(() => {
    const i = 1
    component.parentProps =  { applicationsData: [''], editMode: 1,  activeStepIndexSkills: i}
    fixture.detectChanges();
    const compiled = fixture.debugElement.nativeElement
    expect(compiled.querySelector('.teste').textContent).toContain('teste');

  }))

});

This is a sample of my template:

<ng-container *ngIf="parentProps" >
  <div *ngIf="parentProps.editMode === 1" >
    <br />
    <form class="detalhes-container">
      <ng-container *ngFor="let info of parentProps.applicationsData; let i = index; trackBy: trackByFn">
        <!--Test container-->
        <ng-container *ngIf="i === parentProps.activeStepIndexSkills">
          <p id="teste" >teste</p>
        </ng-container>
        <!---->
        <div
          class="detalhes-bloco"
          *ngIf="parentProps.activeStepIndexSkills === i"
          [formGroup]="parentProps.masterFormEdit[i]"
        >
          <div
            class="detalhes-conhecimento-container"
            formGroupName="conhecimento"
          >
          <!-- <p class="teste" >teste</p> -->
          </div>
        </div>
      </ng-container>
    </form>
   </div>
</ng-container>

As it can be seen I have a test container before the FormGroup and a p tag after it, both for testing purposes. I realized that if I replace i for an integer and set component.parentProps.activeStepIndexSkills with the same value in my spec.ts file I can reach the element p inside the test container, what made me think that I have not been able to get the element because i doesn't exist inside the test, but I have not idea how to fix this. I tried to mock the value of i using component, but it doesn't work. So, is it my theory correct? If it is, how could I fix this?

But as I said, I also have a second problem with parentProps.masterFormEdit[i], which returns Cannot read property '0' of undefined, in this case I couldn't tell if the issue is with i or with masterForm, because I was trying to solve a problem at a time, but since I am here I believe it is worth try to get an answer for this as well.

There is one thing that made me even more confused, I have another component very similar to this one of the question and I am not getting none of these errors.

<div *ngIf="parentProps" class="detalhes-container">
  <div *ngFor="let info of parentProps.applicationsData; let i = index; trackBy: trackByFn">
    <ng-container *ngIf="i === parentProps.activeStepIndexSkills">
      <div class="detalhes-bloco">
        <thead class="detalhes-conhecimento-header">
          <th>Tecnologia</th>
          <th>Nível</th>
        </thead>
        <div class="detalhes-icons">
          <p class="modo-edicao-icon" *ngIf="parentProps.editMode === 1">MODO EDIÇÃO</p>
          <i class="material-icons edit-btn" (click)="onEdit()">edit</i>
        </div>
      </div>
    </ng-container>
  </div>
</div>

spec.ts:

it('function onEdit', fakeAsync(() => {
    component.parentProps =  { applicationsData: [''], activeStepIndexSkills: 0 }
    fixture.detectChanges();

    spyOn(component, 'onEdit');

    let button = fixture.debugElement.nativeElement.querySelector('.edit-btn');
    button.click();
    tick();
    expect(component.onEdit).toHaveBeenCalled();

  }))

As you can see I also have a *ngFor and a *ngIf using an i and it works fine.

Aucun commentaire:

Enregistrer un commentaire