Home > Back-end >  How to test subscribe angular method inside a method in component using Jest
How to test subscribe angular method inside a method in component using Jest

Time:08-26

I'm having such a hard time to test a method with jest. Still learning it I'm trying to mock the result so, but I get undefined.

TS:

 getEntity() {
    this.referentialService?.getBusinessList(localStorage.getItem('entity')).subscribe(response => {
      this.listOperationalUnit = response.filter((item:any) => item.entityType === 1 || item.entityType === 3);
      this.form.controls['entityCode'].setValue(`${response[0].id} - ${response[0].label}`);
    });
  }

SPEC:

describe('ModalCreateUserComponent', () => {
  let component: ModalCreateUserComponent;
  let fixture: ComponentFixture<ModalCreateUserComponent>;
  let referentialService: ReferentialService

  class ReferentialServiceStub {
    public getBusinessList(): any {
      return of(
        [
          { id: 123, label: 'Teste', entityType: 1 },
          { id: 456, label: 'Teste456', entityType: 2 },
          { id: 789, label: 'Teste789', entityType: 3 },
        ]
      );
    }
  }

  beforeEach(async () => {

    await TestBed.configureTestingModule({
      declarations: [ModalCreateUserComponent],
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
      providers: [
        { provide: ReferentialService, useClass: ReferentialServiceStub }
      ],
      imports: [
        BrowserAnimationsModule,
        ReactiveFormsModule,
        RouterTestingModule,
        HttpClientTestingModule,
      ]
    })
      .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(ModalCreateUserComponent);
    component = fixture.componentInstance;
    referentialService = TestBed.inject(ReferentialService);
  });

  it('should test', () => {
    const expectResponse = [
      { id: 123, label: 'Teste', entityType: 1 },
      { id: 789, label: 'Teste789', entityType: 3 },
    ]
    
    component.getEntity();
    expect(component.listOperationalUnit).toBe(expectResponse)
    expect(component.form.get('entityCode')?.value).toBe('123 - teste');
  });

 
}

Expected: [{"entityType": 1, "id": 123, "label": "Teste"}, {"entityType": 3, "id": 789, "label": "Teste789"}]

Received: undefined

I also tried using Spy On

 it('should test', () => {
    const expectResponse = [
      { id: 123, label: 'Teste', entityType: 1 },
      { id: 789, label: 'Teste789', entityType: 3 },
    ]
    
    const spy = jest.spyOn(translateService, 'getBusinessList').mockReturnValue(expectResponse);

    expect(component.listOperationalUnit).toBe(expectResponse)
    expect(component.newUserForm.get('entityCode')?.value).toBe('123 - teste');
  });

but got the error :

No overload matches this call ´

I also tried:

  it('should test', () => {
    const spy = jest.spyOn(referentialService, 'getBusinessList'); 
    component.getEntity();
    expect(spy).toHaveBeenCalledWith();
  });

but got the error :

Expected: called with 0 arguments Received: null

I will be very glad if someone send me some documentation to read about test subscribe with Jest and Angular, because it's been hard. =)

CodePudding user response:

I think you are really close to a solution. I would try to test the function like this:

it('should test', () => {
  const expectResponse = [
    { id: 123, label: 'Teste', entityType: 1 },
    { id: 789, label: 'Teste789', entityType: 3 },
  ]
  const spy = jest.spyOn(referentialService, 'getBusinessList').mockReturnValue(expectResponse); 
  
  component.getEntity();
  fixture.detectChanges();
  expect(spy).toHaveBeenCalled();
});

if your getBusinessList function returns an observable you need to mockReturn an observable containing your expectResponse with the rxjs of() function like this:

const spy = jest.spyOn(referentialService, 'getBusinessList').mockReturnValue(of(expectResponse)); 

Also because i noted your comment on one of the other solutions. you can easily set the values for your localStorage from inside your tests like this:

localStorage.setItem('entity', 'entity');

so for reference your test with returnType Observable would look like this:

it('should test', () => {
  localStorage.setItem('entity', 'entity');
  const expectResponse = [
    { id: 123, label: 'Teste', entityType: 1 },
    { id: 789, label: 'Teste789', entityType: 3 },
  ]
  const spy = jest.spyOn(referentialService, 'getBusinessList').mockReturnValue(of(expectResponse)); 

  component.getEntity();
  fixture.detectChanges();
  expect(spy).toHaveBeenCalled();
}); 

CodePudding user response:

What you have in your first example without the spyOn is correct, I think you just mispelled useClass. You have it as useclass but it should be useClass.

Also, you may need to use fakeAsync and tick.

// add fakeAsync wrapper here
it('should test', fakeAsync(() => {
    const expectResponse = [
      { id: 123, label: 'Teste', entityType: 1 },
      { id: 789, label: 'Teste789', entityType: 3 },
    ]
    
    component.getEntity();
    // add tick to ensure the `subscribe` in the component happens
    // before these assertions
    tick();
    expect(component.listOperationalUnit).toBe(expectResponse)
    expect(component.form.get('entityCode')?.value).toBe('123 - teste');
  }));

The test most likely pass without fakeAsync and tick but it could be good to get in the habit of using it.

  • Related