How to provide service mock in SpectatorRouting

1.7k views Asked by At

I implemented a test using Spectator for the Angular component. Try to find a solution to mocking service with SpectatorRouting. I have simple service like the below:

export class ProductService {
  constructor(private http: HttpClient) {}

  getProduct(productId: string): Observable<Product>;
}

and I have the component like below:

export class ProductComponent {
  product$: Observable<boolean | Product>;

  readonly routes = routes;

  constructor(
    private route: ActivatedRoute,
    private productService: ProductService,
    private router: Router
  ) {

    this.product$ = this.route.paramMap.pipe(
      map((params) => params.get('id')),
      switchMap((val) => productService.getProduct(val)),
      catchError(() => this.router.navigate([routes.notFoundPage]))
    );
  }
}

and I can't find a pretty solution to return value by method mock ProductService. I implement a solution but this is ugly :(.

const productService = {
  getProduct: () => of({}),
};

describe('ProductComponentSpectator', () => {
  let spectator: SpectatorRouting<ProductComponent>;
  const createComponent = createRoutingFactory({
    component: ProductComponent,
    params: { id: '100' },
    declarations: [
      MainProductComponent,
      DetailsProductComponent,
      SpanTooltipComponent,
    ],
    imports: [HttpClientTestingModule, RouterTestingModule],
    providers: [mockProvider(ProductService, productService)],
  });

  beforeEach(() => {
    spyOn(productService, 'getProduct').and.returnValue(of(getProduct()));
    spectator = createComponent();
  });

  it('should get brand name', () => {
    expect(spectator.query('.product-brand')).toHaveExactText('Asus');
  });
});

function getProduct(): Product {
  return {
    productId: '100',
    brand: 'Asus',
  } as Product;
}

I have doubt with this solution, for me, it is a strange approach with creating const service on top of the test and next spyOn the same method. My intuition tells me, that this mock should be defined completely in providers (with method etc). Spectator probably provides a more friendly approach to mocking service for SpectatorRouting, but I didn't find it.

Thanks for your help.

1

There are 1 answers

0
satanTime On BEST ANSWER

if you want to mock it - you can additionally install ng-mocks package for that, then you would not need spyOn and getProduct.

describe('ProductComponentSpectator', () => {
  let spectator: SpectatorRouting<ProductComponent>;
  const createComponent = createRoutingFactory({
    component: ProductComponent,
    params: { id: '100' },
    declarations: [
      MainProductComponent,
      DetailsProductComponent,
      SpanTooltipComponent,
    ],
    imports: [HttpClientTestingModule, RouterTestingModule],
    providers: [
      // MockProvider from ng-mocks (capital M)
      MockProvider(ProductService, {
        getProduct: () => of({
          productId: '100',
          brand: 'Asus',
        } as Product),
      }),
    ],
  });

  beforeEach(() => {
    spectator = createComponent();
  });

  it('should get brand name', () => {
    expect(spectator.query('.product-brand')).toHaveExactText('Asus');
  });
});