Cuando ejecuto las pruebas que obtengo, obtengo el error "TypeError: this.dashboardService.serviceAgents $ .pipe no es una función".

  • Código de página de ServiceDashboard como se muestra a continuación:

     import { Component } from '@angular/core';
     import { ServiceDashboardService } from '../services/service-dashboard.service';
     import { tap } from 'rxjs/operators';
     import { ServiceAgent } from '../interfaces/service-agent';
     @Component({
         selector: 'app-service-dashboard',
         templateUrl: './service-dashboard.page.html',
         styleUrls: ['./service-dashboard.page.css'],
     })
     export class ServiceDashboardPage {
         serviceAgentSlideOptions: any = {
             slidesPerView: 4
         };
         serviceAgents$ = this.dashboardService.serviceAgents$
             .pipe(
                 tap(serviceAgents => {
                     this.serviceAgentSlideOptions.slidesPerView = serviceAgents.length < 4 ? serviceAgents.length : 4;
                 })
             );
         constructor(private dashboardService: ServiceDashboardService) { }
     }  
  • A continuación se muestra el código de prueba unitario para ServiceDashboardPage.
      import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
      import { async, ComponentFixture, TestBed } from '@angular/core/testing';
      import { ServiceDashboardPage } from './service-dashboard.page';
      import { ServiceDashboardService } from '../services/service-dashboard.service';
      import { ServiceAgent } from '../interfaces/service-agent';
      import { of } from 'rxjs';
      describe('ServiceDashboardPage', () => {
          let component: ServiceDashboardPage;
          let fixture: ComponentFixture<ServiceDashboardPage>;
          let serviceDashboardServiceSpy: ServiceDashboardService;
          beforeEach(async(() => {
              serviceDashboardServiceSpy = jasmine.createSpyObj('ServiceDashboardService', 
           ['serviceAgents$']);
              TestBed.configureTestingModule({
                  declarations: [ServiceDashboardPage],
                  schemas: [CUSTOM_ELEMENTS_SCHEMA],
                  providers: [
                      { provide: ServiceDashboardService, useValue: serviceDashboardServiceSpy }
                  ]
              })
              .compileComponents();
          }));
          beforeEach(() => {
              fixture = TestBed.createComponent(ServiceDashboardPage);
              component = fixture.componentInstance;
              fixture.detectChanges();
          });
          it('should create', async(() => {
              (serviceDashboardServiceSpy.serviceAgents$ as unknown as 
           jasmine.Spy).and.returnValue(of([] as ServiceAgent[]));
              expect(component).toBeTruthy();
          }));
      });  
2
Kiran Kumar P 14 oct. 2019 a las 13:48

1 respuesta

La mejor respuesta

Hay una serie de problemas con su código tal como está escrito. Como se señaló en los comentarios anteriores, claramente desea un Observable en el servicio, pero el comando:

serviceDashboardServiceSpy = jasmine.createSpyObj('ServiceDashboardService', ['serviceAgents$']);

Creará serviceAgents$ como una función y no como un Observable.

Pero solo cambiar eso no hará que su código sea comprobable, porque querrá cambiar el valor que devuelve ese Observable y probar para ver que su componente está reaccionando correctamente a esos cambios. Para eso, necesitará refactorizar su código. El motivo de la refactorización es porque la forma en que está configurando su Observable en el componente definiéndolo inmediatamente significa que es muy difícil cambiar el valor y probar fácilmente. Sin embargo, simplemente mover la asignación a ngOnInit() hará que esto sea mucho más fácil de probar.

Luego, necesita mover fixture.detectChanges() fuera de beforeEach() y dentro de la especificación misma (la función it()). La razón de esto es porque fixture.detectChanges() ejecutará ngOnInit() que acabamos de configurar, y queremos controlar más cuidadosamente cuándo se llama.

Finalmente, necesitas configurar algo para simular tu clase de servicio; estabas intentando usar el objeto serviceDashboardServiceSpy para hacerlo, pero en este caso prefiero usar una clase simulada en lugar de un objeto espía. La razón de esto es porque está definiendo serviceAgents$ dentro de la clase de servicio real como una PROPIEDAD y no como una función. Esto hace que sea un poco más complicado de probar y, en mi opinión, configurar una clase simulada en lugar de un objeto espía lo hace un poco más fácil.

Teniendo todas estas cosas en cuenta, configuré este StackBlitz para mostrar que sus pruebas pasaron.

También agregué un par de pruebas para mostrar cómo cambiar el valor en el servicio Observable cambia el valor asociado dentro de su componente.

Aquí está el .spec de ese StackBlitz:

class MockServiceDashboardService {
  get serviceAgents$() {
    return of({length: 2});
  }
}

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

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [ServiceDashboardPage],
            schemas: [CUSTOM_ELEMENTS_SCHEMA],
            providers: [
                { provide: ServiceDashboardService, useClass: MockServiceDashboardService }
            ]
        })
        .compileComponents();
    }));
    beforeEach(() => {
        fixture = TestBed.createComponent(ServiceDashboardPage);
        component = fixture.componentInstance;
    });
    it('should create', () => {
      fixture.detectChanges();
      expect(component).toBeTruthy();
    });
    it('should have length of 2', () => {
      fixture.detectChanges();
      expect(component.serviceAgentSlideOptions.slidesPerView).toEqual(2);
    });
    it('should have a length of 3', () => {
      let dService = TestBed.get(ServiceDashboardService);
      spyOnProperty(dService, 'serviceAgents$').and.returnValue(of({length: 3}))
      fixture.detectChanges();
      expect(component.serviceAgentSlideOptions.slidesPerView).toEqual(3);
    });
}); 
2
dmcgrandle 15 oct. 2019 a las 19:27