0

I am trying to write unit tests for my component but cannot seem to get it to work. My component looks like this:

import { Component, OnInit } from '@angular/core';
import {ModalController} from '@ionic/angular';
import {CheckInsProvider} from '../../providers/check-ins.service';
import * as _ from 'lodash'
import {WeighInsProvider} from '../../pages/clients/client-detail/providers/weigh-ins/weigh-ins.service';

@Component({
  selector: 'app-re-evaluation',
  templateUrl: './re-evaluation.component.html',
  styleUrls: ['./re-evaluation.component.scss'],
})
export class ReEvaluationComponent implements OnInit {
  programId: number;
  initialWeight: number;
  endingWeight: number;
  initialBodyFat: number;
  endingBodyFat: number;
  initialVisceralFat: number;
  endingVisceralFat: number;

  constructor( private modalCtrl: ModalController,
               private checkInsProvider: CheckInsProvider,
               private weighInsProvider: WeighInsProvider ) { }

  ngOnInit() {
    this.fetchWeights()
  }

  fetchWeights() {
    console.log("here", this.weighInsProvider.findFirstWithField('current_weight'))
    this.initialWeight = this.weighInsProvider.findFirstWithField('current_weight').current_weight
    this.endingWeight = this.weighInsProvider.findLastWithField('current_weight').current_weight

    this.initialBodyFat = this.weighInsProvider.findFirstWithField('body_fat').body_fat
    this.endingBodyFat = this.weighInsProvider.findLastWithField('body_fat').body_fat

    this.initialVisceralFat = this.weighInsProvider.findFirstWithField('visceral_fat').visceral_fat
    this.endingVisceralFat = this.weighInsProvider.findLastWithField('visceral_fat').visceral_fat
  }

  dismiss(): void {
    this.modalCtrl.dismiss()
  }
}

and my test looks like this:

describe('ReEvaluationComponent', () => {
  let component: ReEvaluationComponent;
  let fixture: ComponentFixture<ReEvaluationComponent>;
  let mockGlobalsService = jasmine.createSpyObj('GlobalsService', ['base_url'])
  let checkInsService: any;
  let weighInsService: any;
  let injector: TestBed;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ ReEvaluationComponent ],
      imports: [
        IonicModule.forRoot(),
        HttpClientTestingModule,
        RouterTestingModule,
      ],
      providers: [
        WeighInsProvider,
        {provide: GlobalsService, useValue: mockGlobalsService},
        {provide: PurchasesService, useValue: PurchasesServiceMock},
      ]
    }).compileComponents();

    fixture = TestBed.createComponent(ReEvaluationComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  }));

  beforeEach(() => {
    injector = getTestBed()
    checkInsService = injector.get(CheckInsProvider)
    weighInsService = injector.get(WeighInsProvider)
  })

  it('should create', () => {
    spyOn(weighInsService, 'findFirstWithField').and.returnValue({
        current_weight: 200,
        visceral_fat: 20,
        body_fat: 20
      })
    expect(component).toBeTruthy();
  });

  ...

And the should create test fails, stating:

ReEvaluationComponent should create FAILED
Failed: Cannot read properties of undefined (reading 'current_weight')

Which is strange to me because I thought my spy would return the value:

{
    current_weight: 200,
    visceral_fat: 20,
    body_fat: 20
}

What am I doing wrong?

1 Answer 1

1

I believe the problem is, that you are creating a spy too late. You are using current_weight in ngOnInit of your component.

Your component is created (and will run ngOnInit) before your first test, where you do spyOn.

Try to refactor your test as follows:

describe('ReEvaluationComponent', () => {
    let component: ReEvaluationComponent;
    let fixture: ComponentFixture<ReEvaluationComponent>;
    let mockGlobalsService = jasmine.createSpyObj('GlobalsService', ['base_url'])
    let checkInsService: any;
    let weighInsService: any;
    let injector: TestBed;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
        declarations: [ ReEvaluationComponent ],
        imports: [
            IonicModule.forRoot(),
            HttpClientTestingModule,
            RouterTestingModule,
        ],
        providers: [
            WeighInsProvider,
            {provide: GlobalsService, useValue: mockGlobalsService},
            {provide: PurchasesService, useValue: PurchasesServiceMock},
        ]
        }).compileComponents();
    }));

    beforeEach(() => {
        injector = getTestBed()
        checkInsService = injector.get(CheckInsProvider)
        weighInsService = injector.get(WeighInsProvider)

        spyOn(weighInsService, 'findFirstWithField').and.returnValue({
            current_weight: 200,
            visceral_fat: 20,
            body_fat: 20
        });

        spyOn(weighInsService, 'findLastWithField').and.returnValue({
            current_weight: 200,
            visceral_fat: 20,
            body_fat: 20
        });
    });

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

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

...

This will allow you to first set-up mock for your service and only then create a component, which uses the mocked service.

Sign up to request clarification or add additional context in comments.

3 Comments

No luck, same error. Though the print statement in fetchWeights() is now printing the correct object
Try now, I've updated the example. In the spec, there was missing a mock for findLastWithField, I've added it.
Ahhh that was it.... I can't believe it. Thanks for the help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.